diff options
1261 files changed, 151290 insertions, 127056 deletions
@@ -1,4 +1,4 @@ -Copyright (c) 2000-2005 The Regents of The University of Michigan +Copyright (c) 2000-2006 The Regents of The University of Michigan All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/SConscript b/SConscript deleted file mode 100644 index 3ccd66571..000000000 --- a/SConscript +++ /dev/null @@ -1,420 +0,0 @@ -# -*- mode:python -*- - -# 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. - -import os -import sys -from os.path import isdir - -# This file defines how to build a particular configuration of M5 -# based on variable settings in the 'env' build environment. - -# Import build environment variable from SConstruct. -Import('env') - -################################################### -# -# Define needed sources. -# -################################################### - -# Base sources used by all configurations. - -base_sources = Split(''' - base/circlebuf.cc - base/copyright.cc - base/cprintf.cc - base/embedfile.cc - base/fast_alloc.cc - base/fifo_buffer.cc - base/hostinfo.cc - base/hybrid_pred.cc - base/inifile.cc - base/intmath.cc - base/match.cc - base/misc.cc - base/output.cc - base/pollevent.cc - base/range.cc - base/random.cc - base/sat_counter.cc - base/socket.cc - base/statistics.cc - base/str.cc - base/time.cc - base/trace.cc - base/traceflags.cc - base/userinfo.cc - base/compression/lzss_compression.cc - base/loader/aout_object.cc - base/loader/ecoff_object.cc - base/loader/elf_object.cc - base/loader/object_file.cc - base/loader/symtab.cc - base/stats/events.cc - base/stats/statdb.cc - base/stats/visit.cc - base/stats/text.cc - - cpu/activity.cc - cpu/base.cc - cpu/base_dyn_inst.cc - cpu/cpu_exec_context.cc - cpu/exetrace.cc - cpu/pc_event.cc - cpu/quiesce_event.cc - cpu/static_inst.cc - cpu/sampler/sampler.cc - cpu/trace/reader/mem_trace_reader.cc - cpu/trace/reader/ibm_reader.cc - cpu/trace/reader/itx_reader.cc - cpu/trace/reader/m5_reader.cc - cpu/trace/opt_cpu.cc - cpu/trace/trace_cpu.cc - - encumbered/mem/functional/main.cc - - mem/base_hier.cc - mem/base_mem.cc - mem/hier_params.cc - mem/mem_cmd.cc - mem/mem_debug.cc - mem/mem_req.cc - mem/memory_interface.cc - mem/bus/base_interface.cc - mem/bus/bus.cc - mem/bus/bus_bridge.cc - mem/bus/bus_bridge_master.cc - mem/bus/bus_bridge_slave.cc - mem/bus/bus_interface.cc - mem/bus/dma_bus_interface.cc - mem/bus/dma_interface.cc - mem/bus/master_interface.cc - mem/bus/slave_interface.cc - mem/cache/base_cache.cc - mem/cache/cache.cc - mem/cache/cache_builder.cc - mem/cache/coherence/coherence_protocol.cc - mem/cache/coherence/uni_coherence.cc - mem/cache/miss/blocking_buffer.cc - mem/cache/miss/miss_queue.cc - mem/cache/miss/mshr.cc - mem/cache/miss/mshr_queue.cc - mem/cache/prefetch/base_prefetcher.cc - mem/cache/prefetch/prefetcher.cc - mem/cache/prefetch/tagged_prefetcher.cc - mem/cache/tags/base_tags.cc - mem/cache/tags/cache_tags.cc - mem/cache/tags/fa_lru.cc - mem/cache/tags/iic.cc - mem/cache/tags/lru.cc - mem/cache/tags/repl/gen.cc - mem/cache/tags/repl/repl.cc - mem/cache/tags/split.cc - mem/cache/tags/split_lru.cc - mem/cache/tags/split_lifo.cc - mem/functional/functional.cc - mem/timing/base_memory.cc - mem/timing/dram_memory.cc - mem/timing/dram_mem_bank.cc - mem/timing/dram_memory_builder.cc - mem/timing/memory_builder.cc - mem/timing/simple_mem_bank.cc - mem/trace/itx_writer.cc - mem/trace/mem_trace_writer.cc - mem/trace/m5_writer.cc - - python/pyconfig.cc - python/embedded_py.cc - - sim/builder.cc - sim/configfile.cc - sim/debug.cc - sim/eventq.cc - sim/faults.cc - sim/main.cc - sim/param.cc - sim/profile.cc - sim/root.cc - sim/serialize.cc - sim/sim_events.cc - sim/sim_exit.cc - sim/sim_object.cc - sim/startup.cc - sim/stat_context.cc - sim/stat_control.cc - sim/trace_context.cc - ''') - -# Old FullCPU sources -full_cpu_sources = Split(''' - encumbered/cpu/full/bpred.cc - encumbered/cpu/full/commit.cc - encumbered/cpu/full/cpu.cc - encumbered/cpu/full/create_vector.cc - encumbered/cpu/full/cv_spec_state.cc - encumbered/cpu/full/dd_queue.cc - encumbered/cpu/full/dep_link.cc - encumbered/cpu/full/dispatch.cc - encumbered/cpu/full/dyn_inst.cc - encumbered/cpu/full/execute.cc - encumbered/cpu/full/fetch.cc - encumbered/cpu/full/floss_reasons.cc - encumbered/cpu/full/fu_pool.cc - encumbered/cpu/full/inst_fifo.cc - encumbered/cpu/full/instpipe.cc - encumbered/cpu/full/issue.cc - encumbered/cpu/full/ls_queue.cc - encumbered/cpu/full/machine_queue.cc - encumbered/cpu/full/pipetrace.cc - encumbered/cpu/full/readyq.cc - encumbered/cpu/full/reg_info.cc - encumbered/cpu/full/rob_station.cc - encumbered/cpu/full/spec_memory.cc - encumbered/cpu/full/spec_state.cc - encumbered/cpu/full/storebuffer.cc - encumbered/cpu/full/writeback.cc - encumbered/cpu/full/iq/iq_station.cc - encumbered/cpu/full/iq/iqueue.cc - encumbered/cpu/full/iq/segmented/chain_info.cc - encumbered/cpu/full/iq/segmented/chain_wire.cc - encumbered/cpu/full/iq/segmented/iq_seg.cc - encumbered/cpu/full/iq/segmented/iq_segmented.cc - encumbered/cpu/full/iq/segmented/seg_chain.cc - encumbered/cpu/full/iq/seznec/iq_seznec.cc - encumbered/cpu/full/iq/standard/iq_standard.cc - ''') - -# MySql sources -mysql_sources = Split(''' - base/mysql.cc - base/stats/mysql.cc - ''') - -# Full-system sources -full_system_sources = Split(''' - base/crc.cc - base/inet.cc - base/remote_gdb.cc - - cpu/intr_control.cc - cpu/profile.cc - - dev/alpha_console.cc - dev/baddev.cc - dev/simconsole.cc - dev/disk_image.cc - dev/etherbus.cc - dev/etherdump.cc - dev/etherint.cc - dev/etherlink.cc - dev/etherpkt.cc - dev/ethertap.cc - dev/ide_ctrl.cc - dev/ide_disk.cc - dev/io_device.cc - dev/ns_gige.cc - dev/pciconfigall.cc - dev/pcidev.cc - dev/pcifake.cc - dev/pktfifo.cc - dev/platform.cc - dev/sinic.cc - dev/simple_disk.cc - dev/tsunami.cc - dev/tsunami_cchip.cc - dev/isa_fake.cc - dev/tsunami_io.cc - dev/tsunami_pchip.cc - dev/uart.cc - dev/uart8250.cc - - kern/kernel_stats.cc - kern/system_events.cc - kern/linux/events.cc - kern/linux/linux_syscalls.cc - kern/linux/printk.cc - kern/tru64/dump_mbuf.cc - kern/tru64/printf.cc - kern/tru64/tru64_events.cc - kern/tru64/tru64_syscalls.cc - - mem/functional/memory_control.cc - mem/functional/physical.cc - - sim/system.cc - sim/pseudo_inst.cc - ''') - -# turbolaser encumbered sources -turbolaser_sources = Split(''' - encumbered/dev/dma.cc - encumbered/dev/etherdev.cc - encumbered/dev/scsi.cc - encumbered/dev/scsi_ctrl.cc - encumbered/dev/scsi_disk.cc - encumbered/dev/scsi_none.cc - encumbered/dev/tlaser_clock.cc - encumbered/dev/tlaser_ipi.cc - encumbered/dev/tlaser_mbox.cc - encumbered/dev/tlaser_mc146818.cc - encumbered/dev/tlaser_node.cc - encumbered/dev/tlaser_pcia.cc - encumbered/dev/tlaser_pcidev.cc - encumbered/dev/tlaser_serial.cc - encumbered/dev/turbolaser.cc - encumbered/dev/uart8530.cc - ''') - -# Syscall emulation (non-full-system) sources -syscall_emulation_sources = Split(''' - cpu/memtest/memtest.cc - encumbered/eio/eio.cc - encumbered/eio/exolex.cc - encumbered/eio/libexo.cc - kern/linux/linux.cc - kern/tru64/tru64.cc - sim/process.cc - sim/syscall_emul.cc - ''') - -# Add a flag defining what THE_ISA should be for all compilation -env.Append(CPPDEFINES=[('THE_ISA','%s_ISA' % env['TARGET_ISA'].upper())]) - -arch_sources = SConscript('arch/SConscript', - exports = 'env', duplicate = False) - -cpu_sources = SConscript('cpu/SConscript', - exports = 'env', duplicate = False) - -# This is outside of cpu/SConscript since the source directory isn't -# underneath 'cpu'. -if 'FullCPU' in env['CPU_MODELS']: - cpu_sources += full_cpu_sources - -# Set up complete list of sources based on configuration. -sources = base_sources + arch_sources + cpu_sources - -if env['FULL_SYSTEM']: - sources += full_system_sources - if env['ALPHA_TLASER']: - sources += turbolaser_sources -else: - sources += syscall_emulation_sources - -if env['USE_MYSQL']: - sources += mysql_sources - -for opt in env.ExportOptions: - env.ConfigFile(opt) - -################################################### -# -# Special build rules. -# -################################################### - -# base/traceflags.{cc,hh} are generated from base/traceflags.py. -# $TARGET.base will expand to "<build-dir>/base/traceflags". -env.Command(Split('base/traceflags.hh base/traceflags.cc'), - 'base/traceflags.py', - 'python $SOURCE $TARGET.base') - -# libelf build is described in its own SConscript file. -# SConscript-local is the per-config build, which just copies some -# header files into a place where they can be found. -SConscript('libelf/SConscript-local', exports = 'env', duplicate=0) -SConscript('python/SConscript', exports = ['env'], duplicate=0) - -# This function adds the specified sources to the given build -# environment, and returns a list of all the corresponding SCons -# Object nodes (including an extra one for date.cc). We explicitly -# add the Object nodes so we can set up special dependencies for -# date.cc. -def make_objs(sources, env): - objs = [env.Object(s) for s in sources] - # make date.cc depend on all other objects so it always gets - # recompiled whenever anything else does - date_obj = env.Object('base/date.cc') - env.Depends(date_obj, objs) - objs.append(date_obj) - return objs - -################################################### -# -# Define binaries. Each different build type (debug, opt, etc.) gets -# a slightly different build environment. -# -################################################### - -# Include file paths are rooted in this directory. SCons will -# automatically expand '.' to refer to both the source directory and -# the corresponding build directory to pick up generated include -# files. -env.Append(CPPPATH='.') -env.Append(CPPPATH='./libelf') - -# Debug binary -debugEnv = env.Copy(OBJSUFFIX='.do') -debugEnv.Label = 'debug' -debugEnv.Append(CCFLAGS=Split('-g -gdwarf-2 -O0')) -debugEnv.Append(CPPDEFINES='DEBUG') -tlist = debugEnv.Program(target = 'm5.debug', - source = make_objs(sources, debugEnv)) -debugEnv.M5Binary = tlist[0] - -# Optimized binary -optEnv = env.Copy() -optEnv.Label = 'opt' -optEnv.Append(CCFLAGS=Split('-g -O5')) -tlist = optEnv.Program(target = 'm5.opt', - source = make_objs(sources, optEnv)) -optEnv.M5Binary = tlist[0] - -# "Fast" binary -fastEnv = env.Copy(OBJSUFFIX='.fo') -fastEnv.Label = 'fast' -fastEnv.Append(CCFLAGS=Split('-O5')) -fastEnv.Append(CPPDEFINES='NDEBUG') -fastEnv.Program(target = 'm5.fast.unstripped', - source = make_objs(sources, fastEnv)) -tlist = fastEnv.Command(target = 'm5.fast', - source = 'm5.fast.unstripped', - action = 'strip $SOURCE -o $TARGET') -fastEnv.M5Binary = tlist[0] - -# Profiled binary -profEnv = env.Copy(OBJSUFFIX='.po') -profEnv.Label = 'prof' -profEnv.Append(CCFLAGS=Split('-O5 -g -pg'), LINKFLAGS='-pg') -tlist = profEnv.Program(target = 'm5.prof', - source = make_objs(sources, profEnv)) -profEnv.M5Binary = tlist[0] - -envList = [debugEnv, optEnv, fastEnv, profEnv] - -Return('envList') diff --git a/SConstruct b/SConstruct new file mode 100644 index 000000000..0cf15b1f9 --- /dev/null +++ b/SConstruct @@ -0,0 +1,505 @@ +# -*- mode:python -*- + +# 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: Steve Reinhardt + +################################################### +# +# SCons top-level build description (SConstruct) file. +# +# While in this directory ('m5'), just type 'scons' to build the default +# configuration (see below), or type 'scons build/<CONFIG>/<binary>' +# to build some other configuration (e.g., 'build/ALPHA_FS/m5.opt' for +# the optimized full-system version). +# +# You can build M5 in a different directory as long as there is a +# 'build/<CONFIG>' somewhere along the target path. The build system +# expdects that all configs under the same build directory are being +# built for the same host system. +# +# Examples: +# These two commands are equivalent. The '-u' option tells scons to +# search up the directory tree for this SConstruct file. +# % cd <path-to-src>/m5 ; scons build/ALPHA_FS/m5.debug +# % cd <path-to-src>/m5/build/ALPHA_FS; scons -u m5.debug +# These two commands are equivalent and demonstrate building in a +# directory outside of the source tree. The '-C' option tells scons +# to chdir to the specified directory to find this SConstruct file. +# % cd <path-to-src>/m5 ; scons /local/foo/build/ALPHA_FS/m5.debug +# % cd /local/foo/build/ALPHA_FS; scons -C <path-to-src>/m5 m5.debug +# +# You can use 'scons -H' to print scons options. If you're in this +# 'm5' directory (or use -u or -C to tell scons where to find this +# file), you can use 'scons -h' to print all the M5-specific build +# options as well. +# +################################################### + +# Python library imports +import sys +import os + +# Check for recent-enough Python and SCons versions. If your system's +# default installation of Python is not recent enough, you can use a +# non-default installation of the Python interpreter by either (1) +# rearranging your PATH so that scons finds the non-default 'python' +# first or (2) explicitly invoking an alternative interpreter on the +# scons script, e.g., "/usr/local/bin/python2.4 `which scons` [args]". +EnsurePythonVersion(2,4) + +# Ironically, SCons 0.96 dies if you give EnsureSconsVersion a +# 3-element version number. +min_scons_version = (0,96,91) +try: + EnsureSConsVersion(*min_scons_version) +except: + print "Error checking current SCons version." + print "SCons", ".".join(map(str,min_scons_version)), "or greater required." + Exit(2) + + +# The absolute path to the current directory (where this file lives). +ROOT = Dir('.').abspath + +# Paths to the M5 and external source trees. +SRCDIR = os.path.join(ROOT, 'src') + +# tell python where to find m5 python code +sys.path.append(os.path.join(ROOT, 'src/python')) + +################################################### +# +# Figure out which configurations to set up based on the path(s) of +# the target(s). +# +################################################### + +# Find default configuration & binary. +Default(os.environ.get('M5_DEFAULT_BINARY', 'build/ALPHA_SE/m5.debug')) + +# Ask SCons which directory it was invoked from. +launch_dir = GetLaunchDir() + +# Make targets relative to invocation directory +abs_targets = map(lambda x: os.path.normpath(os.path.join(launch_dir, str(x))), + BUILD_TARGETS) + +# helper function: find last occurrence of element in list +def rfind(l, elt, offs = -1): + for i in range(len(l)+offs, 0, -1): + if l[i] == elt: + return i + raise ValueError, "element not found" + +# Each target must have 'build' in the interior of the path; the +# directory below this will determine the build parameters. For +# example, for target 'foo/bar/build/ALPHA_SE/arch/alpha/blah.do' we +# recognize that ALPHA_SE specifies the configuration because it +# follow 'build' in the bulid path. + +# Generate a list of the unique build roots and configs that the +# collected targets reference. +build_paths = [] +build_root = None +for t in abs_targets: + path_dirs = t.split('/') + try: + build_top = rfind(path_dirs, 'build', -2) + except: + print "Error: no non-leaf 'build' dir found on target path", t + Exit(1) + this_build_root = os.path.join('/',*path_dirs[:build_top+1]) + if not build_root: + build_root = this_build_root + else: + if this_build_root != build_root: + print "Error: build targets not under same build root\n"\ + " %s\n %s" % (build_root, this_build_root) + Exit(1) + build_path = os.path.join('/',*path_dirs[:build_top+2]) + if build_path not in build_paths: + build_paths.append(build_path) + +################################################### +# +# Set up the default build environment. This environment is copied +# and modified according to each selected configuration. +# +################################################### + +env = Environment(ENV = os.environ, # inherit user's environment vars + ROOT = ROOT, + SRCDIR = SRCDIR) + +env.SConsignFile("sconsign") + +# Default duplicate option is to use hard links, but this messes up +# when you use emacs to edit a file in the target dir, as emacs moves +# file to file~ then copies to file, breaking the link. Symbolic +# (soft) links work better. +env.SetOption('duplicate', 'soft-copy') + +# I waffle on this setting... it does avoid a few painful but +# unnecessary builds, but it also seems to make trivial builds take +# noticeably longer. +if False: + env.TargetSignatures('content') + +# M5_PLY is used by isa_parser.py to find the PLY package. +env.Append(ENV = { 'M5_PLY' : Dir('ext/ply') }) + +# Set up default C++ compiler flags +env.Append(CCFLAGS='-pipe') +env.Append(CCFLAGS='-fno-strict-aliasing') +env.Append(CCFLAGS=Split('-Wall -Wno-sign-compare -Werror -Wundef')) +if sys.platform == 'cygwin': + # cygwin has some header file issues... + env.Append(CCFLAGS=Split("-Wno-uninitialized")) +env.Append(CPPPATH=[Dir('ext/dnet')]) + +# Find Python include and library directories for embedding the +# interpreter. For consistency, we will use the same Python +# installation used to run scons (and thus this script). If you want +# to link in an alternate version, see above for instructions on how +# to invoke scons with a different copy of the Python interpreter. + +# Get brief Python version name (e.g., "python2.4") for locating +# include & library files +py_version_name = 'python' + sys.version[:3] + +# include path, e.g. /usr/local/include/python2.4 +env.Append(CPPPATH = os.path.join(sys.exec_prefix, 'include', py_version_name)) +env.Append(LIBS = py_version_name) +# add library path too if it's not in the default place +if sys.exec_prefix != '/usr': + env.Append(LIBPATH = os.path.join(sys.exec_prefix, 'lib')) + +# Set up SWIG flags & scanner + +env.Append(SWIGFLAGS=Split('-c++ -python -modern $_CPPINCFLAGS')) + +import SCons.Scanner + +swig_inc_re = '^[ \t]*[%,#][ \t]*(?:include|import)[ \t]*(<|")([^>"]+)(>|")' + +swig_scanner = SCons.Scanner.ClassicCPP("SwigScan", ".i", "CPPPATH", + swig_inc_re) + +env.Append(SCANNERS = swig_scanner) + +# Other default libraries +env.Append(LIBS=['z']) + +# Platform-specific configuration. Note again that we assume that all +# builds under a given build root run on the same host platform. +conf = Configure(env, + conf_dir = os.path.join(build_root, '.scons_config'), + log_file = os.path.join(build_root, 'scons_config.log')) + +# Check for <fenv.h> (C99 FP environment control) +have_fenv = conf.CheckHeader('fenv.h', '<>') +if not have_fenv: + print "Warning: Header file <fenv.h> not found." + print " This host has no IEEE FP rounding mode control." + +# Check for mysql. +mysql_config = WhereIs('mysql_config') +have_mysql = mysql_config != None + +# Check MySQL version. +if have_mysql: + mysql_version = os.popen(mysql_config + ' --version').read() + mysql_version = mysql_version.split('.') + mysql_major = int(mysql_version[0]) + mysql_minor = int(mysql_version[1]) + # This version check is probably overly conservative, but it deals + # with the versions we have installed. + if mysql_major < 4 or (mysql_major == 4 and mysql_minor < 1): + print "Warning: MySQL v4.1 or newer required." + have_mysql = False + +# Set up mysql_config commands. +if have_mysql: + mysql_config_include = mysql_config + ' --include' + if os.system(mysql_config_include + ' > /dev/null') != 0: + # older mysql_config versions don't support --include, use + # --cflags instead + mysql_config_include = mysql_config + ' --cflags | sed s/\\\'//g' + # This seems to work in all versions + mysql_config_libs = mysql_config + ' --libs' + +env = conf.Finish() + +# Define the universe of supported ISAs +env['ALL_ISA_LIST'] = ['alpha', 'sparc', 'mips'] + +# Define the universe of supported CPU models +env['ALL_CPU_LIST'] = ['AtomicSimpleCPU', 'TimingSimpleCPU', + 'FullCPU', 'AlphaFullCPU', + 'OzoneSimpleCPU', 'OzoneCPU', 'CheckerCPU'] + +# Sticky options get saved in the options file so they persist from +# one invocation to the next (unless overridden, in which case the new +# value becomes sticky). +sticky_opts = Options(args=ARGUMENTS) +sticky_opts.AddOptions( + EnumOption('TARGET_ISA', 'Target ISA', 'alpha', env['ALL_ISA_LIST']), + BoolOption('FULL_SYSTEM', 'Full-system support', False), + # There's a bug in scons 0.96.1 that causes ListOptions with list + # values (more than one value) not to be able to be restored from + # a saved option file. If this causes trouble then upgrade to + # scons 0.96.90 or later. + ListOption('CPU_MODELS', 'CPU models', 'AtomicSimpleCPU,TimingSimpleCPU', + env['ALL_CPU_LIST']), + BoolOption('ALPHA_TLASER', + 'Model Alpha TurboLaser platform (vs. Tsunami)', False), + BoolOption('NO_FAST_ALLOC', 'Disable fast object allocator', False), + BoolOption('EFENCE', 'Link with Electric Fence malloc debugger', + False), + BoolOption('SS_COMPATIBLE_FP', + 'Make floating-point results compatible with SimpleScalar', + False), + BoolOption('USE_SSE2', + 'Compile for SSE2 (-msse2) to get IEEE FP on x86 hosts', + False), + BoolOption('USE_MYSQL', 'Use MySQL for stats output', have_mysql), + BoolOption('USE_FENV', 'Use <fenv.h> IEEE mode control', have_fenv), + ('CC', 'C compiler', os.environ.get('CC', env['CC'])), + ('CXX', 'C++ compiler', os.environ.get('CXX', env['CXX'])), + BoolOption('BATCH', 'Use batch pool for build and tests', False), + ('BATCH_CMD', 'Batch pool submission command name', 'qdo') + ) + +# Non-sticky options only apply to the current build. +nonsticky_opts = Options(args=ARGUMENTS) +nonsticky_opts.AddOptions( + BoolOption('update_ref', 'Update test reference outputs', False) + ) + +# These options get exported to #defines in config/*.hh (see m5/SConscript). +env.ExportOptions = ['FULL_SYSTEM', 'ALPHA_TLASER', 'USE_FENV', \ + 'USE_MYSQL', 'NO_FAST_ALLOC', 'SS_COMPATIBLE_FP'] + +# Define a handy 'no-op' action +def no_action(target, source, env): + return 0 + +env.NoAction = Action(no_action, None) + +################################################### +# +# Define a SCons builder for configuration flag headers. +# +################################################### + +# This function generates a config header file that #defines the +# option symbol to the current option setting (0 or 1). The source +# operands are the name of the option and a Value node containing the +# value of the option. +def build_config_file(target, source, env): + (option, value) = [s.get_contents() for s in source] + f = file(str(target[0]), 'w') + print >> f, '#define', option, value + f.close() + return None + +# Generate the message to be printed when building the config file. +def build_config_file_string(target, source, env): + (option, value) = [s.get_contents() for s in source] + return "Defining %s as %s in %s." % (option, value, target[0]) + +# Combine the two functions into a scons Action object. +config_action = Action(build_config_file, build_config_file_string) + +# The emitter munges the source & target node lists to reflect what +# we're really doing. +def config_emitter(target, source, env): + # extract option name from Builder arg + option = str(target[0]) + # True target is config header file + target = os.path.join('config', option.lower() + '.hh') + # Force value to 0/1 even if it's a Python bool + val = int(eval(str(env[option]))) + # Sources are option name & value (packaged in SCons Value nodes) + return ([target], [Value(option), Value(val)]) + +config_builder = Builder(emitter = config_emitter, action = config_action) + +env.Append(BUILDERS = { 'ConfigFile' : config_builder }) + +################################################### +# +# Define a SCons builder for copying files. This is used by the +# Python zipfile code in src/python/SConscript, but is placed up here +# since it's potentially more generally applicable. +# +################################################### + +copy_builder = Builder(action = Copy("$TARGET", "$SOURCE")) + +env.Append(BUILDERS = { 'CopyFile' : copy_builder }) + +################################################### +# +# Define a simple SCons builder to concatenate files. +# +# Used to append the Python zip archive to the executable. +# +################################################### + +concat_builder = Builder(action = Action(['cat $SOURCES > $TARGET', + 'chmod +x $TARGET'])) + +env.Append(BUILDERS = { 'Concat' : concat_builder }) + + +# base help text +help_text = ''' +Usage: scons [scons options] [build options] [target(s)] + +''' + +# libelf build is shared across all configs in the build root. +env.SConscript('ext/libelf/SConscript', + build_dir = os.path.join(build_root, 'libelf'), + exports = 'env') + +################################################### +# +# Define build environments for selected configurations. +# +################################################### + +# rename base env +base_env = env + +for build_path in build_paths: + print "Building in", build_path + # build_dir is the tail component of build path, and is used to + # determine the build parameters (e.g., 'ALPHA_SE') + (build_root, build_dir) = os.path.split(build_path) + # Make a copy of the build-root environment to use for this config. + env = base_env.Copy() + + # Set env options according to the build directory config. + sticky_opts.files = [] + # Options for $BUILD_ROOT/$BUILD_DIR are stored in + # $BUILD_ROOT/options/$BUILD_DIR so you can nuke + # $BUILD_ROOT/$BUILD_DIR without losing your options settings. + current_opts_file = os.path.join(build_root, 'options', build_dir) + if os.path.isfile(current_opts_file): + sticky_opts.files.append(current_opts_file) + print "Using saved options file %s" % current_opts_file + else: + # Build dir-specific options file doesn't exist. + + # Make sure the directory is there so we can create it later + opt_dir = os.path.dirname(current_opts_file) + if not os.path.isdir(opt_dir): + os.mkdir(opt_dir) + + # Get default build options from source tree. Options are + # normally determined by name of $BUILD_DIR, but can be + # overriden by 'default=' arg on command line. + default_opts_file = os.path.join('build_opts', + ARGUMENTS.get('default', build_dir)) + if os.path.isfile(default_opts_file): + sticky_opts.files.append(default_opts_file) + print "Options file %s not found,\n using defaults in %s" \ + % (current_opts_file, default_opts_file) + else: + print "Error: cannot find options file %s or %s" \ + % (current_opts_file, default_opts_file) + Exit(1) + + # Apply current option settings to env + sticky_opts.Update(env) + nonsticky_opts.Update(env) + + help_text += "Sticky options for %s:\n" % build_dir \ + + sticky_opts.GenerateHelpText(env) \ + + "\nNon-sticky options for %s:\n" % build_dir \ + + nonsticky_opts.GenerateHelpText(env) + + # Process option settings. + + if not have_fenv and env['USE_FENV']: + print "Warning: <fenv.h> not available; " \ + "forcing USE_FENV to False in", build_dir + "." + env['USE_FENV'] = False + + if not env['USE_FENV']: + print "Warning: No IEEE FP rounding mode control in", build_dir + "." + print " FP results may deviate slightly from other platforms." + + if env['EFENCE']: + env.Append(LIBS=['efence']) + + if env['USE_MYSQL']: + if not have_mysql: + print "Warning: MySQL not available; " \ + "forcing USE_MYSQL to False in", build_dir + "." + env['USE_MYSQL'] = False + else: + print "Compiling in", build_dir, "with MySQL support." + env.ParseConfig(mysql_config_libs) + env.ParseConfig(mysql_config_include) + + # Save sticky option settings back to current options file + sticky_opts.Save(current_opts_file, env) + + # Do this after we save setting back, or else we'll tack on an + # extra 'qdo' every time we run scons. + if env['BATCH']: + env['CC'] = env['BATCH_CMD'] + ' ' + env['CC'] + env['CXX'] = env['BATCH_CMD'] + ' ' + env['CXX'] + + if env['USE_SSE2']: + env.Append(CCFLAGS='-msse2') + + # The m5/SConscript file sets up the build rules in 'env' according + # to the configured options. It returns a list of environments, + # one for each variant build (debug, opt, etc.) + envList = SConscript('src/SConscript', build_dir = build_path, + exports = 'env') + + # Set up the regression tests for each build. +# for e in envList: +# SConscript('m5-test/SConscript', +# build_dir = os.path.join(build_dir, 'test', e.Label), +# exports = { 'env' : e }, duplicate = False) + +Help(help_text) + +################################################### +# +# Let SCons do its thing. At this point SCons will use the defined +# build environments to build the requested targets. +# +################################################### + diff --git a/arch/SConscript b/arch/SConscript deleted file mode 100644 index 92547c0ae..000000000 --- a/arch/SConscript +++ /dev/null @@ -1,146 +0,0 @@ -# -*- 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. - -import os.path - -# Import build environment variable from SConstruct. -Import('env') - -# Right now there are no source files immediately in this directory -sources = [] - -################################################################# -# -# ISA "switch header" generation. -# -# Auto-generate arch headers that include the right ISA-specific -# header based on the setting of THE_ISA preprocessor variable. -# -################################################################# - -# List of headers to generate -isa_switch_hdrs = Split(''' - isa_traits.hh - tlb.hh - process.hh - arguments.hh - stacktrace.hh - vtophys.hh - faults.hh - ''') - -# Generate the header. target[0] is the full path of the output -# header to generate. 'source' is a dummy variable, since we get the -# list of ISAs from env['ALL_ISA_LIST']. -def gen_switch_hdr(target, source, env): - fname = str(target[0]) - basename = os.path.basename(fname) - f = open(fname, 'w') - f.write('#include "arch/isa_specific.hh"\n') - cond = '#if' - for isa in env['ALL_ISA_LIST']: - f.write('%s THE_ISA == %s_ISA\n#include "arch/%s/%s"\n' - % (cond, isa.upper(), isa, basename)) - cond = '#elif' - f.write('#else\n#error "THE_ISA not set"\n#endif\n') - f.close() - return 0 - -# String to print when generating header -def gen_switch_hdr_string(target, source, env): - return "Generating ISA switch header " + str(target[0]) - -# Build SCons Action object. 'varlist' specifies env vars that this -# action depends on; when env['ALL_ISA_LIST'] changes these actions -# should get re-executed. -switch_hdr_action = Action(gen_switch_hdr, gen_switch_hdr_string, - varlist=['ALL_ISA_LIST']) - -# Instantiate actions for each header -for hdr in isa_switch_hdrs: - env.Command(hdr, [], switch_hdr_action) - -################################################################# -# -# Include architecture-specific files. -# -################################################################# - -# -# Build a SCons scanner for ISA files -# -import SCons.Scanner - -isa_scanner = SCons.Scanner.Classic("ISAScan", - [".isa", ".ISA"], - "SRCDIR", - r'^\s*##include\s+"([\w/.-]*)"') - -env.Append(SCANNERS = isa_scanner) - -# -# Now create a Builder object that uses isa_parser.py to generate C++ -# output from the ISA description (*.isa) files. -# - -# Convert to File node to fix path -isa_parser = File('isa_parser.py') -cpu_models_file = File('#m5/cpu/cpu_models.py') - -# This sucks in the defintions of the CpuModel objects. -execfile(cpu_models_file.srcnode().abspath) - -# Several files are generated from the ISA description. -# We always get the basic decoder and header file. -isa_desc_gen_files = Split('decoder.cc decoder.hh') -# We also get an execute file for each selected CPU model. -isa_desc_gen_files += [CpuModel.dict[cpu].filename - for cpu in env['CPU_MODELS']] - -# The emitter patches up the sources & targets to include the -# autogenerated files as targets and isa parser itself as a source. -def isa_desc_emitter(target, source, env): - return (isa_desc_gen_files, [isa_parser, cpu_models_file] + source) - -# Pieces are in place, so create the builder. -isa_desc_builder = Builder(action='python $SOURCES $TARGET.dir $CPU_MODELS', - emitter = isa_desc_emitter) - -env.Append(BUILDERS = { 'ISADesc' : isa_desc_builder }) - -# -# Now include other ISA-specific sources from the ISA subdirectories. -# - -isa = env['TARGET_ISA'] # someday this may be a list of ISAs - -# Let the target architecture define what additional sources it needs -sources += SConscript(os.path.join(isa, 'SConscript'), - exports = 'env', duplicate = False) - -Return('sources') diff --git a/arch/alpha/SConscript b/arch/alpha/SConscript deleted file mode 100644 index ed7fd3404..000000000 --- a/arch/alpha/SConscript +++ /dev/null @@ -1,91 +0,0 @@ -# -*- mode:python -*- - -# 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. - -import os -import sys -from os.path import isdir - -# This file defines how to build a particular configuration of M5 -# based on variable settings in the 'env' build environment. - -# Import build environment variable from SConstruct. -Import('env') - -################################################### -# -# Define needed sources. -# -################################################### - -# Base sources used by all configurations. -base_sources = Split(''' - faults.cc - isa_traits.cc - ''') - -# Full-system sources -full_system_sources = Split(''' - tlb.cc - arguments.cc - ev5.cc - osfpal.cc - stacktrace.cc - vtophys.cc - system.cc - freebsd/system.cc - linux/system.cc - tru64/system.cc - ''') - - -# Syscall emulation (non-full-system) sources -syscall_emulation_sources = Split(''' - linux/process.cc - tru64/process.cc - process.cc - ''') - -# Set up complete list of sources based on configuration. -sources = base_sources - -if env['FULL_SYSTEM']: - sources += full_system_sources -else: - sources += syscall_emulation_sources - -# Convert file names to SCons File objects. This takes care of the -# path relative to the top of the directory tree. -sources = [File(s) for s in sources] - -# Add in files generated by the ISA description. -isa_desc_files = env.ISADesc('isa/main.isa') -# Only non-header files need to be compiled. -isa_desc_sources = [f for f in isa_desc_files if not f.path.endswith('.hh')] -sources += isa_desc_sources - -Return('sources') diff --git a/arch/alpha/aout_machdep.h b/arch/alpha/aout_machdep.h deleted file mode 100644 index df9d9ac6a..000000000 --- a/arch/alpha/aout_machdep.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __AOUT_MACHDEP_H__ -#define __AOUT_MACHDEP_H__ - -/// -/// Funky Alpha 64-bit a.out header used for PAL code. -/// -struct aout_exechdr { - uint16_t magic; ///< magic number - uint16_t vstamp; ///< version stamp? - uint16_t bldrev; ///< ??? - uint16_t padcell; ///< padding - uint64_t tsize; ///< text segment size - uint64_t dsize; ///< data segment size - uint64_t bsize; ///< bss segment size - uint64_t entry; ///< entry point - uint64_t text_start; ///< text base address - uint64_t data_start; ///< data base address - uint64_t bss_start; ///< bss base address - uint32_t gprmask; ///< GPR mask (unused, AFAIK) - uint32_t fprmask; ///< FPR mask (unused, AFAIK) - uint64_t gp_value; ///< global pointer reg value -}; - -#define AOUT_LDPGSZ 8192 - -#define N_GETMAGIC(ex) ((ex).magic) - -#define N_BADMAX - -#define N_TXTADDR(ex) ((ex).text_start) -#define N_DATADDR(ex) ((ex).data_start) -#define N_BSSADDR(ex) ((ex).bss_start) - -#define N_TXTOFF(ex) \ - (N_GETMAGIC(ex) == ZMAGIC ? 0 : sizeof(struct aout_exechdr)) - -#define N_DATOFF(ex) N_ALIGN(ex, N_TXTOFF(ex) + (ex).tsize) - -#endif /* !__AOUT_MACHDEP_H__*/ diff --git a/arch/alpha/arguments.cc b/arch/alpha/arguments.cc deleted file mode 100644 index 019390aeb..000000000 --- a/arch/alpha/arguments.cc +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include "arch/alpha/arguments.hh" -#include "arch/alpha/vtophys.hh" -#include "cpu/exec_context.hh" -#include "mem/functional/physical.hh" - -using namespace AlphaISA; - -AlphaArguments::Data::~Data() -{ - while (!data.empty()) { - delete [] data.front(); - data.pop_front(); - } -} - -char * -AlphaArguments::Data::alloc(size_t size) -{ - char *buf = new char[size]; - data.push_back(buf); - return buf; -} - -uint64_t -AlphaArguments::getArg(bool fp) -{ - if (number < 6) { - if (fp) - return xc->readFloatRegInt(16 + number); - else - return xc->readIntReg(16 + number); - } else { - Addr sp = xc->readIntReg(30); - Addr paddr = vtophys(xc, sp + (number-6) * sizeof(uint64_t)); - return xc->getPhysMemPtr()->phys_read_qword(paddr); - } -} - diff --git a/arch/alpha/arguments.hh b/arch/alpha/arguments.hh deleted file mode 100644 index 75346bf58..000000000 --- a/arch/alpha/arguments.hh +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __ARGUMENTS_HH__ -#define __ARGUMENTS_HH__ - -#include <assert.h> - -#include "arch/alpha/vtophys.hh" -#include "base/refcnt.hh" -#include "sim/host.hh" - -class ExecContext; - -class AlphaArguments -{ - protected: - ExecContext *xc; - int number; - uint64_t getArg(bool fp = false); - - protected: - class Data : public RefCounted - { - public: - Data(){} - ~Data(); - - private: - std::list<char *> data; - - public: - char *alloc(size_t size); - }; - - RefCountingPtr<Data> data; - - public: - AlphaArguments(ExecContext *ctx, int n = 0) - : xc(ctx), number(n), data(NULL) - { assert(number >= 0); data = new Data;} - AlphaArguments(const AlphaArguments &args) - : xc(args.xc), number(args.number), data(args.data) {} - ~AlphaArguments() {} - - ExecContext *getExecContext() const { return xc; } - - const AlphaArguments &operator=(const AlphaArguments &args) { - xc = args.xc; - number = args.number; - data = args.data; - return *this; - } - - AlphaArguments &operator++() { - ++number; - assert(number >= 0); - return *this; - } - - AlphaArguments operator++(int) { - AlphaArguments args = *this; - ++number; - assert(number >= 0); - return args; - } - - AlphaArguments &operator--() { - --number; - assert(number >= 0); - return *this; - } - - AlphaArguments operator--(int) { - AlphaArguments args = *this; - --number; - assert(number >= 0); - return args; - } - - const AlphaArguments &operator+=(int index) { - number += index; - assert(number >= 0); - return *this; - } - - const AlphaArguments &operator-=(int index) { - number -= index; - assert(number >= 0); - return *this; - } - - AlphaArguments operator[](int index) { - return AlphaArguments(xc, index); - } - - template <class T> - operator T() { - assert(sizeof(T) <= sizeof(uint64_t)); - T data = static_cast<T>(getArg()); - return data; - } - - template <class T> - operator T *() { - T *buf = (T *)data->alloc(sizeof(T)); - CopyData(xc, buf, getArg(), sizeof(T)); - return buf; - } - - operator char *() { - char *buf = data->alloc(2048); - CopyString(xc, buf, getArg(), 2048); - return buf; - } -}; - -#endif // __ARGUMENTS_HH__ diff --git a/arch/alpha/ev5.cc b/arch/alpha/ev5.cc deleted file mode 100644 index f113a2767..000000000 --- a/arch/alpha/ev5.cc +++ /dev/null @@ -1,593 +0,0 @@ -/* - * 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. - */ - -#include "arch/alpha/tlb.hh" -#include "arch/alpha/isa_traits.hh" -#include "arch/alpha/osfpal.hh" -#include "base/kgdb.h" -#include "base/remote_gdb.hh" -#include "base/stats/events.hh" -#include "config/full_system.hh" -#include "cpu/base.hh" -#include "cpu/cpu_exec_context.hh" -#include "cpu/exec_context.hh" -#include "cpu/fast/cpu.hh" -#include "kern/kernel_stats.hh" -#include "sim/debug.hh" -#include "sim/sim_events.hh" - -#if FULL_SYSTEM - -using namespace EV5; - -//////////////////////////////////////////////////////////////////////// -// -// Machine dependent functions -// -void -AlphaISA::initCPU(ExecContext *xc, int cpuId) -{ - initIPRs(xc, cpuId); - - xc->setIntReg(16, cpuId); - xc->setIntReg(0, cpuId); - - xc->setPC(xc->readMiscReg(IPR_PAL_BASE) + (new ResetFault)->vect()); - xc->setNextPC(xc->readPC() + sizeof(MachInst)); -} - -//////////////////////////////////////////////////////////////////////// -// -// -// -void -AlphaISA::initIPRs(ExecContext *xc, int cpuId) -{ - for (int i = 0; i < NumInternalProcRegs; ++i) { - xc->setMiscReg(i, 0); - } - - xc->setMiscReg(IPR_PAL_BASE, PalBase); - xc->setMiscReg(IPR_MCSR, 0x6); - xc->setMiscReg(IPR_PALtemp16, cpuId); -} - - -template <class CPU> -void -AlphaISA::processInterrupts(CPU *cpu) -{ - //Check if there are any outstanding interrupts - //Handle the interrupts - int ipl = 0; - int summary = 0; - - cpu->checkInterrupts = false; - - if (cpu->readMiscReg(IPR_ASTRR)) - panic("asynchronous traps not implemented\n"); - - if (cpu->readMiscReg(IPR_SIRR)) { - for (int i = INTLEVEL_SOFTWARE_MIN; - i < INTLEVEL_SOFTWARE_MAX; i++) { - if (cpu->readMiscReg(IPR_SIRR) & (ULL(1) << i)) { - // See table 4-19 of the 21164 hardware reference - ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1; - summary |= (ULL(1) << i); - } - } - } - - uint64_t interrupts = cpu->intr_status(); - - if (interrupts) { - for (int i = INTLEVEL_EXTERNAL_MIN; - i < INTLEVEL_EXTERNAL_MAX; i++) { - if (interrupts & (ULL(1) << i)) { - // See table 4-19 of the 21164 hardware reference - ipl = i; - summary |= (ULL(1) << i); - } - } - } - - if (ipl && ipl > cpu->readMiscReg(IPR_IPLR)) { - cpu->setMiscReg(IPR_ISR, summary); - cpu->setMiscReg(IPR_INTID, ipl); - cpu->trap(new InterruptFault); - DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", - cpu->readMiscReg(IPR_IPLR), ipl, summary); - } - -} - -template <class CPU> -void -AlphaISA::zeroRegisters(CPU *cpu) -{ - // Insure ISA semantics - // (no longer very clean due to the change in setIntReg() in the - // cpu model. Consider changing later.) - cpu->cpuXC->setIntReg(ZeroReg, 0); - cpu->cpuXC->setFloatRegDouble(ZeroReg, 0.0); -} - -Fault -CPUExecContext::hwrei() -{ - if (!inPalMode()) - return new UnimplementedOpcodeFault; - - setNextPC(readMiscReg(AlphaISA::IPR_EXC_ADDR)); - - if (!misspeculating()) { - if (kernelStats) - kernelStats->hwrei(); - - cpu->checkInterrupts = true; - } - - // FIXME: XXX check for interrupts? XXX - return NoFault; -} - -int -AlphaISA::MiscRegFile::getInstAsid() -{ - return EV5::ITB_ASN_ASN(ipr[IPR_ITB_ASN]); -} - -int -AlphaISA::MiscRegFile::getDataAsid() -{ - return EV5::DTB_ASN_ASN(ipr[IPR_DTB_ASN]); -} - -AlphaISA::MiscReg -AlphaISA::MiscRegFile::readIpr(int idx, Fault &fault, ExecContext *xc) -{ - uint64_t retval = 0; // return value, default 0 - - switch (idx) { - case AlphaISA::IPR_PALtemp0: - case AlphaISA::IPR_PALtemp1: - case AlphaISA::IPR_PALtemp2: - case AlphaISA::IPR_PALtemp3: - case AlphaISA::IPR_PALtemp4: - case AlphaISA::IPR_PALtemp5: - case AlphaISA::IPR_PALtemp6: - case AlphaISA::IPR_PALtemp7: - case AlphaISA::IPR_PALtemp8: - case AlphaISA::IPR_PALtemp9: - case AlphaISA::IPR_PALtemp10: - case AlphaISA::IPR_PALtemp11: - case AlphaISA::IPR_PALtemp12: - case AlphaISA::IPR_PALtemp13: - case AlphaISA::IPR_PALtemp14: - case AlphaISA::IPR_PALtemp15: - case AlphaISA::IPR_PALtemp16: - case AlphaISA::IPR_PALtemp17: - case AlphaISA::IPR_PALtemp18: - case AlphaISA::IPR_PALtemp19: - case AlphaISA::IPR_PALtemp20: - case AlphaISA::IPR_PALtemp21: - case AlphaISA::IPR_PALtemp22: - case AlphaISA::IPR_PALtemp23: - case AlphaISA::IPR_PAL_BASE: - - case AlphaISA::IPR_IVPTBR: - case AlphaISA::IPR_DC_MODE: - case AlphaISA::IPR_MAF_MODE: - case AlphaISA::IPR_ISR: - case AlphaISA::IPR_EXC_ADDR: - case AlphaISA::IPR_IC_PERR_STAT: - case AlphaISA::IPR_DC_PERR_STAT: - case AlphaISA::IPR_MCSR: - case AlphaISA::IPR_ASTRR: - case AlphaISA::IPR_ASTER: - case AlphaISA::IPR_SIRR: - case AlphaISA::IPR_ICSR: - case AlphaISA::IPR_ICM: - case AlphaISA::IPR_DTB_CM: - case AlphaISA::IPR_IPLR: - case AlphaISA::IPR_INTID: - case AlphaISA::IPR_PMCTR: - // no side-effect - retval = ipr[idx]; - break; - - case AlphaISA::IPR_CC: - retval |= ipr[idx] & ULL(0xffffffff00000000); - retval |= xc->getCpuPtr()->curCycle() & ULL(0x00000000ffffffff); - break; - - case AlphaISA::IPR_VA: - retval = ipr[idx]; - break; - - case AlphaISA::IPR_VA_FORM: - case AlphaISA::IPR_MM_STAT: - case AlphaISA::IPR_IFAULT_VA_FORM: - case AlphaISA::IPR_EXC_MASK: - case AlphaISA::IPR_EXC_SUM: - retval = ipr[idx]; - break; - - case AlphaISA::IPR_DTB_PTE: - { - AlphaISA::PTE &pte = xc->getDTBPtr()->index(!xc->misspeculating()); - - retval |= ((u_int64_t)pte.ppn & ULL(0x7ffffff)) << 32; - retval |= ((u_int64_t)pte.xre & ULL(0xf)) << 8; - retval |= ((u_int64_t)pte.xwe & ULL(0xf)) << 12; - retval |= ((u_int64_t)pte.fonr & ULL(0x1)) << 1; - retval |= ((u_int64_t)pte.fonw & ULL(0x1))<< 2; - retval |= ((u_int64_t)pte.asma & ULL(0x1)) << 4; - retval |= ((u_int64_t)pte.asn & ULL(0x7f)) << 57; - } - break; - - // write only registers - case AlphaISA::IPR_HWINT_CLR: - case AlphaISA::IPR_SL_XMIT: - case AlphaISA::IPR_DC_FLUSH: - case AlphaISA::IPR_IC_FLUSH: - case AlphaISA::IPR_ALT_MODE: - case AlphaISA::IPR_DTB_IA: - case AlphaISA::IPR_DTB_IAP: - case AlphaISA::IPR_ITB_IA: - case AlphaISA::IPR_ITB_IAP: - fault = new UnimplementedOpcodeFault; - break; - - default: - // invalid IPR - fault = new UnimplementedOpcodeFault; - break; - } - - return retval; -} - -#ifdef DEBUG -// Cause the simulator to break when changing to the following IPL -int break_ipl = -1; -#endif - -Fault -AlphaISA::MiscRegFile::setIpr(int idx, uint64_t val, ExecContext *xc) -{ - uint64_t old; - - if (xc->misspeculating()) - return NoFault; - - switch (idx) { - case AlphaISA::IPR_PALtemp0: - case AlphaISA::IPR_PALtemp1: - case AlphaISA::IPR_PALtemp2: - case AlphaISA::IPR_PALtemp3: - case AlphaISA::IPR_PALtemp4: - case AlphaISA::IPR_PALtemp5: - case AlphaISA::IPR_PALtemp6: - case AlphaISA::IPR_PALtemp7: - case AlphaISA::IPR_PALtemp8: - case AlphaISA::IPR_PALtemp9: - case AlphaISA::IPR_PALtemp10: - case AlphaISA::IPR_PALtemp11: - case AlphaISA::IPR_PALtemp12: - case AlphaISA::IPR_PALtemp13: - case AlphaISA::IPR_PALtemp14: - case AlphaISA::IPR_PALtemp15: - case AlphaISA::IPR_PALtemp16: - case AlphaISA::IPR_PALtemp17: - case AlphaISA::IPR_PALtemp18: - case AlphaISA::IPR_PALtemp19: - case AlphaISA::IPR_PALtemp20: - case AlphaISA::IPR_PALtemp21: - case AlphaISA::IPR_PALtemp22: - case AlphaISA::IPR_PAL_BASE: - case AlphaISA::IPR_IC_PERR_STAT: - case AlphaISA::IPR_DC_PERR_STAT: - case AlphaISA::IPR_PMCTR: - // write entire quad w/ no side-effect - ipr[idx] = val; - break; - - case AlphaISA::IPR_CC_CTL: - // This IPR resets the cycle counter. We assume this only - // happens once... let's verify that. - assert(ipr[idx] == 0); - ipr[idx] = 1; - break; - - case AlphaISA::IPR_CC: - // This IPR only writes the upper 64 bits. It's ok to write - // all 64 here since we mask out the lower 32 in rpcc (see - // isa_desc). - ipr[idx] = val; - break; - - case AlphaISA::IPR_PALtemp23: - // write entire quad w/ no side-effect - old = ipr[idx]; - ipr[idx] = val; - if (xc->getKernelStats()) - xc->getKernelStats()->context(old, val, xc); - break; - - case AlphaISA::IPR_DTB_PTE: - // write entire quad w/ no side-effect, tag is forthcoming - ipr[idx] = val; - break; - - case AlphaISA::IPR_EXC_ADDR: - // second least significant bit in PC is always zero - ipr[idx] = val & ~2; - break; - - case AlphaISA::IPR_ASTRR: - case AlphaISA::IPR_ASTER: - // only write least significant four bits - privilege mask - ipr[idx] = val & 0xf; - break; - - case AlphaISA::IPR_IPLR: -#ifdef DEBUG - if (break_ipl != -1 && break_ipl == (val & 0x1f)) - debug_break(); -#endif - - // only write least significant five bits - interrupt level - ipr[idx] = val & 0x1f; - if (xc->getKernelStats()) - xc->getKernelStats()->swpipl(ipr[idx]); - break; - - case AlphaISA::IPR_DTB_CM: - if (val & 0x18) { - if (xc->getKernelStats()) - xc->getKernelStats()->mode(Kernel::user, xc); - } else { - if (xc->getKernelStats()) - xc->getKernelStats()->mode(Kernel::kernel, xc); - } - - case AlphaISA::IPR_ICM: - // only write two mode bits - processor mode - ipr[idx] = val & 0x18; - break; - - case AlphaISA::IPR_ALT_MODE: - // only write two mode bits - processor mode - ipr[idx] = val & 0x18; - break; - - case AlphaISA::IPR_MCSR: - // more here after optimization... - ipr[idx] = val; - break; - - case AlphaISA::IPR_SIRR: - // only write software interrupt mask - ipr[idx] = val & 0x7fff0; - break; - - case AlphaISA::IPR_ICSR: - ipr[idx] = val & ULL(0xffffff0300); - break; - - case AlphaISA::IPR_IVPTBR: - case AlphaISA::IPR_MVPTBR: - ipr[idx] = val & ULL(0xffffffffc0000000); - break; - - case AlphaISA::IPR_DC_TEST_CTL: - ipr[idx] = val & 0x1ffb; - break; - - case AlphaISA::IPR_DC_MODE: - case AlphaISA::IPR_MAF_MODE: - ipr[idx] = val & 0x3f; - break; - - case AlphaISA::IPR_ITB_ASN: - ipr[idx] = val & 0x7f0; - break; - - case AlphaISA::IPR_DTB_ASN: - ipr[idx] = val & ULL(0xfe00000000000000); - break; - - case AlphaISA::IPR_EXC_SUM: - case AlphaISA::IPR_EXC_MASK: - // any write to this register clears it - ipr[idx] = 0; - break; - - case AlphaISA::IPR_INTID: - case AlphaISA::IPR_SL_RCV: - case AlphaISA::IPR_MM_STAT: - case AlphaISA::IPR_ITB_PTE_TEMP: - case AlphaISA::IPR_DTB_PTE_TEMP: - // read-only registers - return new UnimplementedOpcodeFault; - - case AlphaISA::IPR_HWINT_CLR: - case AlphaISA::IPR_SL_XMIT: - case AlphaISA::IPR_DC_FLUSH: - case AlphaISA::IPR_IC_FLUSH: - // the following are write only - ipr[idx] = val; - break; - - case AlphaISA::IPR_DTB_IA: - // really a control write - ipr[idx] = 0; - - xc->getDTBPtr()->flushAll(); - break; - - case AlphaISA::IPR_DTB_IAP: - // really a control write - ipr[idx] = 0; - - xc->getDTBPtr()->flushProcesses(); - break; - - case AlphaISA::IPR_DTB_IS: - // really a control write - ipr[idx] = val; - - xc->getDTBPtr()->flushAddr(val, - DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN])); - break; - - case AlphaISA::IPR_DTB_TAG: { - struct AlphaISA::PTE pte; - - // FIXME: granularity hints NYI... - if (DTB_PTE_GH(ipr[AlphaISA::IPR_DTB_PTE]) != 0) - panic("PTE GH field != 0"); - - // write entire quad - ipr[idx] = val; - - // construct PTE for new entry - pte.ppn = DTB_PTE_PPN(ipr[AlphaISA::IPR_DTB_PTE]); - pte.xre = DTB_PTE_XRE(ipr[AlphaISA::IPR_DTB_PTE]); - pte.xwe = DTB_PTE_XWE(ipr[AlphaISA::IPR_DTB_PTE]); - pte.fonr = DTB_PTE_FONR(ipr[AlphaISA::IPR_DTB_PTE]); - pte.fonw = DTB_PTE_FONW(ipr[AlphaISA::IPR_DTB_PTE]); - pte.asma = DTB_PTE_ASMA(ipr[AlphaISA::IPR_DTB_PTE]); - pte.asn = DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN]); - - // insert new TAG/PTE value into data TLB - xc->getDTBPtr()->insert(val, pte); - } - break; - - case AlphaISA::IPR_ITB_PTE: { - struct AlphaISA::PTE pte; - - // FIXME: granularity hints NYI... - if (ITB_PTE_GH(val) != 0) - panic("PTE GH field != 0"); - - // write entire quad - ipr[idx] = val; - - // construct PTE for new entry - pte.ppn = ITB_PTE_PPN(val); - pte.xre = ITB_PTE_XRE(val); - pte.xwe = 0; - pte.fonr = ITB_PTE_FONR(val); - pte.fonw = ITB_PTE_FONW(val); - pte.asma = ITB_PTE_ASMA(val); - pte.asn = ITB_ASN_ASN(ipr[AlphaISA::IPR_ITB_ASN]); - - // insert new TAG/PTE value into data TLB - xc->getITBPtr()->insert(ipr[AlphaISA::IPR_ITB_TAG], pte); - } - break; - - case AlphaISA::IPR_ITB_IA: - // really a control write - ipr[idx] = 0; - - xc->getITBPtr()->flushAll(); - break; - - case AlphaISA::IPR_ITB_IAP: - // really a control write - ipr[idx] = 0; - - xc->getITBPtr()->flushProcesses(); - break; - - case AlphaISA::IPR_ITB_IS: - // really a control write - ipr[idx] = val; - - xc->getITBPtr()->flushAddr(val, - ITB_ASN_ASN(ipr[AlphaISA::IPR_ITB_ASN])); - break; - - default: - // invalid IPR - return new UnimplementedOpcodeFault; - } - - // no error... - return NoFault; -} - -void -AlphaISA::MiscRegFile::copyIprs(ExecContext *xc) -{ - for (int i = IPR_Base_DepTag; i < NumInternalProcRegs; ++i) { - ipr[i] = xc->readMiscReg(i); - } -} - -/** - * Check for special simulator handling of specific PAL calls. - * If return value is false, actual PAL call will be suppressed. - */ -bool -CPUExecContext::simPalCheck(int palFunc) -{ - if (kernelStats) - kernelStats->callpal(palFunc, proxy); - - switch (palFunc) { - case PAL::halt: - halt(); - if (--System::numSystemsRunning == 0) - new SimExitEvent("all cpus halted"); - break; - - case PAL::bpt: - case PAL::bugchk: - if (system->breakpoint()) - return false; - break; - } - - return true; -} - -//Forward instantiation for FastCPU object -template -void AlphaISA::processInterrupts(FastCPU *xc); - -//Forward instantiation for FastCPU object -template -void AlphaISA::zeroRegisters(FastCPU *xc); - -#endif // FULL_SYSTEM diff --git a/arch/alpha/ev5.hh b/arch/alpha/ev5.hh deleted file mode 100644 index 7c8465cfb..000000000 --- a/arch/alpha/ev5.hh +++ /dev/null @@ -1,121 +0,0 @@ -/* - * 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. - */ - -#ifndef __ARCH_ALPHA_EV5_HH__ -#define __ARCH_ALPHA_EV5_HH__ - -#include "config/alpha_tlaser.hh" -#include "arch/alpha/isa_traits.hh" - -namespace EV5 { - -//It seems like a safe assumption EV5 only applies to alpha -using namespace AlphaISA; - -#if ALPHA_TLASER -const uint64_t AsnMask = ULL(0x7f); -#else -const uint64_t AsnMask = ULL(0xff); -#endif - -const int VAddrImplBits = 43; -const Addr VAddrImplMask = (ULL(1) << VAddrImplBits) - 1; -const Addr VAddrUnImplMask = ~VAddrImplMask; -inline Addr VAddrImpl(Addr a) { return a & VAddrImplMask; } -inline Addr VAddrVPN(Addr a) { return a >> AlphaISA::PageShift; } -inline Addr VAddrOffset(Addr a) { return a & AlphaISA::PageOffset; } -inline Addr VAddrSpaceEV5(Addr a) { return a >> 41 & 0x3; } -inline Addr VAddrSpaceEV6(Addr a) { return a >> 41 & 0x7f; } - -#if ALPHA_TLASER -inline bool PAddrIprSpace(Addr a) { return a >= ULL(0xFFFFF00000); } -const int PAddrImplBits = 40; -#else -inline bool PAddrIprSpace(Addr a) { return a >= ULL(0xFFFFFF00000); } -const int PAddrImplBits = 44; // for Tsunami -#endif -const Addr PAddrImplMask = (ULL(1) << PAddrImplBits) - 1; -const Addr PAddrUncachedBit39 = ULL(0x8000000000); -const Addr PAddrUncachedBit40 = ULL(0x10000000000); -const Addr PAddrUncachedBit43 = ULL(0x80000000000); -const Addr PAddrUncachedMask = ULL(0x807ffffffff); // Clear PA<42:35> -inline Addr Phys2K0Seg(Addr addr) -{ -#if !ALPHA_TLASER - if (addr & PAddrUncachedBit43) { - addr &= PAddrUncachedMask; - addr |= PAddrUncachedBit40; - } -#endif - return addr | AlphaISA::K0SegBase; -} - -inline int DTB_ASN_ASN(uint64_t reg) { return reg >> 57 & AsnMask; } -inline Addr DTB_PTE_PPN(uint64_t reg) -{ return reg >> 32 & (ULL(1) << PAddrImplBits - AlphaISA::PageShift) - 1; } -inline int DTB_PTE_XRE(uint64_t reg) { return reg >> 8 & 0xf; } -inline int DTB_PTE_XWE(uint64_t reg) { return reg >> 12 & 0xf; } -inline int DTB_PTE_FONR(uint64_t reg) { return reg >> 1 & 0x1; } -inline int DTB_PTE_FONW(uint64_t reg) { return reg >> 2 & 0x1; } -inline int DTB_PTE_GH(uint64_t reg) { return reg >> 5 & 0x3; } -inline int DTB_PTE_ASMA(uint64_t reg) { return reg >> 4 & 0x1; } - -inline int ITB_ASN_ASN(uint64_t reg) { return reg >> 4 & AsnMask; } -inline Addr ITB_PTE_PPN(uint64_t reg) -{ return reg >> 32 & (ULL(1) << PAddrImplBits - AlphaISA::PageShift) - 1; } -inline int ITB_PTE_XRE(uint64_t reg) { return reg >> 8 & 0xf; } -inline bool ITB_PTE_FONR(uint64_t reg) { return reg >> 1 & 0x1; } -inline bool ITB_PTE_FONW(uint64_t reg) { return reg >> 2 & 0x1; } -inline int ITB_PTE_GH(uint64_t reg) { return reg >> 5 & 0x3; } -inline bool ITB_PTE_ASMA(uint64_t reg) { return reg >> 4 & 0x1; } - -inline uint64_t MCSR_SP(uint64_t reg) { return reg >> 1 & 0x3; } - -inline bool ICSR_SDE(uint64_t reg) { return reg >> 30 & 0x1; } -inline int ICSR_SPE(uint64_t reg) { return reg >> 28 & 0x3; } -inline bool ICSR_FPE(uint64_t reg) { return reg >> 26 & 0x1; } - -inline uint64_t ALT_MODE_AM(uint64_t reg) { return reg >> 3 & 0x3; } -inline uint64_t DTB_CM_CM(uint64_t reg) { return reg >> 3 & 0x3; } -inline uint64_t ICM_CM(uint64_t reg) { return reg >> 3 & 0x3; } - -const uint64_t MM_STAT_BAD_VA_MASK = ULL(0x0020); -const uint64_t MM_STAT_DTB_MISS_MASK = ULL(0x0010); -const uint64_t MM_STAT_FONW_MASK = ULL(0x0008); -const uint64_t MM_STAT_FONR_MASK = ULL(0x0004); -const uint64_t MM_STAT_ACV_MASK = ULL(0x0002); -const uint64_t MM_STAT_WR_MASK = ULL(0x0001); -inline int Opcode(AlphaISA::MachInst inst) { return inst >> 26 & 0x3f; } -inline int Ra(AlphaISA::MachInst inst) { return inst >> 21 & 0x1f; } - -const Addr PalBase = 0x4000; -const Addr PalMax = 0x10000; - -/* namespace EV5 */ } - -#endif // __ARCH_ALPHA_EV5_HH__ diff --git a/arch/alpha/faults.cc b/arch/alpha/faults.cc deleted file mode 100644 index 0083aa9f3..000000000 --- a/arch/alpha/faults.cc +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include "arch/alpha/faults.hh" -#include "cpu/exec_context.hh" -#include "cpu/base.hh" -#include "base/trace.hh" -#if FULL_SYSTEM -#include "arch/alpha/ev5.hh" -#endif - -namespace AlphaISA -{ - -FaultName MachineCheckFault::_name = "mchk"; -FaultVect MachineCheckFault::_vect = 0x0401; -FaultStat MachineCheckFault::_count; - -FaultName AlignmentFault::_name = "unalign"; -FaultVect AlignmentFault::_vect = 0x0301; -FaultStat AlignmentFault::_count; - -FaultName ResetFault::_name = "reset"; -FaultVect ResetFault::_vect = 0x0001; -FaultStat ResetFault::_count; - -FaultName ArithmeticFault::_name = "arith"; -FaultVect ArithmeticFault::_vect = 0x0501; -FaultStat ArithmeticFault::_count; - -FaultName InterruptFault::_name = "interrupt"; -FaultVect InterruptFault::_vect = 0x0101; -FaultStat InterruptFault::_count; - -FaultName NDtbMissFault::_name = "dtb_miss_single"; -FaultVect NDtbMissFault::_vect = 0x0201; -FaultStat NDtbMissFault::_count; - -FaultName PDtbMissFault::_name = "dtb_miss_double"; -FaultVect PDtbMissFault::_vect = 0x0281; -FaultStat PDtbMissFault::_count; - -FaultName DtbPageFault::_name = "dfault"; -FaultVect DtbPageFault::_vect = 0x0381; -FaultStat DtbPageFault::_count; - -FaultName DtbAcvFault::_name = "dfault"; -FaultVect DtbAcvFault::_vect = 0x0381; -FaultStat DtbAcvFault::_count; - -FaultName DtbAlignmentFault::_name = "unalign"; -FaultVect DtbAlignmentFault::_vect = 0x0301; -FaultStat DtbAlignmentFault::_count; - -FaultName ItbMissFault::_name = "itbmiss"; -FaultVect ItbMissFault::_vect = 0x0181; -FaultStat ItbMissFault::_count; - -FaultName ItbPageFault::_name = "itbmiss"; -FaultVect ItbPageFault::_vect = 0x0181; -FaultStat ItbPageFault::_count; - -FaultName ItbAcvFault::_name = "iaccvio"; -FaultVect ItbAcvFault::_vect = 0x0081; -FaultStat ItbAcvFault::_count; - -FaultName UnimplementedOpcodeFault::_name = "opdec"; -FaultVect UnimplementedOpcodeFault::_vect = 0x0481; -FaultStat UnimplementedOpcodeFault::_count; - -FaultName FloatEnableFault::_name = "fen"; -FaultVect FloatEnableFault::_vect = 0x0581; -FaultStat FloatEnableFault::_count; - -FaultName PalFault::_name = "pal"; -FaultVect PalFault::_vect = 0x2001; -FaultStat PalFault::_count; - -FaultName IntegerOverflowFault::_name = "intover"; -FaultVect IntegerOverflowFault::_vect = 0x0501; -FaultStat IntegerOverflowFault::_count; - -#if FULL_SYSTEM - -void AlphaFault::invoke(ExecContext * xc) -{ - FaultBase::invoke(xc); - countStat()++; - - // exception restart address - if (setRestartAddress() || !xc->inPalMode()) - xc->setMiscReg(AlphaISA::IPR_EXC_ADDR, xc->readPC()); - - if (skipFaultingInstruction()) { - // traps... skip faulting instruction. - xc->setMiscReg(AlphaISA::IPR_EXC_ADDR, - xc->readMiscReg(AlphaISA::IPR_EXC_ADDR) + 4); - } - - xc->setPC(xc->readMiscReg(AlphaISA::IPR_PAL_BASE) + vect()); - xc->setNextPC(xc->readPC() + sizeof(MachInst)); -} - -void ArithmeticFault::invoke(ExecContext * xc) -{ - FaultBase::invoke(xc); - panic("Arithmetic traps are unimplemented!"); -} - -void DtbFault::invoke(ExecContext * xc) -{ - // Set fault address and flags. Even though we're modeling an - // EV5, we use the EV6 technique of not latching fault registers - // on VPTE loads (instead of locking the registers until IPR_VA is - // read, like the EV5). The EV6 approach is cleaner and seems to - // work with EV5 PAL code, but not the other way around. - if (!xc->misspeculating() - && !(reqFlags & VPTE) && !(reqFlags & NO_FAULT)) { - // set VA register with faulting address - xc->setMiscReg(AlphaISA::IPR_VA, vaddr); - - // set MM_STAT register flags - xc->setMiscReg(AlphaISA::IPR_MM_STAT, - (((EV5::Opcode(xc->getInst()) & 0x3f) << 11) - | ((EV5::Ra(xc->getInst()) & 0x1f) << 6) - | (flags & 0x3f))); - - // set VA_FORM register with faulting formatted address - xc->setMiscReg(AlphaISA::IPR_VA_FORM, - xc->readMiscReg(AlphaISA::IPR_MVPTBR) | (vaddr.vpn() << 3)); - } - - AlphaFault::invoke(xc); -} - -void ItbFault::invoke(ExecContext * xc) -{ - if (!xc->misspeculating()) { - xc->setMiscReg(AlphaISA::IPR_ITB_TAG, pc); - xc->setMiscReg(AlphaISA::IPR_IFAULT_VA_FORM, - xc->readMiscReg(AlphaISA::IPR_IVPTBR) | - (AlphaISA::VAddr(pc).vpn() << 3)); - } - - AlphaFault::invoke(xc); -} - -#endif - -} // namespace AlphaISA - diff --git a/arch/alpha/faults.hh b/arch/alpha/faults.hh deleted file mode 100644 index e8ccc6b79..000000000 --- a/arch/alpha/faults.hh +++ /dev/null @@ -1,352 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __ALPHA_FAULTS_HH__ -#define __ALPHA_FAULTS_HH__ - -#include "arch/alpha/isa_traits.hh" -#include "sim/faults.hh" - -// The design of the "name" and "vect" functions is in sim/faults.hh - -namespace AlphaISA -{ - -typedef const Addr FaultVect; - -class AlphaFault : public FaultBase -{ - protected: - virtual bool skipFaultingInstruction() {return false;} - virtual bool setRestartAddress() {return true;} - public: -#if FULL_SYSTEM - void invoke(ExecContext * xc); -#endif - virtual FaultVect vect() = 0; - virtual FaultStat & countStat() = 0; -}; - -class MachineCheckFault : public AlphaFault -{ - private: - static FaultName _name; - static FaultVect _vect; - static FaultStat _count; - public: - FaultName name() {return _name;} - FaultVect vect() {return _vect;} - FaultStat & countStat() {return _count;} - bool isMachineCheckFault() {return true;} -}; - -class AlignmentFault : public AlphaFault -{ - private: - static FaultName _name; - static FaultVect _vect; - static FaultStat _count; - public: - FaultName name() {return _name;} - FaultVect vect() {return _vect;} - FaultStat & countStat() {return _count;} - bool isAlignmentFault() {return true;} -}; - -static inline Fault genMachineCheckFault() -{ - return new MachineCheckFault; -} - -static inline Fault genAlignmentFault() -{ - return new AlignmentFault; -} - -class ResetFault : public AlphaFault -{ - private: - static FaultName _name; - static FaultVect _vect; - static FaultStat _count; - public: - FaultName name() {return _name;} - FaultVect vect() {return _vect;} - FaultStat & countStat() {return _count;} -}; - -class ArithmeticFault : public AlphaFault -{ - protected: - bool skipFaultingInstruction() {return true;} - private: - static FaultName _name; - static FaultVect _vect; - static FaultStat _count; - public: - FaultName name() {return _name;} - FaultVect vect() {return _vect;} - FaultStat & countStat() {return _count;} -#if FULL_SYSTEM - void invoke(ExecContext * xc); -#endif -}; - -class InterruptFault : public AlphaFault -{ - protected: - bool setRestartAddress() {return false;} - private: - static FaultName _name; - static FaultVect _vect; - static FaultStat _count; - public: - FaultName name() {return _name;} - FaultVect vect() {return _vect;} - FaultStat & countStat() {return _count;} -}; - -class DtbFault : public AlphaFault -{ -#if FULL_SYSTEM - private: - AlphaISA::VAddr vaddr; - uint32_t reqFlags; - uint64_t flags; - public: - DtbFault(AlphaISA::VAddr _vaddr, uint32_t _reqFlags, uint64_t _flags) - : vaddr(_vaddr), reqFlags(_reqFlags), flags(_flags) - { } -#endif - FaultName name() = 0; - FaultVect vect() = 0; - FaultStat & countStat() = 0; -#if FULL_SYSTEM - void invoke(ExecContext * xc); -#endif -}; - -class NDtbMissFault : public DtbFault -{ - private: - static FaultName _name; - static FaultVect _vect; - static FaultStat _count; - public: -#if FULL_SYSTEM - NDtbMissFault(AlphaISA::VAddr vaddr, uint32_t reqFlags, uint64_t flags) - : DtbFault(vaddr, reqFlags, flags) - { } -#endif - FaultName name() {return _name;} - FaultVect vect() {return _vect;} - FaultStat & countStat() {return _count;} -}; - -class PDtbMissFault : public DtbFault -{ - private: - static FaultName _name; - static FaultVect _vect; - static FaultStat _count; - public: -#if FULL_SYSTEM - PDtbMissFault(AlphaISA::VAddr vaddr, uint32_t reqFlags, uint64_t flags) - : DtbFault(vaddr, reqFlags, flags) - { } -#endif - FaultName name() {return _name;} - FaultVect vect() {return _vect;} - FaultStat & countStat() {return _count;} -}; - -class DtbPageFault : public DtbFault -{ - private: - static FaultName _name; - static FaultVect _vect; - static FaultStat _count; - public: -#if FULL_SYSTEM - DtbPageFault(AlphaISA::VAddr vaddr, uint32_t reqFlags, uint64_t flags) - : DtbFault(vaddr, reqFlags, flags) - { } -#endif - FaultName name() {return _name;} - FaultVect vect() {return _vect;} - FaultStat & countStat() {return _count;} -}; - -class DtbAcvFault : public DtbFault -{ - private: - static FaultName _name; - static FaultVect _vect; - static FaultStat _count; - public: -#if FULL_SYSTEM - DtbAcvFault(AlphaISA::VAddr vaddr, uint32_t reqFlags, uint64_t flags) - : DtbFault(vaddr, reqFlags, flags) - { } -#endif - FaultName name() {return _name;} - FaultVect vect() {return _vect;} - FaultStat & countStat() {return _count;} -}; - -class DtbAlignmentFault : public DtbFault -{ - private: - static FaultName _name; - static FaultVect _vect; - static FaultStat _count; - public: -#if FULL_SYSTEM - DtbAlignmentFault(AlphaISA::VAddr vaddr, uint32_t reqFlags, uint64_t flags) - : DtbFault(vaddr, reqFlags, flags) - { } -#endif - FaultName name() {return _name;} - FaultVect vect() {return _vect;} - FaultStat & countStat() {return _count;} -}; - -class ItbFault : public AlphaFault -{ - private: - Addr pc; - public: - ItbFault(Addr _pc) - : pc(_pc) - { } - FaultName name() = 0; - FaultVect vect() = 0; - FaultStat & countStat() = 0; -#if FULL_SYSTEM - void invoke(ExecContext * xc); -#endif -}; - -class ItbMissFault : public ItbFault -{ - private: - static FaultName _name; - static FaultVect _vect; - static FaultStat _count; - public: - ItbMissFault(Addr pc) - : ItbFault(pc) - { } - FaultName name() {return _name;} - FaultVect vect() {return _vect;} - FaultStat & countStat() {return _count;} -}; - -class ItbPageFault : public ItbFault -{ - private: - static FaultName _name; - static FaultVect _vect; - static FaultStat _count; - public: - ItbPageFault(Addr pc) - : ItbFault(pc) - { } - FaultName name() {return _name;} - FaultVect vect() {return _vect;} - FaultStat & countStat() {return _count;} -}; - -class ItbAcvFault : public ItbFault -{ - private: - static FaultName _name; - static FaultVect _vect; - static FaultStat _count; - public: - ItbAcvFault(Addr pc) - : ItbFault(pc) - { } - FaultName name() {return _name;} - FaultVect vect() {return _vect;} - FaultStat & countStat() {return _count;} -}; - -class UnimplementedOpcodeFault : public AlphaFault -{ - private: - static FaultName _name; - static FaultVect _vect; - static FaultStat _count; - public: - FaultName name() {return _name;} - FaultVect vect() {return _vect;} - FaultStat & countStat() {return _count;} -}; - -class FloatEnableFault : public AlphaFault -{ - private: - static FaultName _name; - static FaultVect _vect; - static FaultStat _count; - public: - FaultName name() {return _name;} - FaultVect vect() {return _vect;} - FaultStat & countStat() {return _count;} -}; - -class PalFault : public AlphaFault -{ - protected: - bool skipFaultingInstruction() {return true;} - private: - static FaultName _name; - static FaultVect _vect; - static FaultStat _count; - public: - FaultName name() {return _name;} - FaultVect vect() {return _vect;} - FaultStat & countStat() {return _count;} -}; - -class IntegerOverflowFault : public AlphaFault -{ - private: - static FaultName _name; - static FaultVect _vect; - static FaultStat _count; - public: - FaultName name() {return _name;} - FaultVect vect() {return _vect;} - FaultStat & countStat() {return _count;} -}; - -} // AlphaISA namespace - -#endif // __FAULTS_HH__ diff --git a/arch/alpha/freebsd/system.cc b/arch/alpha/freebsd/system.cc deleted file mode 100644 index 0f5296265..000000000 --- a/arch/alpha/freebsd/system.cc +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * Modifications for the FreeBSD kernel. - * Based on kern/linux/linux_system.cc. - * - */ - -#include "arch/alpha/system.hh" -#include "arch/alpha/freebsd/system.hh" -#include "base/loader/symtab.hh" -#include "cpu/exec_context.hh" -#include "mem/functional/memory_control.hh" -#include "mem/functional/physical.hh" -#include "arch/isa_traits.hh" -#include "sim/builder.hh" -#include "sim/byteswap.hh" -#include "arch/vtophys.hh" - -#define TIMER_FREQUENCY 1193180 - -using namespace std; -using namespace AlphaISA; - -FreebsdAlphaSystem::FreebsdAlphaSystem(Params *p) - : AlphaSystem(p) -{ - /** - * Any time DELAY is called just skip the function. - * Shouldn't we actually emulate the delay? - */ - skipDelayEvent = addKernelFuncEvent<SkipFuncEvent>("DELAY"); - skipCalibrateClocks = - addKernelFuncEvent<SkipCalibrateClocksEvent>("calibrate_clocks"); -} - - -FreebsdAlphaSystem::~FreebsdAlphaSystem() -{ - delete skipDelayEvent; - delete skipCalibrateClocks; -} - - -void -FreebsdAlphaSystem::doCalibrateClocks(ExecContext *xc) -{ - Addr ppc_vaddr = 0; - Addr timer_vaddr = 0; - Addr ppc_paddr = 0; - Addr timer_paddr = 0; - - ppc_vaddr = (Addr)xc->readIntReg(ArgumentReg1); - timer_vaddr = (Addr)xc->readIntReg(ArgumentReg2); - - ppc_paddr = vtophys(physmem, ppc_vaddr); - timer_paddr = vtophys(physmem, timer_vaddr); - - uint8_t *ppc = physmem->dma_addr(ppc_paddr, sizeof(uint32_t)); - uint8_t *timer = physmem->dma_addr(timer_paddr, sizeof(uint32_t)); - - *(uint32_t *)ppc = htog((uint32_t)Clock::Frequency); - *(uint32_t *)timer = htog((uint32_t)TIMER_FREQUENCY); -} - - -void -FreebsdAlphaSystem::SkipCalibrateClocksEvent::process(ExecContext *xc) -{ - SkipFuncEvent::process(xc); - ((FreebsdAlphaSystem *)xc->getSystemPtr())->doCalibrateClocks(xc); -} - - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(FreebsdAlphaSystem) - - Param<Tick> boot_cpu_frequency; - SimObjectParam<MemoryController *> memctrl; - SimObjectParam<PhysicalMemory *> physmem; - - Param<string> kernel; - Param<string> console; - Param<string> pal; - - Param<string> boot_osflags; - Param<string> readfile; - Param<unsigned int> init_param; - - Param<uint64_t> system_type; - Param<uint64_t> system_rev; - -END_DECLARE_SIM_OBJECT_PARAMS(FreebsdAlphaSystem) - -BEGIN_INIT_SIM_OBJECT_PARAMS(FreebsdAlphaSystem) - - INIT_PARAM(boot_cpu_frequency, "Frequency of the boot CPU"), - INIT_PARAM(memctrl, "memory controller"), - INIT_PARAM(physmem, "phsyical memory"), - INIT_PARAM(kernel, "file that contains the kernel code"), - INIT_PARAM(console, "file that contains the console code"), - INIT_PARAM(pal, "file that contains palcode"), - INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot", - "a"), - INIT_PARAM_DFLT(readfile, "file to read startup script from", ""), - INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0), - INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 34), - INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10) - -END_INIT_SIM_OBJECT_PARAMS(FreebsdAlphaSystem) - -CREATE_SIM_OBJECT(FreebsdAlphaSystem) -{ - AlphaSystem::Params *p = new AlphaSystem::Params; - p->name = getInstanceName(); - p->boot_cpu_frequency = boot_cpu_frequency; - p->memctrl = memctrl; - p->physmem = physmem; - p->kernel_path = kernel; - p->console_path = console; - p->palcode = pal; - p->boot_osflags = boot_osflags; - p->init_param = init_param; - p->readfile = readfile; - p->system_type = system_type; - p->system_rev = system_rev; - return new FreebsdAlphaSystem(p); -} - -REGISTER_SIM_OBJECT("FreebsdAlphaSystem", FreebsdAlphaSystem) - diff --git a/arch/alpha/freebsd/system.hh b/arch/alpha/freebsd/system.hh deleted file mode 100644 index 5d996955e..000000000 --- a/arch/alpha/freebsd/system.hh +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __KERN_FREEBSD_FREEBSD_SYSTEM_HH__ -#define __KERN_FREEBSD_FREEBSD_SYSTEM_HH__ - -#include "kern/system_events.hh" - -class FreebsdAlphaSystem : public AlphaSystem -{ - private: - class SkipCalibrateClocksEvent : public SkipFuncEvent - { - public: - SkipCalibrateClocksEvent(PCEventQueue *q, const std::string &desc, - Addr addr) - : SkipFuncEvent(q, desc, addr) {} - virtual void process(ExecContext *xc); - }; - - SkipFuncEvent *skipDelayEvent; - SkipCalibrateClocksEvent *skipCalibrateClocks; - - public: - FreebsdAlphaSystem(Params *p); - ~FreebsdAlphaSystem(); - void doCalibrateClocks(ExecContext *xc); - -}; - -#endif // __KERN_FREEBSD_FREEBSD_SYSTEM_HH__ diff --git a/arch/alpha/isa/branch.isa b/arch/alpha/isa/branch.isa deleted file mode 100644 index b528df938..000000000 --- a/arch/alpha/isa/branch.isa +++ /dev/null @@ -1,259 +0,0 @@ -// -*- mode:c++ -*- - -// Copyright (c) 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. - -output header {{ - - /** - * Base class for instructions whose disassembly is not purely a - * function of the machine instruction (i.e., it depends on the - * PC). This class overrides the disassemble() method to check - * the PC and symbol table values before re-using a cached - * disassembly string. This is necessary for branches and jumps, - * where the disassembly string includes the target address (which - * may depend on the PC and/or symbol table). - */ - class PCDependentDisassembly : public AlphaStaticInst - { - protected: - /// Cached program counter from last disassembly - mutable Addr cachedPC; - /// Cached symbol table pointer from last disassembly - mutable const SymbolTable *cachedSymtab; - - /// Constructor - PCDependentDisassembly(const char *mnem, ExtMachInst _machInst, - OpClass __opClass) - : AlphaStaticInst(mnem, _machInst, __opClass), - cachedPC(0), cachedSymtab(0) - { - } - - const std::string & - disassemble(Addr pc, const SymbolTable *symtab) const; - }; - - /** - * Base class for branches (PC-relative control transfers), - * conditional or unconditional. - */ - class Branch : public PCDependentDisassembly - { - protected: - /// Displacement to target address (signed). - int32_t disp; - - /// Constructor. - Branch(const char *mnem, ExtMachInst _machInst, OpClass __opClass) - : PCDependentDisassembly(mnem, _machInst, __opClass), - disp(BRDISP << 2) - { - } - - Addr branchTarget(Addr branchPC) const; - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; - - /** - * Base class for jumps (register-indirect control transfers). In - * the Alpha ISA, these are always unconditional. - */ - class Jump : public PCDependentDisassembly - { - protected: - - /// Displacement to target address (signed). - int32_t disp; - - public: - /// Constructor - Jump(const char *mnem, ExtMachInst _machInst, OpClass __opClass) - : PCDependentDisassembly(mnem, _machInst, __opClass), - disp(BRDISP) - { - } - - Addr branchTarget(ExecContext *xc) const; - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; -}}; - -output decoder {{ - Addr - Branch::branchTarget(Addr branchPC) const - { - return branchPC + 4 + disp; - } - - Addr - Jump::branchTarget(ExecContext *xc) const - { - Addr NPC = xc->readPC() + 4; - uint64_t Rb = xc->readIntReg(_srcRegIdx[0]); - return (Rb & ~3) | (NPC & 1); - } - - const std::string & - PCDependentDisassembly::disassemble(Addr pc, - const SymbolTable *symtab) const - { - if (!cachedDisassembly || - pc != cachedPC || symtab != cachedSymtab) - { - if (cachedDisassembly) - delete cachedDisassembly; - - cachedDisassembly = - new std::string(generateDisassembly(pc, symtab)); - cachedPC = pc; - cachedSymtab = symtab; - } - - return *cachedDisassembly; - } - - std::string - Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - std::stringstream ss; - - ccprintf(ss, "%-10s ", mnemonic); - - // There's only one register arg (RA), but it could be - // either a source (the condition for conditional - // branches) or a destination (the link reg for - // unconditional branches) - if (_numSrcRegs > 0) { - printReg(ss, _srcRegIdx[0]); - ss << ","; - } - else if (_numDestRegs > 0) { - printReg(ss, _destRegIdx[0]); - ss << ","; - } - -#ifdef SS_COMPATIBLE_DISASSEMBLY - if (_numSrcRegs == 0 && _numDestRegs == 0) { - printReg(ss, 31); - ss << ","; - } -#endif - - Addr target = pc + 4 + disp; - - std::string str; - if (symtab && symtab->findSymbol(target, str)) - ss << str; - else - ccprintf(ss, "0x%x", target); - - return ss.str(); - } - - std::string - Jump::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - std::stringstream ss; - - ccprintf(ss, "%-10s ", mnemonic); - -#ifdef SS_COMPATIBLE_DISASSEMBLY - if (_numDestRegs == 0) { - printReg(ss, 31); - ss << ","; - } -#endif - - if (_numDestRegs > 0) { - printReg(ss, _destRegIdx[0]); - ss << ","; - } - - ccprintf(ss, "(r%d)", RB); - - return ss.str(); - } -}}; - -def template JumpOrBranchDecode {{ - return (RA == 31) - ? (StaticInst *)new %(class_name)s(machInst) - : (StaticInst *)new %(class_name)sAndLink(machInst); -}}; - -def format CondBranch(code) {{ - code = 'bool cond;\n' + code + '\nif (cond) NPC = NPC + disp;\n'; - iop = InstObjParams(name, Name, 'Branch', CodeBlock(code), - ('IsDirectControl', 'IsCondControl')) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecode.subst(iop) - exec_output = BasicExecute.subst(iop) -}}; - -let {{ -def UncondCtrlBase(name, Name, base_class, npc_expr, flags): - # Declare basic control transfer w/o link (i.e. link reg is R31) - nolink_code = 'NPC = %s;\n' % npc_expr - nolink_iop = InstObjParams(name, Name, base_class, - CodeBlock(nolink_code), flags) - header_output = BasicDeclare.subst(nolink_iop) - decoder_output = BasicConstructor.subst(nolink_iop) - exec_output = BasicExecute.subst(nolink_iop) - - # Generate declaration of '*AndLink' version, append to decls - link_code = 'Ra = NPC & ~3;\n' + nolink_code - link_iop = InstObjParams(name, Name + 'AndLink', base_class, - CodeBlock(link_code), flags) - header_output += BasicDeclare.subst(link_iop) - decoder_output += BasicConstructor.subst(link_iop) - exec_output += BasicExecute.subst(link_iop) - - # need to use link_iop for the decode template since it is expecting - # the shorter version of class_name (w/o "AndLink") - - return (header_output, decoder_output, - JumpOrBranchDecode.subst(nolink_iop), exec_output) -}}; - -def format UncondBranch(*flags) {{ - flags += ('IsUncondControl', 'IsDirectControl') - (header_output, decoder_output, decode_block, exec_output) = \ - UncondCtrlBase(name, Name, 'Branch', 'NPC + disp', flags) -}}; - -def format Jump(*flags) {{ - flags += ('IsUncondControl', 'IsIndirectControl') - (header_output, decoder_output, decode_block, exec_output) = \ - UncondCtrlBase(name, Name, 'Jump', '(Rb & ~3) | (NPC & 1)', flags) -}}; - - diff --git a/arch/alpha/isa/decoder.isa b/arch/alpha/isa/decoder.isa deleted file mode 100644 index b3744a43d..000000000 --- a/arch/alpha/isa/decoder.isa +++ /dev/null @@ -1,819 +0,0 @@ -// -*- mode:c++ -*- - -// 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. - -decode OPCODE default Unknown::unknown() { - - format LoadAddress { - 0x08: lda({{ Ra = Rb + disp; }}); - 0x09: ldah({{ Ra = Rb + (disp << 16); }}); - } - - format LoadOrNop { - 0x0a: ldbu({{ Ra.uq = Mem.ub; }}); - 0x0c: ldwu({{ Ra.uq = Mem.uw; }}); - 0x0b: ldq_u({{ Ra = Mem.uq; }}, ea_code = {{ EA = (Rb + disp) & ~7; }}); - 0x23: ldt({{ Fa = Mem.df; }}); - 0x2a: ldl_l({{ Ra.sl = Mem.sl; }}, mem_flags = LOCKED); - 0x2b: ldq_l({{ Ra.uq = Mem.uq; }}, mem_flags = LOCKED); - 0x20: MiscPrefetch::copy_load({{ EA = Ra; }}, - {{ fault = xc->copySrcTranslate(EA); }}, - inst_flags = [IsMemRef, IsLoad, IsCopy]); - } - - format LoadOrPrefetch { - 0x28: ldl({{ Ra.sl = Mem.sl; }}); - 0x29: ldq({{ Ra.uq = Mem.uq; }}, pf_flags = EVICT_NEXT); - // IsFloating flag on lds gets the prefetch to disassemble - // using f31 instead of r31... funcitonally it's unnecessary - 0x22: lds({{ Fa.uq = s_to_t(Mem.ul); }}, - pf_flags = PF_EXCLUSIVE, inst_flags = IsFloating); - } - - format Store { - 0x0e: stb({{ Mem.ub = Ra<7:0>; }}); - 0x0d: stw({{ Mem.uw = Ra<15:0>; }}); - 0x2c: stl({{ Mem.ul = Ra<31:0>; }}); - 0x2d: stq({{ Mem.uq = Ra.uq; }}); - 0x0f: stq_u({{ Mem.uq = Ra.uq; }}, {{ EA = (Rb + disp) & ~7; }}); - 0x26: sts({{ Mem.ul = t_to_s(Fa.uq); }}); - 0x27: stt({{ Mem.df = Fa; }}); - 0x24: MiscPrefetch::copy_store({{ EA = Rb; }}, - {{ fault = xc->copy(EA); }}, - inst_flags = [IsMemRef, IsStore, IsCopy]); - } - - format StoreCond { - 0x2e: stl_c({{ Mem.ul = Ra<31:0>; }}, - {{ - uint64_t tmp = write_result; - // see stq_c - Ra = (tmp == 0 || tmp == 1) ? tmp : Ra; - }}, mem_flags = LOCKED, inst_flags = IsStoreConditional); - 0x2f: stq_c({{ Mem.uq = Ra; }}, - {{ - uint64_t tmp = write_result; - // If the write operation returns 0 or 1, then - // this was a conventional store conditional, - // and the value indicates the success/failure - // of the operation. If another value is - // returned, then this was a Turbolaser - // mailbox access, and we don't update the - // result register at all. - Ra = (tmp == 0 || tmp == 1) ? tmp : Ra; - }}, mem_flags = LOCKED, inst_flags = IsStoreConditional); - } - - format IntegerOperate { - - 0x10: decode INTFUNC { // integer arithmetic operations - - 0x00: addl({{ Rc.sl = Ra.sl + Rb_or_imm.sl; }}); - 0x40: addlv({{ - uint32_t tmp = Ra.sl + Rb_or_imm.sl; - // signed overflow occurs when operands have same sign - // and sign of result does not match. - if (Ra.sl<31:> == Rb_or_imm.sl<31:> && tmp<31:> != Ra.sl<31:>) - fault = new IntegerOverflowFault; - Rc.sl = tmp; - }}); - 0x02: s4addl({{ Rc.sl = (Ra.sl << 2) + Rb_or_imm.sl; }}); - 0x12: s8addl({{ Rc.sl = (Ra.sl << 3) + Rb_or_imm.sl; }}); - - 0x20: addq({{ Rc = Ra + Rb_or_imm; }}); - 0x60: addqv({{ - uint64_t tmp = Ra + Rb_or_imm; - // signed overflow occurs when operands have same sign - // and sign of result does not match. - if (Ra<63:> == Rb_or_imm<63:> && tmp<63:> != Ra<63:>) - fault = new IntegerOverflowFault; - Rc = tmp; - }}); - 0x22: s4addq({{ Rc = (Ra << 2) + Rb_or_imm; }}); - 0x32: s8addq({{ Rc = (Ra << 3) + Rb_or_imm; }}); - - 0x09: subl({{ Rc.sl = Ra.sl - Rb_or_imm.sl; }}); - 0x49: sublv({{ - uint32_t tmp = Ra.sl - Rb_or_imm.sl; - // signed overflow detection is same as for add, - // except we need to look at the *complemented* - // sign bit of the subtrahend (Rb), i.e., if the initial - // signs are the *same* then no overflow can occur - if (Ra.sl<31:> != Rb_or_imm.sl<31:> && tmp<31:> != Ra.sl<31:>) - fault = new IntegerOverflowFault; - Rc.sl = tmp; - }}); - 0x0b: s4subl({{ Rc.sl = (Ra.sl << 2) - Rb_or_imm.sl; }}); - 0x1b: s8subl({{ Rc.sl = (Ra.sl << 3) - Rb_or_imm.sl; }}); - - 0x29: subq({{ Rc = Ra - Rb_or_imm; }}); - 0x69: subqv({{ - uint64_t tmp = Ra - Rb_or_imm; - // signed overflow detection is same as for add, - // except we need to look at the *complemented* - // sign bit of the subtrahend (Rb), i.e., if the initial - // signs are the *same* then no overflow can occur - if (Ra<63:> != Rb_or_imm<63:> && tmp<63:> != Ra<63:>) - fault = new IntegerOverflowFault; - Rc = tmp; - }}); - 0x2b: s4subq({{ Rc = (Ra << 2) - Rb_or_imm; }}); - 0x3b: s8subq({{ Rc = (Ra << 3) - Rb_or_imm; }}); - - 0x2d: cmpeq({{ Rc = (Ra == Rb_or_imm); }}); - 0x6d: cmple({{ Rc = (Ra.sq <= Rb_or_imm.sq); }}); - 0x4d: cmplt({{ Rc = (Ra.sq < Rb_or_imm.sq); }}); - 0x3d: cmpule({{ Rc = (Ra.uq <= Rb_or_imm.uq); }}); - 0x1d: cmpult({{ Rc = (Ra.uq < Rb_or_imm.uq); }}); - - 0x0f: cmpbge({{ - int hi = 7; - int lo = 0; - uint64_t tmp = 0; - for (int i = 0; i < 8; ++i) { - tmp |= (Ra.uq<hi:lo> >= Rb_or_imm.uq<hi:lo>) << i; - hi += 8; - lo += 8; - } - Rc = tmp; - }}); - } - - 0x11: decode INTFUNC { // integer logical operations - - 0x00: and({{ Rc = Ra & Rb_or_imm; }}); - 0x08: bic({{ Rc = Ra & ~Rb_or_imm; }}); - 0x20: bis({{ Rc = Ra | Rb_or_imm; }}); - 0x28: ornot({{ Rc = Ra | ~Rb_or_imm; }}); - 0x40: xor({{ Rc = Ra ^ Rb_or_imm; }}); - 0x48: eqv({{ Rc = Ra ^ ~Rb_or_imm; }}); - - // conditional moves - 0x14: cmovlbs({{ Rc = ((Ra & 1) == 1) ? Rb_or_imm : Rc; }}); - 0x16: cmovlbc({{ Rc = ((Ra & 1) == 0) ? Rb_or_imm : Rc; }}); - 0x24: cmoveq({{ Rc = (Ra == 0) ? Rb_or_imm : Rc; }}); - 0x26: cmovne({{ Rc = (Ra != 0) ? Rb_or_imm : Rc; }}); - 0x44: cmovlt({{ Rc = (Ra.sq < 0) ? Rb_or_imm : Rc; }}); - 0x46: cmovge({{ Rc = (Ra.sq >= 0) ? Rb_or_imm : Rc; }}); - 0x64: cmovle({{ Rc = (Ra.sq <= 0) ? Rb_or_imm : Rc; }}); - 0x66: cmovgt({{ Rc = (Ra.sq > 0) ? Rb_or_imm : Rc; }}); - - // For AMASK, RA must be R31. - 0x61: decode RA { - 31: amask({{ Rc = Rb_or_imm & ~ULL(0x17); }}); - } - - // For IMPLVER, RA must be R31 and the B operand - // must be the immediate value 1. - 0x6c: decode RA { - 31: decode IMM { - 1: decode INTIMM { - // return EV5 for FULL_SYSTEM and EV6 otherwise - 1: implver({{ -#if FULL_SYSTEM - Rc = 1; -#else - Rc = 2; -#endif - }}); - } - } - } - -#if FULL_SYSTEM - // The mysterious 11.25... - 0x25: WarnUnimpl::eleven25(); -#endif - } - - 0x12: decode INTFUNC { - 0x39: sll({{ Rc = Ra << Rb_or_imm<5:0>; }}); - 0x34: srl({{ Rc = Ra.uq >> Rb_or_imm<5:0>; }}); - 0x3c: sra({{ Rc = Ra.sq >> Rb_or_imm<5:0>; }}); - - 0x02: mskbl({{ Rc = Ra & ~(mask( 8) << (Rb_or_imm<2:0> * 8)); }}); - 0x12: mskwl({{ Rc = Ra & ~(mask(16) << (Rb_or_imm<2:0> * 8)); }}); - 0x22: mskll({{ Rc = Ra & ~(mask(32) << (Rb_or_imm<2:0> * 8)); }}); - 0x32: mskql({{ Rc = Ra & ~(mask(64) << (Rb_or_imm<2:0> * 8)); }}); - - 0x52: mskwh({{ - int bv = Rb_or_imm<2:0>; - Rc = bv ? (Ra & ~(mask(16) >> (64 - 8 * bv))) : Ra; - }}); - 0x62: msklh({{ - int bv = Rb_or_imm<2:0>; - Rc = bv ? (Ra & ~(mask(32) >> (64 - 8 * bv))) : Ra; - }}); - 0x72: mskqh({{ - int bv = Rb_or_imm<2:0>; - Rc = bv ? (Ra & ~(mask(64) >> (64 - 8 * bv))) : Ra; - }}); - - 0x06: extbl({{ Rc = (Ra.uq >> (Rb_or_imm<2:0> * 8))< 7:0>; }}); - 0x16: extwl({{ Rc = (Ra.uq >> (Rb_or_imm<2:0> * 8))<15:0>; }}); - 0x26: extll({{ Rc = (Ra.uq >> (Rb_or_imm<2:0> * 8))<31:0>; }}); - 0x36: extql({{ Rc = (Ra.uq >> (Rb_or_imm<2:0> * 8)); }}); - - 0x5a: extwh({{ - Rc = (Ra << (64 - (Rb_or_imm<2:0> * 8))<5:0>)<15:0>; }}); - 0x6a: extlh({{ - Rc = (Ra << (64 - (Rb_or_imm<2:0> * 8))<5:0>)<31:0>; }}); - 0x7a: extqh({{ - Rc = (Ra << (64 - (Rb_or_imm<2:0> * 8))<5:0>); }}); - - 0x0b: insbl({{ Rc = Ra< 7:0> << (Rb_or_imm<2:0> * 8); }}); - 0x1b: inswl({{ Rc = Ra<15:0> << (Rb_or_imm<2:0> * 8); }}); - 0x2b: insll({{ Rc = Ra<31:0> << (Rb_or_imm<2:0> * 8); }}); - 0x3b: insql({{ Rc = Ra << (Rb_or_imm<2:0> * 8); }}); - - 0x57: inswh({{ - int bv = Rb_or_imm<2:0>; - Rc = bv ? (Ra.uq<15:0> >> (64 - 8 * bv)) : 0; - }}); - 0x67: inslh({{ - int bv = Rb_or_imm<2:0>; - Rc = bv ? (Ra.uq<31:0> >> (64 - 8 * bv)) : 0; - }}); - 0x77: insqh({{ - int bv = Rb_or_imm<2:0>; - Rc = bv ? (Ra.uq >> (64 - 8 * bv)) : 0; - }}); - - 0x30: zap({{ - uint64_t zapmask = 0; - for (int i = 0; i < 8; ++i) { - if (Rb_or_imm<i:>) - zapmask |= (mask(8) << (i * 8)); - } - Rc = Ra & ~zapmask; - }}); - 0x31: zapnot({{ - uint64_t zapmask = 0; - for (int i = 0; i < 8; ++i) { - if (!Rb_or_imm<i:>) - zapmask |= (mask(8) << (i * 8)); - } - Rc = Ra & ~zapmask; - }}); - } - - 0x13: decode INTFUNC { // integer multiplies - 0x00: mull({{ Rc.sl = Ra.sl * Rb_or_imm.sl; }}, IntMultOp); - 0x20: mulq({{ Rc = Ra * Rb_or_imm; }}, IntMultOp); - 0x30: umulh({{ - uint64_t hi, lo; - mul128(Ra, Rb_or_imm, hi, lo); - Rc = hi; - }}, IntMultOp); - 0x40: mullv({{ - // 32-bit multiply with trap on overflow - int64_t Rax = Ra.sl; // sign extended version of Ra.sl - int64_t Rbx = Rb_or_imm.sl; - int64_t tmp = Rax * Rbx; - // To avoid overflow, all the upper 32 bits must match - // the sign bit of the lower 32. We code this as - // checking the upper 33 bits for all 0s or all 1s. - uint64_t sign_bits = tmp<63:31>; - if (sign_bits != 0 && sign_bits != mask(33)) - fault = new IntegerOverflowFault; - Rc.sl = tmp<31:0>; - }}, IntMultOp); - 0x60: mulqv({{ - // 64-bit multiply with trap on overflow - uint64_t hi, lo; - mul128(Ra, Rb_or_imm, hi, lo); - // all the upper 64 bits must match the sign bit of - // the lower 64 - if (!((hi == 0 && lo<63:> == 0) || - (hi == mask(64) && lo<63:> == 1))) - fault = new IntegerOverflowFault; - Rc = lo; - }}, IntMultOp); - } - - 0x1c: decode INTFUNC { - 0x00: decode RA { 31: sextb({{ Rc.sb = Rb_or_imm< 7:0>; }}); } - 0x01: decode RA { 31: sextw({{ Rc.sw = Rb_or_imm<15:0>; }}); } - 0x32: ctlz({{ - uint64_t count = 0; - uint64_t temp = Rb; - if (temp<63:32>) temp >>= 32; else count += 32; - if (temp<31:16>) temp >>= 16; else count += 16; - if (temp<15:8>) temp >>= 8; else count += 8; - if (temp<7:4>) temp >>= 4; else count += 4; - if (temp<3:2>) temp >>= 2; else count += 2; - if (temp<1:1>) temp >>= 1; else count += 1; - if ((temp<0:0>) != 0x1) count += 1; - Rc = count; - }}, IntAluOp); - - 0x33: cttz({{ - uint64_t count = 0; - uint64_t temp = Rb; - if (!(temp<31:0>)) { temp >>= 32; count += 32; } - if (!(temp<15:0>)) { temp >>= 16; count += 16; } - if (!(temp<7:0>)) { temp >>= 8; count += 8; } - if (!(temp<3:0>)) { temp >>= 4; count += 4; } - if (!(temp<1:0>)) { temp >>= 2; count += 2; } - if (!(temp<0:0> & ULL(0x1))) count += 1; - Rc = count; - }}, IntAluOp); - - format FailUnimpl { - 0x30: ctpop(); - 0x31: perr(); - 0x34: unpkbw(); - 0x35: unpkbl(); - 0x36: pkwb(); - 0x37: pklb(); - 0x38: minsb8(); - 0x39: minsw4(); - 0x3a: minub8(); - 0x3b: minuw4(); - 0x3c: maxub8(); - 0x3d: maxuw4(); - 0x3e: maxsb8(); - 0x3f: maxsw4(); - } - - format BasicOperateWithNopCheck { - 0x70: decode RB { - 31: ftoit({{ Rc = Fa.uq; }}, FloatCvtOp); - } - 0x78: decode RB { - 31: ftois({{ Rc.sl = t_to_s(Fa.uq); }}, - FloatCvtOp); - } - } - } - } - - // Conditional branches. - format CondBranch { - 0x39: beq({{ cond = (Ra == 0); }}); - 0x3d: bne({{ cond = (Ra != 0); }}); - 0x3e: bge({{ cond = (Ra.sq >= 0); }}); - 0x3f: bgt({{ cond = (Ra.sq > 0); }}); - 0x3b: ble({{ cond = (Ra.sq <= 0); }}); - 0x3a: blt({{ cond = (Ra.sq < 0); }}); - 0x38: blbc({{ cond = ((Ra & 1) == 0); }}); - 0x3c: blbs({{ cond = ((Ra & 1) == 1); }}); - - 0x31: fbeq({{ cond = (Fa == 0); }}); - 0x35: fbne({{ cond = (Fa != 0); }}); - 0x36: fbge({{ cond = (Fa >= 0); }}); - 0x37: fbgt({{ cond = (Fa > 0); }}); - 0x33: fble({{ cond = (Fa <= 0); }}); - 0x32: fblt({{ cond = (Fa < 0); }}); - } - - // unconditional branches - format UncondBranch { - 0x30: br(); - 0x34: bsr(IsCall); - } - - // indirect branches - 0x1a: decode JMPFUNC { - format Jump { - 0: jmp(); - 1: jsr(IsCall); - 2: ret(IsReturn); - 3: jsr_coroutine(IsCall, IsReturn); - } - } - - // Square root and integer-to-FP moves - 0x14: decode FP_SHORTFUNC { - // Integer to FP register moves must have RB == 31 - 0x4: decode RB { - 31: decode FP_FULLFUNC { - format BasicOperateWithNopCheck { - 0x004: itofs({{ Fc.uq = s_to_t(Ra.ul); }}, FloatCvtOp); - 0x024: itoft({{ Fc.uq = Ra.uq; }}, FloatCvtOp); - 0x014: FailUnimpl::itoff(); // VAX-format conversion - } - } - } - - // Square root instructions must have FA == 31 - 0xb: decode FA { - 31: decode FP_TYPEFUNC { - format FloatingPointOperate { -#if SS_COMPATIBLE_FP - 0x0b: sqrts({{ - if (Fb < 0.0) - fault = new ArithmeticFault; - Fc = sqrt(Fb); - }}, FloatSqrtOp); -#else - 0x0b: sqrts({{ - if (Fb.sf < 0.0) - fault = new ArithmeticFault; - Fc.sf = sqrt(Fb.sf); - }}, FloatSqrtOp); -#endif - 0x2b: sqrtt({{ - if (Fb < 0.0) - fault = new ArithmeticFault; - Fc = sqrt(Fb); - }}, FloatSqrtOp); - } - } - } - - // VAX-format sqrtf and sqrtg are not implemented - 0xa: FailUnimpl::sqrtfg(); - } - - // IEEE floating point - 0x16: decode FP_SHORTFUNC_TOP2 { - // The top two bits of the short function code break this - // space into four groups: binary ops, compares, reserved, and - // conversions. See Table 4-12 of AHB. There are different - // special cases in these different groups, so we decode on - // these top two bits first just to select a decode strategy. - // Most of these instructions may have various trapping and - // rounding mode flags set; these are decoded in the - // FloatingPointDecode template used by the - // FloatingPointOperate format. - - // add/sub/mul/div: just decode on the short function code - // and source type. All valid trapping and rounding modes apply. - 0: decode FP_TRAPMODE { - // check for valid trapping modes here - 0,1,5,7: decode FP_TYPEFUNC { - format FloatingPointOperate { -#if SS_COMPATIBLE_FP - 0x00: adds({{ Fc = Fa + Fb; }}); - 0x01: subs({{ Fc = Fa - Fb; }}); - 0x02: muls({{ Fc = Fa * Fb; }}, FloatMultOp); - 0x03: divs({{ Fc = Fa / Fb; }}, FloatDivOp); -#else - 0x00: adds({{ Fc.sf = Fa.sf + Fb.sf; }}); - 0x01: subs({{ Fc.sf = Fa.sf - Fb.sf; }}); - 0x02: muls({{ Fc.sf = Fa.sf * Fb.sf; }}, FloatMultOp); - 0x03: divs({{ Fc.sf = Fa.sf / Fb.sf; }}, FloatDivOp); -#endif - - 0x20: addt({{ Fc = Fa + Fb; }}); - 0x21: subt({{ Fc = Fa - Fb; }}); - 0x22: mult({{ Fc = Fa * Fb; }}, FloatMultOp); - 0x23: divt({{ Fc = Fa / Fb; }}, FloatDivOp); - } - } - } - - // Floating-point compare instructions must have the default - // rounding mode, and may use the default trapping mode or - // /SU. Both trapping modes are treated the same by M5; the - // only difference on the real hardware (as far a I can tell) - // is that without /SU you'd get an imprecise trap if you - // tried to compare a NaN with something else (instead of an - // "unordered" result). - 1: decode FP_FULLFUNC { - format BasicOperateWithNopCheck { - 0x0a5, 0x5a5: cmpteq({{ Fc = (Fa == Fb) ? 2.0 : 0.0; }}, - FloatCmpOp); - 0x0a7, 0x5a7: cmptle({{ Fc = (Fa <= Fb) ? 2.0 : 0.0; }}, - FloatCmpOp); - 0x0a6, 0x5a6: cmptlt({{ Fc = (Fa < Fb) ? 2.0 : 0.0; }}, - FloatCmpOp); - 0x0a4, 0x5a4: cmptun({{ // unordered - Fc = (!(Fa < Fb) && !(Fa == Fb) && !(Fa > Fb)) ? 2.0 : 0.0; - }}, FloatCmpOp); - } - } - - // The FP-to-integer and integer-to-FP conversion insts - // require that FA be 31. - 3: decode FA { - 31: decode FP_TYPEFUNC { - format FloatingPointOperate { - 0x2f: decode FP_ROUNDMODE { - format FPFixedRounding { - // "chopped" i.e. round toward zero - 0: cvttq({{ Fc.sq = (int64_t)trunc(Fb); }}, - Chopped); - // round to minus infinity - 1: cvttq({{ Fc.sq = (int64_t)floor(Fb); }}, - MinusInfinity); - } - default: cvttq({{ Fc.sq = (int64_t)nearbyint(Fb); }}); - } - - // The cvtts opcode is overloaded to be cvtst if the trap - // mode is 2 or 6 (which are not valid otherwise) - 0x2c: decode FP_FULLFUNC { - format BasicOperateWithNopCheck { - // trap on denorm version "cvtst/s" is - // simulated same as cvtst - 0x2ac, 0x6ac: cvtst({{ Fc = Fb.sf; }}); - } - default: cvtts({{ Fc.sf = Fb; }}); - } - - // The trapping mode for integer-to-FP conversions - // must be /SUI or nothing; /U and /SU are not - // allowed. The full set of rounding modes are - // supported though. - 0x3c: decode FP_TRAPMODE { - 0,7: cvtqs({{ Fc.sf = Fb.sq; }}); - } - 0x3e: decode FP_TRAPMODE { - 0,7: cvtqt({{ Fc = Fb.sq; }}); - } - } - } - } - } - - // misc FP operate - 0x17: decode FP_FULLFUNC { - format BasicOperateWithNopCheck { - 0x010: cvtlq({{ - Fc.sl = (Fb.uq<63:62> << 30) | Fb.uq<58:29>; - }}); - 0x030: cvtql({{ - Fc.uq = (Fb.uq<31:30> << 62) | (Fb.uq<29:0> << 29); - }}); - - // We treat the precise & imprecise trapping versions of - // cvtql identically. - 0x130, 0x530: cvtqlv({{ - // To avoid overflow, all the upper 32 bits must match - // the sign bit of the lower 32. We code this as - // checking the upper 33 bits for all 0s or all 1s. - uint64_t sign_bits = Fb.uq<63:31>; - if (sign_bits != 0 && sign_bits != mask(33)) - fault = new IntegerOverflowFault; - Fc.uq = (Fb.uq<31:30> << 62) | (Fb.uq<29:0> << 29); - }}); - - 0x020: cpys({{ // copy sign - Fc.uq = (Fa.uq<63:> << 63) | Fb.uq<62:0>; - }}); - 0x021: cpysn({{ // copy sign negated - Fc.uq = (~Fa.uq<63:> << 63) | Fb.uq<62:0>; - }}); - 0x022: cpyse({{ // copy sign and exponent - Fc.uq = (Fa.uq<63:52> << 52) | Fb.uq<51:0>; - }}); - - 0x02a: fcmoveq({{ Fc = (Fa == 0) ? Fb : Fc; }}); - 0x02b: fcmovne({{ Fc = (Fa != 0) ? Fb : Fc; }}); - 0x02c: fcmovlt({{ Fc = (Fa < 0) ? Fb : Fc; }}); - 0x02d: fcmovge({{ Fc = (Fa >= 0) ? Fb : Fc; }}); - 0x02e: fcmovle({{ Fc = (Fa <= 0) ? Fb : Fc; }}); - 0x02f: fcmovgt({{ Fc = (Fa > 0) ? Fb : Fc; }}); - - 0x024: mt_fpcr({{ FPCR = Fa.uq; }}, IsIprAccess); - 0x025: mf_fpcr({{ Fa.uq = FPCR; }}, IsIprAccess); - } - } - - // miscellaneous mem-format ops - 0x18: decode MEMFUNC { - format WarnUnimpl { - 0x8000: fetch(); - 0xa000: fetch_m(); - 0xe800: ecb(); - } - - format MiscPrefetch { - 0xf800: wh64({{ EA = Rb & ~ULL(63); }}, - {{ xc->writeHint(EA, 64, memAccessFlags); }}, - mem_flags = NO_FAULT, - inst_flags = [IsMemRef, IsDataPrefetch, - IsStore, MemWriteOp]); - } - - format BasicOperate { - 0xc000: rpcc({{ -#if FULL_SYSTEM - /* Rb is a fake dependency so here is a fun way to get - * the parser to understand that. - */ - Ra = xc->readMiscRegWithEffect(AlphaISA::IPR_CC, fault) + (Rb & 0); - -#else - Ra = curTick; -#endif - }}, IsUnverifiable); - - // All of the barrier instructions below do nothing in - // their execute() methods (hence the empty code blocks). - // All of their functionality is hard-coded in the - // pipeline based on the flags IsSerializing, - // IsMemBarrier, and IsWriteBarrier. In the current - // detailed CPU model, the execute() function only gets - // called at fetch, so there's no way to generate pipeline - // behavior at any other stage. Once we go to an - // exec-in-exec CPU model we should be able to get rid of - // these flags and implement this behavior via the - // execute() methods. - - // trapb is just a barrier on integer traps, where excb is - // a barrier on integer and FP traps. "EXCB is thus a - // superset of TRAPB." (Alpha ARM, Sec 4.11.4) We treat - // them the same though. - 0x0000: trapb({{ }}, IsSerializing, IsSerializeBefore, No_OpClass); - 0x0400: excb({{ }}, IsSerializing, IsSerializeBefore, No_OpClass); - 0x4000: mb({{ }}, IsMemBarrier, MemReadOp); - 0x4400: wmb({{ }}, IsWriteBarrier, MemWriteOp); - } - -#if FULL_SYSTEM - format BasicOperate { - 0xe000: rc({{ - Ra = xc->readIntrFlag(); - xc->setIntrFlag(0); - }}, IsNonSpeculative); - 0xf000: rs({{ - Ra = xc->readIntrFlag(); - xc->setIntrFlag(1); - }}, IsNonSpeculative); - } -#else - format FailUnimpl { - 0xe000: rc(); - 0xf000: rs(); - } -#endif - } - -#if FULL_SYSTEM - 0x00: CallPal::call_pal({{ - if (!palValid || - (palPriv - && xc->readMiscRegWithEffect(AlphaISA::IPR_ICM, fault) != AlphaISA::mode_kernel)) { - // invalid pal function code, or attempt to do privileged - // PAL call in non-kernel mode - fault = new UnimplementedOpcodeFault; - } - else { - // check to see if simulator wants to do something special - // on this PAL call (including maybe suppress it) - bool dopal = xc->simPalCheck(palFunc); - - if (dopal) { - xc->setMiscRegWithEffect(AlphaISA::IPR_EXC_ADDR, NPC); - NPC = xc->readMiscRegWithEffect(AlphaISA::IPR_PAL_BASE, fault) + palOffset; - } - } - }}, IsNonSpeculative); -#else - 0x00: decode PALFUNC { - format EmulatedCallPal { - 0x00: halt ({{ - SimExit(curTick, "halt instruction encountered"); - }}, IsNonSpeculative); - 0x83: callsys({{ - xc->syscall(); - }}, IsNonSpeculative); - // Read uniq reg into ABI return value register (r0) - 0x9e: rduniq({{ R0 = Runiq; }}, IsIprAccess); - // Write uniq reg with value from ABI arg register (r16) - 0x9f: wruniq({{ Runiq = R16; }}, IsIprAccess); - } - } -#endif - -#if FULL_SYSTEM - 0x1b: decode PALMODE { - 0: OpcdecFault::hw_st_quad(); - 1: decode HW_LDST_QUAD { - format HwLoad { - 0: hw_ld({{ EA = (Rb + disp) & ~3; }}, {{ Ra = Mem.ul; }}, L); - 1: hw_ld({{ EA = (Rb + disp) & ~7; }}, {{ Ra = Mem.uq; }}, Q); - } - } - } - - 0x1f: decode PALMODE { - 0: OpcdecFault::hw_st_cond(); - format HwStore { - 1: decode HW_LDST_COND { - 0: decode HW_LDST_QUAD { - 0: hw_st({{ EA = (Rb + disp) & ~3; }}, - {{ Mem.ul = Ra<31:0>; }}, L); - 1: hw_st({{ EA = (Rb + disp) & ~7; }}, - {{ Mem.uq = Ra.uq; }}, Q); - } - - 1: FailUnimpl::hw_st_cond(); - } - } - } - - 0x19: decode PALMODE { - 0: OpcdecFault::hw_mfpr(); - format HwMoveIPR { - 1: hw_mfpr({{ - Ra = xc->readMiscRegWithEffect(ipr_index, fault); - }}, IsIprAccess); - } - } - - 0x1d: decode PALMODE { - 0: OpcdecFault::hw_mtpr(); - format HwMoveIPR { - 1: hw_mtpr({{ - xc->setMiscRegWithEffect(ipr_index, Ra); - if (traceData) { traceData->setData(Ra); } - }}, IsIprAccess); - } - } - - format BasicOperate { - 0x1e: decode PALMODE { - 0: OpcdecFault::hw_rei(); - 1:hw_rei({{ xc->hwrei(); }}, IsSerializing, IsSerializeBefore); - } - - // M5 special opcodes use the reserved 0x01 opcode space - 0x01: decode M5FUNC { - 0x00: arm({{ - AlphaPseudo::arm(xc->xcBase()); - }}, IsNonSpeculative); - 0x01: quiesce({{ - AlphaPseudo::quiesce(xc->xcBase()); - }}, IsNonSpeculative, IsQuiesce); - 0x02: quiesceNs({{ - AlphaPseudo::quiesceNs(xc->xcBase(), R16); - }}, IsNonSpeculative, IsQuiesce); - 0x03: quiesceCycles({{ - AlphaPseudo::quiesceCycles(xc->xcBase(), R16); - }}, IsNonSpeculative, IsQuiesce); - 0x04: quiesceTime({{ - R0 = AlphaPseudo::quiesceTime(xc->xcBase()); - }}, IsNonSpeculative); - 0x10: ivlb({{ - AlphaPseudo::ivlb(xc->xcBase()); - }}, No_OpClass, IsNonSpeculative); - 0x11: ivle({{ - AlphaPseudo::ivle(xc->xcBase()); - }}, No_OpClass, IsNonSpeculative); - 0x20: m5exit_old({{ - AlphaPseudo::m5exit_old(xc->xcBase()); - }}, No_OpClass, IsNonSpeculative); - 0x21: m5exit({{ - AlphaPseudo::m5exit(xc->xcBase(), R16); - }}, No_OpClass, IsNonSpeculative); - 0x30: initparam({{ Ra = xc->xcBase()->getCpuPtr()->system->init_param; }}); - 0x40: resetstats({{ - AlphaPseudo::resetstats(xc->xcBase(), R16, R17); - }}, IsNonSpeculative); - 0x41: dumpstats({{ - AlphaPseudo::dumpstats(xc->xcBase(), R16, R17); - }}, IsNonSpeculative); - 0x42: dumpresetstats({{ - AlphaPseudo::dumpresetstats(xc->xcBase(), R16, R17); - }}, IsNonSpeculative); - 0x43: m5checkpoint({{ - AlphaPseudo::m5checkpoint(xc->xcBase(), R16, R17); - }}, IsNonSpeculative); - 0x50: m5readfile({{ - R0 = AlphaPseudo::readfile(xc->xcBase(), R16, R17, R18); - }}, IsNonSpeculative); - 0x51: m5break({{ - AlphaPseudo::debugbreak(xc->xcBase()); - }}, IsNonSpeculative); - 0x52: m5switchcpu({{ - AlphaPseudo::switchcpu(xc->xcBase()); - }}, IsNonSpeculative); - 0x53: m5addsymbol({{ - AlphaPseudo::addsymbol(xc->xcBase(), R16, R17); - }}, IsNonSpeculative); - 0x54: m5panic({{ - panic("M5 panic instruction called at pc=%#x.", xc->readPC()); - }}, IsNonSpeculative); - - } - } -#endif -} diff --git a/arch/alpha/isa/fp.isa b/arch/alpha/isa/fp.isa deleted file mode 100644 index f34c13c42..000000000 --- a/arch/alpha/isa/fp.isa +++ /dev/null @@ -1,301 +0,0 @@ -// -*- mode:c++ -*- - -// Copyright (c) 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. - -output exec {{ - /// Check "FP enabled" machine status bit. Called when executing any FP - /// instruction in full-system mode. - /// @retval Full-system mode: NoFault if FP is enabled, FenFault - /// if not. Non-full-system mode: always returns NoFault. -#if FULL_SYSTEM - inline Fault checkFpEnableFault(%(CPU_exec_context)s *xc) - { - Fault fault = NoFault; // dummy... this ipr access should not fault - if (!EV5::ICSR_FPE(xc->readMiscRegWithEffect(AlphaISA::IPR_ICSR, fault))) { - fault = new FloatEnableFault; - } - return fault; - } -#else - inline Fault checkFpEnableFault(%(CPU_exec_context)s *xc) - { - return NoFault; - } -#endif -}}; - -output header {{ - /** - * Base class for general floating-point instructions. Includes - * support for various Alpha rounding and trapping modes. Only FP - * instructions that require this support are derived from this - * class; the rest derive directly from AlphaStaticInst. - */ - class AlphaFP : public AlphaStaticInst - { - public: - /// Alpha FP rounding modes. - enum RoundingMode { - Chopped = 0, ///< round toward zero - Minus_Infinity = 1, ///< round toward minus infinity - Normal = 2, ///< round to nearest (default) - Dynamic = 3, ///< use FPCR setting (in instruction) - Plus_Infinity = 3 ///< round to plus inifinity (in FPCR) - }; - - /// Alpha FP trapping modes. - /// For instructions that produce integer results, the - /// "Underflow Enable" modes really mean "Overflow Enable", and - /// the assembly modifier is V rather than U. - enum TrappingMode { - /// default: nothing enabled - Imprecise = 0, ///< no modifier - /// underflow/overflow traps enabled, inexact disabled - Underflow_Imprecise = 1, ///< /U or /V - Underflow_Precise = 5, ///< /SU or /SV - /// underflow/overflow and inexact traps enabled - Underflow_Inexact_Precise = 7 ///< /SUI or /SVI - }; - - protected: - /// Map Alpha rounding mode to C99 constants from <fenv.h>. - static const int alphaToC99RoundingMode[]; - - /// Map enum RoundingMode values to disassembly suffixes. - static const char *roundingModeSuffix[]; - /// Map enum TrappingMode values to FP disassembly suffixes. - static const char *fpTrappingModeSuffix[]; - /// Map enum TrappingMode values to integer disassembly suffixes. - static const char *intTrappingModeSuffix[]; - - /// This instruction's rounding mode. - RoundingMode roundingMode; - /// This instruction's trapping mode. - TrappingMode trappingMode; - - /// Have we warned about this instruction's unsupported - /// rounding mode (if applicable)? - mutable bool warnedOnRounding; - - /// Have we warned about this instruction's unsupported - /// trapping mode (if applicable)? - mutable bool warnedOnTrapping; - - /// Constructor - AlphaFP(const char *mnem, ExtMachInst _machInst, OpClass __opClass) - : AlphaStaticInst(mnem, _machInst, __opClass), - roundingMode((enum RoundingMode)FP_ROUNDMODE), - trappingMode((enum TrappingMode)FP_TRAPMODE), - warnedOnRounding(false), - warnedOnTrapping(false) - { - } - - int getC99RoundingMode(uint64_t fpcr_val) const; - - // This differs from the AlphaStaticInst version only in - // printing suffixes for non-default rounding & trapping modes. - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; - -}}; - - -output decoder {{ - int - AlphaFP::getC99RoundingMode(uint64_t fpcr_val) const - { - if (roundingMode == Dynamic) { - return alphaToC99RoundingMode[bits(fpcr_val, 59, 58)]; - } - else { - return alphaToC99RoundingMode[roundingMode]; - } - } - - std::string - AlphaFP::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - std::string mnem_str(mnemonic); - -#ifndef SS_COMPATIBLE_DISASSEMBLY - std::string suffix(""); - suffix += ((_destRegIdx[0] >= FP_Base_DepTag) - ? fpTrappingModeSuffix[trappingMode] - : intTrappingModeSuffix[trappingMode]); - suffix += roundingModeSuffix[roundingMode]; - - if (suffix != "") { - mnem_str = csprintf("%s/%s", mnemonic, suffix); - } -#endif - - std::stringstream ss; - ccprintf(ss, "%-10s ", mnem_str.c_str()); - - // just print the first two source regs... if there's - // a third one, it's a read-modify-write dest (Rc), - // e.g. for CMOVxx - if (_numSrcRegs > 0) { - printReg(ss, _srcRegIdx[0]); - } - if (_numSrcRegs > 1) { - ss << ","; - printReg(ss, _srcRegIdx[1]); - } - - // just print the first dest... if there's a second one, - // it's generally implicit - if (_numDestRegs > 0) { - if (_numSrcRegs > 0) - ss << ","; - printReg(ss, _destRegIdx[0]); - } - - return ss.str(); - } - - const int AlphaFP::alphaToC99RoundingMode[] = { - FE_TOWARDZERO, // Chopped - FE_DOWNWARD, // Minus_Infinity - FE_TONEAREST, // Normal - FE_UPWARD // Dynamic in inst, Plus_Infinity in FPCR - }; - - const char *AlphaFP::roundingModeSuffix[] = { "c", "m", "", "d" }; - // mark invalid trapping modes, but don't fail on them, because - // you could decode anything on a misspeculated path - const char *AlphaFP::fpTrappingModeSuffix[] = - { "", "u", "INVTM2", "INVTM3", "INVTM4", "su", "INVTM6", "sui" }; - const char *AlphaFP::intTrappingModeSuffix[] = - { "", "v", "INVTM2", "INVTM3", "INVTM4", "sv", "INVTM6", "svi" }; -}}; - -// FP instruction class execute method template. Handles non-standard -// rounding modes. -def template FloatingPointExecute {{ - Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - if (trappingMode != Imprecise && !warnedOnTrapping) { - warn("%s: non-standard trapping mode not supported", - generateDisassembly(0, NULL)); - warnedOnTrapping = true; - } - - Fault fault = NoFault; - - %(fp_enable_check)s; - %(op_decl)s; - %(op_rd)s; -#if USE_FENV - if (roundingMode == Normal) { - %(code)s; - } else { - fesetround(getC99RoundingMode( - xc->readMiscReg(AlphaISA::Fpcr_DepTag))); - %(code)s; - fesetround(FE_TONEAREST); - } -#else - if (roundingMode != Normal && !warnedOnRounding) { - warn("%s: non-standard rounding mode not supported", - generateDisassembly(0, NULL)); - warnedOnRounding = true; - } - %(code)s; -#endif - - if (fault == NoFault) { - %(op_wb)s; - } - - return fault; - } -}}; - -// FP instruction class execute method template where no dynamic -// rounding mode control is needed. Like BasicExecute, but includes -// check & warning for non-standard trapping mode. -def template FPFixedRoundingExecute {{ - Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - if (trappingMode != Imprecise && !warnedOnTrapping) { - warn("%s: non-standard trapping mode not supported", - generateDisassembly(0, NULL)); - warnedOnTrapping = true; - } - - Fault fault = NoFault; - - %(fp_enable_check)s; - %(op_decl)s; - %(op_rd)s; - %(code)s; - - if (fault == NoFault) { - %(op_wb)s; - } - - return fault; - } -}}; - -def template FloatingPointDecode {{ - { - AlphaStaticInst *i = new %(class_name)s(machInst); - if (FC == 31) { - i = makeNop(i); - } - return i; - } -}}; - -// General format for floating-point operate instructions: -// - Checks trapping and rounding mode flags. Trapping modes -// currently unimplemented (will fail). -// - Generates NOP if FC == 31. -def format FloatingPointOperate(code, *opt_args) {{ - iop = InstObjParams(name, Name, 'AlphaFP', CodeBlock(code), opt_args) - decode_block = FloatingPointDecode.subst(iop) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - exec_output = FloatingPointExecute.subst(iop) -}}; - -// Special format for cvttq where rounding mode is pre-decoded -def format FPFixedRounding(code, class_suffix, *opt_args) {{ - Name += class_suffix - iop = InstObjParams(name, Name, 'AlphaFP', CodeBlock(code), opt_args) - decode_block = FloatingPointDecode.subst(iop) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - exec_output = FPFixedRoundingExecute.subst(iop) -}}; - diff --git a/arch/alpha/isa/int.isa b/arch/alpha/isa/int.isa deleted file mode 100644 index 17ecc1a51..000000000 --- a/arch/alpha/isa/int.isa +++ /dev/null @@ -1,128 +0,0 @@ -// -*- mode:c++ -*- - -// Copyright (c) 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. - -output header {{ - /** - * Base class for integer immediate instructions. - */ - class IntegerImm : public AlphaStaticInst - { - protected: - /// Immediate operand value (unsigned 8-bit int). - uint8_t imm; - - /// Constructor - IntegerImm(const char *mnem, ExtMachInst _machInst, OpClass __opClass) - : AlphaStaticInst(mnem, _machInst, __opClass), imm(INTIMM) - { - } - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; -}}; - -output decoder {{ - std::string - IntegerImm::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - std::stringstream ss; - - ccprintf(ss, "%-10s ", mnemonic); - - // just print the first source reg... if there's - // a second one, it's a read-modify-write dest (Rc), - // e.g. for CMOVxx - if (_numSrcRegs > 0) { - printReg(ss, _srcRegIdx[0]); - ss << ","; - } - - ss << (int)imm; - - if (_numDestRegs > 0) { - ss << ","; - printReg(ss, _destRegIdx[0]); - } - - return ss.str(); - } -}}; - - -def template RegOrImmDecode {{ - { - AlphaStaticInst *i = - (IMM) ? (AlphaStaticInst *)new %(class_name)sImm(machInst) - : (AlphaStaticInst *)new %(class_name)s(machInst); - if (RC == 31) { - i = makeNop(i); - } - return i; - } -}}; - -// Primary format for integer operate instructions: -// - Generates both reg-reg and reg-imm versions if Rb_or_imm is used. -// - Generates NOP if RC == 31. -def format IntegerOperate(code, *opt_flags) {{ - # If the code block contains 'Rb_or_imm', we define two instructions, - # one using 'Rb' and one using 'imm', and have the decoder select - # the right one. - uses_imm = (code.find('Rb_or_imm') != -1) - if uses_imm: - orig_code = code - # base code is reg version: - # rewrite by substituting 'Rb' for 'Rb_or_imm' - code = re.sub(r'Rb_or_imm', 'Rb', orig_code) - # generate immediate version by substituting 'imm' - # note that imm takes no extenstion, so we extend - # the regexp to replace any extension as well - imm_code = re.sub(r'Rb_or_imm(\.\w+)?', 'imm', orig_code) - - # generate declaration for register version - cblk = CodeBlock(code) - iop = InstObjParams(name, Name, 'AlphaStaticInst', cblk, opt_flags) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - exec_output = BasicExecute.subst(iop) - - if uses_imm: - # append declaration for imm version - imm_cblk = CodeBlock(imm_code) - imm_iop = InstObjParams(name, Name + 'Imm', 'IntegerImm', imm_cblk, - opt_flags) - header_output += BasicDeclare.subst(imm_iop) - decoder_output += BasicConstructor.subst(imm_iop) - exec_output += BasicExecute.subst(imm_iop) - # decode checks IMM bit to pick correct version - decode_block = RegOrImmDecode.subst(iop) - else: - # no imm version: just check for nop - decode_block = OperateNopCheckDecode.subst(iop) -}}; diff --git a/arch/alpha/isa/main.isa b/arch/alpha/isa/main.isa deleted file mode 100644 index 80a5e9ca1..000000000 --- a/arch/alpha/isa/main.isa +++ /dev/null @@ -1,448 +0,0 @@ -// -*- mode:c++ -*- - -// Copyright (c) 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. - -output header {{ -#include <sstream> -#include <iostream> -#include <iomanip> - -#include "config/ss_compatible_fp.hh" -#include "cpu/static_inst.hh" -#include "arch/alpha/faults.hh" -#include "mem/mem_req.hh" // some constructors use MemReq flags -}}; - -output decoder {{ -#include "base/cprintf.hh" -#include "base/fenv.hh" -#include "base/loader/symtab.hh" -#include "config/ss_compatible_fp.hh" -#include "cpu/exec_context.hh" // for Jump::branchTarget() - -#include <math.h> - -using namespace AlphaISA; -}}; - -output exec {{ -#include <math.h> - -#if FULL_SYSTEM -#include "sim/pseudo_inst.hh" -#endif -#include "base/fenv.hh" -#include "config/ss_compatible_fp.hh" -#include "cpu/base.hh" -#include "cpu/exetrace.hh" -#include "sim/sim_exit.hh" - -using namespace AlphaISA; -}}; - -//////////////////////////////////////////////////////////////////// -// -// Namespace statement. Everything below this line will be in the -// AlphaISAInst namespace. -// - - -namespace AlphaISA; - -//////////////////////////////////////////////////////////////////// -// -// Bitfield definitions. -// - -// Universal (format-independent) fields -def bitfield PALMODE <32:32>; -def bitfield OPCODE <31:26>; -def bitfield RA <25:21>; -def bitfield RB <20:16>; - -// Memory format -def signed bitfield MEMDISP <15: 0>; // displacement -def bitfield MEMFUNC <15: 0>; // function code (same field, unsigned) - -// Memory-format jumps -def bitfield JMPFUNC <15:14>; // function code (disp<15:14>) -def bitfield JMPHINT <13: 0>; // tgt Icache idx hint (disp<13:0>) - -// Branch format -def signed bitfield BRDISP <20: 0>; // displacement - -// Integer operate format(s>; -def bitfield INTIMM <20:13>; // integer immediate (literal) -def bitfield IMM <12:12>; // immediate flag -def bitfield INTFUNC <11: 5>; // function code -def bitfield RC < 4: 0>; // dest reg - -// Floating-point operate format -def bitfield FA <25:21>; -def bitfield FB <20:16>; -def bitfield FP_FULLFUNC <15: 5>; // complete function code - def bitfield FP_TRAPMODE <15:13>; // trapping mode - def bitfield FP_ROUNDMODE <12:11>; // rounding mode - def bitfield FP_TYPEFUNC <10: 5>; // type+func: handiest for decoding - def bitfield FP_SRCTYPE <10: 9>; // source reg type - def bitfield FP_SHORTFUNC < 8: 5>; // short function code - def bitfield FP_SHORTFUNC_TOP2 <8:7>; // top 2 bits of short func code -def bitfield FC < 4: 0>; // dest reg - -// PALcode format -def bitfield PALFUNC <25: 0>; // function code - -// EV5 PAL instructions: -// HW_LD/HW_ST -def bitfield HW_LDST_PHYS <15>; // address is physical -def bitfield HW_LDST_ALT <14>; // use ALT_MODE IPR -def bitfield HW_LDST_WRTCK <13>; // HW_LD only: fault if no write acc -def bitfield HW_LDST_QUAD <12>; // size: 0=32b, 1=64b -def bitfield HW_LDST_VPTE <11>; // HW_LD only: is PTE fetch -def bitfield HW_LDST_LOCK <10>; // HW_LD only: is load locked -def bitfield HW_LDST_COND <10>; // HW_ST only: is store conditional -def signed bitfield HW_LDST_DISP <9:0>; // signed displacement - -// HW_REI -def bitfield HW_REI_TYP <15:14>; // type: stalling vs. non-stallingk -def bitfield HW_REI_MBZ <13: 0>; // must be zero - -// HW_MTPR/MW_MFPR -def bitfield HW_IPR_IDX <15:0>; // IPR index - -// M5 instructions -def bitfield M5FUNC <7:0>; - -def operand_types {{ - 'sb' : ('signed int', 8), - 'ub' : ('unsigned int', 8), - 'sw' : ('signed int', 16), - 'uw' : ('unsigned int', 16), - 'sl' : ('signed int', 32), - 'ul' : ('unsigned int', 32), - 'sq' : ('signed int', 64), - 'uq' : ('unsigned int', 64), - 'sf' : ('float', 32), - 'df' : ('float', 64) -}}; - -def operands {{ - # Int regs default to unsigned, but code should not count on this. - # For clarity, descriptions that depend on unsigned behavior should - # explicitly specify '.uq'. - 'Ra': ('IntReg', 'uq', 'PALMODE ? AlphaISA::reg_redir[RA] : RA', - 'IsInteger', 1), - 'Rb': ('IntReg', 'uq', 'PALMODE ? AlphaISA::reg_redir[RB] : RB', - 'IsInteger', 2), - 'Rc': ('IntReg', 'uq', 'PALMODE ? AlphaISA::reg_redir[RC] : RC', - 'IsInteger', 3), - 'Fa': ('FloatReg', 'df', 'FA', 'IsFloating', 1), - 'Fb': ('FloatReg', 'df', 'FB', 'IsFloating', 2), - 'Fc': ('FloatReg', 'df', 'FC', 'IsFloating', 3), - 'Mem': ('Mem', 'uq', None, ('IsMemRef', 'IsLoad', 'IsStore'), 4), - 'NPC': ('NPC', 'uq', None, ( None, None, 'IsControl' ), 4), - 'Runiq': ('ControlReg', 'uq', 'TheISA::Uniq_DepTag', None, 1), - 'FPCR': (' ControlReg', 'uq', 'TheISA::Fpcr_DepTag', None, 1), - # The next two are hacks for non-full-system call-pal emulation - 'R0': ('IntReg', 'uq', '0', None, 1), - 'R16': ('IntReg', 'uq', '16', None, 1), - 'R17': ('IntReg', 'uq', '17', None, 1), - 'R18': ('IntReg', 'uq', '18', None, 1) -}}; - -//////////////////////////////////////////////////////////////////// -// -// Basic instruction classes/templates/formats etc. -// - -output header {{ -// uncomment the following to get SimpleScalar-compatible disassembly -// (useful for diffing output traces). -// #define SS_COMPATIBLE_DISASSEMBLY - - /** - * Base class for all Alpha static instructions. - */ - class AlphaStaticInst : public StaticInst - { - protected: - - /// Make AlphaISA register dependence tags directly visible in - /// this class and derived classes. Maybe these should really - /// live here and not in the AlphaISA namespace. - enum DependenceTags { - FP_Base_DepTag = AlphaISA::FP_Base_DepTag, - Fpcr_DepTag = AlphaISA::Fpcr_DepTag, - Uniq_DepTag = AlphaISA::Uniq_DepTag, - Lock_Flag_DepTag = AlphaISA::Lock_Flag_DepTag, - Lock_Addr_DepTag = AlphaISA::Lock_Addr_DepTag, - IPR_Base_DepTag = AlphaISA::IPR_Base_DepTag - }; - - /// Constructor. - AlphaStaticInst(const char *mnem, ExtMachInst _machInst, - OpClass __opClass) - : StaticInst(mnem, _machInst, __opClass) - { - } - - /// Print a register name for disassembly given the unique - /// dependence tag number (FP or int). - void printReg(std::ostream &os, int reg) const; - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; -}}; - -output decoder {{ - void - AlphaStaticInst::printReg(std::ostream &os, int reg) const - { - if (reg < FP_Base_DepTag) { - ccprintf(os, "r%d", reg); - } - else { - ccprintf(os, "f%d", reg - FP_Base_DepTag); - } - } - - std::string - AlphaStaticInst::generateDisassembly(Addr pc, - const SymbolTable *symtab) const - { - std::stringstream ss; - - ccprintf(ss, "%-10s ", mnemonic); - - // just print the first two source regs... if there's - // a third one, it's a read-modify-write dest (Rc), - // e.g. for CMOVxx - if (_numSrcRegs > 0) { - printReg(ss, _srcRegIdx[0]); - } - if (_numSrcRegs > 1) { - ss << ","; - printReg(ss, _srcRegIdx[1]); - } - - // just print the first dest... if there's a second one, - // it's generally implicit - if (_numDestRegs > 0) { - if (_numSrcRegs > 0) - ss << ","; - printReg(ss, _destRegIdx[0]); - } - - return ss.str(); - } -}}; - -// Declarations for execute() methods. -def template BasicExecDeclare {{ - Fault execute(%(CPU_exec_context)s *, Trace::InstRecord *) const; -}}; - -// Basic instruction class declaration template. -def template BasicDeclare {{ - /** - * Static instruction class for "%(mnemonic)s". - */ - class %(class_name)s : public %(base_class)s - { - public: - /// Constructor. - %(class_name)s(ExtMachInst machInst); - - %(BasicExecDeclare)s - }; -}}; - -// Basic instruction class constructor template. -def template BasicConstructor {{ - inline %(class_name)s::%(class_name)s(ExtMachInst machInst) - : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s) - { - %(constructor)s; - } -}}; - -// Basic instruction class execute method template. -def template BasicExecute {{ - Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Fault fault = NoFault; - - %(fp_enable_check)s; - %(op_decl)s; - %(op_rd)s; - %(code)s; - - if (fault == NoFault) { - %(op_wb)s; - } - - return fault; - } -}}; - -// Basic decode template. -def template BasicDecode {{ - return new %(class_name)s(machInst); -}}; - -// Basic decode template, passing mnemonic in as string arg to constructor. -def template BasicDecodeWithMnemonic {{ - return new %(class_name)s("%(mnemonic)s", machInst); -}}; - -// The most basic instruction format... used only for a few misc. insts -def format BasicOperate(code, *flags) {{ - iop = InstObjParams(name, Name, 'AlphaStaticInst', CodeBlock(code), flags) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecode.subst(iop) - exec_output = BasicExecute.subst(iop) -}}; - - - -//////////////////////////////////////////////////////////////////// -// -// Nop -// - -output header {{ - /** - * Static instruction class for no-ops. This is a leaf class. - */ - class Nop : public AlphaStaticInst - { - /// Disassembly of original instruction. - const std::string originalDisassembly; - - public: - /// Constructor - Nop(const std::string _originalDisassembly, ExtMachInst _machInst) - : AlphaStaticInst("nop", _machInst, No_OpClass), - originalDisassembly(_originalDisassembly) - { - flags[IsNop] = true; - } - - ~Nop() { } - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - - %(BasicExecDeclare)s - }; - - /// Helper function for decoding nops. Substitute Nop object - /// for original inst passed in as arg (and delete latter). - static inline - AlphaStaticInst * - makeNop(AlphaStaticInst *inst) - { - AlphaStaticInst *nop = new Nop(inst->disassemble(0), inst->machInst); - delete inst; - return nop; - } -}}; - -output decoder {{ - std::string Nop::generateDisassembly(Addr pc, - const SymbolTable *symtab) const - { -#ifdef SS_COMPATIBLE_DISASSEMBLY - return originalDisassembly; -#else - return csprintf("%-10s (%s)", "nop", originalDisassembly); -#endif - } -}}; - -output exec {{ - Fault - Nop::execute(%(CPU_exec_context)s *, Trace::InstRecord *) const - { - return NoFault; - } -}}; - -// integer & FP operate instructions use Rc as dest, so check for -// Rc == 31 to detect nops -def template OperateNopCheckDecode {{ - { - AlphaStaticInst *i = new %(class_name)s(machInst); - if (RC == 31) { - i = makeNop(i); - } - return i; - } -}}; - -// Like BasicOperate format, but generates NOP if RC/FC == 31 -def format BasicOperateWithNopCheck(code, *opt_args) {{ - iop = InstObjParams(name, Name, 'AlphaStaticInst', CodeBlock(code), - opt_args) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = OperateNopCheckDecode.subst(iop) - exec_output = BasicExecute.subst(iop) -}}; - -// Integer instruction templates, formats, etc. -##include "int.isa" - -// Floating-point instruction templates, formats, etc. -##include "fp.isa" - -// Memory instruction templates, formats, etc. -##include "mem.isa" - -// Branch/jump instruction templates, formats, etc. -##include "branch.isa" - -// PAL instruction templates, formats, etc. -##include "pal.isa" - -// Opcdec fault instruction templates, formats, etc. -##include "opcdec.isa" - -// Unimplemented instruction templates, formats, etc. -##include "unimp.isa" - -// Unknown instruction templates, formats, etc. -##include "unknown.isa" - -// Execution utility functions -##include "util.isa" - -// The actual decoder -##include "decoder.isa" diff --git a/arch/alpha/isa/mem.isa b/arch/alpha/isa/mem.isa deleted file mode 100644 index 3c8b4f755..000000000 --- a/arch/alpha/isa/mem.isa +++ /dev/null @@ -1,702 +0,0 @@ -// -*- mode:c++ -*- - -// Copyright (c) 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. - -output header {{ - /** - * Base class for general Alpha memory-format instructions. - */ - class Memory : public AlphaStaticInst - { - protected: - - /// Memory request flags. See mem_req_base.hh. - unsigned memAccessFlags; - /// Pointer to EAComp object. - const StaticInstPtr eaCompPtr; - /// Pointer to MemAcc object. - const StaticInstPtr memAccPtr; - - /// Constructor - Memory(const char *mnem, ExtMachInst _machInst, OpClass __opClass, - StaticInstPtr _eaCompPtr = nullStaticInstPtr, - StaticInstPtr _memAccPtr = nullStaticInstPtr) - : AlphaStaticInst(mnem, _machInst, __opClass), - memAccessFlags(0), eaCompPtr(_eaCompPtr), memAccPtr(_memAccPtr) - { - } - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - - public: - - const StaticInstPtr &eaCompInst() const { return eaCompPtr; } - const StaticInstPtr &memAccInst() const { return memAccPtr; } - }; - - /** - * Base class for memory-format instructions using a 32-bit - * displacement (i.e. most of them). - */ - class MemoryDisp32 : public Memory - { - protected: - /// Displacement for EA calculation (signed). - int32_t disp; - - /// Constructor. - MemoryDisp32(const char *mnem, ExtMachInst _machInst, OpClass __opClass, - StaticInstPtr _eaCompPtr = nullStaticInstPtr, - StaticInstPtr _memAccPtr = nullStaticInstPtr) - : Memory(mnem, _machInst, __opClass, _eaCompPtr, _memAccPtr), - disp(MEMDISP) - { - } - }; - - - /** - * Base class for a few miscellaneous memory-format insts - * that don't interpret the disp field: wh64, fetch, fetch_m, ecb. - * None of these instructions has a destination register either. - */ - class MemoryNoDisp : public Memory - { - protected: - /// Constructor - MemoryNoDisp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, - StaticInstPtr _eaCompPtr = nullStaticInstPtr, - StaticInstPtr _memAccPtr = nullStaticInstPtr) - : Memory(mnem, _machInst, __opClass, _eaCompPtr, _memAccPtr) - { - } - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; -}}; - - -output decoder {{ - std::string - Memory::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - return csprintf("%-10s %c%d,%d(r%d)", mnemonic, - flags[IsFloating] ? 'f' : 'r', RA, MEMDISP, RB); - } - - std::string - MemoryNoDisp::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - return csprintf("%-10s (r%d)", mnemonic, RB); - } -}}; - -def format LoadAddress(code) {{ - iop = InstObjParams(name, Name, 'MemoryDisp32', CodeBlock(code)) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecode.subst(iop) - exec_output = BasicExecute.subst(iop) -}}; - - -def template LoadStoreDeclare {{ - /** - * Static instruction class for "%(mnemonic)s". - */ - class %(class_name)s : public %(base_class)s - { - protected: - - /** - * "Fake" effective address computation class for "%(mnemonic)s". - */ - class EAComp : public %(base_class)s - { - public: - /// Constructor - EAComp(ExtMachInst machInst); - - %(BasicExecDeclare)s - }; - - /** - * "Fake" memory access instruction class for "%(mnemonic)s". - */ - class MemAcc : public %(base_class)s - { - public: - /// Constructor - MemAcc(ExtMachInst machInst); - - %(BasicExecDeclare)s - }; - - public: - - /// Constructor. - %(class_name)s(ExtMachInst machInst); - - %(BasicExecDeclare)s - - %(InitiateAccDeclare)s - - %(CompleteAccDeclare)s - }; -}}; - - -def template InitiateAccDeclare {{ - Fault initiateAcc(%(CPU_exec_context)s *, Trace::InstRecord *) const; -}}; - - -def template CompleteAccDeclare {{ - Fault completeAcc(uint8_t *, %(CPU_exec_context)s *, Trace::InstRecord *) const; -}}; - - -def template LoadStoreConstructor {{ - /** TODO: change op_class to AddrGenOp or something (requires - * creating new member of OpClass enum in op_class.hh, updating - * config files, etc.). */ - inline %(class_name)s::EAComp::EAComp(ExtMachInst machInst) - : %(base_class)s("%(mnemonic)s (EAComp)", machInst, IntAluOp) - { - %(ea_constructor)s; - } - - inline %(class_name)s::MemAcc::MemAcc(ExtMachInst machInst) - : %(base_class)s("%(mnemonic)s (MemAcc)", machInst, %(op_class)s) - { - %(memacc_constructor)s; - } - - inline %(class_name)s::%(class_name)s(ExtMachInst machInst) - : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, - new EAComp(machInst), new MemAcc(machInst)) - { - %(constructor)s; - } -}}; - - -def template EACompExecute {{ - Fault - %(class_name)s::EAComp::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Addr EA; - Fault fault = NoFault; - - %(fp_enable_check)s; - %(op_decl)s; - %(op_rd)s; - %(code)s; - - if (fault == NoFault) { - %(op_wb)s; - xc->setEA(EA); - } - - return fault; - } -}}; - -def template LoadMemAccExecute {{ - Fault - %(class_name)s::MemAcc::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Addr EA; - Fault fault = NoFault; - - %(fp_enable_check)s; - %(op_decl)s; - %(op_rd)s; - EA = xc->getEA(); - - if (fault == NoFault) { - fault = xc->read(EA, (uint%(mem_acc_size)d_t&)Mem, memAccessFlags); - %(code)s; - } - - if (fault == NoFault) { - %(op_wb)s; - } - - return fault; - } -}}; - - -def template LoadExecute {{ - Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Addr EA; - Fault fault = NoFault; - - %(fp_enable_check)s; - %(op_decl)s; - %(op_rd)s; - %(ea_code)s; - - if (fault == NoFault) { - fault = xc->read(EA, (uint%(mem_acc_size)d_t&)Mem, memAccessFlags); - %(memacc_code)s; - } - - if (fault == NoFault) { - %(op_wb)s; - } - - return fault; - } -}}; - - -def template LoadInitiateAcc {{ - Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Addr EA; - Fault fault = NoFault; - - %(fp_enable_check)s; - %(op_src_decl)s; - %(op_rd)s; - %(ea_code)s; - - if (fault == NoFault) { - fault = xc->read(EA, (uint%(mem_acc_size)d_t &)Mem, memAccessFlags); - } - - return fault; - } -}}; - - -def template LoadCompleteAcc {{ - Fault %(class_name)s::completeAcc(uint8_t *data, - %(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Fault fault = NoFault; - - %(fp_enable_check)s; - %(op_src_decl)s; - %(op_dest_decl)s; - - memcpy(&Mem, data, sizeof(Mem)); - - if (fault == NoFault) { - %(memacc_code)s; - } - - if (fault == NoFault) { - %(op_wb)s; - } - - return fault; - } -}}; - - -def template StoreMemAccExecute {{ - Fault - %(class_name)s::MemAcc::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Addr EA; - Fault fault = NoFault; - uint64_t write_result = 0; - - %(fp_enable_check)s; - %(op_decl)s; - %(op_rd)s; - EA = xc->getEA(); - - if (fault == NoFault) { - %(code)s; - } - - if (fault == NoFault) { - fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA, - memAccessFlags, &write_result); - if (traceData) { traceData->setData(Mem); } - } - - if (fault == NoFault) { - %(postacc_code)s; - } - - if (fault == NoFault) { - %(op_wb)s; - } - - return fault; - } -}}; - - -def template StoreExecute {{ - Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Addr EA; - Fault fault = NoFault; - uint64_t write_result = 0; - - %(fp_enable_check)s; - %(op_decl)s; - %(op_rd)s; - %(ea_code)s; - - if (fault == NoFault) { - %(memacc_code)s; - } - - if (fault == NoFault) { - fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA, - memAccessFlags, &write_result); - if (traceData) { traceData->setData(Mem); } - } - - if (fault == NoFault) { - %(postacc_code)s; - } - - if (fault == NoFault) { - %(op_wb)s; - } - - return fault; - } -}}; - -def template StoreInitiateAcc {{ - Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Addr EA; - Fault fault = NoFault; - uint64_t write_result = 0; - - %(fp_enable_check)s; - %(op_src_decl)s; - %(op_dest_decl)s; - %(op_rd)s; - %(ea_code)s; - - if (fault == NoFault) { - %(memacc_code)s; - } - - if (fault == NoFault) { - fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA, - memAccessFlags, &write_result); - if (traceData) { traceData->setData(Mem); } - } - - return fault; - } -}}; - - -def template StoreCompleteAcc {{ - Fault %(class_name)s::completeAcc(uint8_t *data, - %(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Fault fault = NoFault; - uint64_t write_result = 0; - - %(fp_enable_check)s; - %(op_dest_decl)s; - - memcpy(&write_result, data, sizeof(write_result)); - - if (fault == NoFault) { - %(postacc_code)s; - } - - if (fault == NoFault) { - %(op_wb)s; - } - - return fault; - } -}}; - - -def template MiscMemAccExecute {{ - Fault %(class_name)s::MemAcc::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Addr EA; - Fault fault = NoFault; - - %(fp_enable_check)s; - %(op_decl)s; - %(op_rd)s; - EA = xc->getEA(); - - if (fault == NoFault) { - %(code)s; - } - - return NoFault; - } -}}; - -def template MiscExecute {{ - Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Addr EA; - Fault fault = NoFault; - - %(fp_enable_check)s; - %(op_decl)s; - %(op_rd)s; - %(ea_code)s; - - if (fault == NoFault) { - %(memacc_code)s; - } - - return NoFault; - } -}}; - -def template MiscInitiateAcc {{ - Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - panic("Misc instruction does not support split access method!"); - return NoFault; - } -}}; - - -def template MiscCompleteAcc {{ - Fault %(class_name)s::completeAcc(uint8_t *data, - %(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - panic("Misc instruction does not support split access method!"); - - return NoFault; - } -}}; - -// load instructions use Ra as dest, so check for -// Ra == 31 to detect nops -def template LoadNopCheckDecode {{ - { - AlphaStaticInst *i = new %(class_name)s(machInst); - if (RA == 31) { - i = makeNop(i); - } - return i; - } -}}; - - -// for some load instructions, Ra == 31 indicates a prefetch (not a nop) -def template LoadPrefetchCheckDecode {{ - { - if (RA != 31) { - return new %(class_name)s(machInst); - } - else { - return new %(class_name)sPrefetch(machInst); - } - } -}}; - - -let {{ -def LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, - postacc_code = '', base_class = 'MemoryDisp32', - decode_template = BasicDecode, exec_template_base = ''): - # Make sure flags are in lists (convert to lists if not). - mem_flags = makeList(mem_flags) - inst_flags = makeList(inst_flags) - - # add hook to get effective addresses into execution trace output. - ea_code += '\nif (traceData) { traceData->setAddr(EA); }\n' - - # generate code block objects - ea_cblk = CodeBlock(ea_code) - memacc_cblk = CodeBlock(memacc_code) - postacc_cblk = CodeBlock(postacc_code) - - # Some CPU models execute the memory operation as an atomic unit, - # while others want to separate them into an effective address - # computation and a memory access operation. As a result, we need - # to generate three StaticInst objects. Note that the latter two - # are nested inside the larger "atomic" one. - - # generate InstObjParams for EAComp object - ea_iop = InstObjParams(name, Name, base_class, ea_cblk, inst_flags) - - # generate InstObjParams for MemAcc object - memacc_iop = InstObjParams(name, Name, base_class, memacc_cblk, inst_flags) - # in the split execution model, the MemAcc portion is responsible - # for the post-access code. - memacc_iop.postacc_code = postacc_cblk.code - - # generate InstObjParams for InitiateAcc, CompleteAcc object - # The code used depends on the template being used - if (exec_template_base == 'Load'): - initiateacc_cblk = CodeBlock(ea_code + memacc_code) - completeacc_cblk = CodeBlock(memacc_code + postacc_code) - elif (exec_template_base == 'Store'): - initiateacc_cblk = CodeBlock(ea_code + memacc_code) - completeacc_cblk = CodeBlock(postacc_code) - else: - initiateacc_cblk = '' - completeacc_cblk = '' - - initiateacc_iop = InstObjParams(name, Name, base_class, initiateacc_cblk, - inst_flags) - - completeacc_iop = InstObjParams(name, Name, base_class, completeacc_cblk, - inst_flags) - - if (exec_template_base == 'Load'): - initiateacc_iop.ea_code = ea_cblk.code - initiateacc_iop.memacc_code = memacc_cblk.code - completeacc_iop.memacc_code = memacc_cblk.code - completeacc_iop.postacc_code = postacc_cblk.code - elif (exec_template_base == 'Store'): - initiateacc_iop.ea_code = ea_cblk.code - initiateacc_iop.memacc_code = memacc_cblk.code - completeacc_iop.postacc_code = postacc_cblk.code - - # generate InstObjParams for unified execution - cblk = CodeBlock(ea_code + memacc_code + postacc_code) - iop = InstObjParams(name, Name, base_class, cblk, inst_flags) - - iop.ea_constructor = ea_cblk.constructor - iop.ea_code = ea_cblk.code - iop.memacc_constructor = memacc_cblk.constructor - iop.memacc_code = memacc_cblk.code - iop.postacc_code = postacc_cblk.code - - if mem_flags: - s = '\n\tmemAccessFlags = ' + string.join(mem_flags, '|') + ';' - iop.constructor += s - memacc_iop.constructor += s - - # select templates - memAccExecTemplate = eval(exec_template_base + 'MemAccExecute') - fullExecTemplate = eval(exec_template_base + 'Execute') - initiateAccTemplate = eval(exec_template_base + 'InitiateAcc') - completeAccTemplate = eval(exec_template_base + 'CompleteAcc') - - # (header_output, decoder_output, decode_block, exec_output) - return (LoadStoreDeclare.subst(iop), LoadStoreConstructor.subst(iop), - decode_template.subst(iop), - EACompExecute.subst(ea_iop) - + memAccExecTemplate.subst(memacc_iop) - + fullExecTemplate.subst(iop) - + initiateAccTemplate.subst(initiateacc_iop) - + completeAccTemplate.subst(completeacc_iop)) -}}; - - -def format LoadOrNop(memacc_code, ea_code = {{ EA = Rb + disp; }}, - mem_flags = [], inst_flags = []) {{ - (header_output, decoder_output, decode_block, exec_output) = \ - LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, - decode_template = LoadNopCheckDecode, - exec_template_base = 'Load') -}}; - - -// Note that the flags passed in apply only to the prefetch version -def format LoadOrPrefetch(memacc_code, ea_code = {{ EA = Rb + disp; }}, - mem_flags = [], pf_flags = [], inst_flags = []) {{ - # declare the load instruction object and generate the decode block - (header_output, decoder_output, decode_block, exec_output) = \ - LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, - decode_template = LoadPrefetchCheckDecode, - exec_template_base = 'Load') - - # Declare the prefetch instruction object. - - # Make sure flag args are lists so we can mess with them. - mem_flags = makeList(mem_flags) - pf_flags = makeList(pf_flags) - inst_flags = makeList(inst_flags) - - pf_mem_flags = mem_flags + pf_flags + ['NO_FAULT'] - pf_inst_flags = inst_flags + ['IsMemRef', 'IsLoad', - 'IsDataPrefetch', 'MemReadOp'] - - (pf_header_output, pf_decoder_output, _, pf_exec_output) = \ - LoadStoreBase(name, Name + 'Prefetch', ea_code, - 'xc->prefetch(EA, memAccessFlags);', - pf_mem_flags, pf_inst_flags, exec_template_base = 'Misc') - - header_output += pf_header_output - decoder_output += pf_decoder_output - exec_output += pf_exec_output -}}; - - -def format Store(memacc_code, ea_code = {{ EA = Rb + disp; }}, - mem_flags = [], inst_flags = []) {{ - (header_output, decoder_output, decode_block, exec_output) = \ - LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, - exec_template_base = 'Store') -}}; - - -def format StoreCond(memacc_code, postacc_code, - ea_code = {{ EA = Rb + disp; }}, - mem_flags = [], inst_flags = []) {{ - (header_output, decoder_output, decode_block, exec_output) = \ - LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, - postacc_code, exec_template_base = 'Store') -}}; - - -// Use 'MemoryNoDisp' as base: for wh64, fetch, ecb -def format MiscPrefetch(ea_code, memacc_code, - mem_flags = [], inst_flags = []) {{ - (header_output, decoder_output, decode_block, exec_output) = \ - LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, - base_class = 'MemoryNoDisp', exec_template_base = 'Misc') -}}; - - diff --git a/arch/alpha/isa/opcdec.isa b/arch/alpha/isa/opcdec.isa deleted file mode 100644 index bb2f91e5c..000000000 --- a/arch/alpha/isa/opcdec.isa +++ /dev/null @@ -1,72 +0,0 @@ -// -*- mode:c++ -*- - -// Copyright (c) 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. - -output header {{ - /** - * Static instruction class for instructions that cause an OPCDEC fault - * when executed. This is currently only for PAL mode instructions - * executed in non-PAL mode. - */ - class OpcdecFault : public AlphaStaticInst - { - public: - /// Constructor - OpcdecFault(ExtMachInst _machInst) - : AlphaStaticInst("opcdec fault", _machInst, No_OpClass) - { - } - - %(BasicExecDeclare)s - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; -}}; - -output decoder {{ - std::string - OpcdecFault::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - return csprintf("%-10s (inst 0x%x, opcode 0x%x)", - " OPCDEC fault", machInst, OPCODE); - } -}}; - -output exec {{ - Fault - OpcdecFault::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - return new UnimplementedOpcodeFault; - } -}}; - -def format OpcdecFault() {{ - decode_block = 'return new OpcdecFault(machInst);\n' -}}; - diff --git a/arch/alpha/isa/pal.isa b/arch/alpha/isa/pal.isa deleted file mode 100644 index 63af56359..000000000 --- a/arch/alpha/isa/pal.isa +++ /dev/null @@ -1,273 +0,0 @@ -// -*- mode:c++ -*- - -// Copyright (c) 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. - -output header {{ - /** - * Base class for emulated call_pal calls (used only in - * non-full-system mode). - */ - class EmulatedCallPal : public AlphaStaticInst - { - protected: - - /// Constructor. - EmulatedCallPal(const char *mnem, ExtMachInst _machInst, - OpClass __opClass) - : AlphaStaticInst(mnem, _machInst, __opClass) - { - } - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; -}}; - -output decoder {{ - std::string - EmulatedCallPal::generateDisassembly(Addr pc, - const SymbolTable *symtab) const - { -#ifdef SS_COMPATIBLE_DISASSEMBLY - return csprintf("%s %s", "call_pal", mnemonic); -#else - return csprintf("%-10s %s", "call_pal", mnemonic); -#endif - } -}}; - -def format EmulatedCallPal(code, *flags) {{ - iop = InstObjParams(name, Name, 'EmulatedCallPal', CodeBlock(code), flags) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecode.subst(iop) - exec_output = BasicExecute.subst(iop) -}}; - -output header {{ - /** - * Base class for full-system-mode call_pal instructions. - * Probably could turn this into a leaf class and get rid of the - * parser template. - */ - class CallPalBase : public AlphaStaticInst - { - protected: - int palFunc; ///< Function code part of instruction - int palOffset; ///< Target PC, offset from IPR_PAL_BASE - bool palValid; ///< is the function code valid? - bool palPriv; ///< is this call privileged? - - /// Constructor. - CallPalBase(const char *mnem, ExtMachInst _machInst, - OpClass __opClass); - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; -}}; - -output decoder {{ - inline - CallPalBase::CallPalBase(const char *mnem, ExtMachInst _machInst, - OpClass __opClass) - : AlphaStaticInst(mnem, _machInst, __opClass), - palFunc(PALFUNC) - { - // From the 21164 HRM (paraphrased): - // Bit 7 of the function code (mask 0x80) indicates - // whether the call is privileged (bit 7 == 0) or - // unprivileged (bit 7 == 1). The privileged call table - // starts at 0x2000, the unprivielged call table starts at - // 0x3000. Bits 5-0 (mask 0x3f) are used to calculate the - // offset. - const int palPrivMask = 0x80; - const int palOffsetMask = 0x3f; - - // Pal call is invalid unless all other bits are 0 - palValid = ((machInst & ~(palPrivMask | palOffsetMask)) == 0); - palPriv = ((machInst & palPrivMask) == 0); - int shortPalFunc = (machInst & palOffsetMask); - // Add 1 to base to set pal-mode bit - palOffset = (palPriv ? 0x2001 : 0x3001) + (shortPalFunc << 6); - } - - std::string - CallPalBase::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - return csprintf("%-10s %#x", "call_pal", palFunc); - } -}}; - -def format CallPal(code, *flags) {{ - iop = InstObjParams(name, Name, 'CallPalBase', CodeBlock(code), flags) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecode.subst(iop) - exec_output = BasicExecute.subst(iop) -}}; - -//////////////////////////////////////////////////////////////////// -// -// hw_ld, hw_st -// - -output header {{ - /** - * Base class for hw_ld and hw_st. - */ - class HwLoadStore : public Memory - { - protected: - - /// Displacement for EA calculation (signed). - int16_t disp; - - /// Constructor - HwLoadStore(const char *mnem, ExtMachInst _machInst, OpClass __opClass, - StaticInstPtr _eaCompPtr = nullStaticInstPtr, - StaticInstPtr _memAccPtr = nullStaticInstPtr); - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; -}}; - - -output decoder {{ - inline - HwLoadStore::HwLoadStore(const char *mnem, ExtMachInst _machInst, - OpClass __opClass, - StaticInstPtr _eaCompPtr, - StaticInstPtr _memAccPtr) - : Memory(mnem, _machInst, __opClass, _eaCompPtr, _memAccPtr), - disp(HW_LDST_DISP) - { - memAccessFlags = 0; - if (HW_LDST_PHYS) memAccessFlags |= PHYSICAL; - if (HW_LDST_ALT) memAccessFlags |= ALTMODE; - if (HW_LDST_VPTE) memAccessFlags |= VPTE; - if (HW_LDST_LOCK) memAccessFlags |= LOCKED; - } - - std::string - HwLoadStore::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { -#ifdef SS_COMPATIBLE_DISASSEMBLY - return csprintf("%-10s r%d,%d(r%d)", mnemonic, RA, disp, RB); -#else - // HW_LDST_LOCK and HW_LDST_COND are the same bit. - const char *lock_str = - (HW_LDST_LOCK) ? (flags[IsLoad] ? ",LOCK" : ",COND") : ""; - - return csprintf("%-10s r%d,%d(r%d)%s%s%s%s%s", - mnemonic, RA, disp, RB, - HW_LDST_PHYS ? ",PHYS" : "", - HW_LDST_ALT ? ",ALT" : "", - HW_LDST_QUAD ? ",QUAD" : "", - HW_LDST_VPTE ? ",VPTE" : "", - lock_str); -#endif - } -}}; - -def format HwLoad(ea_code, memacc_code, class_ext, *flags) {{ - (header_output, decoder_output, decode_block, exec_output) = \ - LoadStoreBase(name, Name + class_ext, ea_code, memacc_code, - mem_flags = [], inst_flags = flags, - base_class = 'HwLoadStore', exec_template_base = 'Load') -}}; - - -def format HwStore(ea_code, memacc_code, class_ext, *flags) {{ - (header_output, decoder_output, decode_block, exec_output) = \ - LoadStoreBase(name, Name + class_ext, ea_code, memacc_code, - mem_flags = [], inst_flags = flags, - base_class = 'HwLoadStore', exec_template_base = 'Store') -}}; - - -def format HwStoreCond(ea_code, memacc_code, postacc_code, class_ext, - *flags) {{ - (header_output, decoder_output, decode_block, exec_output) = \ - LoadStoreBase(name, Name + class_ext, ea_code, memacc_code, - postacc_code, mem_flags = [], inst_flags = flags, - base_class = 'HwLoadStore') -}}; - - -output header {{ - /** - * Base class for hw_mfpr and hw_mtpr. - */ - class HwMoveIPR : public AlphaStaticInst - { - protected: - /// Index of internal processor register. - int ipr_index; - - /// Constructor - HwMoveIPR(const char *mnem, ExtMachInst _machInst, OpClass __opClass) - : AlphaStaticInst(mnem, _machInst, __opClass), - ipr_index(HW_IPR_IDX) - { - } - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; -}}; - -output decoder {{ - std::string - HwMoveIPR::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - if (_numSrcRegs > 0) { - // must be mtpr - return csprintf("%-10s r%d,IPR(%#x)", - mnemonic, RA, ipr_index); - } - else { - // must be mfpr - return csprintf("%-10s IPR(%#x),r%d", - mnemonic, ipr_index, RA); - } - } -}}; - -def format HwMoveIPR(code, *flags) {{ - all_flags = ['IprAccessOp'] - all_flags += flags - iop = InstObjParams(name, Name, 'HwMoveIPR', CodeBlock(code), - all_flags) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecode.subst(iop) - exec_output = BasicExecute.subst(iop) -}}; - - diff --git a/arch/alpha/isa/unimp.isa b/arch/alpha/isa/unimp.isa deleted file mode 100644 index 392522801..000000000 --- a/arch/alpha/isa/unimp.isa +++ /dev/null @@ -1,165 +0,0 @@ -// -*- mode:c++ -*- - -// Copyright (c) 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. - -output header {{ - /** - * Static instruction class for unimplemented instructions that - * cause simulator termination. Note that these are recognized - * (legal) instructions that the simulator does not support; the - * 'Unknown' class is used for unrecognized/illegal instructions. - * This is a leaf class. - */ - class FailUnimplemented : public AlphaStaticInst - { - public: - /// Constructor - FailUnimplemented(const char *_mnemonic, ExtMachInst _machInst) - : AlphaStaticInst(_mnemonic, _machInst, No_OpClass) - { - // don't call execute() (which panics) if we're on a - // speculative path - flags[IsNonSpeculative] = true; - } - - %(BasicExecDeclare)s - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; - - /** - * Base class for unimplemented instructions that cause a warning - * to be printed (but do not terminate simulation). This - * implementation is a little screwy in that it will print a - * warning for each instance of a particular unimplemented machine - * instruction, not just for each unimplemented opcode. Should - * probably make the 'warned' flag a static member of the derived - * class. - */ - class WarnUnimplemented : public AlphaStaticInst - { - private: - /// Have we warned on this instruction yet? - mutable bool warned; - - public: - /// Constructor - WarnUnimplemented(const char *_mnemonic, ExtMachInst _machInst) - : AlphaStaticInst(_mnemonic, _machInst, No_OpClass), warned(false) - { - // don't call execute() (which panics) if we're on a - // speculative path - flags[IsNonSpeculative] = true; - } - - %(BasicExecDeclare)s - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; -}}; - -output decoder {{ - std::string - FailUnimplemented::generateDisassembly(Addr pc, - const SymbolTable *symtab) const - { - return csprintf("%-10s (unimplemented)", mnemonic); - } - - std::string - WarnUnimplemented::generateDisassembly(Addr pc, - const SymbolTable *symtab) const - { -#ifdef SS_COMPATIBLE_DISASSEMBLY - return csprintf("%-10s", mnemonic); -#else - return csprintf("%-10s (unimplemented)", mnemonic); -#endif - } -}}; - -output exec {{ - Fault - FailUnimplemented::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - panic("attempt to execute unimplemented instruction '%s' " - "(inst 0x%08x, opcode 0x%x)", mnemonic, machInst, OPCODE); - return new UnimplementedOpcodeFault; - } - - Fault - WarnUnimplemented::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - if (!warned) { - warn("instruction '%s' unimplemented\n", mnemonic); - warned = true; - } - - return NoFault; - } -}}; - - -def format FailUnimpl() {{ - iop = InstObjParams(name, 'FailUnimplemented') - decode_block = BasicDecodeWithMnemonic.subst(iop) -}}; - -def format WarnUnimpl() {{ - iop = InstObjParams(name, 'WarnUnimplemented') - decode_block = BasicDecodeWithMnemonic.subst(iop) -}}; - -output header {{ - /** - * Static instruction class for unknown (illegal) instructions. - * These cause simulator termination if they are executed in a - * non-speculative mode. This is a leaf class. - */ - class Unknown : public AlphaStaticInst - { - public: - /// Constructor - Unknown(ExtMachInst _machInst) - : AlphaStaticInst("unknown", _machInst, No_OpClass) - { - // don't call execute() (which panics) if we're on a - // speculative path - flags[IsNonSpeculative] = true; - } - - %(BasicExecDeclare)s - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; -}}; - diff --git a/arch/alpha/isa/unknown.isa b/arch/alpha/isa/unknown.isa deleted file mode 100644 index 47d166255..000000000 --- a/arch/alpha/isa/unknown.isa +++ /dev/null @@ -1,52 +0,0 @@ -// -*- mode:c++ -*- - -// Copyright (c) 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. - -output decoder {{ - std::string - Unknown::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - return csprintf("%-10s (inst 0x%x, opcode 0x%x)", - "unknown", machInst, OPCODE); - } -}}; - -output exec {{ - Fault - Unknown::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - panic("attempt to execute unknown instruction " - "(inst 0x%08x, opcode 0x%x)", machInst, OPCODE); - return new UnimplementedOpcodeFault; - } -}}; - -def format Unknown() {{ - decode_block = 'return new Unknown(machInst);\n' -}}; - diff --git a/arch/alpha/isa/util.isa b/arch/alpha/isa/util.isa deleted file mode 100644 index 9fbbf6636..000000000 --- a/arch/alpha/isa/util.isa +++ /dev/null @@ -1,112 +0,0 @@ -// -*- mode:c++ -*- - -// Copyright (c) 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. - -output exec {{ - - /// Return opa + opb, summing carry into third arg. - inline uint64_t - addc(uint64_t opa, uint64_t opb, int &carry) - { - uint64_t res = opa + opb; - if (res < opa || res < opb) - ++carry; - return res; - } - - /// Multiply two 64-bit values (opa * opb), returning the 128-bit - /// product in res_hi and res_lo. - inline void - mul128(uint64_t opa, uint64_t opb, uint64_t &res_hi, uint64_t &res_lo) - { - // do a 64x64 --> 128 multiply using four 32x32 --> 64 multiplies - uint64_t opa_hi = opa<63:32>; - uint64_t opa_lo = opa<31:0>; - uint64_t opb_hi = opb<63:32>; - uint64_t opb_lo = opb<31:0>; - - res_lo = opa_lo * opb_lo; - - // The middle partial products logically belong in bit - // positions 95 to 32. Thus the lower 32 bits of each product - // sum into the upper 32 bits of the low result, while the - // upper 32 sum into the low 32 bits of the upper result. - uint64_t partial1 = opa_hi * opb_lo; - uint64_t partial2 = opa_lo * opb_hi; - - uint64_t partial1_lo = partial1<31:0> << 32; - uint64_t partial1_hi = partial1<63:32>; - uint64_t partial2_lo = partial2<31:0> << 32; - uint64_t partial2_hi = partial2<63:32>; - - // Add partial1_lo and partial2_lo to res_lo, keeping track - // of any carries out - int carry_out = 0; - res_lo = addc(partial1_lo, res_lo, carry_out); - res_lo = addc(partial2_lo, res_lo, carry_out); - - // Now calculate the high 64 bits... - res_hi = (opa_hi * opb_hi) + partial1_hi + partial2_hi + carry_out; - } - - /// Map 8-bit S-floating exponent to 11-bit T-floating exponent. - /// See Table 2-2 of Alpha AHB. - inline int - map_s(int old_exp) - { - int hibit = old_exp<7:>; - int lobits = old_exp<6:0>; - - if (hibit == 1) { - return (lobits == 0x7f) ? 0x7ff : (0x400 | lobits); - } - else { - return (lobits == 0) ? 0 : (0x380 | lobits); - } - } - - /// Convert a 32-bit S-floating value to the equivalent 64-bit - /// representation to be stored in an FP reg. - inline uint64_t - s_to_t(uint32_t s_val) - { - uint64_t tmp = s_val; - return (tmp<31:> << 63 // sign bit - | (uint64_t)map_s(tmp<30:23>) << 52 // exponent - | tmp<22:0> << 29); // fraction - } - - /// Convert a 64-bit T-floating value to the equivalent 32-bit - /// S-floating representation to be stored in memory. - inline int32_t - t_to_s(uint64_t t_val) - { - return (t_val<63:62> << 30 // sign bit & hi exp bit - | t_val<58:29>); // rest of exp & fraction - } -}}; - diff --git a/arch/alpha/isa_traits.hh b/arch/alpha/isa_traits.hh deleted file mode 100644 index 878193881..000000000 --- a/arch/alpha/isa_traits.hh +++ /dev/null @@ -1,384 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __ARCH_ALPHA_ISA_TRAITS_HH__ -#define __ARCH_ALPHA_ISA_TRAITS_HH__ - -namespace LittleEndianGuest {} -using namespace LittleEndianGuest; - -//#include "arch/alpha/faults.hh" -#include "base/misc.hh" -#include "config/full_system.hh" -#include "sim/host.hh" -#include "sim/faults.hh" - -class ExecContext; -class FastCPU; -class FullCPU; -class Checkpoint; - -#define TARGET_ALPHA - -class StaticInst; -class StaticInstPtr; - -namespace EV5 { -int DTB_ASN_ASN(uint64_t reg); -int ITB_ASN_ASN(uint64_t reg); -} - -#if !FULL_SYSTEM -class SyscallReturn { - public: - template <class T> - SyscallReturn(T v, bool s) - { - retval = (uint64_t)v; - success = s; - } - - template <class T> - SyscallReturn(T v) - { - success = (v >= 0); - retval = (uint64_t)v; - } - - ~SyscallReturn() {} - - SyscallReturn& operator=(const SyscallReturn& s) { - retval = s.retval; - success = s.success; - return *this; - } - - bool successful() { return success; } - uint64_t value() { return retval; } - - - private: - uint64_t retval; - bool success; -}; - -#endif - - - -namespace AlphaISA -{ - - typedef uint32_t MachInst; - typedef uint64_t ExtMachInst; - typedef uint8_t RegIndex; - - const int NumIntArchRegs = 32; - const int NumPALShadowRegs = 8; - const int NumFloatArchRegs = 32; - // @todo: Figure out what this number really should be. - const int NumMiscArchRegs = 32; - - // Static instruction parameters - const int MaxInstSrcRegs = 3; - const int MaxInstDestRegs = 2; - - // semantically meaningful register indices - const int ZeroReg = 31; // architecturally meaningful - // the rest of these depend on the ABI - const int StackPointerReg = 30; - const int GlobalPointerReg = 29; - const int ProcedureValueReg = 27; - const int ReturnAddressReg = 26; - const int ReturnValueReg = 0; - const int FramePointerReg = 15; - const int ArgumentReg0 = 16; - const int ArgumentReg1 = 17; - const int ArgumentReg2 = 18; - const int ArgumentReg3 = 19; - const int ArgumentReg4 = 20; - const int ArgumentReg5 = 21; - const int SyscallNumReg = ReturnValueReg; - const int SyscallPseudoReturnReg = ArgumentReg4; - const int SyscallSuccessReg = 19; - - - - const int LogVMPageSize = 13; // 8K bytes - const int VMPageSize = (1 << LogVMPageSize); - - const int BranchPredAddrShiftAmt = 2; // instructions are 4-byte aligned - - const int WordBytes = 4; - const int HalfwordBytes = 2; - const int ByteBytes = 1; - - - const int NumIntRegs = NumIntArchRegs + NumPALShadowRegs; - const int NumFloatRegs = NumFloatArchRegs; - const int NumMiscRegs = NumMiscArchRegs; - - // These enumerate all the registers for dependence tracking. - enum DependenceTags { - // 0..31 are the integer regs 0..31 - // 32..63 are the FP regs 0..31, i.e. use (reg + FP_Base_DepTag) - FP_Base_DepTag = 40, - Ctrl_Base_DepTag = 72, - Fpcr_DepTag = 72, // floating point control register - Uniq_DepTag = 73, - Lock_Flag_DepTag = 74, - Lock_Addr_DepTag = 75, - IPR_Base_DepTag = 76 - }; - - typedef uint64_t IntReg; - typedef IntReg IntRegFile[NumIntRegs]; - - // floating point register file entry type - typedef union { - uint64_t q; - double d; - } FloatReg; - - typedef union { - uint64_t q[NumFloatRegs]; // integer qword view - double d[NumFloatRegs]; // double-precision floating point view - } FloatRegFile; - -extern const Addr PageShift; -extern const Addr PageBytes; -extern const Addr PageMask; -extern const Addr PageOffset; - -// redirected register map, really only used for the full system case. -extern const int reg_redir[NumIntRegs]; - -#if FULL_SYSTEM - - typedef uint64_t InternalProcReg; - -#include "arch/alpha/isa_fullsys_traits.hh" - -#else - const int NumInternalProcRegs = 0; -#endif - - // control register file contents - typedef uint64_t MiscReg; - class MiscRegFile { - protected: - uint64_t fpcr; // floating point condition codes - uint64_t uniq; // process-unique register - bool lock_flag; // lock flag for LL/SC - Addr lock_addr; // lock address for LL/SC - - public: - MiscReg readReg(int misc_reg); - - //These functions should be removed once the simplescalar cpu model - //has been replaced. - int getInstAsid(); - int getDataAsid(); - - MiscReg readRegWithEffect(int misc_reg, Fault &fault, ExecContext *xc); - - Fault setReg(int misc_reg, const MiscReg &val); - - Fault setRegWithEffect(int misc_reg, const MiscReg &val, - ExecContext *xc); - - void copyMiscRegs(ExecContext *xc); - -#if FULL_SYSTEM - protected: - InternalProcReg ipr[NumInternalProcRegs]; // Internal processor regs - - private: - MiscReg readIpr(int idx, Fault &fault, ExecContext *xc); - - Fault setIpr(int idx, uint64_t val, ExecContext *xc); - - void copyIprs(ExecContext *xc); -#endif - friend class RegFile; - }; - - const int TotalNumRegs = NumIntRegs + NumFloatRegs + - NumMiscRegs + NumInternalProcRegs; - - const int TotalDataRegs = NumIntRegs + NumFloatRegs; - - typedef union { - IntReg intreg; - FloatReg fpreg; - MiscReg ctrlreg; - } AnyReg; - - struct RegFile { - IntRegFile intRegFile; // (signed) integer register file - FloatRegFile floatRegFile; // floating point register file - MiscRegFile miscRegs; // control register file - Addr pc; // program counter - Addr npc; // next-cycle program counter - Addr nnpc; - -#if FULL_SYSTEM - int intrflag; // interrupt flag - inline int instAsid() - { return EV5::ITB_ASN_ASN(miscRegs.ipr[IPR_ITB_ASN]); } - inline int dataAsid() - { return EV5::DTB_ASN_ASN(miscRegs.ipr[IPR_DTB_ASN]); } -#endif // FULL_SYSTEM - - void serialize(std::ostream &os); - void unserialize(Checkpoint *cp, const std::string §ion); - }; - - static inline ExtMachInst makeExtMI(MachInst inst, const uint64_t &pc); - - StaticInstPtr decodeInst(ExtMachInst); - - // return a no-op instruction... used for instruction fetch faults - extern const ExtMachInst NoopMachInst; - - enum annotes { - ANNOTE_NONE = 0, - // An impossible number for instruction annotations - ITOUCH_ANNOTE = 0xffffffff, - }; - - static inline bool isCallerSaveIntegerRegister(unsigned int reg) { - panic("register classification not implemented"); - return (reg >= 1 && reg <= 8 || reg >= 22 && reg <= 25 || reg == 27); - } - - static inline bool isCalleeSaveIntegerRegister(unsigned int reg) { - panic("register classification not implemented"); - return (reg >= 9 && reg <= 15); - } - - static inline bool isCallerSaveFloatRegister(unsigned int reg) { - panic("register classification not implemented"); - return false; - } - - static inline bool isCalleeSaveFloatRegister(unsigned int reg) { - panic("register classification not implemented"); - return false; - } - - static inline Addr alignAddress(const Addr &addr, - unsigned int nbytes) { - return (addr & ~(nbytes - 1)); - } - - // Instruction address compression hooks - static inline Addr realPCToFetchPC(const Addr &addr) { - return addr; - } - - static inline Addr fetchPCToRealPC(const Addr &addr) { - return addr; - } - - // the size of "fetched" instructions (not necessarily the size - // of real instructions for PISA) - static inline size_t fetchInstSize() { - return sizeof(MachInst); - } - - static inline MachInst makeRegisterCopy(int dest, int src) { - panic("makeRegisterCopy not implemented"); - return 0; - } - - // Machine operations - - void saveMachineReg(AnyReg &savereg, const RegFile ®_file, - int regnum); - - void restoreMachineReg(RegFile ®s, const AnyReg ®, - int regnum); - -#if 0 - static void serializeSpecialRegs(const Serializable::Proxy &proxy, - const RegFile ®s); - - static void unserializeSpecialRegs(const IniFile *db, - const std::string &category, - ConfigNode *node, - RegFile ®s); -#endif - - /** - * Function to insure ISA semantics about 0 registers. - * @param xc The execution context. - */ - template <class XC> - void zeroRegisters(XC *xc); - - const Addr MaxAddr = (Addr)-1; - -#if !FULL_SYSTEM - static inline void setSyscallReturn(SyscallReturn return_value, RegFile *regs) - { - // check for error condition. Alpha syscall convention is to - // indicate success/failure in reg a3 (r19) and put the - // return value itself in the standard return value reg (v0). - if (return_value.successful()) { - // no error - regs->intRegFile[SyscallSuccessReg] = 0; - regs->intRegFile[ReturnValueReg] = return_value.value(); - } else { - // got an error, return details - regs->intRegFile[SyscallSuccessReg] = (IntReg) -1; - regs->intRegFile[ReturnValueReg] = -return_value.value(); - } - } -#endif -}; - -static inline AlphaISA::ExtMachInst -AlphaISA::makeExtMI(AlphaISA::MachInst inst, const uint64_t &pc) { -#if FULL_SYSTEM - AlphaISA::ExtMachInst ext_inst = inst; - if (pc && 0x1) - return ext_inst|=(static_cast<AlphaISA::ExtMachInst>(pc & 0x1) << 32); - else - return ext_inst; -#else - return AlphaISA::ExtMachInst(inst); -#endif -} - -#if FULL_SYSTEM - -#include "arch/alpha/ev5.hh" -#endif - -#endif // __ARCH_ALPHA_ISA_TRAITS_HH__ diff --git a/arch/alpha/linux/aligned.hh b/arch/alpha/linux/aligned.hh deleted file mode 100644 index cabecb283..000000000 --- a/arch/alpha/linux/aligned.hh +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2004 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. - */ - -#ifndef __ARCH_ALPHA_LINUX_ALIGNED_HH__ -#define __ARCH_ALPHA_LINUX_ALIGNED_HH__ - - -/* GCC 3.3.X has a bug in which attributes+typedefs don't work. 3.2.X is fine - * as in 3.4.X, but the bug is marked will not fix in 3.3.X so here is - * the work around. - */ -#if (__GNUC__ == 3 && __GNUC_MINOR__ != 3) || __GNUC__ > 3 -typedef uint64_t uint64_ta __attribute__ ((aligned (8))) ; -typedef int64_t int64_ta __attribute__ ((aligned (8))) ; -typedef Addr Addr_a __attribute__ ((aligned (8))) ; -#else -#define uint64_ta uint64_t __attribute__ ((aligned (8))) -#define int64_ta int64_t __attribute__ ((aligned (8))) -#define Addr_a Addr __attribute__ ((aligned (8))) -#endif /* __GNUC__ __GNUC_MINOR__ */ - -#endif /* __ARCH_ALPHA_LINUX_ALIGNED_HH__ */ diff --git a/arch/alpha/linux/process.cc b/arch/alpha/linux/process.cc deleted file mode 100644 index 1c911bc50..000000000 --- a/arch/alpha/linux/process.cc +++ /dev/null @@ -1,589 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include "arch/alpha/linux/process.hh" -#include "arch/alpha/isa_traits.hh" - -#include "base/trace.hh" -#include "cpu/exec_context.hh" -#include "kern/linux/linux.hh" -#include "mem/functional/functional.hh" - -#include "sim/process.hh" -#include "sim/syscall_emul.hh" - -using namespace std; -using namespace AlphaISA; - - - -/// Target uname() handler. -static SyscallReturn -unameFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - TypedBufferArg<Linux::utsname> name(xc->getSyscallArg(0)); - - strcpy(name->sysname, "Linux"); - strcpy(name->nodename, "m5.eecs.umich.edu"); - strcpy(name->release, "2.4.20"); - strcpy(name->version, "#1 Mon Aug 18 11:32:15 EDT 2003"); - strcpy(name->machine, "alpha"); - - name.copyOut(xc->getMemPtr()); - return 0; -} - -/// Target osf_getsysyinfo() handler. Even though this call is -/// borrowed from Tru64, the subcases that get used appear to be -/// different in practice from those used by Tru64 processes. -static SyscallReturn -osf_getsysinfoFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - unsigned op = xc->getSyscallArg(0); - // unsigned nbytes = xc->getSyscallArg(2); - - switch (op) { - - case 45: { // GSI_IEEE_FP_CONTROL - TypedBufferArg<uint64_t> fpcr(xc->getSyscallArg(1)); - // I don't think this exactly matches the HW FPCR - *fpcr = 0; - fpcr.copyOut(xc->getMemPtr()); - return 0; - } - - default: - cerr << "osf_getsysinfo: unknown op " << op << endl; - abort(); - break; - } - - return 1; -} - -/// Target osf_setsysinfo() handler. -static SyscallReturn -osf_setsysinfoFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - unsigned op = xc->getSyscallArg(0); - // unsigned nbytes = xc->getSyscallArg(2); - - switch (op) { - - case 14: { // SSI_IEEE_FP_CONTROL - TypedBufferArg<uint64_t> fpcr(xc->getSyscallArg(1)); - // I don't think this exactly matches the HW FPCR - fpcr.copyIn(xc->getMemPtr()); - DPRINTFR(SyscallVerbose, "osf_setsysinfo(SSI_IEEE_FP_CONTROL): " - " setting FPCR to 0x%x\n", gtoh(*(uint64_t*)fpcr)); - return 0; - } - - default: - cerr << "osf_setsysinfo: unknown op " << op << endl; - abort(); - break; - } - - return 1; -} - - -SyscallDesc AlphaLinuxProcess::syscallDescs[] = { - /* 0 */ SyscallDesc("osf_syscall", unimplementedFunc), - /* 1 */ SyscallDesc("exit", exitFunc), - /* 2 */ SyscallDesc("fork", unimplementedFunc), - /* 3 */ SyscallDesc("read", readFunc), - /* 4 */ SyscallDesc("write", writeFunc), - /* 5 */ SyscallDesc("osf_old_open", unimplementedFunc), - /* 6 */ SyscallDesc("close", closeFunc), - /* 7 */ SyscallDesc("osf_wait4", unimplementedFunc), - /* 8 */ SyscallDesc("osf_old_creat", unimplementedFunc), - /* 9 */ SyscallDesc("link", unimplementedFunc), - /* 10 */ SyscallDesc("unlink", unlinkFunc), - /* 11 */ SyscallDesc("osf_execve", unimplementedFunc), - /* 12 */ SyscallDesc("chdir", unimplementedFunc), - /* 13 */ SyscallDesc("fchdir", unimplementedFunc), - /* 14 */ SyscallDesc("mknod", unimplementedFunc), - /* 15 */ SyscallDesc("chmod", chmodFunc<Linux>), - /* 16 */ SyscallDesc("chown", chownFunc), - /* 17 */ SyscallDesc("brk", obreakFunc), - /* 18 */ SyscallDesc("osf_getfsstat", unimplementedFunc), - /* 19 */ SyscallDesc("lseek", lseekFunc), - /* 20 */ SyscallDesc("getxpid", getpidPseudoFunc), - /* 21 */ SyscallDesc("osf_mount", unimplementedFunc), - /* 22 */ SyscallDesc("umount", unimplementedFunc), - /* 23 */ SyscallDesc("setuid", setuidFunc), - /* 24 */ SyscallDesc("getxuid", getuidPseudoFunc), - /* 25 */ SyscallDesc("exec_with_loader", unimplementedFunc), - /* 26 */ SyscallDesc("osf_ptrace", unimplementedFunc), - /* 27 */ SyscallDesc("osf_nrecvmsg", unimplementedFunc), - /* 28 */ SyscallDesc("osf_nsendmsg", unimplementedFunc), - /* 29 */ SyscallDesc("osf_nrecvfrom", unimplementedFunc), - /* 30 */ SyscallDesc("osf_naccept", unimplementedFunc), - /* 31 */ SyscallDesc("osf_ngetpeername", unimplementedFunc), - /* 32 */ SyscallDesc("osf_ngetsockname", unimplementedFunc), - /* 33 */ SyscallDesc("access", unimplementedFunc), - /* 34 */ SyscallDesc("osf_chflags", unimplementedFunc), - /* 35 */ SyscallDesc("osf_fchflags", unimplementedFunc), - /* 36 */ SyscallDesc("sync", unimplementedFunc), - /* 37 */ SyscallDesc("kill", unimplementedFunc), - /* 38 */ SyscallDesc("osf_old_stat", unimplementedFunc), - /* 39 */ SyscallDesc("setpgid", unimplementedFunc), - /* 40 */ SyscallDesc("osf_old_lstat", unimplementedFunc), - /* 41 */ SyscallDesc("dup", unimplementedFunc), - /* 42 */ SyscallDesc("pipe", pipePseudoFunc), - /* 43 */ SyscallDesc("osf_set_program_attributes", unimplementedFunc), - /* 44 */ SyscallDesc("osf_profil", unimplementedFunc), - /* 45 */ SyscallDesc("open", openFunc<Linux>), - /* 46 */ SyscallDesc("osf_old_sigaction", unimplementedFunc), - /* 47 */ SyscallDesc("getxgid", getgidPseudoFunc), - /* 48 */ SyscallDesc("osf_sigprocmask", ignoreFunc), - /* 49 */ SyscallDesc("osf_getlogin", unimplementedFunc), - /* 50 */ SyscallDesc("osf_setlogin", unimplementedFunc), - /* 51 */ SyscallDesc("acct", unimplementedFunc), - /* 52 */ SyscallDesc("sigpending", unimplementedFunc), - /* 53 */ SyscallDesc("osf_classcntl", unimplementedFunc), - /* 54 */ SyscallDesc("ioctl", ioctlFunc<Linux>), - /* 55 */ SyscallDesc("osf_reboot", unimplementedFunc), - /* 56 */ SyscallDesc("osf_revoke", unimplementedFunc), - /* 57 */ SyscallDesc("symlink", unimplementedFunc), - /* 58 */ SyscallDesc("readlink", unimplementedFunc), - /* 59 */ SyscallDesc("execve", unimplementedFunc), - /* 60 */ SyscallDesc("umask", unimplementedFunc), - /* 61 */ SyscallDesc("chroot", unimplementedFunc), - /* 62 */ SyscallDesc("osf_old_fstat", unimplementedFunc), - /* 63 */ SyscallDesc("getpgrp", unimplementedFunc), - /* 64 */ SyscallDesc("getpagesize", getpagesizeFunc), - /* 65 */ SyscallDesc("osf_mremap", unimplementedFunc), - /* 66 */ SyscallDesc("vfork", unimplementedFunc), - /* 67 */ SyscallDesc("stat", statFunc<Linux>), - /* 68 */ SyscallDesc("lstat", lstatFunc<Linux>), - /* 69 */ SyscallDesc("osf_sbrk", unimplementedFunc), - /* 70 */ SyscallDesc("osf_sstk", unimplementedFunc), - /* 71 */ SyscallDesc("mmap", mmapFunc<Linux>), - /* 72 */ SyscallDesc("osf_old_vadvise", unimplementedFunc), - /* 73 */ SyscallDesc("munmap", munmapFunc), - /* 74 */ SyscallDesc("mprotect", ignoreFunc), - /* 75 */ SyscallDesc("madvise", unimplementedFunc), - /* 76 */ SyscallDesc("vhangup", unimplementedFunc), - /* 77 */ SyscallDesc("osf_kmodcall", unimplementedFunc), - /* 78 */ SyscallDesc("osf_mincore", unimplementedFunc), - /* 79 */ SyscallDesc("getgroups", unimplementedFunc), - /* 80 */ SyscallDesc("setgroups", unimplementedFunc), - /* 81 */ SyscallDesc("osf_old_getpgrp", unimplementedFunc), - /* 82 */ SyscallDesc("setpgrp", unimplementedFunc), - /* 83 */ SyscallDesc("osf_setitimer", unimplementedFunc), - /* 84 */ SyscallDesc("osf_old_wait", unimplementedFunc), - /* 85 */ SyscallDesc("osf_table", unimplementedFunc), - /* 86 */ SyscallDesc("osf_getitimer", unimplementedFunc), - /* 87 */ SyscallDesc("gethostname", gethostnameFunc), - /* 88 */ SyscallDesc("sethostname", unimplementedFunc), - /* 89 */ SyscallDesc("getdtablesize", unimplementedFunc), - /* 90 */ SyscallDesc("dup2", unimplementedFunc), - /* 91 */ SyscallDesc("fstat", fstatFunc<Linux>), - /* 92 */ SyscallDesc("fcntl", fcntlFunc), - /* 93 */ SyscallDesc("osf_select", unimplementedFunc), - /* 94 */ SyscallDesc("poll", unimplementedFunc), - /* 95 */ SyscallDesc("fsync", unimplementedFunc), - /* 96 */ SyscallDesc("setpriority", unimplementedFunc), - /* 97 */ SyscallDesc("socket", unimplementedFunc), - /* 98 */ SyscallDesc("connect", unimplementedFunc), - /* 99 */ SyscallDesc("accept", unimplementedFunc), - /* 100 */ SyscallDesc("getpriority", unimplementedFunc), - /* 101 */ SyscallDesc("send", unimplementedFunc), - /* 102 */ SyscallDesc("recv", unimplementedFunc), - /* 103 */ SyscallDesc("sigreturn", unimplementedFunc), - /* 104 */ SyscallDesc("bind", unimplementedFunc), - /* 105 */ SyscallDesc("setsockopt", unimplementedFunc), - /* 106 */ SyscallDesc("listen", unimplementedFunc), - /* 107 */ SyscallDesc("osf_plock", unimplementedFunc), - /* 108 */ SyscallDesc("osf_old_sigvec", unimplementedFunc), - /* 109 */ SyscallDesc("osf_old_sigblock", unimplementedFunc), - /* 110 */ SyscallDesc("osf_old_sigsetmask", unimplementedFunc), - /* 111 */ SyscallDesc("sigsuspend", unimplementedFunc), - /* 112 */ SyscallDesc("osf_sigstack", ignoreFunc), - /* 113 */ SyscallDesc("recvmsg", unimplementedFunc), - /* 114 */ SyscallDesc("sendmsg", unimplementedFunc), - /* 115 */ SyscallDesc("osf_old_vtrace", unimplementedFunc), - /* 116 */ SyscallDesc("osf_gettimeofday", unimplementedFunc), - /* 117 */ SyscallDesc("osf_getrusage", unimplementedFunc), - /* 118 */ SyscallDesc("getsockopt", unimplementedFunc), - /* 119 */ SyscallDesc("numa_syscalls", unimplementedFunc), - /* 120 */ SyscallDesc("readv", unimplementedFunc), - /* 121 */ SyscallDesc("writev", writevFunc<Linux>), - /* 122 */ SyscallDesc("osf_settimeofday", unimplementedFunc), - /* 123 */ SyscallDesc("fchown", fchownFunc), - /* 124 */ SyscallDesc("fchmod", fchmodFunc<Linux>), - /* 125 */ SyscallDesc("recvfrom", unimplementedFunc), - /* 126 */ SyscallDesc("setreuid", unimplementedFunc), - /* 127 */ SyscallDesc("setregid", unimplementedFunc), - /* 128 */ SyscallDesc("rename", renameFunc), - /* 129 */ SyscallDesc("truncate", unimplementedFunc), - /* 130 */ SyscallDesc("ftruncate", unimplementedFunc), - /* 131 */ SyscallDesc("flock", unimplementedFunc), - /* 132 */ SyscallDesc("setgid", unimplementedFunc), - /* 133 */ SyscallDesc("sendto", unimplementedFunc), - /* 134 */ SyscallDesc("shutdown", unimplementedFunc), - /* 135 */ SyscallDesc("socketpair", unimplementedFunc), - /* 136 */ SyscallDesc("mkdir", unimplementedFunc), - /* 137 */ SyscallDesc("rmdir", unimplementedFunc), - /* 138 */ SyscallDesc("osf_utimes", unimplementedFunc), - /* 139 */ SyscallDesc("osf_old_sigreturn", unimplementedFunc), - /* 140 */ SyscallDesc("osf_adjtime", unimplementedFunc), - /* 141 */ SyscallDesc("getpeername", unimplementedFunc), - /* 142 */ SyscallDesc("osf_gethostid", unimplementedFunc), - /* 143 */ SyscallDesc("osf_sethostid", unimplementedFunc), - /* 144 */ SyscallDesc("getrlimit", getrlimitFunc<Linux>), - /* 145 */ SyscallDesc("setrlimit", ignoreFunc), - /* 146 */ SyscallDesc("osf_old_killpg", unimplementedFunc), - /* 147 */ SyscallDesc("setsid", unimplementedFunc), - /* 148 */ SyscallDesc("quotactl", unimplementedFunc), - /* 149 */ SyscallDesc("osf_oldquota", unimplementedFunc), - /* 150 */ SyscallDesc("getsockname", unimplementedFunc), - /* 151 */ SyscallDesc("osf_pread", unimplementedFunc), - /* 152 */ SyscallDesc("osf_pwrite", unimplementedFunc), - /* 153 */ SyscallDesc("osf_pid_block", unimplementedFunc), - /* 154 */ SyscallDesc("osf_pid_unblock", unimplementedFunc), - /* 155 */ SyscallDesc("osf_signal_urti", unimplementedFunc), - /* 156 */ SyscallDesc("sigaction", ignoreFunc), - /* 157 */ SyscallDesc("osf_sigwaitprim", unimplementedFunc), - /* 158 */ SyscallDesc("osf_nfssvc", unimplementedFunc), - /* 159 */ SyscallDesc("osf_getdirentries", unimplementedFunc), - /* 160 */ SyscallDesc("osf_statfs", unimplementedFunc), - /* 161 */ SyscallDesc("osf_fstatfs", unimplementedFunc), - /* 162 */ SyscallDesc("unknown #162", unimplementedFunc), - /* 163 */ SyscallDesc("osf_async_daemon", unimplementedFunc), - /* 164 */ SyscallDesc("osf_getfh", unimplementedFunc), - /* 165 */ SyscallDesc("osf_getdomainname", unimplementedFunc), - /* 166 */ SyscallDesc("setdomainname", unimplementedFunc), - /* 167 */ SyscallDesc("unknown #167", unimplementedFunc), - /* 168 */ SyscallDesc("unknown #168", unimplementedFunc), - /* 169 */ SyscallDesc("osf_exportfs", unimplementedFunc), - /* 170 */ SyscallDesc("unknown #170", unimplementedFunc), - /* 171 */ SyscallDesc("unknown #171", unimplementedFunc), - /* 172 */ SyscallDesc("unknown #172", unimplementedFunc), - /* 173 */ SyscallDesc("unknown #173", unimplementedFunc), - /* 174 */ SyscallDesc("unknown #174", unimplementedFunc), - /* 175 */ SyscallDesc("unknown #175", unimplementedFunc), - /* 176 */ SyscallDesc("unknown #176", unimplementedFunc), - /* 177 */ SyscallDesc("unknown #177", unimplementedFunc), - /* 178 */ SyscallDesc("unknown #178", unimplementedFunc), - /* 179 */ SyscallDesc("unknown #179", unimplementedFunc), - /* 180 */ SyscallDesc("unknown #180", unimplementedFunc), - /* 181 */ SyscallDesc("osf_alt_plock", unimplementedFunc), - /* 182 */ SyscallDesc("unknown #182", unimplementedFunc), - /* 183 */ SyscallDesc("unknown #183", unimplementedFunc), - /* 184 */ SyscallDesc("osf_getmnt", unimplementedFunc), - /* 185 */ SyscallDesc("unknown #185", unimplementedFunc), - /* 186 */ SyscallDesc("unknown #186", unimplementedFunc), - /* 187 */ SyscallDesc("osf_alt_sigpending", unimplementedFunc), - /* 188 */ SyscallDesc("osf_alt_setsid", unimplementedFunc), - /* 189 */ SyscallDesc("unknown #189", unimplementedFunc), - /* 190 */ SyscallDesc("unknown #190", unimplementedFunc), - /* 191 */ SyscallDesc("unknown #191", unimplementedFunc), - /* 192 */ SyscallDesc("unknown #192", unimplementedFunc), - /* 193 */ SyscallDesc("unknown #193", unimplementedFunc), - /* 194 */ SyscallDesc("unknown #194", unimplementedFunc), - /* 195 */ SyscallDesc("unknown #195", unimplementedFunc), - /* 196 */ SyscallDesc("unknown #196", unimplementedFunc), - /* 197 */ SyscallDesc("unknown #197", unimplementedFunc), - /* 198 */ SyscallDesc("unknown #198", unimplementedFunc), - /* 199 */ SyscallDesc("osf_swapon", unimplementedFunc), - /* 200 */ SyscallDesc("msgctl", unimplementedFunc), - /* 201 */ SyscallDesc("msgget", unimplementedFunc), - /* 202 */ SyscallDesc("msgrcv", unimplementedFunc), - /* 203 */ SyscallDesc("msgsnd", unimplementedFunc), - /* 204 */ SyscallDesc("semctl", unimplementedFunc), - /* 205 */ SyscallDesc("semget", unimplementedFunc), - /* 206 */ SyscallDesc("semop", unimplementedFunc), - /* 207 */ SyscallDesc("osf_utsname", unimplementedFunc), - /* 208 */ SyscallDesc("lchown", unimplementedFunc), - /* 209 */ SyscallDesc("osf_shmat", unimplementedFunc), - /* 210 */ SyscallDesc("shmctl", unimplementedFunc), - /* 211 */ SyscallDesc("shmdt", unimplementedFunc), - /* 212 */ SyscallDesc("shmget", unimplementedFunc), - /* 213 */ SyscallDesc("osf_mvalid", unimplementedFunc), - /* 214 */ SyscallDesc("osf_getaddressconf", unimplementedFunc), - /* 215 */ SyscallDesc("osf_msleep", unimplementedFunc), - /* 216 */ SyscallDesc("osf_mwakeup", unimplementedFunc), - /* 217 */ SyscallDesc("msync", unimplementedFunc), - /* 218 */ SyscallDesc("osf_signal", unimplementedFunc), - /* 219 */ SyscallDesc("osf_utc_gettime", unimplementedFunc), - /* 220 */ SyscallDesc("osf_utc_adjtime", unimplementedFunc), - /* 221 */ SyscallDesc("unknown #221", unimplementedFunc), - /* 222 */ SyscallDesc("osf_security", unimplementedFunc), - /* 223 */ SyscallDesc("osf_kloadcall", unimplementedFunc), - /* 224 */ SyscallDesc("unknown #224", unimplementedFunc), - /* 225 */ SyscallDesc("unknown #225", unimplementedFunc), - /* 226 */ SyscallDesc("unknown #226", unimplementedFunc), - /* 227 */ SyscallDesc("unknown #227", unimplementedFunc), - /* 228 */ SyscallDesc("unknown #228", unimplementedFunc), - /* 229 */ SyscallDesc("unknown #229", unimplementedFunc), - /* 230 */ SyscallDesc("unknown #230", unimplementedFunc), - /* 231 */ SyscallDesc("unknown #231", unimplementedFunc), - /* 232 */ SyscallDesc("unknown #232", unimplementedFunc), - /* 233 */ SyscallDesc("getpgid", unimplementedFunc), - /* 234 */ SyscallDesc("getsid", unimplementedFunc), - /* 235 */ SyscallDesc("sigaltstack", ignoreFunc), - /* 236 */ SyscallDesc("osf_waitid", unimplementedFunc), - /* 237 */ SyscallDesc("osf_priocntlset", unimplementedFunc), - /* 238 */ SyscallDesc("osf_sigsendset", unimplementedFunc), - /* 239 */ SyscallDesc("osf_set_speculative", unimplementedFunc), - /* 240 */ SyscallDesc("osf_msfs_syscall", unimplementedFunc), - /* 241 */ SyscallDesc("osf_sysinfo", unimplementedFunc), - /* 242 */ SyscallDesc("osf_uadmin", unimplementedFunc), - /* 243 */ SyscallDesc("osf_fuser", unimplementedFunc), - /* 244 */ SyscallDesc("osf_proplist_syscall", unimplementedFunc), - /* 245 */ SyscallDesc("osf_ntp_adjtime", unimplementedFunc), - /* 246 */ SyscallDesc("osf_ntp_gettime", unimplementedFunc), - /* 247 */ SyscallDesc("osf_pathconf", unimplementedFunc), - /* 248 */ SyscallDesc("osf_fpathconf", unimplementedFunc), - /* 249 */ SyscallDesc("unknown #249", unimplementedFunc), - /* 250 */ SyscallDesc("osf_uswitch", unimplementedFunc), - /* 251 */ SyscallDesc("osf_usleep_thread", unimplementedFunc), - /* 252 */ SyscallDesc("osf_audcntl", unimplementedFunc), - /* 253 */ SyscallDesc("osf_audgen", unimplementedFunc), - /* 254 */ SyscallDesc("sysfs", unimplementedFunc), - /* 255 */ SyscallDesc("osf_subsys_info", unimplementedFunc), - /* 256 */ SyscallDesc("osf_getsysinfo", osf_getsysinfoFunc), - /* 257 */ SyscallDesc("osf_setsysinfo", osf_setsysinfoFunc), - /* 258 */ SyscallDesc("osf_afs_syscall", unimplementedFunc), - /* 259 */ SyscallDesc("osf_swapctl", unimplementedFunc), - /* 260 */ SyscallDesc("osf_memcntl", unimplementedFunc), - /* 261 */ SyscallDesc("osf_fdatasync", unimplementedFunc), - /* 262 */ SyscallDesc("unknown #262", unimplementedFunc), - /* 263 */ SyscallDesc("unknown #263", unimplementedFunc), - /* 264 */ SyscallDesc("unknown #264", unimplementedFunc), - /* 265 */ SyscallDesc("unknown #265", unimplementedFunc), - /* 266 */ SyscallDesc("unknown #266", unimplementedFunc), - /* 267 */ SyscallDesc("unknown #267", unimplementedFunc), - /* 268 */ SyscallDesc("unknown #268", unimplementedFunc), - /* 269 */ SyscallDesc("unknown #269", unimplementedFunc), - /* 270 */ SyscallDesc("unknown #270", unimplementedFunc), - /* 271 */ SyscallDesc("unknown #271", unimplementedFunc), - /* 272 */ SyscallDesc("unknown #272", unimplementedFunc), - /* 273 */ SyscallDesc("unknown #273", unimplementedFunc), - /* 274 */ SyscallDesc("unknown #274", unimplementedFunc), - /* 275 */ SyscallDesc("unknown #275", unimplementedFunc), - /* 276 */ SyscallDesc("unknown #276", unimplementedFunc), - /* 277 */ SyscallDesc("unknown #277", unimplementedFunc), - /* 278 */ SyscallDesc("unknown #278", unimplementedFunc), - /* 279 */ SyscallDesc("unknown #279", unimplementedFunc), - /* 280 */ SyscallDesc("unknown #280", unimplementedFunc), - /* 281 */ SyscallDesc("unknown #281", unimplementedFunc), - /* 282 */ SyscallDesc("unknown #282", unimplementedFunc), - /* 283 */ SyscallDesc("unknown #283", unimplementedFunc), - /* 284 */ SyscallDesc("unknown #284", unimplementedFunc), - /* 285 */ SyscallDesc("unknown #285", unimplementedFunc), - /* 286 */ SyscallDesc("unknown #286", unimplementedFunc), - /* 287 */ SyscallDesc("unknown #287", unimplementedFunc), - /* 288 */ SyscallDesc("unknown #288", unimplementedFunc), - /* 289 */ SyscallDesc("unknown #289", unimplementedFunc), - /* 290 */ SyscallDesc("unknown #290", unimplementedFunc), - /* 291 */ SyscallDesc("unknown #291", unimplementedFunc), - /* 292 */ SyscallDesc("unknown #292", unimplementedFunc), - /* 293 */ SyscallDesc("unknown #293", unimplementedFunc), - /* 294 */ SyscallDesc("unknown #294", unimplementedFunc), - /* 295 */ SyscallDesc("unknown #295", unimplementedFunc), - /* 296 */ SyscallDesc("unknown #296", unimplementedFunc), - /* 297 */ SyscallDesc("unknown #297", unimplementedFunc), - /* 298 */ SyscallDesc("unknown #298", unimplementedFunc), - /* 299 */ SyscallDesc("unknown #299", unimplementedFunc), -/* - * Linux-specific system calls begin at 300 - */ - /* 300 */ SyscallDesc("bdflush", unimplementedFunc), - /* 301 */ SyscallDesc("sethae", unimplementedFunc), - /* 302 */ SyscallDesc("mount", unimplementedFunc), - /* 303 */ SyscallDesc("old_adjtimex", unimplementedFunc), - /* 304 */ SyscallDesc("swapoff", unimplementedFunc), - /* 305 */ SyscallDesc("getdents", unimplementedFunc), - /* 306 */ SyscallDesc("create_module", unimplementedFunc), - /* 307 */ SyscallDesc("init_module", unimplementedFunc), - /* 308 */ SyscallDesc("delete_module", unimplementedFunc), - /* 309 */ SyscallDesc("get_kernel_syms", unimplementedFunc), - /* 310 */ SyscallDesc("syslog", unimplementedFunc), - /* 311 */ SyscallDesc("reboot", unimplementedFunc), - /* 312 */ SyscallDesc("clone", unimplementedFunc), - /* 313 */ SyscallDesc("uselib", unimplementedFunc), - /* 314 */ SyscallDesc("mlock", unimplementedFunc), - /* 315 */ SyscallDesc("munlock", unimplementedFunc), - /* 316 */ SyscallDesc("mlockall", unimplementedFunc), - /* 317 */ SyscallDesc("munlockall", unimplementedFunc), - /* 318 */ SyscallDesc("sysinfo", unimplementedFunc), - /* 319 */ SyscallDesc("_sysctl", unimplementedFunc), - /* 320 */ SyscallDesc("was sys_idle", unimplementedFunc), - /* 321 */ SyscallDesc("oldumount", unimplementedFunc), - /* 322 */ SyscallDesc("swapon", unimplementedFunc), - /* 323 */ SyscallDesc("times", ignoreFunc), - /* 324 */ SyscallDesc("personality", unimplementedFunc), - /* 325 */ SyscallDesc("setfsuid", unimplementedFunc), - /* 326 */ SyscallDesc("setfsgid", unimplementedFunc), - /* 327 */ SyscallDesc("ustat", unimplementedFunc), - /* 328 */ SyscallDesc("statfs", unimplementedFunc), - /* 329 */ SyscallDesc("fstatfs", unimplementedFunc), - /* 330 */ SyscallDesc("sched_setparam", unimplementedFunc), - /* 331 */ SyscallDesc("sched_getparam", unimplementedFunc), - /* 332 */ SyscallDesc("sched_setscheduler", unimplementedFunc), - /* 333 */ SyscallDesc("sched_getscheduler", unimplementedFunc), - /* 334 */ SyscallDesc("sched_yield", unimplementedFunc), - /* 335 */ SyscallDesc("sched_get_priority_max", unimplementedFunc), - /* 336 */ SyscallDesc("sched_get_priority_min", unimplementedFunc), - /* 337 */ SyscallDesc("sched_rr_get_interval", unimplementedFunc), - /* 338 */ SyscallDesc("afs_syscall", unimplementedFunc), - /* 339 */ SyscallDesc("uname", unameFunc), - /* 340 */ SyscallDesc("nanosleep", unimplementedFunc), - /* 341 */ SyscallDesc("mremap", unimplementedFunc), - /* 342 */ SyscallDesc("nfsservctl", unimplementedFunc), - /* 343 */ SyscallDesc("setresuid", unimplementedFunc), - /* 344 */ SyscallDesc("getresuid", unimplementedFunc), - /* 345 */ SyscallDesc("pciconfig_read", unimplementedFunc), - /* 346 */ SyscallDesc("pciconfig_write", unimplementedFunc), - /* 347 */ SyscallDesc("query_module", unimplementedFunc), - /* 348 */ SyscallDesc("prctl", unimplementedFunc), - /* 349 */ SyscallDesc("pread", unimplementedFunc), - /* 350 */ SyscallDesc("pwrite", unimplementedFunc), - /* 351 */ SyscallDesc("rt_sigreturn", unimplementedFunc), - /* 352 */ SyscallDesc("rt_sigaction", ignoreFunc), - /* 353 */ SyscallDesc("rt_sigprocmask", unimplementedFunc), - /* 354 */ SyscallDesc("rt_sigpending", unimplementedFunc), - /* 355 */ SyscallDesc("rt_sigtimedwait", unimplementedFunc), - /* 356 */ SyscallDesc("rt_sigqueueinfo", unimplementedFunc), - /* 357 */ SyscallDesc("rt_sigsuspend", unimplementedFunc), - /* 358 */ SyscallDesc("select", unimplementedFunc), - /* 359 */ SyscallDesc("gettimeofday", gettimeofdayFunc<Linux>), - /* 360 */ SyscallDesc("settimeofday", unimplementedFunc), - /* 361 */ SyscallDesc("getitimer", unimplementedFunc), - /* 362 */ SyscallDesc("setitimer", unimplementedFunc), - /* 363 */ SyscallDesc("utimes", utimesFunc<Linux>), - /* 364 */ SyscallDesc("getrusage", getrusageFunc<Linux>), - /* 365 */ SyscallDesc("wait4", unimplementedFunc), - /* 366 */ SyscallDesc("adjtimex", unimplementedFunc), - /* 367 */ SyscallDesc("getcwd", unimplementedFunc), - /* 368 */ SyscallDesc("capget", unimplementedFunc), - /* 369 */ SyscallDesc("capset", unimplementedFunc), - /* 370 */ SyscallDesc("sendfile", unimplementedFunc), - /* 371 */ SyscallDesc("setresgid", unimplementedFunc), - /* 372 */ SyscallDesc("getresgid", unimplementedFunc), - /* 373 */ SyscallDesc("dipc", unimplementedFunc), - /* 374 */ SyscallDesc("pivot_root", unimplementedFunc), - /* 375 */ SyscallDesc("mincore", unimplementedFunc), - /* 376 */ SyscallDesc("pciconfig_iobase", unimplementedFunc), - /* 377 */ SyscallDesc("getdents64", unimplementedFunc), - /* 378 */ SyscallDesc("gettid", unimplementedFunc), - /* 379 */ SyscallDesc("readahead", unimplementedFunc), - /* 380 */ SyscallDesc("security", unimplementedFunc), - /* 381 */ SyscallDesc("tkill", unimplementedFunc), - /* 382 */ SyscallDesc("setxattr", unimplementedFunc), - /* 383 */ SyscallDesc("lsetxattr", unimplementedFunc), - /* 384 */ SyscallDesc("fsetxattr", unimplementedFunc), - /* 385 */ SyscallDesc("getxattr", unimplementedFunc), - /* 386 */ SyscallDesc("lgetxattr", unimplementedFunc), - /* 387 */ SyscallDesc("fgetxattr", unimplementedFunc), - /* 388 */ SyscallDesc("listxattr", unimplementedFunc), - /* 389 */ SyscallDesc("llistxattr", unimplementedFunc), - /* 390 */ SyscallDesc("flistxattr", unimplementedFunc), - /* 391 */ SyscallDesc("removexattr", unimplementedFunc), - /* 392 */ SyscallDesc("lremovexattr", unimplementedFunc), - /* 393 */ SyscallDesc("fremovexattr", unimplementedFunc), - /* 394 */ SyscallDesc("futex", unimplementedFunc), - /* 395 */ SyscallDesc("sched_setaffinity", unimplementedFunc), - /* 396 */ SyscallDesc("sched_getaffinity", unimplementedFunc), - /* 397 */ SyscallDesc("tuxcall", unimplementedFunc), - /* 398 */ SyscallDesc("io_setup", unimplementedFunc), - /* 399 */ SyscallDesc("io_destroy", unimplementedFunc), - /* 400 */ SyscallDesc("io_getevents", unimplementedFunc), - /* 401 */ SyscallDesc("io_submit", unimplementedFunc), - /* 402 */ SyscallDesc("io_cancel", unimplementedFunc), - /* 403 */ SyscallDesc("unknown #403", unimplementedFunc), - /* 404 */ SyscallDesc("unknown #404", unimplementedFunc), - /* 405 */ SyscallDesc("exit_group", exitFunc), // exit all threads... - /* 406 */ SyscallDesc("lookup_dcookie", unimplementedFunc), - /* 407 */ SyscallDesc("sys_epoll_create", unimplementedFunc), - /* 408 */ SyscallDesc("sys_epoll_ctl", unimplementedFunc), - /* 409 */ SyscallDesc("sys_epoll_wait", unimplementedFunc), - /* 410 */ SyscallDesc("remap_file_pages", unimplementedFunc), - /* 411 */ SyscallDesc("set_tid_address", unimplementedFunc), - /* 412 */ SyscallDesc("restart_syscall", unimplementedFunc), - /* 413 */ SyscallDesc("fadvise64", unimplementedFunc), - /* 414 */ SyscallDesc("timer_create", unimplementedFunc), - /* 415 */ SyscallDesc("timer_settime", unimplementedFunc), - /* 416 */ SyscallDesc("timer_gettime", unimplementedFunc), - /* 417 */ SyscallDesc("timer_getoverrun", unimplementedFunc), - /* 418 */ SyscallDesc("timer_delete", unimplementedFunc), - /* 419 */ SyscallDesc("clock_settime", unimplementedFunc), - /* 420 */ SyscallDesc("clock_gettime", unimplementedFunc), - /* 421 */ SyscallDesc("clock_getres", unimplementedFunc), - /* 422 */ SyscallDesc("clock_nanosleep", unimplementedFunc), - /* 423 */ SyscallDesc("semtimedop", unimplementedFunc), - /* 424 */ SyscallDesc("tgkill", unimplementedFunc), - /* 425 */ SyscallDesc("stat64", unimplementedFunc), - /* 426 */ SyscallDesc("lstat64", lstat64Func<Linux>), - /* 427 */ SyscallDesc("fstat64", fstat64Func<Linux>), - /* 428 */ SyscallDesc("vserver", unimplementedFunc), - /* 429 */ SyscallDesc("mbind", unimplementedFunc), - /* 430 */ SyscallDesc("get_mempolicy", unimplementedFunc), - /* 431 */ SyscallDesc("set_mempolicy", unimplementedFunc), - /* 432 */ SyscallDesc("mq_open", unimplementedFunc), - /* 433 */ SyscallDesc("mq_unlink", unimplementedFunc), - /* 434 */ SyscallDesc("mq_timedsend", unimplementedFunc), - /* 435 */ SyscallDesc("mq_timedreceive", unimplementedFunc), - /* 436 */ SyscallDesc("mq_notify", unimplementedFunc), - /* 437 */ SyscallDesc("mq_getsetattr", unimplementedFunc), - /* 438 */ SyscallDesc("waitid", unimplementedFunc), - /* 439 */ SyscallDesc("add_key", unimplementedFunc), - /* 440 */ SyscallDesc("request_key", unimplementedFunc), - /* 441 */ SyscallDesc("keyctl", unimplementedFunc) -}; - -AlphaLinuxProcess::AlphaLinuxProcess(const std::string &name, - ObjectFile *objFile, - int stdin_fd, - int stdout_fd, - int stderr_fd, - std::vector<std::string> &argv, - std::vector<std::string> &envp) - : LiveProcess(name, objFile, stdin_fd, stdout_fd, stderr_fd, argv, envp), - Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc)) -{ - init_regs->intRegFile[0] = 0; -} - - - -SyscallDesc* -AlphaLinuxProcess::getDesc(int callnum) -{ - if (callnum < 0 || callnum > Num_Syscall_Descs) - return NULL; - return &syscallDescs[callnum]; -} diff --git a/arch/alpha/linux/process.hh b/arch/alpha/linux/process.hh deleted file mode 100644 index 7de1b1ac1..000000000 --- a/arch/alpha/linux/process.hh +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2003-2004 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. - */ - -#ifndef __ALPHA_LINUX_PROCESS_HH__ -#define __ALPHA_LINUX_PROCESS_HH__ - -#include "sim/process.hh" - - -/// A process with emulated Alpha/Linux syscalls. -class AlphaLinuxProcess : public LiveProcess -{ - public: - /// Constructor. - AlphaLinuxProcess(const std::string &name, - ObjectFile *objFile, - int stdin_fd, int stdout_fd, int stderr_fd, - std::vector<std::string> &argv, - std::vector<std::string> &envp); - - virtual SyscallDesc* getDesc(int callnum); - - /// The target system's hostname. - static const char *hostname; - - /// Array of syscall descriptors, indexed by call number. - static SyscallDesc syscallDescs[]; - - const int Num_Syscall_Descs; -}; - - -#endif // __ALPHA_LINUX_PROCESS_HH__ diff --git a/arch/alpha/linux/system.cc b/arch/alpha/linux/system.cc deleted file mode 100644 index 245a0cabf..000000000 --- a/arch/alpha/linux/system.cc +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * This code loads the linux kernel, console, pal and patches certain - * functions. The symbol tables are loaded so that traces can show - * the executing function and we can skip functions. Various delay - * loops are skipped and their final values manually computed to speed - * up boot time. - */ - -#include "arch/arguments.hh" -#include "arch/vtophys.hh" -#include "arch/alpha/linux/system.hh" -#include "arch/alpha/linux/threadinfo.hh" -#include "arch/alpha/system.hh" -#include "base/loader/symtab.hh" -#include "cpu/exec_context.hh" -#include "cpu/base.hh" -#include "dev/platform.hh" -#include "kern/linux/printk.hh" -#include "kern/linux/events.hh" -#include "mem/functional/memory_control.hh" -#include "mem/functional/physical.hh" -#include "sim/builder.hh" -#include "sim/byteswap.hh" - -using namespace std; -using namespace AlphaISA; -using namespace Linux; - -LinuxAlphaSystem::LinuxAlphaSystem(Params *p) - : AlphaSystem(p) -{ - Addr addr = 0; - Addr paddr = 0; - - /** - * The symbol swapper_pg_dir marks the beginning of the kernel and - * the location of bootloader passed arguments - */ - if (!kernelSymtab->findAddress("swapper_pg_dir", KernelStart)) { - panic("Could not determine start location of kernel"); - } - - /** - * Since we aren't using a bootloader, we have to copy the - * kernel arguments directly into the kernel's memory. - */ - paddr = vtophys(physmem, CommandLine()); - char *commandline = (char *)physmem->dma_addr(paddr, sizeof(uint64_t)); - if (commandline) - strncpy(commandline, params()->boot_osflags.c_str(), CommandLineSize); - - /** - * find the address of the est_cycle_freq variable and insert it - * so we don't through the lengthly process of trying to - * calculated it by using the PIT, RTC, etc. - */ - if (kernelSymtab->findAddress("est_cycle_freq", addr)) { - paddr = vtophys(physmem, addr); - uint8_t *est_cycle_frequency = - physmem->dma_addr(paddr, sizeof(uint64_t)); - - if (est_cycle_frequency) - *(uint64_t *)est_cycle_frequency = - Clock::Frequency / p->boot_cpu_frequency; - } - - - /** - * EV5 only supports 127 ASNs so we are going to tell the kernel that the - * paritiuclar EV6 we have only supports 127 asns. - * @todo At some point we should change ev5.hh and the palcode to support - * 255 ASNs. - */ - if (kernelSymtab->findAddress("dp264_mv", addr)) { - paddr = vtophys(physmem, addr); - char *dp264_mv = (char *)physmem->dma_addr(paddr, sizeof(uint64_t)); - - if (dp264_mv) { - *(uint32_t*)(dp264_mv+0x18) = LittleEndianGuest::htog((uint32_t)127); - } else - panic("could not translate dp264_mv addr\n"); - - } else - panic("could not find dp264_mv\n"); - -#ifndef NDEBUG - kernelPanicEvent = addKernelFuncEvent<BreakPCEvent>("panic"); - if (!kernelPanicEvent) - panic("could not find kernel symbol \'panic\'"); - -#if 0 - kernelDieEvent = addKernelFuncEvent<BreakPCEvent>("die_if_kernel"); - if (!kernelDieEvent) - panic("could not find kernel symbol \'die_if_kernel\'"); -#endif - -#endif - - /** - * Any time ide_delay_50ms, calibarte_delay or - * determine_cpu_caches is called just skip the - * function. Currently determine_cpu_caches only is used put - * information in proc, however if that changes in the future we - * will have to fill in the cache size variables appropriately. - */ - - skipIdeDelay50msEvent = - addKernelFuncEvent<SkipFuncEvent>("ide_delay_50ms"); - skipDelayLoopEvent = - addKernelFuncEvent<SkipDelayLoopEvent>("calibrate_delay"); - skipCacheProbeEvent = - addKernelFuncEvent<SkipFuncEvent>("determine_cpu_caches"); - debugPrintkEvent = addKernelFuncEvent<DebugPrintkEvent>("dprintk"); - idleStartEvent = addKernelFuncEvent<IdleStartEvent>("cpu_idle"); - - if (kernelSymtab->findAddress("alpha_switch_to", addr) && DTRACE(Thread)) { - printThreadEvent = new PrintThreadInfo(&pcEventQueue, "threadinfo", - addr + sizeof(MachInst) * 6); - } else { - printThreadEvent = NULL; - } -} - -LinuxAlphaSystem::~LinuxAlphaSystem() -{ -#ifndef NDEBUG - delete kernelPanicEvent; -#endif - delete skipIdeDelay50msEvent; - delete skipDelayLoopEvent; - delete skipCacheProbeEvent; - delete debugPrintkEvent; - delete idleStartEvent; - delete printThreadEvent; - delete intStartEvent; - delete intEndEvent; - delete intEndEvent2; -} - - -void -LinuxAlphaSystem::setDelayLoop(ExecContext *xc) -{ - Addr addr = 0; - if (kernelSymtab->findAddress("loops_per_jiffy", addr)) { - Addr paddr = vtophys(physmem, addr); - - uint8_t *loops_per_jiffy = - physmem->dma_addr(paddr, sizeof(uint32_t)); - - Tick cpuFreq = xc->getCpuPtr()->frequency(); - Tick intrFreq = platform->intrFrequency(); - *(uint32_t *)loops_per_jiffy = - (uint32_t)((cpuFreq / intrFreq) * 0.9988); - } -} - - -void -LinuxAlphaSystem::SkipDelayLoopEvent::process(ExecContext *xc) -{ - SkipFuncEvent::process(xc); - // calculate and set loops_per_jiffy - ((LinuxAlphaSystem *)xc->getSystemPtr())->setDelayLoop(xc); -} - -void -LinuxAlphaSystem::PrintThreadInfo::process(ExecContext *xc) -{ - Linux::ThreadInfo ti(xc); - - DPRINTF(Thread, "Currently Executing Thread %s, pid %d, started at: %d\n", - ti.curTaskName(), ti.curTaskPID(), ti.curTaskStart()); -} - - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(LinuxAlphaSystem) - - Param<Tick> boot_cpu_frequency; - SimObjectParam<MemoryController *> memctrl; - SimObjectParam<PhysicalMemory *> physmem; - - Param<string> kernel; - Param<string> console; - Param<string> pal; - - Param<string> boot_osflags; - Param<string> readfile; - Param<unsigned int> init_param; - - Param<uint64_t> system_type; - Param<uint64_t> system_rev; - -END_DECLARE_SIM_OBJECT_PARAMS(LinuxAlphaSystem) - -BEGIN_INIT_SIM_OBJECT_PARAMS(LinuxAlphaSystem) - - INIT_PARAM(boot_cpu_frequency, "Frequency of the boot CPU"), - INIT_PARAM(memctrl, "memory controller"), - INIT_PARAM(physmem, "phsyical memory"), - INIT_PARAM(kernel, "file that contains the kernel code"), - INIT_PARAM(console, "file that contains the console code"), - INIT_PARAM(pal, "file that contains palcode"), - INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot", - "a"), - INIT_PARAM_DFLT(readfile, "file to read startup script from", ""), - INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0), - INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 34), - INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10) - -END_INIT_SIM_OBJECT_PARAMS(LinuxAlphaSystem) - -CREATE_SIM_OBJECT(LinuxAlphaSystem) -{ - AlphaSystem::Params *p = new AlphaSystem::Params; - p->name = getInstanceName(); - p->boot_cpu_frequency = boot_cpu_frequency; - p->memctrl = memctrl; - p->physmem = physmem; - p->kernel_path = kernel; - p->console_path = console; - p->palcode = pal; - p->boot_osflags = boot_osflags; - p->init_param = init_param; - p->readfile = readfile; - p->system_type = system_type; - p->system_rev = system_rev; - return new LinuxAlphaSystem(p); -} - -REGISTER_SIM_OBJECT("LinuxAlphaSystem", LinuxAlphaSystem) - diff --git a/arch/alpha/linux/system.hh b/arch/alpha/linux/system.hh deleted file mode 100644 index a33ec6b1c..000000000 --- a/arch/alpha/linux/system.hh +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __ARCH_ALPHA_LINUX_SYSTEM_HH__ -#define __ARCH_ALPHA_LINUX_SYSTEM_HH__ - -class ExecContext; - -class BreakPCEvent; -class IdleStartEvent; - -#include "arch/alpha/system.hh" -#include "kern/linux/events.hh" - -using namespace AlphaISA; -using namespace Linux; -using namespace std; - -/** - * This class contains linux specific system code (Loading, Events). - * It points to objects that are the system binaries to load and patches them - * appropriately to work in simulator. - */ -class LinuxAlphaSystem : public AlphaSystem -{ - private: - class SkipDelayLoopEvent : public SkipFuncEvent - { - public: - SkipDelayLoopEvent(PCEventQueue *q, const std::string &desc, Addr addr) - : SkipFuncEvent(q, desc, addr) {} - virtual void process(ExecContext *xc); - }; - - class PrintThreadInfo : public PCEvent - { - public: - PrintThreadInfo(PCEventQueue *q, const std::string &desc, Addr addr) - : PCEvent(q, desc, addr) {} - virtual void process(ExecContext *xc); - }; - - - /** - * Addresses defining where the kernel bootloader places various - * elements. Details found in include/asm-alpha/system.h - */ - Addr KernelStart; // Lookup the symbol swapper_pg_dir - - public: - Addr InitStack() const { return KernelStart + 0x02000; } - Addr EmptyPGT() const { return KernelStart + 0x04000; } - Addr EmptyPGE() const { return KernelStart + 0x08000; } - Addr ZeroPGE() const { return KernelStart + 0x0A000; } - Addr StartAddr() const { return KernelStart + 0x10000; } - - Addr Param() const { return ZeroPGE() + 0x0; } - Addr CommandLine() const { return Param() + 0x0; } - Addr InitrdStart() const { return Param() + 0x100; } - Addr InitrdSize() const { return Param() + 0x108; } - static const int CommandLineSize = 256; - - private: -#ifndef NDEBUG - /** Event to halt the simulator if the kernel calls panic() */ - BreakPCEvent *kernelPanicEvent; - - /** Event to halt the simulator if the kernel calls die_if_kernel */ - BreakPCEvent *kernelDieEvent; -#endif - - /** - * Event to skip determine_cpu_caches() because we don't support - * the IPRs that the code can access to figure out cache sizes - */ - SkipFuncEvent *skipCacheProbeEvent; - - /** PC based event to skip the ide_delay_50ms() call */ - SkipFuncEvent *skipIdeDelay50msEvent; - - /** - * PC based event to skip the dprink() call and emulate its - * functionality - */ - DebugPrintkEvent *debugPrintkEvent; - - /** - * Skip calculate_delay_loop() rather than waiting for this to be - * calculated - */ - SkipDelayLoopEvent *skipDelayLoopEvent; - - /** - * Event to print information about thread switches if the trace flag - * Thread is set - */ - PrintThreadInfo *printThreadEvent; - - /** Grab the PCBB of the idle process when it starts */ - IdleStartEvent *idleStartEvent; - - public: - LinuxAlphaSystem(Params *p); - ~LinuxAlphaSystem(); - - void setDelayLoop(ExecContext *xc); -}; - -#endif // __ARCH_ALPHA_LINUX_SYSTEM_HH__ diff --git a/arch/alpha/linux/thread_info.hh b/arch/alpha/linux/thread_info.hh deleted file mode 100644 index 88791b00d..000000000 --- a/arch/alpha/linux/thread_info.hh +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __ARCH_ALPHA_LINUX_THREAD_INFO_H__ -#define __ARCH_ALPHA_LINUX_THREAD_INFO_H__ - -#include "arch/alpha/linux/hwrpb.hh" - -namespace Linux { - struct thread_info { - struct pcb_struct pcb; - Addr_a task; - }; -} - -#endif // __ARCH_ALPHA_LINUX_THREAD_INFO_H__ diff --git a/arch/alpha/linux/threadinfo.hh b/arch/alpha/linux/threadinfo.hh deleted file mode 100644 index 8f03c9314..000000000 --- a/arch/alpha/linux/threadinfo.hh +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2004 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. - */ - -#ifndef __ARCH_ALPHA_LINUX_LINUX_TREADNIFO_HH__ -#define __ARCH_ALPHA_LINUX_LINUX_TREADNIFO_HH__ - -#include "arch/alpha/linux/thread_info.hh" -#include "cpu/exec_context.hh" -#include "kern/linux/sched.hh" -#include "sim/vptr.hh" - -namespace Linux { - -class ThreadInfo -{ - private: - ExecContext *xc; - - public: - ThreadInfo(ExecContext *exec) : xc(exec) {} - ~ThreadInfo() {} - - inline VPtr<thread_info> - curThreadInfo() - { - Addr current; - - /* Each kernel stack is only 2 pages, the start of which is the - * thread_info struct. So we can get the address by masking off - * the lower 14 bits. - */ - current = xc->readIntReg(TheISA::StackPointerReg) & ~0x3fff; - return VPtr<thread_info>(xc, current); - } - - inline VPtr<task_struct> - curTaskInfo() - { - Addr task = curThreadInfo()->task; - return VPtr<task_struct>(xc, task); - } - - std::string - curTaskName() - { - return curTaskInfo()->name; - } - - int32_t - curTaskPID() - { - return curTaskInfo()->pid; - } - - uint64_t - curTaskStart() - { - return curTaskInfo()->start; - } -}; - -/* namespace Linux */ } - -#endif // __ARCH_ALPHA_LINUX_LINUX_THREADINFO_HH__ diff --git a/arch/alpha/osfpal.cc b/arch/alpha/osfpal.cc deleted file mode 100644 index a48bd28d9..000000000 --- a/arch/alpha/osfpal.cc +++ /dev/null @@ -1,304 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include "arch/alpha/osfpal.hh" - -namespace { - const char *strings[PAL::NumCodes] = { - // Priviledged PAL instructions - "halt", // 0x00 - "cflush", // 0x01 - "draina", // 0x02 - 0, // 0x03 - 0, // 0x04 - 0, // 0x05 - 0, // 0x06 - 0, // 0x07 - 0, // 0x08 - "cserve", // 0x09 - "swppal", // 0x0a - 0, // 0x0b - 0, // 0x0c - "wripir", // 0x0d - 0, // 0x0e - 0, // 0x0f - "rdmces", // 0x10 - "wrmces", // 0x11 - 0, // 0x12 - 0, // 0x13 - 0, // 0x14 - 0, // 0x15 - 0, // 0x16 - 0, // 0x17 - 0, // 0x18 - 0, // 0x19 - 0, // 0x1a - 0, // 0x1b - 0, // 0x1c - 0, // 0x1d - 0, // 0x1e - 0, // 0x1f - 0, // 0x20 - 0, // 0x21 - 0, // 0x22 - 0, // 0x23 - 0, // 0x24 - 0, // 0x25 - 0, // 0x26 - 0, // 0x27 - 0, // 0x28 - 0, // 0x29 - 0, // 0x2a - "wrfen", // 0x2b - 0, // 0x2c - "wrvptptr", // 0x2d - 0, // 0x2e - 0, // 0x2f - "swpctx", // 0x30 - "wrval", // 0x31 - "rdval", // 0x32 - "tbi", // 0x33 - "wrent", // 0x34 - "swpipl", // 0x35 - "rdps", // 0x36 - "wrkgp", // 0x37 - "wrusp", // 0x38 - "wrperfmon", // 0x39 - "rdusp", // 0x3a - 0, // 0x3b - "whami", // 0x3c - "retsys", // 0x3d - "wtint", // 0x3e - "rti", // 0x3f - 0, // 0x40 - 0, // 0x41 - 0, // 0x42 - 0, // 0x43 - 0, // 0x44 - 0, // 0x45 - 0, // 0x46 - 0, // 0x47 - 0, // 0x48 - 0, // 0x49 - 0, // 0x4a - 0, // 0x4b - 0, // 0x4c - 0, // 0x4d - 0, // 0x4e - 0, // 0x4f - 0, // 0x50 - 0, // 0x51 - 0, // 0x52 - 0, // 0x53 - 0, // 0x54 - 0, // 0x55 - 0, // 0x56 - 0, // 0x57 - 0, // 0x58 - 0, // 0x59 - 0, // 0x5a - 0, // 0x5b - 0, // 0x5c - 0, // 0x5d - 0, // 0x5e - 0, // 0x5f - 0, // 0x60 - 0, // 0x61 - 0, // 0x62 - 0, // 0x63 - 0, // 0x64 - 0, // 0x65 - 0, // 0x66 - 0, // 0x67 - 0, // 0x68 - 0, // 0x69 - 0, // 0x6a - 0, // 0x6b - 0, // 0x6c - 0, // 0x6d - 0, // 0x6e - 0, // 0x6f - 0, // 0x70 - 0, // 0x71 - 0, // 0x72 - 0, // 0x73 - 0, // 0x74 - 0, // 0x75 - 0, // 0x76 - 0, // 0x77 - 0, // 0x78 - 0, // 0x79 - 0, // 0x7a - 0, // 0x7b - 0, // 0x7c - 0, // 0x7d - 0, // 0x7e - 0, // 0x7f - - // Unpriviledged PAL instructions - "bpt", // 0x80 - "bugchk", // 0x81 - 0, // 0x82 - "callsys", // 0x83 - 0, // 0x84 - 0, // 0x85 - "imb", // 0x86 - 0, // 0x87 - 0, // 0x88 - 0, // 0x89 - 0, // 0x8a - 0, // 0x8b - 0, // 0x8c - 0, // 0x8d - 0, // 0x8e - 0, // 0x8f - 0, // 0x90 - 0, // 0x91 - "urti", // 0x92 - 0, // 0x93 - 0, // 0x94 - 0, // 0x95 - 0, // 0x96 - 0, // 0x97 - 0, // 0x98 - 0, // 0x99 - 0, // 0x9a - 0, // 0x9b - 0, // 0x9c - 0, // 0x9d - "rdunique", // 0x9e - "wrunique", // 0x9f - 0, // 0xa0 - 0, // 0xa1 - 0, // 0xa2 - 0, // 0xa3 - 0, // 0xa4 - 0, // 0xa5 - 0, // 0xa6 - 0, // 0xa7 - 0, // 0xa8 - 0, // 0xa9 - "gentrap", // 0xaa - 0, // 0xab - 0, // 0xac - 0, // 0xad - "clrfen", // 0xae - 0, // 0xaf - 0, // 0xb0 - 0, // 0xb1 - 0, // 0xb2 - 0, // 0xb3 - 0, // 0xb4 - 0, // 0xb5 - 0, // 0xb6 - 0, // 0xb7 - 0, // 0xb8 - 0, // 0xb9 - 0, // 0xba - 0, // 0xbb - 0, // 0xbc - 0, // 0xbd - "nphalt", // 0xbe - "copypal", // 0xbf -#if 0 - 0, // 0xc0 - 0, // 0xc1 - 0, // 0xc2 - 0, // 0xc3 - 0, // 0xc4 - 0, // 0xc5 - 0, // 0xc6 - 0, // 0xc7 - 0, // 0xc8 - 0, // 0xc9 - 0, // 0xca - 0, // 0xcb - 0, // 0xcc - 0, // 0xcd - 0, // 0xce - 0, // 0xcf - 0, // 0xd0 - 0, // 0xd1 - 0, // 0xd2 - 0, // 0xd3 - 0, // 0xd4 - 0, // 0xd5 - 0, // 0xd6 - 0, // 0xd7 - 0, // 0xd8 - 0, // 0xd9 - 0, // 0xda - 0, // 0xdb - 0, // 0xdc - 0, // 0xdd - 0, // 0xde - 0, // 0xdf - 0, // 0xe0 - 0, // 0xe1 - 0, // 0xe2 - 0, // 0xe3 - 0, // 0xe4 - 0, // 0xe5 - 0, // 0xe6 - 0, // 0xe7 - 0, // 0xe8 - 0, // 0xe9 - 0, // 0xea - 0, // 0xeb - 0, // 0xec - 0, // 0xed - 0, // 0xee - 0, // 0xef - 0, // 0xf0 - 0, // 0xf1 - 0, // 0xf2 - 0, // 0xf3 - 0, // 0xf4 - 0, // 0xf5 - 0, // 0xf6 - 0, // 0xf7 - 0, // 0xf8 - 0, // 0xf9 - 0, // 0xfa - 0, // 0xfb - 0, // 0xfc - 0, // 0xfd - 0, // 0xfe - 0 // 0xff -#endif - }; -} - -const char * -PAL::name(int index) -{ - if (index > NumCodes || index < 0) - return 0; - - return strings[index]; -} diff --git a/arch/alpha/osfpal.hh b/arch/alpha/osfpal.hh deleted file mode 100644 index f46d2bce1..000000000 --- a/arch/alpha/osfpal.hh +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __OSFPAL_HH__ -#define __OSFPAL_HH__ - -struct PAL -{ - enum { - // Privileged PAL functions - halt = 0x00, - cflush = 0x01, - draina = 0x02, - cserve = 0x09, - swppal = 0x0a, - wripir = 0x0d, - rdmces = 0x10, - wrmces = 0x11, - wrfen = 0x2b, - wrvptptr = 0x2d, - swpctx = 0x30, - wrval = 0x31, - rdval = 0x32, - tbi = 0x33, - wrent = 0x34, - swpipl = 0x35, - rdps = 0x36, - wrkgp = 0x37, - wrusp = 0x38, - wrperfmon = 0x39, - rdusp = 0x3a, - whami = 0x3c, - retsys = 0x3d, - wtint = 0x3e, - rti = 0x3f, - - // unprivileged pal functions - bpt = 0x80, - bugchk = 0x81, - callsys = 0x83, - imb = 0x86, - urti = 0x92, - rdunique = 0x9e, - wrunique = 0x9f, - gentrap = 0xaa, - clrfen = 0xae, - nphalt = 0xbe, - copypal = 0xbf, - NumCodes - }; - - static const char *name(int index); -}; - -#endif // __OSFPAL_HH__ diff --git a/arch/alpha/process.cc b/arch/alpha/process.cc deleted file mode 100644 index b2dbe7ad1..000000000 --- a/arch/alpha/process.cc +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2003-2004 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. - */ - -#include "arch/alpha/process.hh" - -namespace AlphaISA -{ - -LiveProcess * -createProcess(const std::string &nm, ObjectFile * objFile, - int stdin_fd, int stdout_fd, int stderr_fd, - std::vector<std::string> &argv, std::vector<std::string> &envp) -{ - LiveProcess * process = NULL; - if (objFile->getArch() != ObjectFile::Alpha) - fatal("Object file does not match architecture."); - switch (objFile->getOpSys()) { - case ObjectFile::Tru64: - process = new AlphaTru64Process(nm, objFile, - stdin_fd, stdout_fd, stderr_fd, - argv, envp); - break; - - case ObjectFile::Linux: - process = new AlphaLinuxProcess(nm, objFile, - stdin_fd, stdout_fd, stderr_fd, - argv, envp); - break; - - default: - fatal("Unknown/unsupported operating system."); - } - return process; -} - -} // namespace AlphaISA diff --git a/arch/alpha/process.hh b/arch/alpha/process.hh deleted file mode 100644 index 4a2a4212e..000000000 --- a/arch/alpha/process.hh +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2003-2004 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. - */ - -#ifndef __ALPHA_PROCESS_HH__ -#define __ALPHA_PROCESS_HH__ - -#include <string> - -#include "arch/alpha/linux/process.hh" -#include "arch/alpha/tru64/process.hh" -#include "base/loader/object_file.hh" - -namespace AlphaISA -{ - -LiveProcess * -createProcess(const std::string &nm, ObjectFile * objFile, - int stdin_fd, int stdout_fd, int stderr_fd, - std::vector<std::string> &argv, std::vector<std::string> &envp); - -} // namespace AlphaISA - -#endif // __ALPHA_PROCESS_HH__ diff --git a/arch/alpha/stacktrace.cc b/arch/alpha/stacktrace.cc deleted file mode 100644 index 26656ab5c..000000000 --- a/arch/alpha/stacktrace.cc +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include <string> - -#include "arch/alpha/isa_traits.hh" -#include "arch/alpha/stacktrace.hh" -#include "arch/alpha/vtophys.hh" -#include "base/bitfield.hh" -#include "base/trace.hh" -#include "cpu/base.hh" -#include "cpu/exec_context.hh" -#include "sim/system.hh" - -using namespace std; -using namespace AlphaISA; - -ProcessInfo::ProcessInfo(ExecContext *_xc) - : xc(_xc) -{ - Addr addr = 0; - - if (!xc->getSystemPtr()->kernelSymtab->findAddress("thread_info_size", addr)) - panic("thread info not compiled into kernel\n"); - thread_info_size = *(int32_t *)vtomem(xc, addr, sizeof(int32_t)); - - if (!xc->getSystemPtr()->kernelSymtab->findAddress("task_struct_size", addr)) - panic("thread info not compiled into kernel\n"); - task_struct_size = *(int32_t *)vtomem(xc, addr, sizeof(int32_t)); - - if (!xc->getSystemPtr()->kernelSymtab->findAddress("thread_info_task", addr)) - panic("thread info not compiled into kernel\n"); - task_off = *(int32_t *)vtomem(xc, addr, sizeof(int32_t)); - - if (!xc->getSystemPtr()->kernelSymtab->findAddress("task_struct_pid", addr)) - panic("thread info not compiled into kernel\n"); - pid_off = *(int32_t *)vtomem(xc, addr, sizeof(int32_t)); - - if (!xc->getSystemPtr()->kernelSymtab->findAddress("task_struct_comm", addr)) - panic("thread info not compiled into kernel\n"); - name_off = *(int32_t *)vtomem(xc, addr, sizeof(int32_t)); -} - -Addr -ProcessInfo::task(Addr ksp) const -{ - Addr base = ksp & ~0x3fff; - if (base == ULL(0xfffffc0000000000)) - return 0; - - Addr task; - CopyOut(xc, &task, base + task_off, sizeof(task)); - return task; -} - -int -ProcessInfo::pid(Addr ksp) const -{ - Addr task = this->task(ksp); - if (!task) - return -1; - - uint16_t pid; - CopyOut(xc, &pid, task + pid_off, sizeof(pid)); - return pid; -} - -string -ProcessInfo::name(Addr ksp) const -{ - Addr task = this->task(ksp); - if (!task) - return "console"; - - char comm[256]; - CopyString(xc, comm, task + name_off, sizeof(comm)); - if (!comm[0]) - return "startup"; - - return comm; -} - -StackTrace::StackTrace() - : xc(0), stack(64) -{ -} - -StackTrace::StackTrace(ExecContext *_xc, StaticInstPtr inst) - : xc(0), stack(64) -{ - trace(_xc, inst); -} - -StackTrace::~StackTrace() -{ -} - -void -StackTrace::trace(ExecContext *_xc, bool is_call) -{ - xc = _xc; - - bool usermode = (xc->readMiscReg(AlphaISA::IPR_DTB_CM) & 0x18) != 0; - - Addr pc = xc->readNextPC(); - bool kernel = xc->getSystemPtr()->kernelStart <= pc && - pc <= xc->getSystemPtr()->kernelEnd; - - if (usermode) { - stack.push_back(user); - return; - } - - if (!kernel) { - stack.push_back(console); - return; - } - - SymbolTable *symtab = xc->getSystemPtr()->kernelSymtab; - Addr ksp = xc->readIntReg(TheISA::StackPointerReg); - Addr bottom = ksp & ~0x3fff; - Addr addr; - - if (is_call) { - if (!symtab->findNearestAddr(pc, addr)) - panic("could not find address %#x", pc); - - stack.push_back(addr); - pc = xc->readPC(); - } - - Addr ra; - int size; - - while (ksp > bottom) { - if (!symtab->findNearestAddr(pc, addr)) - panic("could not find symbol for pc=%#x", pc); - assert(pc >= addr && "symbol botch: callpc < func"); - - stack.push_back(addr); - - if (isEntry(addr)) - return; - - if (decodePrologue(ksp, pc, addr, size, ra)) { - if (!ra) - return; - - if (size <= 0) { - stack.push_back(unknown); - return; - } - - pc = ra; - ksp += size; - } else { - stack.push_back(unknown); - return; - } - - bool kernel = xc->getSystemPtr()->kernelStart <= pc && - pc <= xc->getSystemPtr()->kernelEnd; - if (!kernel) - return; - - if (stack.size() >= 1000) - panic("unwinding too far"); - } - - panic("unwinding too far"); -} - -bool -StackTrace::isEntry(Addr addr) -{ - if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp12)) - return true; - - if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp7)) - return true; - - if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp11)) - return true; - - if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp21)) - return true; - - if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp9)) - return true; - - if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp2)) - return true; - - return false; -} - -bool -StackTrace::decodeStack(MachInst inst, int &disp) -{ - // lda $sp, -disp($sp) - // - // Opcode<31:26> == 0x08 - // RA<25:21> == 30 - // RB<20:16> == 30 - // Disp<15:0> - const MachInst mem_mask = 0xffff0000; - const MachInst lda_pattern = 0x23de0000; - const MachInst lda_disp_mask = 0x0000ffff; - - // subq $sp, disp, $sp - // addq $sp, disp, $sp - // - // Opcode<31:26> == 0x10 - // RA<25:21> == 30 - // Lit<20:13> - // One<12> = 1 - // Func<11:5> == 0x20 (addq) - // Func<11:5> == 0x29 (subq) - // RC<4:0> == 30 - const MachInst intop_mask = 0xffe01fff; - const MachInst addq_pattern = 0x43c0141e; - const MachInst subq_pattern = 0x43c0153e; - const MachInst intop_disp_mask = 0x001fe000; - const int intop_disp_shift = 13; - - if ((inst & mem_mask) == lda_pattern) - disp = -sext<16>(inst & lda_disp_mask); - else if ((inst & intop_mask) == addq_pattern) - disp = -int((inst & intop_disp_mask) >> intop_disp_shift); - else if ((inst & intop_mask) == subq_pattern) - disp = int((inst & intop_disp_mask) >> intop_disp_shift); - else - return false; - - return true; -} - -bool -StackTrace::decodeSave(MachInst inst, int ®, int &disp) -{ - // lda $stq, disp($sp) - // - // Opcode<31:26> == 0x08 - // RA<25:21> == ? - // RB<20:16> == 30 - // Disp<15:0> - const MachInst stq_mask = 0xfc1f0000; - const MachInst stq_pattern = 0xb41e0000; - const MachInst stq_disp_mask = 0x0000ffff; - const MachInst reg_mask = 0x03e00000; - const int reg_shift = 21; - - if ((inst & stq_mask) == stq_pattern) { - reg = (inst & reg_mask) >> reg_shift; - disp = sext<16>(inst & stq_disp_mask); - } else { - return false; - } - - return true; -} - -/* - * Decode the function prologue for the function we're in, and note - * which registers are stored where, and how large the stack frame is. - */ -bool -StackTrace::decodePrologue(Addr sp, Addr callpc, Addr func, - int &size, Addr &ra) -{ - size = 0; - ra = 0; - - for (Addr pc = func; pc < callpc; pc += sizeof(MachInst)) { - MachInst inst; - CopyOut(xc, (uint8_t *)&inst, pc, sizeof(MachInst)); - - int reg, disp; - if (decodeStack(inst, disp)) { - if (size) { - // panic("decoding frame size again"); - return true; - } - size += disp; - } else if (decodeSave(inst, reg, disp)) { - if (!ra && reg == ReturnAddressReg) { - CopyOut(xc, (uint8_t *)&ra, sp + disp, sizeof(Addr)); - if (!ra) { - // panic("no return address value pc=%#x\n", pc); - return false; - } - } - } - } - - return true; -} - -#if TRACING_ON -void -StackTrace::dump() -{ - StringWrap name(xc->getCpuPtr()->name()); - SymbolTable *symtab = xc->getSystemPtr()->kernelSymtab; - - DPRINTFN("------ Stack ------\n"); - - string symbol; - for (int i = 0, size = stack.size(); i < size; ++i) { - Addr addr = stack[size - i - 1]; - if (addr == user) - symbol = "user"; - else if (addr == console) - symbol = "console"; - else if (addr == unknown) - symbol = "unknown"; - else - symtab->findSymbol(addr, symbol); - - DPRINTFN("%#x: %s\n", addr, symbol); - } -} -#endif diff --git a/arch/alpha/stacktrace.hh b/arch/alpha/stacktrace.hh deleted file mode 100644 index 1d8d97a79..000000000 --- a/arch/alpha/stacktrace.hh +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __ARCH_ALPHA_STACKTRACE_HH__ -#define __ARCH_ALPHA_STACKTRACE_HH__ - -#include "base/trace.hh" -#include "cpu/static_inst.hh" - -class ExecContext; -class StackTrace; - -class ProcessInfo -{ - private: - ExecContext *xc; - - int thread_info_size; - int task_struct_size; - int task_off; - int pid_off; - int name_off; - - public: - ProcessInfo(ExecContext *_xc); - - Addr task(Addr ksp) const; - int pid(Addr ksp) const; - std::string name(Addr ksp) const; -}; - -class StackTrace -{ - protected: - typedef TheISA::MachInst MachInst; - private: - ExecContext *xc; - std::vector<Addr> stack; - - private: - bool isEntry(Addr addr); - bool decodePrologue(Addr sp, Addr callpc, Addr func, int &size, Addr &ra); - bool decodeSave(MachInst inst, int ®, int &disp); - bool decodeStack(MachInst inst, int &disp); - - void trace(ExecContext *xc, bool is_call); - - public: - StackTrace(); - StackTrace(ExecContext *xc, StaticInstPtr inst); - ~StackTrace(); - - void clear() - { - xc = 0; - stack.clear(); - } - - bool valid() const { return xc != NULL; } - bool trace(ExecContext *xc, StaticInstPtr inst); - - public: - const std::vector<Addr> &getstack() const { return stack; } - - static const int user = 1; - static const int console = 2; - static const int unknown = 3; - -#if TRACING_ON - private: - void dump(); - - public: - void dprintf() { if (DTRACE(Stack)) dump(); } -#else - public: - void dprintf() {} -#endif -}; - -inline bool -StackTrace::trace(ExecContext *xc, StaticInstPtr inst) -{ - if (!inst->isCall() && !inst->isReturn()) - return false; - - if (valid()) - clear(); - - trace(xc, !inst->isReturn()); - return true; -} - -#endif // __ARCH_ALPHA_STACKTRACE_HH__ diff --git a/arch/alpha/system.cc b/arch/alpha/system.cc deleted file mode 100644 index 83c4bfe78..000000000 --- a/arch/alpha/system.cc +++ /dev/null @@ -1,289 +0,0 @@ -/* - * 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. - */ - -#include "arch/alpha/system.hh" -#include "arch/vtophys.hh" -#include "base/remote_gdb.hh" -#include "base/loader/object_file.hh" -#include "base/loader/symtab.hh" -#include "base/trace.hh" -#include "mem/functional/memory_control.hh" -#include "mem/functional/physical.hh" -#include "sim/byteswap.hh" -#include "sim/builder.hh" - - -using namespace LittleEndianGuest; - -AlphaSystem::AlphaSystem(Params *p) - : System(p) -{ - consoleSymtab = new SymbolTable; - palSymtab = new SymbolTable; - - - /** - * Load the pal, and console code into memory - */ - // Load Console Code - console = createObjectFile(params()->console_path); - if (console == NULL) - fatal("Could not load console file %s", params()->console_path); - - // Load pal file - pal = createObjectFile(params()->palcode); - if (pal == NULL) - fatal("Could not load PALcode file %s", params()->palcode); - - - // Load program sections into memory - pal->loadSections(physmem, true); - console->loadSections(physmem, true); - - // load symbols - if (!console->loadGlobalSymbols(consoleSymtab)) - panic("could not load console symbols\n"); - - if (!pal->loadGlobalSymbols(palSymtab)) - panic("could not load pal symbols\n"); - - if (!pal->loadLocalSymbols(palSymtab)) - panic("could not load pal symbols\n"); - - if (!console->loadGlobalSymbols(debugSymbolTable)) - panic("could not load console symbols\n"); - - if (!pal->loadGlobalSymbols(debugSymbolTable)) - panic("could not load pal symbols\n"); - - if (!pal->loadLocalSymbols(debugSymbolTable)) - panic("could not load pal symbols\n"); - - Addr addr = 0; -#ifndef NDEBUG - consolePanicEvent = addConsoleFuncEvent<BreakPCEvent>("panic"); -#endif - - /** - * Copy the osflags (kernel arguments) into the consoles - * memory. (Presently Linux does not use the console service - * routine to get these command line arguments, but Tru64 and - * others do.) - */ - if (consoleSymtab->findAddress("env_booted_osflags", addr)) { - Addr paddr = vtophys(physmem, addr); - char *osflags = (char *)physmem->dma_addr(paddr, sizeof(uint32_t)); - - if (osflags) - strcpy(osflags, params()->boot_osflags.c_str()); - } - - /** - * Set the hardware reset parameter block system type and revision - * information to Tsunami. - */ - if (consoleSymtab->findAddress("m5_rpb", addr)) { - Addr paddr = vtophys(physmem, addr); - char *hwrpb = (char *)physmem->dma_addr(paddr, sizeof(uint64_t)); - - if (!hwrpb) - panic("could not translate hwrpb addr\n"); - - *(uint64_t*)(hwrpb+0x50) = htog(params()->system_type); - *(uint64_t*)(hwrpb+0x58) = htog(params()->system_rev); - } else - panic("could not find hwrpb\n"); - -} - -AlphaSystem::~AlphaSystem() -{ - delete consoleSymtab; - delete console; - delete pal; -#ifdef DEBUG - delete consolePanicEvent; -#endif -} - -/** - * This function fixes up addresses that are used to match PCs for - * hooking simulator events on to target function executions. - * - * Alpha binaries may have multiple global offset table (GOT) - * sections. A function that uses the GOT starts with a - * two-instruction prolog which sets the global pointer (gp == r29) to - * the appropriate GOT section. The proper gp value is calculated - * based on the function address, which must be passed by the caller - * in the procedure value register (pv aka t12 == r27). This sequence - * looks like the following: - * - * opcode Ra Rb offset - * ldah gp,X(pv) 09 29 27 X - * lda gp,Y(gp) 08 29 29 Y - * - * for some constant offsets X and Y. The catch is that the linker - * (or maybe even the compiler, I'm not sure) may recognize that the - * caller and callee are using the same GOT section, making this - * prolog redundant, and modify the call target to skip these - * instructions. If we check for execution of the first instruction - * of a function (the one the symbol points to) to detect when to skip - * it, we'll miss all these modified calls. It might work to - * unconditionally check for the third instruction, but not all - * functions have this prolog, and there's some chance that those - * first two instructions could have undesired consequences. So we do - * the Right Thing and pattern-match the first two instructions of the - * function to decide where to patch. - * - * Eventually this code should be moved into an ISA-specific file. - */ -Addr -AlphaSystem::fixFuncEventAddr(Addr addr) -{ - // mask for just the opcode, Ra, and Rb fields (not the offset) - const uint32_t inst_mask = 0xffff0000; - // ldah gp,X(pv): opcode 9, Ra = 29, Rb = 27 - const uint32_t gp_ldah_pattern = (9 << 26) | (29 << 21) | (27 << 16); - // lda gp,Y(gp): opcode 8, Ra = 29, rb = 29 - const uint32_t gp_lda_pattern = (8 << 26) | (29 << 21) | (29 << 16); - // instruction size - const int sz = sizeof(uint32_t); - - Addr paddr = vtophys(physmem, addr); - uint32_t i1 = *(uint32_t *)physmem->dma_addr(paddr, sz); - uint32_t i2 = *(uint32_t *)physmem->dma_addr(paddr+sz, sz); - - if ((i1 & inst_mask) == gp_ldah_pattern && - (i2 & inst_mask) == gp_lda_pattern) { - Addr new_addr = addr + 2*sz; - DPRINTF(Loader, "fixFuncEventAddr: %p -> %p", addr, new_addr); - return new_addr; - } else { - return addr; - } -} - - -void -AlphaSystem::setAlphaAccess(Addr access) -{ - Addr addr = 0; - if (consoleSymtab->findAddress("m5AlphaAccess", addr)) { - Addr paddr = vtophys(physmem, addr); - uint64_t *m5AlphaAccess = - (uint64_t *)physmem->dma_addr(paddr, sizeof(uint64_t)); - - if (!m5AlphaAccess) - panic("could not translate m5AlphaAccess addr\n"); - - *m5AlphaAccess = htog(EV5::Phys2K0Seg(access)); - } else - panic("could not find m5AlphaAccess\n"); -} - -bool -AlphaSystem::breakpoint() -{ - return remoteGDB[0]->trap(ALPHA_KENTRY_INT); -} - -void -AlphaSystem::serialize(std::ostream &os) -{ - System::serialize(os); - consoleSymtab->serialize("console_symtab", os); - palSymtab->serialize("pal_symtab", os); -} - - -void -AlphaSystem::unserialize(Checkpoint *cp, const std::string §ion) -{ - System::unserialize(cp,section); - consoleSymtab->unserialize("console_symtab", cp, section); - palSymtab->unserialize("pal_symtab", cp, section); -} - - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaSystem) - - Param<Tick> boot_cpu_frequency; - SimObjectParam<MemoryController *> memctrl; - SimObjectParam<PhysicalMemory *> physmem; - - Param<std::string> kernel; - Param<std::string> console; - Param<std::string> pal; - - Param<std::string> boot_osflags; - Param<std::string> readfile; - Param<unsigned int> init_param; - - Param<uint64_t> system_type; - Param<uint64_t> system_rev; - -END_DECLARE_SIM_OBJECT_PARAMS(AlphaSystem) - -BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaSystem) - - INIT_PARAM(boot_cpu_frequency, "Frequency of the boot CPU"), - INIT_PARAM(memctrl, "memory controller"), - INIT_PARAM(physmem, "phsyical memory"), - INIT_PARAM(kernel, "file that contains the kernel code"), - INIT_PARAM(console, "file that contains the console code"), - INIT_PARAM(pal, "file that contains palcode"), - INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot", - "a"), - INIT_PARAM_DFLT(readfile, "file to read startup script from", ""), - INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0), - INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 34), - INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10) - -END_INIT_SIM_OBJECT_PARAMS(AlphaSystem) - -CREATE_SIM_OBJECT(AlphaSystem) -{ - AlphaSystem::Params *p = new AlphaSystem::Params; - p->name = getInstanceName(); - p->boot_cpu_frequency = boot_cpu_frequency; - p->memctrl = memctrl; - p->physmem = physmem; - p->kernel_path = kernel; - p->console_path = console; - p->palcode = pal; - p->boot_osflags = boot_osflags; - p->init_param = init_param; - p->readfile = readfile; - p->system_type = system_type; - p->system_rev = system_rev; - return new AlphaSystem(p); -} - -REGISTER_SIM_OBJECT("AlphaSystem", AlphaSystem) - - diff --git a/arch/alpha/system.hh b/arch/alpha/system.hh deleted file mode 100644 index fe1307ac3..000000000 --- a/arch/alpha/system.hh +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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. - */ - -#ifndef __ARCH_ALPHA_SYSTEM_HH__ -#define __ARCH_ALPHA_SYSTEM_HH__ - -#include <string> -#include <vector> - -#include "sim/system.hh" -#include "base/loader/symtab.hh" -#include "cpu/pc_event.hh" -#include "kern/system_events.hh" -#include "sim/sim_object.hh" - -class AlphaSystem : public System -{ - public: - struct Params : public System::Params - { - std::string console_path; - std::string palcode; - std::string boot_osflags; - uint64_t system_type; - uint64_t system_rev; - }; - - AlphaSystem(Params *p); - - ~AlphaSystem(); - - virtual bool breakpoint(); - -/** - * Serialization stuff - */ - public: - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); - - /** - * Set the m5AlphaAccess pointer in the console - */ - void setAlphaAccess(Addr access); - - /** console symbol table */ - SymbolTable *consoleSymtab; - - /** pal symbol table */ - SymbolTable *palSymtab; - - /** Object pointer for the console code */ - ObjectFile *console; - - /** Object pointer for the PAL code */ - ObjectFile *pal; - -#ifndef NDEBUG - /** Event to halt the simulator if the console calls panic() */ - BreakPCEvent *consolePanicEvent; -#endif - protected: - const Params *params() const { return (const Params *)_params; } - - /** Add a function-based event to PALcode. */ - template <class T> - T *AlphaSystem::addPalFuncEvent(const char *lbl) - { - return addFuncEvent<T>(palSymtab, lbl); - } - - /** Add a function-based event to the console code. */ - template <class T> - T *AlphaSystem::addConsoleFuncEvent(const char *lbl) - { - return addFuncEvent<T>(consoleSymtab, lbl); - } - - virtual Addr fixFuncEventAddr(Addr addr); - -}; - -#endif - diff --git a/arch/alpha/tlb.cc b/arch/alpha/tlb.cc deleted file mode 100644 index 562235ef8..000000000 --- a/arch/alpha/tlb.cc +++ /dev/null @@ -1,643 +0,0 @@ -/* - * 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. - */ - -#include <sstream> -#include <string> -#include <vector> - -#include "arch/alpha/tlb.hh" -#include "base/inifile.hh" -#include "base/str.hh" -#include "base/trace.hh" -#include "config/alpha_tlaser.hh" -#include "cpu/exec_context.hh" -#include "sim/builder.hh" - -using namespace std; -using namespace EV5; - -/////////////////////////////////////////////////////////////////////// -// -// Alpha TLB -// -#ifdef DEBUG -bool uncacheBit39 = false; -bool uncacheBit40 = false; -#endif - -#define MODE2MASK(X) (1 << (X)) - -AlphaTLB::AlphaTLB(const string &name, int s) - : SimObject(name), size(s), nlu(0) -{ - table = new AlphaISA::PTE[size]; - memset(table, 0, sizeof(AlphaISA::PTE[size])); -} - -AlphaTLB::~AlphaTLB() -{ - if (table) - delete [] table; -} - -// look up an entry in the TLB -AlphaISA::PTE * -AlphaTLB::lookup(Addr vpn, uint8_t asn) const -{ - // assume not found... - AlphaISA::PTE *retval = NULL; - - PageTable::const_iterator i = lookupTable.find(vpn); - if (i != lookupTable.end()) { - while (i->first == vpn) { - int index = i->second; - AlphaISA::PTE *pte = &table[index]; - assert(pte->valid); - if (vpn == pte->tag && (pte->asma || pte->asn == asn)) { - retval = pte; - break; - } - - ++i; - } - } - - DPRINTF(TLB, "lookup %#x, asn %#x -> %s ppn %#x\n", vpn, (int)asn, - retval ? "hit" : "miss", retval ? retval->ppn : 0); - return retval; -} - - -void -AlphaTLB::checkCacheability(MemReqPtr &req) -{ - // in Alpha, cacheability is controlled by upper-level bits of the - // physical address - - /* - * We support having the uncacheable bit in either bit 39 or bit 40. - * The Turbolaser platform (and EV5) support having the bit in 39, but - * Tsunami (which Linux assumes uses an EV6) generates accesses with - * the bit in 40. So we must check for both, but we have debug flags - * to catch a weird case where both are used, which shouldn't happen. - */ - - -#if ALPHA_TLASER - if (req->paddr & PAddrUncachedBit39) { -#else - if (req->paddr & PAddrUncachedBit43) { -#endif - // IPR memory space not implemented - if (PAddrIprSpace(req->paddr)) { - if (!req->xc->misspeculating()) { - switch (req->paddr) { - case ULL(0xFFFFF00188): - req->data = 0; - break; - - default: - panic("IPR memory space not implemented! PA=%x\n", - req->paddr); - } - } - } else { - // mark request as uncacheable - req->flags |= UNCACHEABLE; - -#if !ALPHA_TLASER - // Clear bits 42:35 of the physical address (10-2 in Tsunami manual) - req->paddr &= PAddrUncachedMask; -#endif - } - } -} - - -// insert a new TLB entry -void -AlphaTLB::insert(Addr addr, AlphaISA::PTE &pte) -{ - AlphaISA::VAddr vaddr = addr; - if (table[nlu].valid) { - Addr oldvpn = table[nlu].tag; - PageTable::iterator i = lookupTable.find(oldvpn); - - if (i == lookupTable.end()) - panic("TLB entry not found in lookupTable"); - - int index; - while ((index = i->second) != nlu) { - if (table[index].tag != oldvpn) - panic("TLB entry not found in lookupTable"); - - ++i; - } - - DPRINTF(TLB, "remove @%d: %#x -> %#x\n", nlu, oldvpn, table[nlu].ppn); - - lookupTable.erase(i); - } - - DPRINTF(TLB, "insert @%d: %#x -> %#x\n", nlu, vaddr.vpn(), pte.ppn); - - table[nlu] = pte; - table[nlu].tag = vaddr.vpn(); - table[nlu].valid = true; - - lookupTable.insert(make_pair(vaddr.vpn(), nlu)); - nextnlu(); -} - -void -AlphaTLB::flushAll() -{ - DPRINTF(TLB, "flushAll\n"); - memset(table, 0, sizeof(AlphaISA::PTE[size])); - lookupTable.clear(); - nlu = 0; -} - -void -AlphaTLB::flushProcesses() -{ - PageTable::iterator i = lookupTable.begin(); - PageTable::iterator end = lookupTable.end(); - while (i != end) { - int index = i->second; - AlphaISA::PTE *pte = &table[index]; - assert(pte->valid); - - // we can't increment i after we erase it, so save a copy and - // increment it to get the next entry now - PageTable::iterator cur = i; - ++i; - - if (!pte->asma) { - DPRINTF(TLB, "flush @%d: %#x -> %#x\n", index, pte->tag, pte->ppn); - pte->valid = false; - lookupTable.erase(cur); - } - } -} - -void -AlphaTLB::flushAddr(Addr addr, uint8_t asn) -{ - AlphaISA::VAddr vaddr = addr; - - PageTable::iterator i = lookupTable.find(vaddr.vpn()); - if (i == lookupTable.end()) - return; - - while (i->first == vaddr.vpn()) { - int index = i->second; - AlphaISA::PTE *pte = &table[index]; - assert(pte->valid); - - if (vaddr.vpn() == pte->tag && (pte->asma || pte->asn == asn)) { - DPRINTF(TLB, "flushaddr @%d: %#x -> %#x\n", index, vaddr.vpn(), - pte->ppn); - - // invalidate this entry - pte->valid = false; - - lookupTable.erase(i); - } - - ++i; - } -} - - -void -AlphaTLB::serialize(ostream &os) -{ - SERIALIZE_SCALAR(size); - SERIALIZE_SCALAR(nlu); - - for (int i = 0; i < size; i++) { - nameOut(os, csprintf("%s.PTE%d", name(), i)); - table[i].serialize(os); - } -} - -void -AlphaTLB::unserialize(Checkpoint *cp, const string §ion) -{ - UNSERIALIZE_SCALAR(size); - UNSERIALIZE_SCALAR(nlu); - - for (int i = 0; i < size; i++) { - table[i].unserialize(cp, csprintf("%s.PTE%d", section, i)); - if (table[i].valid) { - lookupTable.insert(make_pair(table[i].tag, i)); - } - } -} - - -/////////////////////////////////////////////////////////////////////// -// -// Alpha ITB -// -AlphaITB::AlphaITB(const std::string &name, int size) - : AlphaTLB(name, size) -{} - - -void -AlphaITB::regStats() -{ - hits - .name(name() + ".hits") - .desc("ITB hits"); - misses - .name(name() + ".misses") - .desc("ITB misses"); - acv - .name(name() + ".acv") - .desc("ITB acv"); - accesses - .name(name() + ".accesses") - .desc("ITB accesses"); - - accesses = hits + misses; -} - - -Fault -AlphaITB::translate(MemReqPtr &req) const -{ - ExecContext *xc = req->xc; - - if (AlphaISA::PcPAL(req->vaddr)) { - // strip off PAL PC marker (lsb is 1) - req->paddr = (req->vaddr & ~3) & PAddrImplMask; - hits++; - return NoFault; - } - - if (req->flags & PHYSICAL) { - req->paddr = req->vaddr; - } else { - // verify that this is a good virtual address - if (!validVirtualAddress(req->vaddr)) { - acv++; - return new ItbAcvFault(req->vaddr); - } - - - // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13> for EV5 - // VA<47:41> == 0x7e, VA<40:13> maps directly to PA<40:13> for EV6 -#if ALPHA_TLASER - if ((MCSR_SP(xc->readMiscReg(AlphaISA::IPR_MCSR)) & 2) && - VAddrSpaceEV5(req->vaddr) == 2) { -#else - if (VAddrSpaceEV6(req->vaddr) == 0x7e) { -#endif - // only valid in kernel mode - if (ICM_CM(xc->readMiscReg(AlphaISA::IPR_ICM)) != - AlphaISA::mode_kernel) { - acv++; - return new ItbAcvFault(req->vaddr); - } - - req->paddr = req->vaddr & PAddrImplMask; - -#if !ALPHA_TLASER - // sign extend the physical address properly - if (req->paddr & PAddrUncachedBit40) - req->paddr |= ULL(0xf0000000000); - else - req->paddr &= ULL(0xffffffffff); -#endif - - } else { - // not a physical address: need to look up pte - int asn = DTB_ASN_ASN(xc->readMiscReg(AlphaISA::IPR_DTB_ASN)); - AlphaISA::PTE *pte = lookup(AlphaISA::VAddr(req->vaddr).vpn(), - asn); - - if (!pte) { - misses++; - return new ItbPageFault(req->vaddr); - } - - req->paddr = (pte->ppn << AlphaISA::PageShift) + - (AlphaISA::VAddr(req->vaddr).offset() & ~3); - - // check permissions for this access - if (!(pte->xre & - (1 << ICM_CM(xc->readMiscReg(AlphaISA::IPR_ICM))))) { - // instruction access fault - acv++; - return new ItbAcvFault(req->vaddr); - } - - hits++; - } - } - - // check that the physical address is ok (catch bad physical addresses) - if (req->paddr & ~PAddrImplMask) - return genMachineCheckFault(); - - checkCacheability(req); - - return NoFault; -} - -/////////////////////////////////////////////////////////////////////// -// -// Alpha DTB -// -AlphaDTB::AlphaDTB(const std::string &name, int size) - : AlphaTLB(name, size) -{} - -void -AlphaDTB::regStats() -{ - read_hits - .name(name() + ".read_hits") - .desc("DTB read hits") - ; - - read_misses - .name(name() + ".read_misses") - .desc("DTB read misses") - ; - - read_acv - .name(name() + ".read_acv") - .desc("DTB read access violations") - ; - - read_accesses - .name(name() + ".read_accesses") - .desc("DTB read accesses") - ; - - write_hits - .name(name() + ".write_hits") - .desc("DTB write hits") - ; - - write_misses - .name(name() + ".write_misses") - .desc("DTB write misses") - ; - - write_acv - .name(name() + ".write_acv") - .desc("DTB write access violations") - ; - - write_accesses - .name(name() + ".write_accesses") - .desc("DTB write accesses") - ; - - hits - .name(name() + ".hits") - .desc("DTB hits") - ; - - misses - .name(name() + ".misses") - .desc("DTB misses") - ; - - acv - .name(name() + ".acv") - .desc("DTB access violations") - ; - - accesses - .name(name() + ".accesses") - .desc("DTB accesses") - ; - - hits = read_hits + write_hits; - misses = read_misses + write_misses; - acv = read_acv + write_acv; - accesses = read_accesses + write_accesses; -} - -Fault -AlphaDTB::translate(MemReqPtr &req, bool write) const -{ - ExecContext *xc = req->xc; - Addr pc = xc->readPC(); - - AlphaISA::mode_type mode = - (AlphaISA::mode_type)DTB_CM_CM(xc->readMiscReg(AlphaISA::IPR_DTB_CM)); - - - /** - * Check for alignment faults - */ - if (req->vaddr & (req->size - 1)) { - DPRINTF(TLB, "Alignment Fault on %#x, size = %d", req->vaddr, - req->size); - uint64_t flags = write ? MM_STAT_WR_MASK : 0; - return new DtbAlignmentFault(req->vaddr, req->flags, flags); - } - - if (pc & 0x1) { - mode = (req->flags & ALTMODE) ? - (AlphaISA::mode_type)ALT_MODE_AM( - xc->readMiscReg(AlphaISA::IPR_ALT_MODE)) - : AlphaISA::mode_kernel; - } - - if (req->flags & PHYSICAL) { - req->paddr = req->vaddr; - } else { - // verify that this is a good virtual address - if (!validVirtualAddress(req->vaddr)) { - if (write) { write_acv++; } else { read_acv++; } - uint64_t flags = (write ? MM_STAT_WR_MASK : 0) | - MM_STAT_BAD_VA_MASK | - MM_STAT_ACV_MASK; - return new DtbPageFault(req->vaddr, req->flags, flags); - } - - // Check for "superpage" mapping -#if ALPHA_TLASER - if ((MCSR_SP(xc->readMiscReg(AlphaISA::IPR_MCSR)) & 2) && - VAddrSpaceEV5(req->vaddr) == 2) { -#else - if (VAddrSpaceEV6(req->vaddr) == 0x7e) { -#endif - - // only valid in kernel mode - if (DTB_CM_CM(xc->readMiscReg(AlphaISA::IPR_DTB_CM)) != - AlphaISA::mode_kernel) { - if (write) { write_acv++; } else { read_acv++; } - uint64_t flags = ((write ? MM_STAT_WR_MASK : 0) | - MM_STAT_ACV_MASK); - return new DtbAcvFault(req->vaddr, req->flags, flags); - } - - req->paddr = req->vaddr & PAddrImplMask; - -#if !ALPHA_TLASER - // sign extend the physical address properly - if (req->paddr & PAddrUncachedBit40) - req->paddr |= ULL(0xf0000000000); - else - req->paddr &= ULL(0xffffffffff); -#endif - - } else { - if (write) - write_accesses++; - else - read_accesses++; - - int asn = DTB_ASN_ASN(xc->readMiscReg(AlphaISA::IPR_DTB_ASN)); - - // not a physical address: need to look up pte - AlphaISA::PTE *pte = lookup(AlphaISA::VAddr(req->vaddr).vpn(), - asn); - - if (!pte) { - // page fault - if (write) { write_misses++; } else { read_misses++; } - uint64_t flags = (write ? MM_STAT_WR_MASK : 0) | - MM_STAT_DTB_MISS_MASK; - return (req->flags & VPTE) ? - (Fault)(new PDtbMissFault(req->vaddr, req->flags, - flags)) : - (Fault)(new NDtbMissFault(req->vaddr, req->flags, - flags)); - } - - req->paddr = (pte->ppn << AlphaISA::PageShift) + - AlphaISA::VAddr(req->vaddr).offset(); - - if (write) { - if (!(pte->xwe & MODE2MASK(mode))) { - // declare the instruction access fault - write_acv++; - uint64_t flags = MM_STAT_WR_MASK | - MM_STAT_ACV_MASK | - (pte->fonw ? MM_STAT_FONW_MASK : 0); - return new DtbPageFault(req->vaddr, req->flags, flags); - } - if (pte->fonw) { - write_acv++; - uint64_t flags = MM_STAT_WR_MASK | - MM_STAT_FONW_MASK; - return new DtbPageFault(req->vaddr, req->flags, flags); - } - } else { - if (!(pte->xre & MODE2MASK(mode))) { - read_acv++; - uint64_t flags = MM_STAT_ACV_MASK | - (pte->fonr ? MM_STAT_FONR_MASK : 0); - return new DtbAcvFault(req->vaddr, req->flags, flags); - } - if (pte->fonr) { - read_acv++; - uint64_t flags = MM_STAT_FONR_MASK; - return new DtbPageFault(req->vaddr, req->flags, flags); - } - } - } - - if (write) - write_hits++; - else - read_hits++; - } - - // check that the physical address is ok (catch bad physical addresses) - if (req->paddr & ~PAddrImplMask) - return genMachineCheckFault(); - - checkCacheability(req); - - return NoFault; -} - -AlphaISA::PTE & -AlphaTLB::index(bool advance) -{ - AlphaISA::PTE *pte = &table[nlu]; - - if (advance) - nextnlu(); - - return *pte; -} - -DEFINE_SIM_OBJECT_CLASS_NAME("AlphaTLB", AlphaTLB) - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaITB) - - Param<int> size; - -END_DECLARE_SIM_OBJECT_PARAMS(AlphaITB) - -BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaITB) - - INIT_PARAM_DFLT(size, "TLB size", 48) - -END_INIT_SIM_OBJECT_PARAMS(AlphaITB) - - -CREATE_SIM_OBJECT(AlphaITB) -{ - return new AlphaITB(getInstanceName(), size); -} - -REGISTER_SIM_OBJECT("AlphaITB", AlphaITB) - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaDTB) - - Param<int> size; - -END_DECLARE_SIM_OBJECT_PARAMS(AlphaDTB) - -BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaDTB) - - INIT_PARAM_DFLT(size, "TLB size", 64) - -END_INIT_SIM_OBJECT_PARAMS(AlphaDTB) - - -CREATE_SIM_OBJECT(AlphaDTB) -{ - return new AlphaDTB(getInstanceName(), size); -} - -REGISTER_SIM_OBJECT("AlphaDTB", AlphaDTB) - diff --git a/arch/alpha/tlb.hh b/arch/alpha/tlb.hh deleted file mode 100644 index 676345f01..000000000 --- a/arch/alpha/tlb.hh +++ /dev/null @@ -1,121 +0,0 @@ -/* - * 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. - */ - -#ifndef __ALPHA_MEMORY_HH__ -#define __ALPHA_MEMORY_HH__ - -#include <map> - -#include "arch/alpha/ev5.hh" -#include "arch/alpha/isa_traits.hh" -#include "arch/alpha/faults.hh" -#include "base/statistics.hh" -#include "mem/mem_req.hh" -#include "sim/sim_object.hh" - -class ExecContext; - -class AlphaTLB : public SimObject -{ - protected: - typedef std::multimap<Addr, int> PageTable; - PageTable lookupTable; // Quick lookup into page table - - AlphaISA::PTE *table; // the Page Table - int size; // TLB Size - int nlu; // not last used entry (for replacement) - - void nextnlu() { if (++nlu >= size) nlu = 0; } - AlphaISA::PTE *lookup(Addr vpn, uint8_t asn) const; - - public: - AlphaTLB(const std::string &name, int size); - virtual ~AlphaTLB(); - - int getsize() const { return size; } - - AlphaISA::PTE &index(bool advance = true); - void insert(Addr vaddr, AlphaISA::PTE &pte); - - void flushAll(); - void flushProcesses(); - void flushAddr(Addr addr, uint8_t asn); - - // static helper functions... really EV5 VM traits - static bool validVirtualAddress(Addr vaddr) { - // unimplemented bits must be all 0 or all 1 - Addr unimplBits = vaddr & EV5::VAddrUnImplMask; - return (unimplBits == 0) || (unimplBits == EV5::VAddrUnImplMask); - } - - static void checkCacheability(MemReqPtr &req); - - // Checkpointing - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); -}; - -class AlphaITB : public AlphaTLB -{ - protected: - mutable Stats::Scalar<> hits; - mutable Stats::Scalar<> misses; - mutable Stats::Scalar<> acv; - mutable Stats::Formula accesses; - - public: - AlphaITB(const std::string &name, int size); - virtual void regStats(); - - Fault translate(MemReqPtr &req) const; -}; - -class AlphaDTB : public AlphaTLB -{ - protected: - mutable Stats::Scalar<> read_hits; - mutable Stats::Scalar<> read_misses; - mutable Stats::Scalar<> read_acv; - mutable Stats::Scalar<> read_accesses; - mutable Stats::Scalar<> write_hits; - mutable Stats::Scalar<> write_misses; - mutable Stats::Scalar<> write_acv; - mutable Stats::Scalar<> write_accesses; - Stats::Formula hits; - Stats::Formula misses; - Stats::Formula acv; - Stats::Formula accesses; - - public: - AlphaDTB(const std::string &name, int size); - virtual void regStats(); - - Fault translate(MemReqPtr &req, bool write) const; -}; - -#endif // __ALPHA_MEMORY_HH__ diff --git a/arch/alpha/tru64/process.cc b/arch/alpha/tru64/process.cc deleted file mode 100644 index ae83bb649..000000000 --- a/arch/alpha/tru64/process.cc +++ /dev/null @@ -1,542 +0,0 @@ -/* - * 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. - */ - -#include "arch/alpha/isa_traits.hh" -#include "arch/alpha/tru64/process.hh" -#include "cpu/exec_context.hh" -#include "kern/tru64/tru64.hh" -#include "mem/functional/functional.hh" -#include "sim/process.hh" -#include "sim/syscall_emul.hh" - -using namespace std; -using namespace AlphaISA; - -/// Target uname() handler. -static SyscallReturn -unameFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - TypedBufferArg<Tru64::utsname> name(xc->getSyscallArg(0)); - - strcpy(name->sysname, "OSF1"); - strcpy(name->nodename, "m5.eecs.umich.edu"); - strcpy(name->release, "V5.1"); - strcpy(name->version, "732"); - strcpy(name->machine, "alpha"); - - name.copyOut(xc->getMemPtr()); - return 0; -} - -/// Target getsysyinfo() handler. -static SyscallReturn -getsysinfoFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - unsigned op = xc->getSyscallArg(0); - unsigned nbytes = xc->getSyscallArg(2); - - switch (op) { - - case Tru64::GSI_MAX_CPU: { - TypedBufferArg<uint32_t> max_cpu(xc->getSyscallArg(1)); - *max_cpu = htog((uint32_t)process->numCpus()); - max_cpu.copyOut(xc->getMemPtr()); - return 1; - } - - case Tru64::GSI_CPUS_IN_BOX: { - TypedBufferArg<uint32_t> cpus_in_box(xc->getSyscallArg(1)); - *cpus_in_box = htog((uint32_t)process->numCpus()); - cpus_in_box.copyOut(xc->getMemPtr()); - return 1; - } - - case Tru64::GSI_PHYSMEM: { - TypedBufferArg<uint64_t> physmem(xc->getSyscallArg(1)); - *physmem = htog((uint64_t)1024 * 1024); // physical memory in KB - physmem.copyOut(xc->getMemPtr()); - return 1; - } - - case Tru64::GSI_CPU_INFO: { - TypedBufferArg<Tru64::cpu_info> infop(xc->getSyscallArg(1)); - - infop->current_cpu = htog(0); - infop->cpus_in_box = htog(process->numCpus()); - infop->cpu_type = htog(57); - infop->ncpus = htog(process->numCpus()); - uint64_t cpumask = (1 << process->numCpus()) - 1; - infop->cpus_present = infop->cpus_running = htog(cpumask); - infop->cpu_binding = htog(0); - infop->cpu_ex_binding = htog(0); - infop->mhz = htog(667); - - infop.copyOut(xc->getMemPtr()); - return 1; - } - - case Tru64::GSI_PROC_TYPE: { - TypedBufferArg<uint64_t> proc_type(xc->getSyscallArg(1)); - *proc_type = htog((uint64_t)11); - proc_type.copyOut(xc->getMemPtr()); - return 1; - } - - case Tru64::GSI_PLATFORM_NAME: { - BufferArg bufArg(xc->getSyscallArg(1), nbytes); - strncpy((char *)bufArg.bufferPtr(), - "COMPAQ Professional Workstation XP1000", - nbytes); - bufArg.copyOut(xc->getMemPtr()); - return 1; - } - - case Tru64::GSI_CLK_TCK: { - TypedBufferArg<uint64_t> clk_hz(xc->getSyscallArg(1)); - *clk_hz = htog((uint64_t)1024); - clk_hz.copyOut(xc->getMemPtr()); - return 1; - } - - default: - warn("getsysinfo: unknown op %d\n", op); - break; - } - - return 0; -} - -/// Target setsysyinfo() handler. -static SyscallReturn -setsysinfoFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - unsigned op = xc->getSyscallArg(0); - - switch (op) { - case Tru64::SSI_IEEE_FP_CONTROL: - warn("setsysinfo: ignoring ieee_set_fp_control() arg 0x%x\n", - xc->getSyscallArg(1)); - break; - - default: - warn("setsysinfo: unknown op %d\n", op); - break; - } - - return 0; -} - - -SyscallDesc AlphaTru64Process::syscallDescs[] = { - /* 0 */ SyscallDesc("syscall (#0)", Tru64::indirectSyscallFunc, - SyscallDesc::SuppressReturnValue), - /* 1 */ SyscallDesc("exit", exitFunc), - /* 2 */ SyscallDesc("fork", unimplementedFunc), - /* 3 */ SyscallDesc("read", readFunc), - /* 4 */ SyscallDesc("write", writeFunc), - /* 5 */ SyscallDesc("old_open", unimplementedFunc), - /* 6 */ SyscallDesc("close", closeFunc), - /* 7 */ SyscallDesc("wait4", unimplementedFunc), - /* 8 */ SyscallDesc("old_creat", unimplementedFunc), - /* 9 */ SyscallDesc("link", unimplementedFunc), - /* 10 */ SyscallDesc("unlink", unlinkFunc), - /* 11 */ SyscallDesc("execv", unimplementedFunc), - /* 12 */ SyscallDesc("chdir", unimplementedFunc), - /* 13 */ SyscallDesc("fchdir", unimplementedFunc), - /* 14 */ SyscallDesc("mknod", unimplementedFunc), - /* 15 */ SyscallDesc("chmod", unimplementedFunc), - /* 16 */ SyscallDesc("chown", unimplementedFunc), - /* 17 */ SyscallDesc("obreak", obreakFunc), - /* 18 */ SyscallDesc("pre_F64_getfsstat", unimplementedFunc), - /* 19 */ SyscallDesc("lseek", lseekFunc), - /* 20 */ SyscallDesc("getpid", getpidPseudoFunc), - /* 21 */ SyscallDesc("mount", unimplementedFunc), - /* 22 */ SyscallDesc("unmount", unimplementedFunc), - /* 23 */ SyscallDesc("setuid", setuidFunc), - /* 24 */ SyscallDesc("getuid", getuidPseudoFunc), - /* 25 */ SyscallDesc("exec_with_loader", unimplementedFunc), - /* 26 */ SyscallDesc("ptrace", unimplementedFunc), - /* 27 */ SyscallDesc("recvmsg", unimplementedFunc), - /* 28 */ SyscallDesc("sendmsg", unimplementedFunc), - /* 29 */ SyscallDesc("recvfrom", unimplementedFunc), - /* 30 */ SyscallDesc("accept", unimplementedFunc), - /* 31 */ SyscallDesc("getpeername", unimplementedFunc), - /* 32 */ SyscallDesc("getsockname", unimplementedFunc), - /* 33 */ SyscallDesc("access", unimplementedFunc), - /* 34 */ SyscallDesc("chflags", unimplementedFunc), - /* 35 */ SyscallDesc("fchflags", unimplementedFunc), - /* 36 */ SyscallDesc("sync", unimplementedFunc), - /* 37 */ SyscallDesc("kill", unimplementedFunc), - /* 38 */ SyscallDesc("old_stat", unimplementedFunc), - /* 39 */ SyscallDesc("setpgid", unimplementedFunc), - /* 40 */ SyscallDesc("old_lstat", unimplementedFunc), - /* 41 */ SyscallDesc("dup", unimplementedFunc), - /* 42 */ SyscallDesc("pipe", unimplementedFunc), - /* 43 */ SyscallDesc("set_program_attributes", unimplementedFunc), - /* 44 */ SyscallDesc("profil", unimplementedFunc), - /* 45 */ SyscallDesc("open", openFunc<Tru64>), - /* 46 */ SyscallDesc("obsolete osigaction", unimplementedFunc), - /* 47 */ SyscallDesc("getgid", getgidPseudoFunc), - /* 48 */ SyscallDesc("sigprocmask", ignoreFunc), - /* 49 */ SyscallDesc("getlogin", unimplementedFunc), - /* 50 */ SyscallDesc("setlogin", unimplementedFunc), - /* 51 */ SyscallDesc("acct", unimplementedFunc), - /* 52 */ SyscallDesc("sigpending", unimplementedFunc), - /* 53 */ SyscallDesc("classcntl", unimplementedFunc), - /* 54 */ SyscallDesc("ioctl", ioctlFunc<Tru64>), - /* 55 */ SyscallDesc("reboot", unimplementedFunc), - /* 56 */ SyscallDesc("revoke", unimplementedFunc), - /* 57 */ SyscallDesc("symlink", unimplementedFunc), - /* 58 */ SyscallDesc("readlink", unimplementedFunc), - /* 59 */ SyscallDesc("execve", unimplementedFunc), - /* 60 */ SyscallDesc("umask", unimplementedFunc), - /* 61 */ SyscallDesc("chroot", unimplementedFunc), - /* 62 */ SyscallDesc("old_fstat", unimplementedFunc), - /* 63 */ SyscallDesc("getpgrp", unimplementedFunc), - /* 64 */ SyscallDesc("getpagesize", getpagesizeFunc), - /* 65 */ SyscallDesc("mremap", unimplementedFunc), - /* 66 */ SyscallDesc("vfork", unimplementedFunc), - /* 67 */ SyscallDesc("pre_F64_stat", statFunc<Tru64::PreF64>), - /* 68 */ SyscallDesc("pre_F64_lstat", lstatFunc<Tru64::PreF64>), - /* 69 */ SyscallDesc("sbrk", unimplementedFunc), - /* 70 */ SyscallDesc("sstk", unimplementedFunc), - /* 71 */ SyscallDesc("mmap", mmapFunc<Tru64>), - /* 72 */ SyscallDesc("ovadvise", unimplementedFunc), - /* 73 */ SyscallDesc("munmap", munmapFunc), - /* 74 */ SyscallDesc("mprotect", ignoreFunc), - /* 75 */ SyscallDesc("madvise", unimplementedFunc), - /* 76 */ SyscallDesc("old_vhangup", unimplementedFunc), - /* 77 */ SyscallDesc("kmodcall", unimplementedFunc), - /* 78 */ SyscallDesc("mincore", unimplementedFunc), - /* 79 */ SyscallDesc("getgroups", unimplementedFunc), - /* 80 */ SyscallDesc("setgroups", unimplementedFunc), - /* 81 */ SyscallDesc("old_getpgrp", unimplementedFunc), - /* 82 */ SyscallDesc("setpgrp", unimplementedFunc), - /* 83 */ SyscallDesc("setitimer", unimplementedFunc), - /* 84 */ SyscallDesc("old_wait", unimplementedFunc), - /* 85 */ SyscallDesc("table", Tru64::tableFunc), - /* 86 */ SyscallDesc("getitimer", unimplementedFunc), - /* 87 */ SyscallDesc("gethostname", gethostnameFunc), - /* 88 */ SyscallDesc("sethostname", unimplementedFunc), - /* 89 */ SyscallDesc("getdtablesize", unimplementedFunc), - /* 90 */ SyscallDesc("dup2", unimplementedFunc), - /* 91 */ SyscallDesc("pre_F64_fstat", fstatFunc<Tru64::PreF64>), - /* 92 */ SyscallDesc("fcntl", fcntlFunc), - /* 93 */ SyscallDesc("select", unimplementedFunc), - /* 94 */ SyscallDesc("poll", unimplementedFunc), - /* 95 */ SyscallDesc("fsync", unimplementedFunc), - /* 96 */ SyscallDesc("setpriority", unimplementedFunc), - /* 97 */ SyscallDesc("socket", unimplementedFunc), - /* 98 */ SyscallDesc("connect", unimplementedFunc), - /* 99 */ SyscallDesc("old_accept", unimplementedFunc), - /* 100 */ SyscallDesc("getpriority", unimplementedFunc), - /* 101 */ SyscallDesc("old_send", unimplementedFunc), - /* 102 */ SyscallDesc("old_recv", unimplementedFunc), - /* 103 */ SyscallDesc("sigreturn", Tru64::sigreturnFunc, - SyscallDesc::SuppressReturnValue), - /* 104 */ SyscallDesc("bind", unimplementedFunc), - /* 105 */ SyscallDesc("setsockopt", unimplementedFunc), - /* 106 */ SyscallDesc("listen", unimplementedFunc), - /* 107 */ SyscallDesc("plock", unimplementedFunc), - /* 108 */ SyscallDesc("old_sigvec", unimplementedFunc), - /* 109 */ SyscallDesc("old_sigblock", unimplementedFunc), - /* 110 */ SyscallDesc("old_sigsetmask", unimplementedFunc), - /* 111 */ SyscallDesc("sigsuspend", unimplementedFunc), - /* 112 */ SyscallDesc("sigstack", ignoreFunc), - /* 113 */ SyscallDesc("old_recvmsg", unimplementedFunc), - /* 114 */ SyscallDesc("old_sendmsg", unimplementedFunc), - /* 115 */ SyscallDesc("obsolete vtrace", unimplementedFunc), - /* 116 */ SyscallDesc("gettimeofday", gettimeofdayFunc<Tru64>), - /* 117 */ SyscallDesc("getrusage", getrusageFunc<Tru64>), - /* 118 */ SyscallDesc("getsockopt", unimplementedFunc), - /* 119 */ SyscallDesc("numa_syscalls", unimplementedFunc), - /* 120 */ SyscallDesc("readv", unimplementedFunc), - /* 121 */ SyscallDesc("writev", unimplementedFunc), - /* 122 */ SyscallDesc("settimeofday", unimplementedFunc), - /* 123 */ SyscallDesc("fchown", unimplementedFunc), - /* 124 */ SyscallDesc("fchmod", unimplementedFunc), - /* 125 */ SyscallDesc("old_recvfrom", unimplementedFunc), - /* 126 */ SyscallDesc("setreuid", unimplementedFunc), - /* 127 */ SyscallDesc("setregid", unimplementedFunc), - /* 128 */ SyscallDesc("rename", renameFunc), - /* 129 */ SyscallDesc("truncate", truncateFunc), - /* 130 */ SyscallDesc("ftruncate", ftruncateFunc), - /* 131 */ SyscallDesc("flock", unimplementedFunc), - /* 132 */ SyscallDesc("setgid", unimplementedFunc), - /* 133 */ SyscallDesc("sendto", unimplementedFunc), - /* 134 */ SyscallDesc("shutdown", unimplementedFunc), - /* 135 */ SyscallDesc("socketpair", unimplementedFunc), - /* 136 */ SyscallDesc("mkdir", unimplementedFunc), - /* 137 */ SyscallDesc("rmdir", unimplementedFunc), - /* 138 */ SyscallDesc("utimes", unimplementedFunc), - /* 139 */ SyscallDesc("obsolete 4.2 sigreturn", unimplementedFunc), - /* 140 */ SyscallDesc("adjtime", unimplementedFunc), - /* 141 */ SyscallDesc("old_getpeername", unimplementedFunc), - /* 142 */ SyscallDesc("gethostid", unimplementedFunc), - /* 143 */ SyscallDesc("sethostid", unimplementedFunc), - /* 144 */ SyscallDesc("getrlimit", getrlimitFunc<Tru64>), - /* 145 */ SyscallDesc("setrlimit", ignoreFunc), - /* 146 */ SyscallDesc("old_killpg", unimplementedFunc), - /* 147 */ SyscallDesc("setsid", unimplementedFunc), - /* 148 */ SyscallDesc("quotactl", unimplementedFunc), - /* 149 */ SyscallDesc("oldquota", unimplementedFunc), - /* 150 */ SyscallDesc("old_getsockname", unimplementedFunc), - /* 151 */ SyscallDesc("pread", unimplementedFunc), - /* 152 */ SyscallDesc("pwrite", unimplementedFunc), - /* 153 */ SyscallDesc("pid_block", unimplementedFunc), - /* 154 */ SyscallDesc("pid_unblock", unimplementedFunc), - /* 155 */ SyscallDesc("signal_urti", unimplementedFunc), - /* 156 */ SyscallDesc("sigaction", ignoreFunc), - /* 157 */ SyscallDesc("sigwaitprim", unimplementedFunc), - /* 158 */ SyscallDesc("nfssvc", unimplementedFunc), - /* 159 */ SyscallDesc("getdirentries", Tru64::getdirentriesFunc), - /* 160 */ SyscallDesc("pre_F64_statfs", statfsFunc<Tru64::PreF64>), - /* 161 */ SyscallDesc("pre_F64_fstatfs", fstatfsFunc<Tru64::PreF64>), - /* 162 */ SyscallDesc("unknown #162", unimplementedFunc), - /* 163 */ SyscallDesc("async_daemon", unimplementedFunc), - /* 164 */ SyscallDesc("getfh", unimplementedFunc), - /* 165 */ SyscallDesc("getdomainname", unimplementedFunc), - /* 166 */ SyscallDesc("setdomainname", unimplementedFunc), - /* 167 */ SyscallDesc("unknown #167", unimplementedFunc), - /* 168 */ SyscallDesc("unknown #168", unimplementedFunc), - /* 169 */ SyscallDesc("exportfs", unimplementedFunc), - /* 170 */ SyscallDesc("unknown #170", unimplementedFunc), - /* 171 */ SyscallDesc("unknown #171", unimplementedFunc), - /* 172 */ SyscallDesc("unknown #172", unimplementedFunc), - /* 173 */ SyscallDesc("unknown #173", unimplementedFunc), - /* 174 */ SyscallDesc("unknown #174", unimplementedFunc), - /* 175 */ SyscallDesc("unknown #175", unimplementedFunc), - /* 176 */ SyscallDesc("unknown #176", unimplementedFunc), - /* 177 */ SyscallDesc("unknown #177", unimplementedFunc), - /* 178 */ SyscallDesc("unknown #178", unimplementedFunc), - /* 179 */ SyscallDesc("unknown #179", unimplementedFunc), - /* 180 */ SyscallDesc("unknown #180", unimplementedFunc), - /* 181 */ SyscallDesc("alt_plock", unimplementedFunc), - /* 182 */ SyscallDesc("unknown #182", unimplementedFunc), - /* 183 */ SyscallDesc("unknown #183", unimplementedFunc), - /* 184 */ SyscallDesc("getmnt", unimplementedFunc), - /* 185 */ SyscallDesc("unknown #185", unimplementedFunc), - /* 186 */ SyscallDesc("unknown #186", unimplementedFunc), - /* 187 */ SyscallDesc("alt_sigpending", unimplementedFunc), - /* 188 */ SyscallDesc("alt_setsid", unimplementedFunc), - /* 189 */ SyscallDesc("unknown #189", unimplementedFunc), - /* 190 */ SyscallDesc("unknown #190", unimplementedFunc), - /* 191 */ SyscallDesc("unknown #191", unimplementedFunc), - /* 192 */ SyscallDesc("unknown #192", unimplementedFunc), - /* 193 */ SyscallDesc("unknown #193", unimplementedFunc), - /* 194 */ SyscallDesc("unknown #194", unimplementedFunc), - /* 195 */ SyscallDesc("unknown #195", unimplementedFunc), - /* 196 */ SyscallDesc("unknown #196", unimplementedFunc), - /* 197 */ SyscallDesc("unknown #197", unimplementedFunc), - /* 198 */ SyscallDesc("unknown #198", unimplementedFunc), - /* 199 */ SyscallDesc("swapon", unimplementedFunc), - /* 200 */ SyscallDesc("msgctl", unimplementedFunc), - /* 201 */ SyscallDesc("msgget", unimplementedFunc), - /* 202 */ SyscallDesc("msgrcv", unimplementedFunc), - /* 203 */ SyscallDesc("msgsnd", unimplementedFunc), - /* 204 */ SyscallDesc("semctl", unimplementedFunc), - /* 205 */ SyscallDesc("semget", unimplementedFunc), - /* 206 */ SyscallDesc("semop", unimplementedFunc), - /* 207 */ SyscallDesc("uname", unameFunc), - /* 208 */ SyscallDesc("lchown", unimplementedFunc), - /* 209 */ SyscallDesc("shmat", unimplementedFunc), - /* 210 */ SyscallDesc("shmctl", unimplementedFunc), - /* 211 */ SyscallDesc("shmdt", unimplementedFunc), - /* 212 */ SyscallDesc("shmget", unimplementedFunc), - /* 213 */ SyscallDesc("mvalid", unimplementedFunc), - /* 214 */ SyscallDesc("getaddressconf", unimplementedFunc), - /* 215 */ SyscallDesc("msleep", unimplementedFunc), - /* 216 */ SyscallDesc("mwakeup", unimplementedFunc), - /* 217 */ SyscallDesc("msync", unimplementedFunc), - /* 218 */ SyscallDesc("signal", unimplementedFunc), - /* 219 */ SyscallDesc("utc_gettime", unimplementedFunc), - /* 220 */ SyscallDesc("utc_adjtime", unimplementedFunc), - /* 221 */ SyscallDesc("unknown #221", unimplementedFunc), - /* 222 */ SyscallDesc("security", unimplementedFunc), - /* 223 */ SyscallDesc("kloadcall", unimplementedFunc), - /* 224 */ SyscallDesc("stat", statFunc<Tru64::F64>), - /* 225 */ SyscallDesc("lstat", lstatFunc<Tru64::F64>), - /* 226 */ SyscallDesc("fstat", fstatFunc<Tru64::F64>), - /* 227 */ SyscallDesc("statfs", statfsFunc<Tru64::F64>), - /* 228 */ SyscallDesc("fstatfs", fstatfsFunc<Tru64::F64>), - /* 229 */ SyscallDesc("getfsstat", unimplementedFunc), - /* 230 */ SyscallDesc("gettimeofday64", unimplementedFunc), - /* 231 */ SyscallDesc("settimeofday64", unimplementedFunc), - /* 232 */ SyscallDesc("unknown #232", unimplementedFunc), - /* 233 */ SyscallDesc("getpgid", unimplementedFunc), - /* 234 */ SyscallDesc("getsid", unimplementedFunc), - /* 235 */ SyscallDesc("sigaltstack", ignoreFunc), - /* 236 */ SyscallDesc("waitid", unimplementedFunc), - /* 237 */ SyscallDesc("priocntlset", unimplementedFunc), - /* 238 */ SyscallDesc("sigsendset", unimplementedFunc), - /* 239 */ SyscallDesc("set_speculative", unimplementedFunc), - /* 240 */ SyscallDesc("msfs_syscall", unimplementedFunc), - /* 241 */ SyscallDesc("sysinfo", unimplementedFunc), - /* 242 */ SyscallDesc("uadmin", unimplementedFunc), - /* 243 */ SyscallDesc("fuser", unimplementedFunc), - /* 244 */ SyscallDesc("proplist_syscall", unimplementedFunc), - /* 245 */ SyscallDesc("ntp_adjtime", unimplementedFunc), - /* 246 */ SyscallDesc("ntp_gettime", unimplementedFunc), - /* 247 */ SyscallDesc("pathconf", unimplementedFunc), - /* 248 */ SyscallDesc("fpathconf", unimplementedFunc), - /* 249 */ SyscallDesc("sync2", unimplementedFunc), - /* 250 */ SyscallDesc("uswitch", unimplementedFunc), - /* 251 */ SyscallDesc("usleep_thread", unimplementedFunc), - /* 252 */ SyscallDesc("audcntl", unimplementedFunc), - /* 253 */ SyscallDesc("audgen", unimplementedFunc), - /* 254 */ SyscallDesc("sysfs", unimplementedFunc), - /* 255 */ SyscallDesc("subsys_info", unimplementedFunc), - /* 256 */ SyscallDesc("getsysinfo", getsysinfoFunc), - /* 257 */ SyscallDesc("setsysinfo", setsysinfoFunc), - /* 258 */ SyscallDesc("afs_syscall", unimplementedFunc), - /* 259 */ SyscallDesc("swapctl", unimplementedFunc), - /* 260 */ SyscallDesc("memcntl", unimplementedFunc), - /* 261 */ SyscallDesc("fdatasync", unimplementedFunc), - /* 262 */ SyscallDesc("oflock", unimplementedFunc), - /* 263 */ SyscallDesc("F64_readv", unimplementedFunc), - /* 264 */ SyscallDesc("F64_writev", unimplementedFunc), - /* 265 */ SyscallDesc("cdslxlate", unimplementedFunc), - /* 266 */ SyscallDesc("sendfile", unimplementedFunc), -}; - - - -SyscallDesc AlphaTru64Process::machSyscallDescs[] = { - /* 0 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 1 */ SyscallDesc("m5_mutex_lock", Tru64::m5_mutex_lockFunc), - /* 2 */ SyscallDesc("m5_mutex_trylock", Tru64::m5_mutex_trylockFunc), - /* 3 */ SyscallDesc("m5_mutex_unlock", Tru64::m5_mutex_unlockFunc), - /* 4 */ SyscallDesc("m5_cond_signal", Tru64::m5_cond_signalFunc), - /* 5 */ SyscallDesc("m5_cond_broadcast", Tru64::m5_cond_broadcastFunc), - /* 6 */ SyscallDesc("m5_cond_wait", Tru64::m5_cond_waitFunc), - /* 7 */ SyscallDesc("m5_thread_exit", Tru64::m5_thread_exitFunc), - /* 8 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 9 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 10 */ SyscallDesc("task_self", unimplementedFunc), - /* 11 */ SyscallDesc("thread_reply", unimplementedFunc), - /* 12 */ SyscallDesc("task_notify", unimplementedFunc), - /* 13 */ SyscallDesc("thread_self", unimplementedFunc), - /* 14 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 15 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 16 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 17 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 18 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 19 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 20 */ SyscallDesc("msg_send_trap", unimplementedFunc), - /* 21 */ SyscallDesc("msg_receive_trap", unimplementedFunc), - /* 22 */ SyscallDesc("msg_rpc_trap", unimplementedFunc), - /* 23 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 24 */ SyscallDesc("nxm_block", Tru64::nxm_blockFunc), - /* 25 */ SyscallDesc("nxm_unblock", Tru64::nxm_unblockFunc), - /* 26 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 27 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 28 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 29 */ SyscallDesc("nxm_thread_destroy", unimplementedFunc), - /* 30 */ SyscallDesc("lw_wire", unimplementedFunc), - /* 31 */ SyscallDesc("lw_unwire", unimplementedFunc), - /* 32 */ SyscallDesc("nxm_thread_create", Tru64::nxm_thread_createFunc), - /* 33 */ SyscallDesc("nxm_task_init", Tru64::nxm_task_initFunc), - /* 34 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 35 */ SyscallDesc("nxm_idle", Tru64::nxm_idleFunc), - /* 36 */ SyscallDesc("nxm_wakeup_idle", unimplementedFunc), - /* 37 */ SyscallDesc("nxm_set_pthid", unimplementedFunc), - /* 38 */ SyscallDesc("nxm_thread_kill", unimplementedFunc), - /* 39 */ SyscallDesc("nxm_thread_block", Tru64::nxm_thread_blockFunc), - /* 40 */ SyscallDesc("nxm_thread_wakeup", unimplementedFunc), - /* 41 */ SyscallDesc("init_process", unimplementedFunc), - /* 42 */ SyscallDesc("nxm_get_binding", unimplementedFunc), - /* 43 */ SyscallDesc("map_fd", unimplementedFunc), - /* 44 */ SyscallDesc("nxm_resched", unimplementedFunc), - /* 45 */ SyscallDesc("nxm_set_cancel", unimplementedFunc), - /* 46 */ SyscallDesc("nxm_set_binding", unimplementedFunc), - /* 47 */ SyscallDesc("stack_create", Tru64::stack_createFunc), - /* 48 */ SyscallDesc("nxm_get_state", unimplementedFunc), - /* 49 */ SyscallDesc("nxm_thread_suspend", unimplementedFunc), - /* 50 */ SyscallDesc("nxm_thread_resume", unimplementedFunc), - /* 51 */ SyscallDesc("nxm_signal_check", unimplementedFunc), - /* 52 */ SyscallDesc("htg_unix_syscall", unimplementedFunc), - /* 53 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 54 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 55 */ SyscallDesc("host_self", unimplementedFunc), - /* 56 */ SyscallDesc("host_priv_self", unimplementedFunc), - /* 57 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 58 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 59 */ SyscallDesc("swtch_pri", Tru64::swtch_priFunc), - /* 60 */ SyscallDesc("swtch", unimplementedFunc), - /* 61 */ SyscallDesc("thread_switch", unimplementedFunc), - /* 62 */ SyscallDesc("semop_fast", unimplementedFunc), - /* 63 */ SyscallDesc("nxm_pshared_init", unimplementedFunc), - /* 64 */ SyscallDesc("nxm_pshared_block", unimplementedFunc), - /* 65 */ SyscallDesc("nxm_pshared_unblock", unimplementedFunc), - /* 66 */ SyscallDesc("nxm_pshared_destroy", unimplementedFunc), - /* 67 */ SyscallDesc("nxm_swtch_pri", Tru64::swtch_priFunc), - /* 68 */ SyscallDesc("lw_syscall", unimplementedFunc), - /* 69 */ SyscallDesc("kern_invalid", unimplementedFunc), - /* 70 */ SyscallDesc("mach_sctimes_0", unimplementedFunc), - /* 71 */ SyscallDesc("mach_sctimes_1", unimplementedFunc), - /* 72 */ SyscallDesc("mach_sctimes_2", unimplementedFunc), - /* 73 */ SyscallDesc("mach_sctimes_3", unimplementedFunc), - /* 74 */ SyscallDesc("mach_sctimes_4", unimplementedFunc), - /* 75 */ SyscallDesc("mach_sctimes_5", unimplementedFunc), - /* 76 */ SyscallDesc("mach_sctimes_6", unimplementedFunc), - /* 77 */ SyscallDesc("mach_sctimes_7", unimplementedFunc), - /* 78 */ SyscallDesc("mach_sctimes_8", unimplementedFunc), - /* 79 */ SyscallDesc("mach_sctimes_9", unimplementedFunc), - /* 80 */ SyscallDesc("mach_sctimes_10", unimplementedFunc), - /* 81 */ SyscallDesc("mach_sctimes_11", unimplementedFunc), - /* 82 */ SyscallDesc("mach_sctimes_port_alloc_dealloc", unimplementedFunc) -}; - -SyscallDesc* -AlphaTru64Process::getDesc(int callnum) -{ - if (callnum < -Num_Mach_Syscall_Descs || callnum > Num_Syscall_Descs) - return NULL; - - if (callnum < 0) - return &machSyscallDescs[-callnum]; - else - return &syscallDescs[callnum]; -} - - -AlphaTru64Process::AlphaTru64Process(const std::string &name, - ObjectFile *objFile, - int stdin_fd, - int stdout_fd, - int stderr_fd, - std::vector<std::string> &argv, - std::vector<std::string> &envp) - : LiveProcess(name, objFile, stdin_fd, stdout_fd, stderr_fd, argv, envp), - Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc)), - Num_Mach_Syscall_Descs(sizeof(machSyscallDescs) / sizeof(SyscallDesc)) -{ -} diff --git a/arch/alpha/tru64/process.hh b/arch/alpha/tru64/process.hh deleted file mode 100644 index 051760702..000000000 --- a/arch/alpha/tru64/process.hh +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2003-2004 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. - */ - -#ifndef __ALPHA_TRU64_PROCESS_HH__ -#define __ALPHA_TRU64_PROCESS_HH__ - -#include "sim/process.hh" - -/// A process with emulated Alpha Tru64 syscalls. -class AlphaTru64Process : public LiveProcess -{ - public: - /// Constructor. - AlphaTru64Process(const std::string &name, - ObjectFile *objFile, - int stdin_fd, int stdout_fd, int stderr_fd, - std::vector<std::string> &argv, - std::vector<std::string> &envp); - - /// Array of syscall descriptors, indexed by call number. - static SyscallDesc syscallDescs[]; - - /// Array of mach syscall descriptors, indexed by call number. - static SyscallDesc machSyscallDescs[]; - - const int Num_Syscall_Descs; - const int Num_Mach_Syscall_Descs; - - virtual SyscallDesc* getDesc(int callnum); -}; - - -#endif // __ALPHA_TRU64_PROCESS_HH__ diff --git a/arch/alpha/tru64/system.cc b/arch/alpha/tru64/system.cc deleted file mode 100644 index 344f23c4f..000000000 --- a/arch/alpha/tru64/system.cc +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include "arch/alpha/tru64/system.hh" -#include "arch/isa_traits.hh" -#include "arch/vtophys.hh" -#include "base/loader/symtab.hh" -#include "base/trace.hh" -#include "cpu/base.hh" -#include "cpu/exec_context.hh" -#include "kern/tru64/tru64_events.hh" -#include "kern/system_events.hh" -#include "mem/functional/memory_control.hh" -#include "mem/functional/physical.hh" -#include "sim/builder.hh" - -using namespace std; - -Tru64AlphaSystem::Tru64AlphaSystem(Tru64AlphaSystem::Params *p) - : AlphaSystem(p) -{ - Addr addr = 0; - if (kernelSymtab->findAddress("enable_async_printf", addr)) { - Addr paddr = vtophys(physmem, addr); - uint8_t *enable_async_printf = - physmem->dma_addr(paddr, sizeof(uint32_t)); - - if (enable_async_printf) - *(uint32_t *)enable_async_printf = 0; - } - -#ifdef DEBUG - kernelPanicEvent = addKernelFuncEvent<BreakPCEvent>("panic"); - if (!kernelPanicEvent) - panic("could not find kernel symbol \'panic\'"); -#endif - - badaddrEvent = addKernelFuncEvent<BadAddrEvent>("badaddr"); - if (!badaddrEvent) - panic("could not find kernel symbol \'badaddr\'"); - - skipPowerStateEvent = - addKernelFuncEvent<SkipFuncEvent>("tl_v48_capture_power_state"); - skipScavengeBootEvent = - addKernelFuncEvent<SkipFuncEvent>("pmap_scavenge_boot"); - -#if TRACING_ON - printfEvent = addKernelFuncEvent<PrintfEvent>("printf"); - debugPrintfEvent = addKernelFuncEvent<DebugPrintfEvent>("m5printf"); - debugPrintfrEvent = addKernelFuncEvent<DebugPrintfrEvent>("m5printfr"); - dumpMbufEvent = addKernelFuncEvent<DumpMbufEvent>("m5_dump_mbuf"); -#endif -} - -Tru64AlphaSystem::~Tru64AlphaSystem() -{ -#ifdef DEBUG - delete kernelPanicEvent; -#endif - delete badaddrEvent; - delete skipPowerStateEvent; - delete skipScavengeBootEvent; -#if TRACING_ON - delete printfEvent; - delete debugPrintfEvent; - delete debugPrintfrEvent; - delete dumpMbufEvent; -#endif -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(Tru64AlphaSystem) - - Param<Tick> boot_cpu_frequency; - SimObjectParam<MemoryController *> memctrl; - SimObjectParam<PhysicalMemory *> physmem; - - Param<string> kernel; - Param<string> console; - Param<string> pal; - - Param<string> boot_osflags; - Param<string> readfile; - Param<unsigned int> init_param; - - Param<uint64_t> system_type; - Param<uint64_t> system_rev; - -END_DECLARE_SIM_OBJECT_PARAMS(Tru64AlphaSystem) - -BEGIN_INIT_SIM_OBJECT_PARAMS(Tru64AlphaSystem) - - INIT_PARAM(boot_cpu_frequency, "frequency of the boot cpu"), - INIT_PARAM(memctrl, "memory controller"), - INIT_PARAM(physmem, "phsyical memory"), - INIT_PARAM(kernel, "file that contains the kernel code"), - INIT_PARAM(console, "file that contains the console code"), - INIT_PARAM(pal, "file that contains palcode"), - INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot", - "a"), - INIT_PARAM_DFLT(readfile, "file to read startup script from", ""), - INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0), - INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 12), - INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 2<<1) - -END_INIT_SIM_OBJECT_PARAMS(Tru64AlphaSystem) - -CREATE_SIM_OBJECT(Tru64AlphaSystem) -{ - AlphaSystem::Params *p = new AlphaSystem::Params; - p->name = getInstanceName(); - p->boot_cpu_frequency = boot_cpu_frequency; - p->memctrl = memctrl; - p->physmem = physmem; - p->kernel_path = kernel; - p->console_path = console; - p->palcode = pal; - p->boot_osflags = boot_osflags; - p->init_param = init_param; - p->readfile = readfile; - p->system_type = system_type; - p->system_rev = system_rev; - - return new Tru64AlphaSystem(p); -} - -REGISTER_SIM_OBJECT("Tru64AlphaSystem", Tru64AlphaSystem) diff --git a/arch/alpha/tru64/system.hh b/arch/alpha/tru64/system.hh deleted file mode 100644 index 0e0cc1bc8..000000000 --- a/arch/alpha/tru64/system.hh +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __ARCH_ALPHA_TRU64_SYSTEM_HH__ -#define __ARCH_ALPHA_TRU64_SYSTEM_HH__ - -#include "arch/alpha/system.hh" -#include "arch/isa_traits.hh" -#include "sim/system.hh" - -class ExecContext; - -class BreakPCEvent; -class BadAddrEvent; -class SkipFuncEvent; -class PrintfEvent; -class DebugPrintfEvent; -class DebugPrintfrEvent; -class DumpMbufEvent; -class AlphaArguments; - -class Tru64AlphaSystem : public AlphaSystem -{ - private: -#ifdef DEBUG - /** Event to halt the simulator if the kernel calls panic() */ - BreakPCEvent *kernelPanicEvent; -#endif - - BadAddrEvent *badaddrEvent; - SkipFuncEvent *skipPowerStateEvent; - SkipFuncEvent *skipScavengeBootEvent; - PrintfEvent *printfEvent; - DebugPrintfEvent *debugPrintfEvent; - DebugPrintfrEvent *debugPrintfrEvent; - DumpMbufEvent *dumpMbufEvent; - - public: - Tru64AlphaSystem(Params *p); - ~Tru64AlphaSystem(); - - static void Printf(AlphaArguments args); - static void DumpMbuf(AlphaArguments args); -}; - -#endif // __ARCH_ALPHA_TRU64_SYSTEM_HH__ diff --git a/arch/alpha/vtophys.cc b/arch/alpha/vtophys.cc deleted file mode 100644 index 40261426d..000000000 --- a/arch/alpha/vtophys.cc +++ /dev/null @@ -1,268 +0,0 @@ -/* - * 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. - */ - -#include <string> - -#include "arch/alpha/vtophys.hh" -#include "base/trace.hh" -#include "cpu/exec_context.hh" -#include "mem/functional/physical.hh" - -using namespace std; -using namespace AlphaISA; - -AlphaISA::PageTableEntry -kernel_pte_lookup(PhysicalMemory *pmem, Addr ptbr, AlphaISA::VAddr vaddr) -{ - Addr level1_pte = ptbr + vaddr.level1(); - AlphaISA::PageTableEntry level1 = pmem->phys_read_qword(level1_pte); - if (!level1.valid()) { - DPRINTF(VtoPhys, "level 1 PTE not valid, va = %#\n", vaddr); - return 0; - } - - Addr level2_pte = level1.paddr() + vaddr.level2(); - AlphaISA::PageTableEntry level2 = pmem->phys_read_qword(level2_pte); - if (!level2.valid()) { - DPRINTF(VtoPhys, "level 2 PTE not valid, va = %#x\n", vaddr); - return 0; - } - - Addr level3_pte = level2.paddr() + vaddr.level3(); - AlphaISA::PageTableEntry level3 = pmem->phys_read_qword(level3_pte); - if (!level3.valid()) { - DPRINTF(VtoPhys, "level 3 PTE not valid, va = %#x\n", vaddr); - return 0; - } - return level3; -} - -Addr -vtophys(PhysicalMemory *xc, Addr vaddr) -{ - Addr paddr = 0; - if (AlphaISA::IsUSeg(vaddr)) - DPRINTF(VtoPhys, "vtophys: invalid vaddr %#x", vaddr); - else if (AlphaISA::IsK0Seg(vaddr)) - paddr = AlphaISA::K0Seg2Phys(vaddr); - else - panic("vtophys: ptbr is not set on virtual lookup"); - - DPRINTF(VtoPhys, "vtophys(%#x) -> %#x\n", vaddr, paddr); - - return paddr; -} - -Addr -vtophys(ExecContext *xc, Addr addr) -{ - AlphaISA::VAddr vaddr = addr; - Addr ptbr = xc->readMiscReg(AlphaISA::IPR_PALtemp20); - Addr paddr = 0; - //@todo Andrew couldn't remember why he commented some of this code - //so I put it back in. Perhaps something to do with gdb debugging? - if (AlphaISA::PcPAL(vaddr) && (vaddr < EV5::PalMax)) { - paddr = vaddr & ~ULL(1); - } else { - if (AlphaISA::IsK0Seg(vaddr)) { - paddr = AlphaISA::K0Seg2Phys(vaddr); - } else if (!ptbr) { - paddr = vaddr; - } else { - AlphaISA::PageTableEntry pte = - kernel_pte_lookup(xc->getPhysMemPtr(), ptbr, vaddr); - if (pte.valid()) - paddr = pte.paddr() | vaddr.offset(); - } - } - - - DPRINTF(VtoPhys, "vtophys(%#x) -> %#x\n", vaddr, paddr); - - return paddr; -} - -uint8_t * -ptomem(ExecContext *xc, Addr paddr, size_t len) -{ - return xc->getPhysMemPtr()->dma_addr(paddr, len); -} - -uint8_t * -vtomem(ExecContext *xc, Addr vaddr, size_t len) -{ - Addr paddr = vtophys(xc, vaddr); - return xc->getPhysMemPtr()->dma_addr(paddr, len); -} - -void -CopyOut(ExecContext *xc, void *dest, Addr src, size_t cplen) -{ - Addr paddr; - char *dmaaddr; - char *dst = (char *)dest; - int len; - - paddr = vtophys(xc, src); - len = min((int)(AlphaISA::PageBytes - (paddr & AlphaISA::PageOffset)), - (int)cplen); - dmaaddr = (char *)xc->getPhysMemPtr()->dma_addr(paddr, len); - assert(dmaaddr); - - memcpy(dst, dmaaddr, len); - if (len == cplen) - return; - - cplen -= len; - dst += len; - src += len; - - while (cplen > AlphaISA::PageBytes) { - paddr = vtophys(xc, src); - dmaaddr = (char *)xc->getPhysMemPtr()->dma_addr(paddr, - AlphaISA::PageBytes); - assert(dmaaddr); - - memcpy(dst, dmaaddr, AlphaISA::PageBytes); - cplen -= AlphaISA::PageBytes; - dst += AlphaISA::PageBytes; - src += AlphaISA::PageBytes; - } - - if (cplen > 0) { - paddr = vtophys(xc, src); - dmaaddr = (char *)xc->getPhysMemPtr()->dma_addr(paddr, cplen); - assert(dmaaddr); - - memcpy(dst, dmaaddr, cplen); - } -} - -void -CopyIn(ExecContext *xc, Addr dest, void *source, size_t cplen) -{ - Addr paddr; - char *dmaaddr; - char *src = (char *)source; - int len; - - paddr = vtophys(xc, dest); - len = min((int)(AlphaISA::PageBytes - (paddr & AlphaISA::PageOffset)), - (int)cplen); - dmaaddr = (char *)xc->getPhysMemPtr()->dma_addr(paddr, len); - assert(dmaaddr); - - memcpy(dmaaddr, src, len); - if (len == cplen) - return; - - cplen -= len; - src += len; - dest += len; - - while (cplen > AlphaISA::PageBytes) { - paddr = vtophys(xc, dest); - dmaaddr = (char *)xc->getPhysMemPtr()->dma_addr(paddr, - AlphaISA::PageBytes); - assert(dmaaddr); - - memcpy(dmaaddr, src, AlphaISA::PageBytes); - cplen -= AlphaISA::PageBytes; - src += AlphaISA::PageBytes; - dest += AlphaISA::PageBytes; - } - - if (cplen > 0) { - paddr = vtophys(xc, dest); - dmaaddr = (char *)xc->getPhysMemPtr()->dma_addr(paddr, cplen); - assert(dmaaddr); - - memcpy(dmaaddr, src, cplen); - } -} - -void -CopyString(ExecContext *xc, char *dst, Addr vaddr, size_t maxlen) -{ - Addr paddr; - char *dmaaddr; - int len; - - paddr = vtophys(xc, vaddr); - len = min((int)(AlphaISA::PageBytes - (paddr & AlphaISA::PageOffset)), - (int)maxlen); - dmaaddr = (char *)xc->getPhysMemPtr()->dma_addr(paddr, len); - assert(dmaaddr); - - char *term = (char *)memchr(dmaaddr, 0, len); - if (term) - len = term - dmaaddr + 1; - - memcpy(dst, dmaaddr, len); - - if (term || len == maxlen) - return; - - maxlen -= len; - dst += len; - vaddr += len; - - while (maxlen > AlphaISA::PageBytes) { - paddr = vtophys(xc, vaddr); - dmaaddr = (char *)xc->getPhysMemPtr()->dma_addr(paddr, - AlphaISA::PageBytes); - assert(dmaaddr); - - char *term = (char *)memchr(dmaaddr, 0, AlphaISA::PageBytes); - len = term ? (term - dmaaddr + 1) : AlphaISA::PageBytes; - - memcpy(dst, dmaaddr, len); - if (term) - return; - - maxlen -= AlphaISA::PageBytes; - dst += AlphaISA::PageBytes; - vaddr += AlphaISA::PageBytes; - } - - if (maxlen > 0) { - paddr = vtophys(xc, vaddr); - dmaaddr = (char *)xc->getPhysMemPtr()->dma_addr(paddr, maxlen); - assert(dmaaddr); - - char *term = (char *)memchr(dmaaddr, 0, maxlen); - len = term ? (term - dmaaddr + 1) : maxlen; - - memcpy(dst, dmaaddr, len); - - maxlen -= len; - } - - if (maxlen == 0) - dst[maxlen] = '\0'; -} diff --git a/arch/alpha/vtophys.hh b/arch/alpha/vtophys.hh deleted file mode 100644 index 95430ce77..000000000 --- a/arch/alpha/vtophys.hh +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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. - */ - -#ifndef __ARCH_ALPHA_VTOPHYS_H__ -#define __ARCH_ALPHA_VTOPHYS_H__ - -#include "arch/alpha/isa_traits.hh" - -class ExecContext; -class PhysicalMemory; - -AlphaISA::PageTableEntry -kernel_pte_lookup(PhysicalMemory *pmem, Addr ptbr, AlphaISA::VAddr vaddr); - -Addr vtophys(PhysicalMemory *xc, Addr vaddr); -Addr vtophys(ExecContext *xc, Addr vaddr); -uint8_t *vtomem(ExecContext *xc, Addr vaddr, size_t len); -uint8_t *ptomem(ExecContext *xc, Addr paddr, size_t len); - -void CopyOut(ExecContext *xc, void *dst, Addr src, size_t len); -void CopyIn(ExecContext *xc, Addr dst, void *src, size_t len); -void CopyString(ExecContext *xc, char *dst, Addr vaddr, size_t maxlen); - -#endif // __ARCH_ALPHA_VTOPHYS_H__ - diff --git a/arch/isa_parser.py b/arch/isa_parser.py deleted file mode 100755 index b0f10783f..000000000 --- a/arch/isa_parser.py +++ /dev/null @@ -1,1772 +0,0 @@ -# Copyright (c) 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. - -import os -import sys -import re -import string -import traceback -# get type names -from types import * - -# Prepend the directory where the PLY lex & yacc modules are found -# to the search path. Assumes we're compiling in a subdirectory -# of 'build' in the current tree. -sys.path[0:0] = [os.environ['M5_EXT'] + '/ply'] - -import lex -import yacc - -##################################################################### -# -# Lexer -# -# The PLY lexer module takes two things as input: -# - A list of token names (the string list 'tokens') -# - A regular expression describing a match for each token. The -# regexp for token FOO can be provided in two ways: -# - as a string variable named t_FOO -# - as the doc string for a function named t_FOO. In this case, -# the function is also executed, allowing an action to be -# associated with each token match. -# -##################################################################### - -# Reserved words. These are listed separately as they are matched -# using the same regexp as generic IDs, but distinguished in the -# t_ID() function. The PLY documentation suggests this approach. -reserved = ( - 'BITFIELD', 'DECODE', 'DECODER', 'DEFAULT', 'DEF', 'EXEC', 'FORMAT', - 'HEADER', 'LET', 'NAMESPACE', 'OPERAND_TYPES', 'OPERANDS', - 'OUTPUT', 'SIGNED', 'TEMPLATE' - ) - -# List of tokens. The lex module requires this. -tokens = reserved + ( - # identifier - 'ID', - - # integer literal - 'INTLIT', - - # string literal - 'STRLIT', - - # code literal - 'CODELIT', - - # ( ) [ ] { } < > , ; : :: * - 'LPAREN', 'RPAREN', - 'LBRACKET', 'RBRACKET', - 'LBRACE', 'RBRACE', - 'LESS', 'GREATER', 'EQUALS', - 'COMMA', 'SEMI', 'COLON', 'DBLCOLON', - 'ASTERISK', - - # C preprocessor directives - 'CPPDIRECTIVE' - -# The following are matched but never returned. commented out to -# suppress PLY warning - # newfile directive -# 'NEWFILE', - - # endfile directive -# 'ENDFILE' -) - -# Regular expressions for token matching -t_LPAREN = r'\(' -t_RPAREN = r'\)' -t_LBRACKET = r'\[' -t_RBRACKET = r'\]' -t_LBRACE = r'\{' -t_RBRACE = r'\}' -t_LESS = r'\<' -t_GREATER = r'\>' -t_EQUALS = r'=' -t_COMMA = r',' -t_SEMI = r';' -t_COLON = r':' -t_DBLCOLON = r'::' -t_ASTERISK = r'\*' - -# Identifiers and reserved words -reserved_map = { } -for r in reserved: - reserved_map[r.lower()] = r - -def t_ID(t): - r'[A-Za-z_]\w*' - t.type = reserved_map.get(t.value,'ID') - return t - -# Integer literal -def t_INTLIT(t): - r'(0x[\da-fA-F]+)|\d+' - try: - t.value = int(t.value,0) - except ValueError: - error(t.lineno, 'Integer value "%s" too large' % t.value) - t.value = 0 - return t - -# String literal. Note that these use only single quotes, and -# can span multiple lines. -def t_STRLIT(t): - r"(?m)'([^'])+'" - # strip off quotes - t.value = t.value[1:-1] - t.lineno += t.value.count('\n') - return t - - -# "Code literal"... like a string literal, but delimiters are -# '{{' and '}}' so they get formatted nicely under emacs c-mode -def t_CODELIT(t): - r"(?m)\{\{([^\}]|}(?!\}))+\}\}" - # strip off {{ & }} - t.value = t.value[2:-2] - t.lineno += t.value.count('\n') - return t - -def t_CPPDIRECTIVE(t): - r'^\#[^\#].*\n' - t.lineno += t.value.count('\n') - return t - -def t_NEWFILE(t): - r'^\#\#newfile\s+"[\w/.-]*"' - fileNameStack.push((t.value[11:-1], t.lineno)) - t.lineno = 0 - -def t_ENDFILE(t): - r'^\#\#endfile' - (old_filename, t.lineno) = fileNameStack.pop() - -# -# The functions t_NEWLINE, t_ignore, and t_error are -# special for the lex module. -# - -# Newlines -def t_NEWLINE(t): - r'\n+' - t.lineno += t.value.count('\n') - -# Comments -def t_comment(t): - r'//.*' - -# Completely ignored characters -t_ignore = ' \t\x0c' - -# Error handler -def t_error(t): - error(t.lineno, "illegal character '%s'" % t.value[0]) - t.skip(1) - -# Build the lexer -lex.lex() - -##################################################################### -# -# Parser -# -# Every function whose name starts with 'p_' defines a grammar rule. -# The rule is encoded in the function's doc string, while the -# function body provides the action taken when the rule is matched. -# The argument to each function is a list of the values of the -# rule's symbols: t[0] for the LHS, and t[1..n] for the symbols -# on the RHS. For tokens, the value is copied from the t.value -# attribute provided by the lexer. For non-terminals, the value -# is assigned by the producing rule; i.e., the job of the grammar -# rule function is to set the value for the non-terminal on the LHS -# (by assigning to t[0]). -##################################################################### - -# The LHS of the first grammar rule is used as the start symbol -# (in this case, 'specification'). Note that this rule enforces -# that there will be exactly one namespace declaration, with 0 or more -# global defs/decls before and after it. The defs & decls before -# the namespace decl will be outside the namespace; those after -# will be inside. The decoder function is always inside the namespace. -def p_specification(t): - 'specification : opt_defs_and_outputs name_decl opt_defs_and_outputs decode_block' - global_code = t[1] - isa_name = t[2] - namespace = isa_name + "Inst" - # wrap the decode block as a function definition - t[4].wrap_decode_block(''' -StaticInstPtr -%(isa_name)s::decodeInst(%(isa_name)s::ExtMachInst machInst) -{ - using namespace %(namespace)s; -''' % vars(), '}') - # both the latter output blocks and the decode block are in the namespace - namespace_code = t[3] + t[4] - # pass it all back to the caller of yacc.parse() - t[0] = (isa_name, namespace, global_code, namespace_code) - -# ISA name declaration looks like "namespace <foo>;" -def p_name_decl(t): - 'name_decl : NAMESPACE ID SEMI' - t[0] = t[2] - -# 'opt_defs_and_outputs' is a possibly empty sequence of -# def and/or output statements. -def p_opt_defs_and_outputs_0(t): - 'opt_defs_and_outputs : empty' - t[0] = GenCode() - -def p_opt_defs_and_outputs_1(t): - 'opt_defs_and_outputs : defs_and_outputs' - t[0] = t[1] - -def p_defs_and_outputs_0(t): - 'defs_and_outputs : def_or_output' - t[0] = t[1] - -def p_defs_and_outputs_1(t): - 'defs_and_outputs : defs_and_outputs def_or_output' - t[0] = t[1] + t[2] - -# The list of possible definition/output statements. -def p_def_or_output(t): - '''def_or_output : def_format - | def_bitfield - | def_template - | def_operand_types - | def_operands - | output_header - | output_decoder - | output_exec - | global_let''' - t[0] = t[1] - -# Output blocks 'output <foo> {{...}}' (C++ code blocks) are copied -# directly to the appropriate output section. - - -# Protect any non-dict-substitution '%'s in a format string -# (i.e. those not followed by '(') -def protect_non_subst_percents(s): - return re.sub(r'%(?!\()', '%%', s) - -# Massage output block by substituting in template definitions and bit -# operators. We handle '%'s embedded in the string that don't -# indicate template substitutions (or CPU-specific symbols, which get -# handled in GenCode) by doubling them first so that the format -# operation will reduce them back to single '%'s. -def process_output(s): - s = protect_non_subst_percents(s) - # protects cpu-specific symbols too - s = protect_cpu_symbols(s) - return substBitOps(s % templateMap) - -def p_output_header(t): - 'output_header : OUTPUT HEADER CODELIT SEMI' - t[0] = GenCode(header_output = process_output(t[3])) - -def p_output_decoder(t): - 'output_decoder : OUTPUT DECODER CODELIT SEMI' - t[0] = GenCode(decoder_output = process_output(t[3])) - -def p_output_exec(t): - 'output_exec : OUTPUT EXEC CODELIT SEMI' - t[0] = GenCode(exec_output = process_output(t[3])) - -# global let blocks 'let {{...}}' (Python code blocks) are executed -# directly when seen. Note that these execute in a special variable -# context 'exportContext' to prevent the code from polluting this -# script's namespace. -def p_global_let(t): - 'global_let : LET CODELIT SEMI' - updateExportContext() - try: - exec fixPythonIndentation(t[2]) in exportContext - except Exception, exc: - error(t.lineno(1), - 'error: %s in global let block "%s".' % (exc, t[2])) - t[0] = GenCode() # contributes nothing to the output C++ file - -# Define the mapping from operand type extensions to C++ types and bit -# widths (stored in operandTypeMap). -def p_def_operand_types(t): - 'def_operand_types : DEF OPERAND_TYPES CODELIT SEMI' - try: - userDict = eval('{' + t[3] + '}') - except Exception, exc: - error(t.lineno(1), - 'error: %s in def operand_types block "%s".' % (exc, t[3])) - buildOperandTypeMap(userDict, t.lineno(1)) - t[0] = GenCode() # contributes nothing to the output C++ file - -# Define the mapping from operand names to operand classes and other -# traits. Stored in operandNameMap. -def p_def_operands(t): - 'def_operands : DEF OPERANDS CODELIT SEMI' - if not globals().has_key('operandTypeMap'): - error(t.lineno(1), - 'error: operand types must be defined before operands') - try: - userDict = eval('{' + t[3] + '}') - except Exception, exc: - error(t.lineno(1), - 'error: %s in def operands block "%s".' % (exc, t[3])) - buildOperandNameMap(userDict, t.lineno(1)) - t[0] = GenCode() # contributes nothing to the output C++ file - -# A bitfield definition looks like: -# 'def [signed] bitfield <ID> [<first>:<last>]' -# This generates a preprocessor macro in the output file. -def p_def_bitfield_0(t): - 'def_bitfield : DEF opt_signed BITFIELD ID LESS INTLIT COLON INTLIT GREATER SEMI' - expr = 'bits(machInst, %2d, %2d)' % (t[6], t[8]) - if (t[2] == 'signed'): - expr = 'sext<%d>(%s)' % (t[6] - t[8] + 1, expr) - hash_define = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr) - t[0] = GenCode(header_output = hash_define) - -# alternate form for single bit: 'def [signed] bitfield <ID> [<bit>]' -def p_def_bitfield_1(t): - 'def_bitfield : DEF opt_signed BITFIELD ID LESS INTLIT GREATER SEMI' - expr = 'bits(machInst, %2d, %2d)' % (t[6], t[6]) - if (t[2] == 'signed'): - expr = 'sext<%d>(%s)' % (1, expr) - hash_define = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr) - t[0] = GenCode(header_output = hash_define) - -def p_opt_signed_0(t): - 'opt_signed : SIGNED' - t[0] = t[1] - -def p_opt_signed_1(t): - 'opt_signed : empty' - t[0] = '' - -# Global map variable to hold templates -templateMap = {} - -def p_def_template(t): - 'def_template : DEF TEMPLATE ID CODELIT SEMI' - templateMap[t[3]] = Template(t[4]) - t[0] = GenCode() - -# An instruction format definition looks like -# "def format <fmt>(<params>) {{...}};" -def p_def_format(t): - 'def_format : DEF FORMAT ID LPAREN param_list RPAREN CODELIT SEMI' - (id, params, code) = (t[3], t[5], t[7]) - defFormat(id, params, code, t.lineno(1)) - t[0] = GenCode() - -# The formal parameter list for an instruction format is a possibly -# empty list of comma-separated parameters. Positional (standard, -# non-keyword) parameters must come first, followed by keyword -# parameters, followed by a '*foo' parameter that gets excess -# positional arguments (as in Python). Each of these three parameter -# categories is optional. -# -# Note that we do not support the '**foo' parameter for collecting -# otherwise undefined keyword args. Otherwise the parameter list is -# (I believe) identical to what is supported in Python. -# -# The param list generates a tuple, where the first element is a list of -# the positional params and the second element is a dict containing the -# keyword params. -def p_param_list_0(t): - 'param_list : positional_param_list COMMA nonpositional_param_list' - t[0] = t[1] + t[3] - -def p_param_list_1(t): - '''param_list : positional_param_list - | nonpositional_param_list''' - t[0] = t[1] - -def p_positional_param_list_0(t): - 'positional_param_list : empty' - t[0] = [] - -def p_positional_param_list_1(t): - 'positional_param_list : ID' - t[0] = [t[1]] - -def p_positional_param_list_2(t): - 'positional_param_list : positional_param_list COMMA ID' - t[0] = t[1] + [t[3]] - -def p_nonpositional_param_list_0(t): - 'nonpositional_param_list : keyword_param_list COMMA excess_args_param' - t[0] = t[1] + t[3] - -def p_nonpositional_param_list_1(t): - '''nonpositional_param_list : keyword_param_list - | excess_args_param''' - t[0] = t[1] - -def p_keyword_param_list_0(t): - 'keyword_param_list : keyword_param' - t[0] = [t[1]] - -def p_keyword_param_list_1(t): - 'keyword_param_list : keyword_param_list COMMA keyword_param' - t[0] = t[1] + [t[3]] - -def p_keyword_param(t): - 'keyword_param : ID EQUALS expr' - t[0] = t[1] + ' = ' + t[3].__repr__() - -def p_excess_args_param(t): - 'excess_args_param : ASTERISK ID' - # Just concatenate them: '*ID'. Wrap in list to be consistent - # with positional_param_list and keyword_param_list. - t[0] = [t[1] + t[2]] - -# End of format definition-related rules. -############## - -# -# A decode block looks like: -# decode <field1> [, <field2>]* [default <inst>] { ... } -# -def p_decode_block(t): - 'decode_block : DECODE ID opt_default LBRACE decode_stmt_list RBRACE' - default_defaults = defaultStack.pop() - codeObj = t[5] - # use the "default defaults" only if there was no explicit - # default statement in decode_stmt_list - if not codeObj.has_decode_default: - codeObj += default_defaults - codeObj.wrap_decode_block('switch (%s) {\n' % t[2], '}\n') - t[0] = codeObj - -# The opt_default statement serves only to push the "default defaults" -# onto defaultStack. This value will be used by nested decode blocks, -# and used and popped off when the current decode_block is processed -# (in p_decode_block() above). -def p_opt_default_0(t): - 'opt_default : empty' - # no default specified: reuse the one currently at the top of the stack - defaultStack.push(defaultStack.top()) - # no meaningful value returned - t[0] = None - -def p_opt_default_1(t): - 'opt_default : DEFAULT inst' - # push the new default - codeObj = t[2] - codeObj.wrap_decode_block('\ndefault:\n', 'break;\n') - defaultStack.push(codeObj) - # no meaningful value returned - t[0] = None - -def p_decode_stmt_list_0(t): - 'decode_stmt_list : decode_stmt' - t[0] = t[1] - -def p_decode_stmt_list_1(t): - 'decode_stmt_list : decode_stmt decode_stmt_list' - if (t[1].has_decode_default and t[2].has_decode_default): - error(t.lineno(1), 'Two default cases in decode block') - t[0] = t[1] + t[2] - -# -# Decode statement rules -# -# There are four types of statements allowed in a decode block: -# 1. Format blocks 'format <foo> { ... }' -# 2. Nested decode blocks -# 3. Instruction definitions. -# 4. C preprocessor directives. - - -# Preprocessor directives found in a decode statement list are passed -# through to the output, replicated to all of the output code -# streams. This works well for ifdefs, so we can ifdef out both the -# declarations and the decode cases generated by an instruction -# definition. Handling them as part of the grammar makes it easy to -# keep them in the right place with respect to the code generated by -# the other statements. -def p_decode_stmt_cpp(t): - 'decode_stmt : CPPDIRECTIVE' - t[0] = GenCode(t[1], t[1], t[1], t[1]) - -# A format block 'format <foo> { ... }' sets the default instruction -# format used to handle instruction definitions inside the block. -# This format can be overridden by using an explicit format on the -# instruction definition or with a nested format block. -def p_decode_stmt_format(t): - 'decode_stmt : FORMAT push_format_id LBRACE decode_stmt_list RBRACE' - # The format will be pushed on the stack when 'push_format_id' is - # processed (see below). Once the parser has recognized the full - # production (though the right brace), we're done with the format, - # so now we can pop it. - formatStack.pop() - t[0] = t[4] - -# This rule exists so we can set the current format (& push the stack) -# when we recognize the format name part of the format block. -def p_push_format_id(t): - 'push_format_id : ID' - try: - formatStack.push(formatMap[t[1]]) - t[0] = ('', '// format %s' % t[1]) - except KeyError: - error(t.lineno(1), 'instruction format "%s" not defined.' % t[1]) - -# Nested decode block: if the value of the current field matches the -# specified constant, do a nested decode on some other field. -def p_decode_stmt_decode(t): - 'decode_stmt : case_label COLON decode_block' - label = t[1] - codeObj = t[3] - # just wrap the decoding code from the block as a case in the - # outer switch statement. - codeObj.wrap_decode_block('\n%s:\n' % label) - codeObj.has_decode_default = (label == 'default') - t[0] = codeObj - -# Instruction definition (finally!). -def p_decode_stmt_inst(t): - 'decode_stmt : case_label COLON inst SEMI' - label = t[1] - codeObj = t[3] - codeObj.wrap_decode_block('\n%s:' % label, 'break;\n') - codeObj.has_decode_default = (label == 'default') - t[0] = codeObj - -# The case label is either a list of one or more constants or 'default' -def p_case_label_0(t): - 'case_label : intlit_list' - t[0] = ': '.join(map(lambda a: 'case %#x' % a, t[1])) - -def p_case_label_1(t): - 'case_label : DEFAULT' - t[0] = 'default' - -# -# The constant list for a decode case label must be non-empty, but may have -# one or more comma-separated integer literals in it. -# -def p_intlit_list_0(t): - 'intlit_list : INTLIT' - t[0] = [t[1]] - -def p_intlit_list_1(t): - 'intlit_list : intlit_list COMMA INTLIT' - t[0] = t[1] - t[0].append(t[3]) - -# Define an instruction using the current instruction format (specified -# by an enclosing format block). -# "<mnemonic>(<args>)" -def p_inst_0(t): - 'inst : ID LPAREN arg_list RPAREN' - # Pass the ID and arg list to the current format class to deal with. - currentFormat = formatStack.top() - codeObj = currentFormat.defineInst(t[1], t[3], t.lineno(1)) - args = ','.join(map(str, t[3])) - args = re.sub('(?m)^', '//', args) - args = re.sub('^//', '', args) - comment = '\n// %s::%s(%s)\n' % (currentFormat.id, t[1], args) - codeObj.prepend_all(comment) - t[0] = codeObj - -# Define an instruction using an explicitly specified format: -# "<fmt>::<mnemonic>(<args>)" -def p_inst_1(t): - 'inst : ID DBLCOLON ID LPAREN arg_list RPAREN' - try: - format = formatMap[t[1]] - except KeyError: - error(t.lineno(1), 'instruction format "%s" not defined.' % t[1]) - codeObj = format.defineInst(t[3], t[5], t.lineno(1)) - comment = '\n// %s::%s(%s)\n' % (t[1], t[3], t[5]) - codeObj.prepend_all(comment) - t[0] = codeObj - -# The arg list generates a tuple, where the first element is a list of -# the positional args and the second element is a dict containing the -# keyword args. -def p_arg_list_0(t): - 'arg_list : positional_arg_list COMMA keyword_arg_list' - t[0] = ( t[1], t[3] ) - -def p_arg_list_1(t): - 'arg_list : positional_arg_list' - t[0] = ( t[1], {} ) - -def p_arg_list_2(t): - 'arg_list : keyword_arg_list' - t[0] = ( [], t[1] ) - -def p_positional_arg_list_0(t): - 'positional_arg_list : empty' - t[0] = [] - -def p_positional_arg_list_1(t): - 'positional_arg_list : expr' - t[0] = [t[1]] - -def p_positional_arg_list_2(t): - 'positional_arg_list : positional_arg_list COMMA expr' - t[0] = t[1] + [t[3]] - -def p_keyword_arg_list_0(t): - 'keyword_arg_list : keyword_arg' - t[0] = t[1] - -def p_keyword_arg_list_1(t): - 'keyword_arg_list : keyword_arg_list COMMA keyword_arg' - t[0] = t[1] - t[0].update(t[3]) - -def p_keyword_arg(t): - 'keyword_arg : ID EQUALS expr' - t[0] = { t[1] : t[3] } - -# -# Basic expressions. These constitute the argument values of -# "function calls" (i.e. instruction definitions in the decode block) -# and default values for formal parameters of format functions. -# -# Right now, these are either strings, integers, or (recursively) -# lists of exprs (using Python square-bracket list syntax). Note that -# bare identifiers are trated as string constants here (since there -# isn't really a variable namespace to refer to). -# -def p_expr_0(t): - '''expr : ID - | INTLIT - | STRLIT - | CODELIT''' - t[0] = t[1] - -def p_expr_1(t): - '''expr : LBRACKET list_expr RBRACKET''' - t[0] = t[2] - -def p_list_expr_0(t): - 'list_expr : expr' - t[0] = [t[1]] - -def p_list_expr_1(t): - 'list_expr : list_expr COMMA expr' - t[0] = t[1] + [t[3]] - -def p_list_expr_2(t): - 'list_expr : empty' - t[0] = [] - -# -# Empty production... use in other rules for readability. -# -def p_empty(t): - 'empty :' - pass - -# Parse error handler. Note that the argument here is the offending -# *token*, not a grammar symbol (hence the need to use t.value) -def p_error(t): - if t: - error(t.lineno, "syntax error at '%s'" % t.value) - else: - error(0, "unknown syntax error", True) - -# END OF GRAMMAR RULES -# -# Now build the parser. -yacc.yacc() - - -##################################################################### -# -# Support Classes -# -##################################################################### - -# Expand template with CPU-specific references into a dictionary with -# an entry for each CPU model name. The entry key is the model name -# and the corresponding value is the template with the CPU-specific -# refs substituted for that model. -def expand_cpu_symbols_to_dict(template): - # Protect '%'s that don't go with CPU-specific terms - t = re.sub(r'%(?!\(CPU_)', '%%', template) - result = {} - for cpu in cpu_models: - result[cpu.name] = t % cpu.strings - return result - -# *If* the template has CPU-specific references, return a single -# string containing a copy of the template for each CPU model with the -# corresponding values substituted in. If the template has no -# CPU-specific references, it is returned unmodified. -def expand_cpu_symbols_to_string(template): - if template.find('%(CPU_') != -1: - return reduce(lambda x,y: x+y, - expand_cpu_symbols_to_dict(template).values()) - else: - return template - -# Protect CPU-specific references by doubling the corresponding '%'s -# (in preparation for substituting a different set of references into -# the template). -def protect_cpu_symbols(template): - return re.sub(r'%(?=\(CPU_)', '%%', template) - -############### -# GenCode class -# -# The GenCode class encapsulates generated code destined for various -# output files. The header_output and decoder_output attributes are -# strings containing code destined for decoder.hh and decoder.cc -# respectively. The decode_block attribute contains code to be -# incorporated in the decode function itself (that will also end up in -# decoder.cc). The exec_output attribute is a dictionary with a key -# for each CPU model name; the value associated with a particular key -# is the string of code for that CPU model's exec.cc file. The -# has_decode_default attribute is used in the decode block to allow -# explicit default clauses to override default default clauses. - -class GenCode: - # Constructor. At this point we substitute out all CPU-specific - # symbols. For the exec output, these go into the per-model - # dictionary. For all other output types they get collapsed into - # a single string. - def __init__(self, - header_output = '', decoder_output = '', exec_output = '', - decode_block = '', has_decode_default = False): - self.header_output = expand_cpu_symbols_to_string(header_output) - self.decoder_output = expand_cpu_symbols_to_string(decoder_output) - if isinstance(exec_output, dict): - self.exec_output = exec_output - elif isinstance(exec_output, str): - # If the exec_output arg is a single string, we replicate - # it for each of the CPU models, substituting and - # %(CPU_foo)s params appropriately. - self.exec_output = expand_cpu_symbols_to_dict(exec_output) - self.decode_block = expand_cpu_symbols_to_string(decode_block) - self.has_decode_default = has_decode_default - - # Override '+' operator: generate a new GenCode object that - # concatenates all the individual strings in the operands. - def __add__(self, other): - exec_output = {} - for cpu in cpu_models: - n = cpu.name - exec_output[n] = self.exec_output[n] + other.exec_output[n] - return GenCode(self.header_output + other.header_output, - self.decoder_output + other.decoder_output, - exec_output, - self.decode_block + other.decode_block, - self.has_decode_default or other.has_decode_default) - - # Prepend a string (typically a comment) to all the strings. - def prepend_all(self, pre): - self.header_output = pre + self.header_output - self.decoder_output = pre + self.decoder_output - self.decode_block = pre + self.decode_block - for cpu in cpu_models: - self.exec_output[cpu.name] = pre + self.exec_output[cpu.name] - - # Wrap the decode block in a pair of strings (e.g., 'case foo:' - # and 'break;'). Used to build the big nested switch statement. - def wrap_decode_block(self, pre, post = ''): - self.decode_block = pre + indent(self.decode_block) + post - -################ -# Format object. -# -# A format object encapsulates an instruction format. It must provide -# a defineInst() method that generates the code for an instruction -# definition. - -exportContextSymbols = ('InstObjParams', 'CodeBlock', - 'makeList', 're', 'string') - -exportContext = {} - -def updateExportContext(): - exportContext.update(exportDict(*exportContextSymbols)) - exportContext.update(templateMap) - -def exportDict(*symNames): - return dict([(s, eval(s)) for s in symNames]) - - -class Format: - def __init__(self, id, params, code): - # constructor: just save away arguments - self.id = id - self.params = params - label = 'def format ' + id - self.user_code = compile(fixPythonIndentation(code), label, 'exec') - param_list = string.join(params, ", ") - f = '''def defInst(_code, _context, %s): - my_locals = vars().copy() - exec _code in _context, my_locals - return my_locals\n''' % param_list - c = compile(f, label + ' wrapper', 'exec') - exec c - self.func = defInst - - def defineInst(self, name, args, lineno): - context = {} - updateExportContext() - context.update(exportContext) - context.update({ 'name': name, 'Name': string.capitalize(name) }) - try: - vars = self.func(self.user_code, context, *args[0], **args[1]) - except Exception, exc: - error(lineno, 'error defining "%s": %s.' % (name, exc)) - for k in vars.keys(): - if k not in ('header_output', 'decoder_output', - 'exec_output', 'decode_block'): - del vars[k] - return GenCode(**vars) - -# Special null format to catch an implicit-format instruction -# definition outside of any format block. -class NoFormat: - def __init__(self): - self.defaultInst = '' - - def defineInst(self, name, args, lineno): - error(lineno, - 'instruction definition "%s" with no active format!' % name) - -# This dictionary maps format name strings to Format objects. -formatMap = {} - -# Define a new format -def defFormat(id, params, code, lineno): - # make sure we haven't already defined this one - if formatMap.get(id, None) != None: - error(lineno, 'format %s redefined.' % id) - # create new object and store in global map - formatMap[id] = Format(id, params, code) - - -############## -# Stack: a simple stack object. Used for both formats (formatStack) -# and default cases (defaultStack). Simply wraps a list to give more -# stack-like syntax and enable initialization with an argument list -# (as opposed to an argument that's a list). - -class Stack(list): - def __init__(self, *items): - list.__init__(self, items) - - def push(self, item): - self.append(item); - - def top(self): - return self[-1] - -# The global format stack. -formatStack = Stack(NoFormat()) - -# The global default case stack. -defaultStack = Stack( None ) - -# Global stack that tracks current file and line number. -# Each element is a tuple (filename, lineno) that records the -# *current* filename and the line number in the *previous* file where -# it was included. -fileNameStack = Stack() - -################### -# Utility functions - -# -# Indent every line in string 's' by two spaces -# (except preprocessor directives). -# Used to make nested code blocks look pretty. -# -def indent(s): - return re.sub(r'(?m)^(?!#)', ' ', s) - -# -# Munge a somewhat arbitrarily formatted piece of Python code -# (e.g. from a format 'let' block) into something whose indentation -# will get by the Python parser. -# -# The two keys here are that Python will give a syntax error if -# there's any whitespace at the beginning of the first line, and that -# all lines at the same lexical nesting level must have identical -# indentation. Unfortunately the way code literals work, an entire -# let block tends to have some initial indentation. Rather than -# trying to figure out what that is and strip it off, we prepend 'if -# 1:' to make the let code the nested block inside the if (and have -# the parser automatically deal with the indentation for us). -# -# We don't want to do this if (1) the code block is empty or (2) the -# first line of the block doesn't have any whitespace at the front. - -def fixPythonIndentation(s): - # get rid of blank lines first - s = re.sub(r'(?m)^\s*\n', '', s); - if (s != '' and re.match(r'[ \t]', s[0])): - s = 'if 1:\n' + s - return s - -# Error handler. Just call exit. Output formatted to work under -# Emacs compile-mode. Optional 'print_traceback' arg, if set to True, -# prints a Python stack backtrace too (can be handy when trying to -# debug the parser itself). -def error(lineno, string, print_traceback = False): - spaces = "" - for (filename, line) in fileNameStack[0:-1]: - print spaces + "In file included from " + filename + ":" - spaces += " " - # Print a Python stack backtrace if requested. - if (print_traceback): - traceback.print_exc() - if lineno != 0: - line_str = "%d:" % lineno - else: - line_str = "" - sys.exit(spaces + "%s:%s %s" % (fileNameStack[-1][0], line_str, string)) - - -##################################################################### -# -# Bitfield Operator Support -# -##################################################################### - -bitOp1ArgRE = re.compile(r'<\s*(\w+)\s*:\s*>') - -bitOpWordRE = re.compile(r'(?<![\w\.])([\w\.]+)<\s*(\w+)\s*:\s*(\w+)\s*>') -bitOpExprRE = re.compile(r'\)<\s*(\w+)\s*:\s*(\w+)\s*>') - -def substBitOps(code): - # first convert single-bit selectors to two-index form - # i.e., <n> --> <n:n> - code = bitOp1ArgRE.sub(r'<\1:\1>', code) - # simple case: selector applied to ID (name) - # i.e., foo<a:b> --> bits(foo, a, b) - code = bitOpWordRE.sub(r'bits(\1, \2, \3)', code) - # if selector is applied to expression (ending in ')'), - # we need to search backward for matching '(' - match = bitOpExprRE.search(code) - while match: - exprEnd = match.start() - here = exprEnd - 1 - nestLevel = 1 - while nestLevel > 0: - if code[here] == '(': - nestLevel -= 1 - elif code[here] == ')': - nestLevel += 1 - here -= 1 - if here < 0: - sys.exit("Didn't find '('!") - exprStart = here+1 - newExpr = r'bits(%s, %s, %s)' % (code[exprStart:exprEnd+1], - match.group(1), match.group(2)) - code = code[:exprStart] + newExpr + code[match.end():] - match = bitOpExprRE.search(code) - return code - - -#################### -# Template objects. -# -# Template objects are format strings that allow substitution from -# the attribute spaces of other objects (e.g. InstObjParams instances). - -class Template: - def __init__(self, t): - self.template = t - - def subst(self, d): - # Start with the template namespace. Make a copy since we're - # going to modify it. - myDict = templateMap.copy() - # if the argument is a dictionary, we just use it. - if isinstance(d, dict): - myDict.update(d) - # if the argument is an object, we use its attribute map. - elif hasattr(d, '__dict__'): - myDict.update(d.__dict__) - else: - raise TypeError, "Template.subst() arg must be or have dictionary" - # Protect non-Python-dict substitutions (e.g. if there's a printf - # in the templated C++ code) - template = protect_non_subst_percents(self.template) - # CPU-model-specific substitutions are handled later (in GenCode). - template = protect_cpu_symbols(template) - return template % myDict - - # Convert to string. This handles the case when a template with a - # CPU-specific term gets interpolated into another template or into - # an output block. - def __str__(self): - return expand_cpu_symbols_to_string(self.template) - -##################################################################### -# -# Code Parser -# -# The remaining code is the support for automatically extracting -# instruction characteristics from pseudocode. -# -##################################################################### - -# Force the argument to be a list. Useful for flags, where a caller -# can specify a singleton flag or a list of flags. Also usful for -# converting tuples to lists so they can be modified. -def makeList(arg): - if isinstance(arg, list): - return arg - elif isinstance(arg, tuple): - return list(arg) - elif not arg: - return [] - else: - return [ arg ] - -# Generate operandTypeMap from the user's 'def operand_types' -# statement. -def buildOperandTypeMap(userDict, lineno): - global operandTypeMap - operandTypeMap = {} - for (ext, (desc, size)) in userDict.iteritems(): - if desc == 'signed int': - ctype = 'int%d_t' % size - is_signed = 1 - elif desc == 'unsigned int': - ctype = 'uint%d_t' % size - is_signed = 0 - elif desc == 'float': - is_signed = 1 # shouldn't really matter - if size == 32: - ctype = 'float' - elif size == 64: - ctype = 'double' - if ctype == '': - error(lineno, 'Unrecognized type description "%s" in userDict') - operandTypeMap[ext] = (size, ctype, is_signed) - -# -# -# -# Base class for operand descriptors. An instance of this class (or -# actually a class derived from this one) represents a specific -# operand for a code block (e.g, "Rc.sq" as a dest). Intermediate -# derived classes encapsulates the traits of a particular operand type -# (e.g., "32-bit integer register"). -# -class Operand(object): - def __init__(self, full_name, ext, is_src, is_dest): - self.full_name = full_name - self.ext = ext - self.is_src = is_src - self.is_dest = is_dest - # The 'effective extension' (eff_ext) is either the actual - # extension, if one was explicitly provided, or the default. - if ext: - self.eff_ext = ext - else: - self.eff_ext = self.dflt_ext - - (self.size, self.ctype, self.is_signed) = operandTypeMap[self.eff_ext] - - # note that mem_acc_size is undefined for non-mem operands... - # template must be careful not to use it if it doesn't apply. - if self.isMem(): - self.mem_acc_size = self.makeAccSize() - self.mem_acc_type = self.ctype - - # Finalize additional fields (primarily code fields). This step - # is done separately since some of these fields may depend on the - # register index enumeration that hasn't been performed yet at the - # time of __init__(). - def finalize(self): - self.flags = self.getFlags() - self.constructor = self.makeConstructor() - self.op_decl = self.makeDecl() - - if self.is_src: - self.op_rd = self.makeRead() - self.op_src_decl = self.makeDecl() - else: - self.op_rd = '' - self.op_src_decl = '' - - if self.is_dest: - self.op_wb = self.makeWrite() - self.op_dest_decl = self.makeDecl() - else: - self.op_wb = '' - self.op_dest_decl = '' - - def isMem(self): - return 0 - - def isReg(self): - return 0 - - def isFloatReg(self): - return 0 - - def isIntReg(self): - return 0 - - def isControlReg(self): - return 0 - - def getFlags(self): - # note the empty slice '[:]' gives us a copy of self.flags[0] - # instead of a reference to it - my_flags = self.flags[0][:] - if self.is_src: - my_flags += self.flags[1] - if self.is_dest: - my_flags += self.flags[2] - return my_flags - - def makeDecl(self): - # Note that initializations in the declarations are solely - # to avoid 'uninitialized variable' errors from the compiler. - return self.ctype + ' ' + self.base_name + ' = 0;\n'; - -class IntRegOperand(Operand): - def isReg(self): - return 1 - - def isIntReg(self): - return 1 - - def makeConstructor(self): - c = '' - if self.is_src: - c += '\n\t_srcRegIdx[%d] = %s;' % \ - (self.src_reg_idx, self.reg_spec) - if self.is_dest: - c += '\n\t_destRegIdx[%d] = %s;' % \ - (self.dest_reg_idx, self.reg_spec) - return c - - def makeRead(self): - if (self.ctype == 'float' or self.ctype == 'double'): - error(0, 'Attempt to read integer register as FP') - if (self.size == self.dflt_size): - return '%s = xc->readIntReg(this, %d);\n' % \ - (self.base_name, self.src_reg_idx) - else: - return '%s = bits(xc->readIntReg(this, %d), %d, 0);\n' % \ - (self.base_name, self.src_reg_idx, self.size-1) - - def makeWrite(self): - if (self.ctype == 'float' or self.ctype == 'double'): - error(0, 'Attempt to write integer register as FP') - if (self.size != self.dflt_size and self.is_signed): - final_val = 'sext<%d>(%s)' % (self.size, self.base_name) - else: - final_val = self.base_name - wb = ''' - { - %s final_val = %s; - xc->setIntReg(this, %d, final_val);\n - if (traceData) { traceData->setData(final_val); } - }''' % (self.dflt_ctype, final_val, self.dest_reg_idx) - return wb - -class FloatRegOperand(Operand): - def isReg(self): - return 1 - - def isFloatReg(self): - return 1 - - def makeConstructor(self): - c = '' - if self.is_src: - c += '\n\t_srcRegIdx[%d] = %s + FP_Base_DepTag;' % \ - (self.src_reg_idx, self.reg_spec) - if self.is_dest: - c += '\n\t_destRegIdx[%d] = %s + FP_Base_DepTag;' % \ - (self.dest_reg_idx, self.reg_spec) - return c - - def makeRead(self): - bit_select = 0 - if (self.ctype == 'float'): - func = 'readFloatRegSingle' - elif (self.ctype == 'double'): - func = 'readFloatRegDouble' - else: - func = 'readFloatRegInt' - if (self.size != self.dflt_size): - bit_select = 1 - base = 'xc->%s(this, %d)' % \ - (func, self.src_reg_idx) - if bit_select: - return '%s = bits(%s, %d, 0);\n' % \ - (self.base_name, base, self.size-1) - else: - return '%s = %s;\n' % (self.base_name, base) - - def makeWrite(self): - final_val = self.base_name - final_ctype = self.ctype - if (self.ctype == 'float'): - func = 'setFloatRegSingle' - elif (self.ctype == 'double'): - func = 'setFloatRegDouble' - else: - func = 'setFloatRegInt' - final_ctype = 'uint%d_t' % self.dflt_size - if (self.size != self.dflt_size and self.is_signed): - final_val = 'sext<%d>(%s)' % (self.size, self.base_name) - wb = ''' - { - %s final_val = %s; - xc->%s(this, %d, final_val);\n - if (traceData) { traceData->setData(final_val); } - }''' % (final_ctype, final_val, func, self.dest_reg_idx) - return wb - -class ControlRegOperand(Operand): - def isReg(self): - return 1 - - def isControlReg(self): - return 1 - - def makeConstructor(self): - c = '' - if self.is_src: - c += '\n\t_srcRegIdx[%d] = %s;' % \ - (self.src_reg_idx, self.reg_spec) - if self.is_dest: - c += '\n\t_destRegIdx[%d] = %s;' % \ - (self.dest_reg_idx, self.reg_spec) - return c - - def makeRead(self): - bit_select = 0 - if (self.ctype == 'float' or self.ctype == 'double'): - error(0, 'Attempt to read control register as FP') - base = 'xc->readMiscReg(%s)' % self.reg_spec - if self.size == self.dflt_size: - return '%s = %s;\n' % (self.base_name, base) - else: - return '%s = bits(%s, %d, 0);\n' % \ - (self.base_name, base, self.size-1) - - def makeWrite(self): - if (self.ctype == 'float' or self.ctype == 'double'): - error(0, 'Attempt to write control register as FP') - wb = 'xc->setMiscReg(%s, %s);\n' % (self.reg_spec, self.base_name) - wb += 'if (traceData) { traceData->setData(%s); }' % \ - self.base_name - return wb - -class MemOperand(Operand): - def isMem(self): - return 1 - - def makeConstructor(self): - return '' - - def makeDecl(self): - # Note that initializations in the declarations are solely - # to avoid 'uninitialized variable' errors from the compiler. - # Declare memory data variable. - c = '%s %s = 0;\n' % (self.ctype, self.base_name) - return c - - def makeRead(self): - return '' - - def makeWrite(self): - return '' - - # Return the memory access size *in bits*, suitable for - # forming a type via "uint%d_t". Divide by 8 if you want bytes. - def makeAccSize(self): - return self.size - - -class NPCOperand(Operand): - def makeConstructor(self): - return '' - - def makeRead(self): - return '%s = xc->readPC() + 4;\n' % self.base_name - - def makeWrite(self): - return 'xc->setNextPC(%s);\n' % self.base_name - -class NNPCOperand(Operand): - def makeConstructor(self): - return '' - - def makeRead(self): - return '%s = xc->readPC() + 8;\n' % self.base_name - - def makeWrite(self): - return 'xc->setNextNPC(%s);\n' % self.base_name - -def buildOperandNameMap(userDict, lineno): - global operandNameMap - operandNameMap = {} - for (op_name, val) in userDict.iteritems(): - (base_cls_name, dflt_ext, reg_spec, flags, sort_pri) = val - (dflt_size, dflt_ctype, dflt_is_signed) = operandTypeMap[dflt_ext] - # Canonical flag structure is a triple of lists, where each list - # indicates the set of flags implied by this operand always, when - # used as a source, and when used as a dest, respectively. - # For simplicity this can be initialized using a variety of fairly - # obvious shortcuts; we convert these to canonical form here. - if not flags: - # no flags specified (e.g., 'None') - flags = ( [], [], [] ) - elif isinstance(flags, str): - # a single flag: assumed to be unconditional - flags = ( [ flags ], [], [] ) - elif isinstance(flags, list): - # a list of flags: also assumed to be unconditional - flags = ( flags, [], [] ) - elif isinstance(flags, tuple): - # it's a tuple: it should be a triple, - # but each item could be a single string or a list - (uncond_flags, src_flags, dest_flags) = flags - flags = (makeList(uncond_flags), - makeList(src_flags), makeList(dest_flags)) - # Accumulate attributes of new operand class in tmp_dict - tmp_dict = {} - for attr in ('dflt_ext', 'reg_spec', 'flags', 'sort_pri', - 'dflt_size', 'dflt_ctype', 'dflt_is_signed'): - tmp_dict[attr] = eval(attr) - tmp_dict['base_name'] = op_name - # New class name will be e.g. "IntReg_Ra" - cls_name = base_cls_name + '_' + op_name - # Evaluate string arg to get class object. Note that the - # actual base class for "IntReg" is "IntRegOperand", i.e. we - # have to append "Operand". - try: - base_cls = eval(base_cls_name + 'Operand') - except NameError: - error(lineno, - 'error: unknown operand base class "%s"' % base_cls_name) - # The following statement creates a new class called - # <cls_name> as a subclass of <base_cls> with the attributes - # in tmp_dict, just as if we evaluated a class declaration. - operandNameMap[op_name] = type(cls_name, (base_cls,), tmp_dict) - - # Define operand variables. - operands = userDict.keys() - - operandsREString = (r''' - (?<![\w\.]) # neg. lookbehind assertion: prevent partial matches - ((%s)(?:\.(\w+))?) # match: operand with optional '.' then suffix - (?![\w\.]) # neg. lookahead assertion: prevent partial matches - ''' - % string.join(operands, '|')) - - global operandsRE - operandsRE = re.compile(operandsREString, re.MULTILINE|re.VERBOSE) - - # Same as operandsREString, but extension is mandatory, and only two - # groups are returned (base and ext, not full name as above). - # Used for subtituting '_' for '.' to make C++ identifiers. - operandsWithExtREString = (r'(?<![\w\.])(%s)\.(\w+)(?![\w\.])' - % string.join(operands, '|')) - - global operandsWithExtRE - operandsWithExtRE = re.compile(operandsWithExtREString, re.MULTILINE) - - -class OperandList: - - # Find all the operands in the given code block. Returns an operand - # descriptor list (instance of class OperandList). - def __init__(self, code): - self.items = [] - self.bases = {} - # delete comments so we don't match on reg specifiers inside - code = commentRE.sub('', code) - # search for operands - next_pos = 0 - while 1: - match = operandsRE.search(code, next_pos) - if not match: - # no more matches: we're done - break - op = match.groups() - # regexp groups are operand full name, base, and extension - (op_full, op_base, op_ext) = op - # if the token following the operand is an assignment, this is - # a destination (LHS), else it's a source (RHS) - is_dest = (assignRE.match(code, match.end()) != None) - is_src = not is_dest - # see if we've already seen this one - op_desc = self.find_base(op_base) - if op_desc: - if op_desc.ext != op_ext: - error(0, 'Inconsistent extensions for operand %s' % \ - op_base) - op_desc.is_src = op_desc.is_src or is_src - op_desc.is_dest = op_desc.is_dest or is_dest - else: - # new operand: create new descriptor - op_desc = operandNameMap[op_base](op_full, op_ext, - is_src, is_dest) - self.append(op_desc) - # start next search after end of current match - next_pos = match.end() - self.sort() - # enumerate source & dest register operands... used in building - # constructor later - self.numSrcRegs = 0 - self.numDestRegs = 0 - self.numFPDestRegs = 0 - self.numIntDestRegs = 0 - self.memOperand = None - for op_desc in self.items: - if op_desc.isReg(): - if op_desc.is_src: - op_desc.src_reg_idx = self.numSrcRegs - self.numSrcRegs += 1 - if op_desc.is_dest: - op_desc.dest_reg_idx = self.numDestRegs - self.numDestRegs += 1 - if op_desc.isFloatReg(): - self.numFPDestRegs += 1 - elif op_desc.isIntReg(): - self.numIntDestRegs += 1 - elif op_desc.isMem(): - if self.memOperand: - error(0, "Code block has more than one memory operand.") - self.memOperand = op_desc - # now make a final pass to finalize op_desc fields that may depend - # on the register enumeration - for op_desc in self.items: - op_desc.finalize() - - def __len__(self): - return len(self.items) - - def __getitem__(self, index): - return self.items[index] - - def append(self, op_desc): - self.items.append(op_desc) - self.bases[op_desc.base_name] = op_desc - - def find_base(self, base_name): - # like self.bases[base_name], but returns None if not found - # (rather than raising exception) - return self.bases.get(base_name) - - # internal helper function for concat[Some]Attr{Strings|Lists} - def __internalConcatAttrs(self, attr_name, filter, result): - for op_desc in self.items: - if filter(op_desc): - result += getattr(op_desc, attr_name) - return result - - # return a single string that is the concatenation of the (string) - # values of the specified attribute for all operands - def concatAttrStrings(self, attr_name): - return self.__internalConcatAttrs(attr_name, lambda x: 1, '') - - # like concatAttrStrings, but only include the values for the operands - # for which the provided filter function returns true - def concatSomeAttrStrings(self, filter, attr_name): - return self.__internalConcatAttrs(attr_name, filter, '') - - # return a single list that is the concatenation of the (list) - # values of the specified attribute for all operands - def concatAttrLists(self, attr_name): - return self.__internalConcatAttrs(attr_name, lambda x: 1, []) - - # like concatAttrLists, but only include the values for the operands - # for which the provided filter function returns true - def concatSomeAttrLists(self, filter, attr_name): - return self.__internalConcatAttrs(attr_name, filter, []) - - def sort(self): - self.items.sort(lambda a, b: a.sort_pri - b.sort_pri) - -# Regular expression object to match C++ comments -# (used in findOperands()) -commentRE = re.compile(r'//.*\n') - -# Regular expression object to match assignment statements -# (used in findOperands()) -assignRE = re.compile(r'\s*=(?!=)', re.MULTILINE) - -# Munge operand names in code string to make legal C++ variable names. -# This means getting rid of the type extension if any. -# (Will match base_name attribute of Operand object.) -def substMungedOpNames(code): - return operandsWithExtRE.sub(r'\1', code) - -def joinLists(t): - return map(string.join, t) - -def makeFlagConstructor(flag_list): - if len(flag_list) == 0: - return '' - # filter out repeated flags - flag_list.sort() - i = 1 - while i < len(flag_list): - if flag_list[i] == flag_list[i-1]: - del flag_list[i] - else: - i += 1 - pre = '\n\tflags[' - post = '] = true;' - code = pre + string.join(flag_list, post + pre) + post - return code - -class CodeBlock: - def __init__(self, code): - self.orig_code = code - self.operands = OperandList(code) - self.code = substMungedOpNames(substBitOps(code)) - self.constructor = self.operands.concatAttrStrings('constructor') - self.constructor += \ - '\n\t_numSrcRegs = %d;' % self.operands.numSrcRegs - self.constructor += \ - '\n\t_numDestRegs = %d;' % self.operands.numDestRegs - self.constructor += \ - '\n\t_numFPDestRegs = %d;' % self.operands.numFPDestRegs - self.constructor += \ - '\n\t_numIntDestRegs = %d;' % self.operands.numIntDestRegs - - self.op_decl = self.operands.concatAttrStrings('op_decl') - - is_src = lambda op: op.is_src - is_dest = lambda op: op.is_dest - - self.op_src_decl = \ - self.operands.concatSomeAttrStrings(is_src, 'op_src_decl') - self.op_dest_decl = \ - self.operands.concatSomeAttrStrings(is_dest, 'op_dest_decl') - - self.op_rd = self.operands.concatAttrStrings('op_rd') - self.op_wb = self.operands.concatAttrStrings('op_wb') - - self.flags = self.operands.concatAttrLists('flags') - - if self.operands.memOperand: - self.mem_acc_size = self.operands.memOperand.mem_acc_size - self.mem_acc_type = self.operands.memOperand.mem_acc_type - - # Make a basic guess on the operand class (function unit type). - # These are good enough for most cases, and will be overridden - # later otherwise. - if 'IsStore' in self.flags: - self.op_class = 'MemWriteOp' - elif 'IsLoad' in self.flags or 'IsPrefetch' in self.flags: - self.op_class = 'MemReadOp' - elif 'IsFloating' in self.flags: - self.op_class = 'FloatAddOp' - else: - self.op_class = 'IntAluOp' - -# Assume all instruction flags are of the form 'IsFoo' -instFlagRE = re.compile(r'Is.*') - -# OpClass constants end in 'Op' except No_OpClass -opClassRE = re.compile(r'.*Op|No_OpClass') - -class InstObjParams: - def __init__(self, mnem, class_name, base_class = '', - code_block = None, opt_args = []): - self.mnemonic = mnem - self.class_name = class_name - self.base_class = base_class - if code_block: - for code_attr in code_block.__dict__.keys(): - setattr(self, code_attr, getattr(code_block, code_attr)) - else: - self.constructor = '' - self.flags = [] - # Optional arguments are assumed to be either StaticInst flags - # or an OpClass value. To avoid having to import a complete - # list of these values to match against, we do it ad-hoc - # with regexps. - for oa in opt_args: - if instFlagRE.match(oa): - self.flags.append(oa) - elif opClassRE.match(oa): - self.op_class = oa - else: - error(0, 'InstObjParams: optional arg "%s" not recognized ' - 'as StaticInst::Flag or OpClass.' % oa) - - # add flag initialization to contructor here to include - # any flags added via opt_args - self.constructor += makeFlagConstructor(self.flags) - - # if 'IsFloating' is set, add call to the FP enable check - # function (which should be provided by isa_desc via a declare) - if 'IsFloating' in self.flags: - self.fp_enable_check = 'fault = checkFpEnableFault(xc);' - else: - self.fp_enable_check = '' - -####################### -# -# Output file template -# - -file_template = ''' -/* - * DO NOT EDIT THIS FILE!!! - * - * It was automatically generated from the ISA description in %(filename)s - */ - -%(includes)s - -%(global_output)s - -namespace %(namespace)s { - -%(namespace_output)s - -} // namespace %(namespace)s - -%(decode_function)s -''' - - -# Update the output file only if the new contents are different from -# the current contents. Minimizes the files that need to be rebuilt -# after minor changes. -def update_if_needed(file, contents): - update = False - if os.access(file, os.R_OK): - f = open(file, 'r') - old_contents = f.read() - f.close() - if contents != old_contents: - print 'Updating', file - os.remove(file) # in case it's write-protected - update = True - else: - print 'File', file, 'is unchanged' - else: - print 'Generating', file - update = True - if update: - f = open(file, 'w') - f.write(contents) - f.close() - -# This regular expression matches '##include' directives -includeRE = re.compile(r'^\s*##include\s+"(?P<filename>[\w/.-]*)".*$', - re.MULTILINE) - -# Function to replace a matched '##include' directive with the -# contents of the specified file (with nested ##includes replaced -# recursively). 'matchobj' is an re match object (from a match of -# includeRE) and 'dirname' is the directory relative to which the file -# path should be resolved. -def replace_include(matchobj, dirname): - fname = matchobj.group('filename') - full_fname = os.path.normpath(os.path.join(dirname, fname)) - contents = '##newfile "%s"\n%s\n##endfile\n' % \ - (full_fname, read_and_flatten(full_fname)) - return contents - -# Read a file and recursively flatten nested '##include' files. -def read_and_flatten(filename): - current_dir = os.path.dirname(filename) - try: - contents = open(filename).read() - except IOError: - error(0, 'Error including file "%s"' % filename) - fileNameStack.push((filename, 0)) - # Find any includes and include them - contents = includeRE.sub(lambda m: replace_include(m, current_dir), - contents) - fileNameStack.pop() - return contents - -# -# Read in and parse the ISA description. -# -def parse_isa_desc(isa_desc_file, output_dir): - # Read file and (recursively) all included files into a string. - # PLY requires that the input be in a single string so we have to - # do this up front. - isa_desc = read_and_flatten(isa_desc_file) - - # Initialize filename stack with outer file. - fileNameStack.push((isa_desc_file, 0)) - - # Parse it. - (isa_name, namespace, global_code, namespace_code) = yacc.parse(isa_desc) - - # grab the last three path components of isa_desc_file to put in - # the output - filename = '/'.join(isa_desc_file.split('/')[-3:]) - - # generate decoder.hh - includes = '#include "base/bitfield.hh" // for bitfield support' - global_output = global_code.header_output - namespace_output = namespace_code.header_output - decode_function = '' - update_if_needed(output_dir + '/decoder.hh', file_template % vars()) - - # generate decoder.cc - includes = '#include "decoder.hh"' - global_output = global_code.decoder_output - namespace_output = namespace_code.decoder_output - # namespace_output += namespace_code.decode_block - decode_function = namespace_code.decode_block - update_if_needed(output_dir + '/decoder.cc', file_template % vars()) - - # generate per-cpu exec files - for cpu in cpu_models: - includes = '#include "decoder.hh"\n' - includes += cpu.includes - global_output = global_code.exec_output[cpu.name] - namespace_output = namespace_code.exec_output[cpu.name] - decode_function = '' - update_if_needed(output_dir + '/' + cpu.filename, - file_template % vars()) - -# global list of CpuModel objects (see cpu_models.py) -cpu_models = [] - -# Called as script: get args from command line. -# Args are: <path to cpu_models.py> <isa desc file> <output dir> <cpu models> -if __name__ == '__main__': - execfile(sys.argv[1]) # read in CpuModel definitions - cpu_models = [CpuModel.dict[cpu] for cpu in sys.argv[4:]] - parse_isa_desc(sys.argv[2], sys.argv[3]) diff --git a/arch/isa_specific.hh b/arch/isa_specific.hh deleted file mode 100644 index 44f8e9d64..000000000 --- a/arch/isa_specific.hh +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __ARCH_ISA_SPECIFIC_HH__ -#define __ARCH_ISA_SPECIFIC_HH__ - -//This file provides a mechanism for other source code to bring in -//files from the ISA being compiled with - -//These are constants so you can selective compile code based on the isa -//To use them, do something like -// -//#if THE_ISA == YOUR_FAVORITE_ISA -// conditional_code -//#endif -// -//Note that this is how this file sets up the other isa "hooks" - -//These macros have numerical values because otherwise the preprocessor -//would treat them as 0 in comparisons. -#define ALPHA_ISA 21064 -#define SPARC_ISA 42 -#define MIPS_ISA 1337 - -//These tell the preprocessor where to find the files of a particular -//ISA, and set the "TheISA" macro for use elsewhere. -#if THE_ISA == ALPHA_ISA - #define TheISA AlphaISA -#elif THE_ISA == SPARC_ISA - #define TheISA SparcISA -#elif THE_ISA == MIPS_ISA - #define TheISA MipsISA -#else - #error "THE_ISA not set" -#endif - -#endif diff --git a/arch/mips/SConscript b/arch/mips/SConscript deleted file mode 100644 index b8efa7ef9..000000000 --- a/arch/mips/SConscript +++ /dev/null @@ -1,83 +0,0 @@ -# -*- mode:python -*- - -# 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. - -import os -import sys -from os.path import isdir - -# Import build environment variable from SConstruct. -Import('env') - -################################################### -# -# Define needed sources. -# -################################################### - -# Base sources used by all configurations. -base_sources = Split(''' - faults.cc - isa_traits.cc - ''') - -# Full-system sources -full_system_sources = Split(''' - memory.cc - arguments.cc - mips34k.cc - osfpal.cc - stacktrace.cc - vtophys.cc - ''') - -# Syscall emulation (non-full-system) sources -syscall_emulation_sources = Split(''' - common_syscall_emul.cc - linux_process.cc - tru64_process.cc - ''') - -# Set up complete list of sources based on configuration. -sources = base_sources - -if env['FULL_SYSTEM']: - sources += full_system_sources -else: - sources += syscall_emulation_sources - -# Convert file names to SCons File objects. This takes care of the -# path relative to the top of the directory tree. -sources = [File(s) for s in sources] - -# Add in files generated by the ISA description. -isa_desc_files = env.ISADesc('isa/main.isa') -# Only non-header files need to be compiled. -isa_desc_sources = [f for f in isa_desc_files if not f.path.endswith('.hh')] -sources += isa_desc_sources - -Return('sources') diff --git a/arch/mips/faults.cc b/arch/mips/faults.cc deleted file mode 100644 index 142dfe0a4..000000000 --- a/arch/mips/faults.cc +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include "arch/mips/faults.hh" - -ResetFaultType * const ResetFault = - new ResetFaultType("reset", 1, 0x0001); -ArithmeticFaultType * const ArithmeticFault = - new ArithmeticFaultType("arith", 3, 0x0501); -InterruptFaultType * const InterruptFault = - new InterruptFaultType("interrupt", 4, 0x0101); -NDtbMissFaultType * const NDtbMissFault = - new NDtbMissFaultType("dtb_miss_single", 5, 0x0201); -PDtbMissFaultType * const PDtbMissFault = - new PDtbMissFaultType("dtb_miss_double", 6, 0x0281); -DtbPageFaultType * const DtbPageFault = - new DtbPageFaultType("dfault", 8, 0x0381); -DtbAcvFaultType * const DtbAcvFault = - new DtbAcvFaultType("dfault", 9, 0x0381); -ItbMissFaultType * const ItbMissFault = - new ItbMissFaultType("itbmiss", 10, 0x0181); -ItbPageFaultType * const ItbPageFault = - new ItbPageFaultType("itbmiss", 11, 0x0181); -ItbAcvFaultType * const ItbAcvFault = - new ItbAcvFaultType("iaccvio", 12, 0x0081); -UnimplementedOpcodeFaultType * const UnimplementedOpcodeFault = - new UnimplementedOpcodeFaultType("opdec", 13, 0x0481); -FloatEnableFaultType * const FloatEnableFault = - new FloatEnableFaultType("fen", 14, 0x0581); -PalFaultType * const PalFault = - new PalFaultType("pal", 15, 0x2001); -IntegerOverflowFaultType * const IntegerOverflowFault = - new IntegerOverflowFaultType("intover", 16, 0x0501); - -Fault ** ListOfFaults[] = { - (Fault **)&NoFault, - (Fault **)&ResetFault, - (Fault **)&MachineCheckFault, - (Fault **)&ArithmeticFault, - (Fault **)&InterruptFault, - (Fault **)&NDtbMissFault, - (Fault **)&PDtbMissFault, - (Fault **)&AlignmentFault, - (Fault **)&DtbPageFault, - (Fault **)&DtbAcvFault, - (Fault **)&ItbMissFault, - (Fault **)&ItbPageFault, - (Fault **)&ItbAcvFault, - (Fault **)&UnimplementedOpcodeFault, - (Fault **)&FloatEnableFault, - (Fault **)&PalFault, - (Fault **)&IntegerOverflowFault, - }; - -int NumFaults = sizeof(ListOfFaults) / sizeof(Fault **); diff --git a/arch/mips/faults.hh b/arch/mips/faults.hh deleted file mode 100644 index c1cb956b0..000000000 --- a/arch/mips/faults.hh +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __MIPS_FAULTS_HH__ -#define __MIPS_FAULTS_HH__ - -#include "sim/faults.hh" -#include "arch/isa_traits.hh" //For the Addr type - -class MipsFault : public FaultBase -{ - public: - MipsFault(char * newName, int newId, Addr newVect) - : FaultBase(newName, newId), vect(newVect) - {;} - - Addr vect; -}; - -extern class ResetFaultType : public MipsFault -{ - public: - ResetFaultType(char * newName, int newId, Addr newVect) - : MipsFault(newName, newId, newVect) - {;} -} * const ResetFault; - -extern class ArithmeticFaultType : public MipsFault -{ - public: - ArithmeticFaultType(char * newName, int newId, Addr newVect) - : MipsFault(newName, newId, newVect) - {;} -} * const ArithmeticFault; - -extern class InterruptFaultType : public MipsFault -{ - public: - InterruptFaultType(char * newName, int newId, Addr newVect) - : MipsFault(newName, newId, newVect) - {;} -} * const InterruptFault; - -extern class NDtbMissFaultType : public MipsFault -{ - public: - NDtbMissFaultType(char * newName, int newId, Addr newVect) - : MipsFault(newName, newId, newVect) - {;} -} * const NDtbMissFault; - -extern class PDtbMissFaultType : public MipsFault -{ - public: - PDtbMissFaultType(char * newName, int newId, Addr newVect) - : MipsFault(newName, newId, newVect) - {;} -} * const PDtbMissFault; - -extern class DtbPageFaultType : public MipsFault -{ - public: - DtbPageFaultType(char * newName, int newId, Addr newVect) - : MipsFault(newName, newId, newVect) - {;} -} * const DtbPageFault; - -extern class DtbAcvFaultType : public MipsFault -{ - public: - DtbAcvFaultType(char * newName, int newId, Addr newVect) - : MipsFault(newName, newId, newVect) - {;} -} * const DtbAcvFault; - -extern class ItbMissFaultType : public MipsFault -{ - public: - ItbMissFaultType(char * newName, int newId, Addr newVect) - : MipsFault(newName, newId, newVect) - {;} -} * const ItbMissFault; - -extern class ItbPageFaultType : public MipsFault -{ - public: - ItbPageFaultType(char * newName, int newId, Addr newVect) - : MipsFault(newName, newId, newVect) - {;} -} * const ItbPageFault; - -extern class ItbAcvFaultType : public MipsFault -{ - public: - ItbAcvFaultType(char * newName, int newId, Addr newVect) - : MipsFault(newName, newId, newVect) - {;} -} * const ItbAcvFault; - -extern class UnimplementedOpcodeFaultType : public MipsFault -{ - public: - UnimplementedOpcodeFaultType(char * newName, int newId, Addr newVect) - : MipsFault(newName, newId, newVect) - {;} -} * const UnimplementedOpcodeFault; - -extern class FloatEnableFaultType : public MipsFault -{ - public: - FloatEnableFaultType(char * newName, int newId, Addr newVect) - : MipsFault(newName, newId, newVect) - {;} -} * const FloatEnableFault; - -extern class PalFaultType : public MipsFault -{ - public: - PalFaultType(char * newName, int newId, Addr newVect) - : MipsFault(newName, newId, newVect) - {;} -} * const PalFault; - -extern class IntegerOverflowFaultType : public MipsFault -{ - public: - IntegerOverflowFaultType(char * newName, int newId, Addr newVect) - : MipsFault(newName, newId, newVect) - {;} -} * const IntegerOverflowFault; - -extern Fault ** ListOfFaults[]; -extern int NumFaults; - -#endif // __FAULTS_HH__ diff --git a/arch/mips/isa/base.isa b/arch/mips/isa/base.isa deleted file mode 100644 index 4125b5101..000000000 --- a/arch/mips/isa/base.isa +++ /dev/null @@ -1,96 +0,0 @@ -// -*- mode:c++ -*- - -//////////////////////////////////////////////////////////////////// -// -// Base class for MIPS instructions, and some support functions -// - -//Outputs to decoder.hh -output header {{ - -#define R31 31 -#include "arch/mips/faults.hh" -#include "arch/mips/isa_traits.hh" - - using namespace MipsISA; - - - /** - * Base class for all MIPS static instructions. - */ - class MipsStaticInst : public StaticInst - { - protected: - - /// Make MipsISA register dependence tags directly visible in - /// this class and derived classes. Maybe these should really - /// live here and not in the MipsISA namespace. - /*enum DependenceTags { - FP_Base_DepTag = MipsISA::FP_Base_DepTag, - Fpcr_DepTag = MipsISA::Fpcr_DepTag, - Uniq_DepTag = MipsISA::Uniq_DepTag, - IPR_Base_DepTag = MipsISA::IPR_Base_DepTag - };*/ - - // Constructor - MipsStaticInst(const char *mnem, MachInst _machInst, OpClass __opClass) - : StaticInst(mnem, _machInst, __opClass) - { - } - - /// Print a register name for disassembly given the unique - /// dependence tag number (FP or int). - void printReg(std::ostream &os, int reg) const; - - std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; - -}}; - -//Ouputs to decoder.cc -output decoder {{ - - void MipsStaticInst::printReg(std::ostream &os, int reg) const - { - if (reg < FP_Base_DepTag) { - ccprintf(os, "r%d", reg); - } - else { - ccprintf(os, "f%d", reg - FP_Base_DepTag); - } - } - - std::string MipsStaticInst::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - std::stringstream ss; - - ccprintf(ss, "%-10s ", mnemonic); - - // just print the first two source regs... if there's - // a third one, it's a read-modify-write dest (Rc), - // e.g. for CMOVxx - if(_numSrcRegs > 0) - { - printReg(ss, _srcRegIdx[0]); - } - - if(_numSrcRegs > 1) - { - ss << ","; - printReg(ss, _srcRegIdx[1]); - } - - // just print the first dest... if there's a second one, - // it's generally implicit - if(_numDestRegs > 0) - { - if(_numSrcRegs > 0) - ss << ","; - printReg(ss, _destRegIdx[0]); - } - - return ss.str(); - } - -}}; - diff --git a/arch/mips/isa/bitfields.isa b/arch/mips/isa/bitfields.isa deleted file mode 100644 index 58d487ad2..000000000 --- a/arch/mips/isa/bitfields.isa +++ /dev/null @@ -1,67 +0,0 @@ -// -*- mode:c++ -*- - -//////////////////////////////////////////////////////////////////// -// -// Bitfield definitions. -// - -def bitfield OPCODE <31:26>; -def bitfield OPCODE_HI <31:29>; -def bitfield OPCODE_LO <28:26>; - -def bitfield REGIMM <20:16>; -def bitfield REGIMM_HI <20:19>; -def bitfield REGIMM_LO <18:16>; - -def bitfield FUNCTION < 5: 0>; -def bitfield FUNCTION_HI < 5: 3>; -def bitfield FUNCTION_LO < 2: 0>; - -// Integer operate format -def bitfield RT <20:16>; -def bitfield RT_HI <20:19>; -def bitfield RT_LO <18:16>; - -def bitfield RS <25:21>; -def bitfield RS_MSB <25:25>; -def bitfield RS_HI <25:24>; -def bitfield RS_LO <23:21>; - -def bitfield RD <15:11>; - -def bitfield INTIMM <15: 0>; // integer immediate (literal) - -// Floating-point operate format -def bitfield FMT <25:21>; -def bitfield FR <25:21>; -def bitfield FT <20:16>; -def bitfield FS <15:11>; -def bitfield FD <10:6>; - -def bitfield CC <20:18>; -def bitfield ND <17:17>; -def bitfield TF <16:16>; -def bitfield MOVCI <16:16>; -def bitfield MOVCF <16:16>; -def bitfield SRL <21:21>; -def bitfield SRLV < 6: 6>; -def bitfield SA <10: 6>; - -// CP0 Register Select -def bitfield SEL < 2: 0>; - -// Interrupts -def bitfield SC < 5: 5>; - -// Branch format -def bitfield OFFSET <15: 0>; // displacement - -// Jmp format -def bitfield JMPTARG <25: 0>; -def bitfield HINT <10: 6>; - -def bitfield SYSCALLCODE <25: 6>; -def bitfield TRAPCODE <15:13>; - -// M5 instructions -def bitfield M5FUNC <7:0>; diff --git a/arch/mips/isa/decoder.isa b/arch/mips/isa/decoder.isa deleted file mode 100644 index 3f054f6a5..000000000 --- a/arch/mips/isa/decoder.isa +++ /dev/null @@ -1,930 +0,0 @@ -// -*- mode:c++ -*- - -//////////////////////////////////////////////////////////////////// -// -// The actual MIPS32 ISA decoder -// ----------------------------- -// The following instructions are specified in the MIPS32 ISA -// Specification. Decoding closely follows the style specified -// in the MIPS32 ISAthe specification document starting with Table -// A-2 (document available @ www.mips.com) -// -//@todo: Distinguish "unknown/future" use insts from "reserved" -// ones -decode OPCODE_HI default Unknown::unknown() { - - // Derived From ... Table A-2 MIPS32 ISA Manual - 0x0: decode OPCODE_LO { - - 0x0: decode FUNCTION_HI { - 0x0: decode FUNCTION_LO { - 0x1: decode MOVCI { - format BasicOp { - 0: movf({{ if (xc->readMiscReg(FPCR,0) != CC) Rd = Rs}}); - 1: movt({{ if (xc->readMiscReg(FPCR,0) == CC) Rd = Rs}}); - } - } - - format BasicOp { - - //Table A-3 Note: "1. Specific encodings of the rt, rd, and sa fields - //are used to distinguish among the SLL, NOP, SSNOP and EHB functions." - - 0x0: decode RS { - 0x0: decode RT default BasicOp::sll({{ Rd = Rt.uw << SA; }}) { - 0x0: decode RD{ - 0x0: decode HINT { - 0x0:nop({{}}); //really sll r0,r0,0 - 0x1:ssnop({{}});//really sll r0,r0,1 - 0x3:ehb({{}}); //really sll r0,r0,3 - } - } - } - } - - 0x2: decode SRL { - 0: srl({{ Rd = Rt.uw >> SA; }}); - - //Hardcoded assuming 32-bit ISA, probably need parameter here - 1: rotr({{ Rd = (Rt.uw << (32 - SA)) | (Rt.uw >> SA);}}); - } - - 0x3: sra({{ Rd = Rt.sw >> SA; }}); - - 0x4: sllv({{ Rd = Rt.uw << Rs<4:0>; }}); - - 0x6: decode SRLV { - 0: srlv({{ Rd = Rt.uw >> Rs<4:0>; }}); - - //Hardcoded assuming 32-bit ISA, probably need parameter here - 1: rotrv({{ Rd = (Rt.uw << (32 - Rs<4:0>)) | (Rt.uw >> Rs<4:0>);}}); - } - - 0x7: srav({{ Rd = Rt.sw >> Rs<4:0>; }}); - } - } - - 0x1: decode FUNCTION_LO { - - //Table A-3 Note: "Specific encodings of the hint field are used - //to distinguish JR from JR.HB and JALR from JALR.HB" - format Jump { - 0x0: decode HINT { - 0:jr({{ NNPC = Rs & ~1; }},IsReturn); - - 1:jr_hb({{ NNPC = Rs & ~1; clear_exe_inst_hazards(); }},IsReturn); - } - - 0x1: decode HINT { - 0: jalr({{ NNPC = Rs; }},IsCall,IsReturn); - - 1: jalr_hb({{ NNPC = Rs; clear_exe_inst_hazards();}},IsCall,IsReturn); - } - } - - format BasicOp { - 0x2: movz({{ if (Rt == 0) Rd = Rs; }}); - 0x3: movn({{ if (Rt != 0) Rd = Rs; }}); - } - - format WarnUnimpl { - 0x4: syscall();//{{ xc->syscall()}},IsNonSpeculative - 0x5: break(); - 0x7: sync(); - } - } - - 0x2: decode FUNCTION_LO { - format BasicOp { - 0x0: mfhi({{ Rd = xc->readMiscReg(Hi); }}); - 0x1: mthi({{ xc->setMiscReg(Hi,Rs); }}); - 0x2: mflo({{ Rd = xc->readMiscReg(Lo); }}); - 0x3: mtlo({{ xc->setMiscReg(Lo,Rs); }}); - } - } - - 0x3: decode FUNCTION_LO { - format IntOp { - 0x0: mult({{ - int64_t temp1 = Rs.sw * Rt.sw; - xc->setMiscReg(Hi,temp1<63:32>); - xc->setMiscReg(Lo,temp1<31:0>); - }}); - - 0x1: multu({{ - int64_t temp1 = Rs.uw * Rt.uw; - xc->setMiscReg(Hi,temp1<63:32>); - xc->setMiscReg(Lo,temp1<31:0>); - }}); - - 0x2: div({{ - xc->setMiscReg(Hi,Rs.sw % Rt.sw); - xc->setMiscReg(Lo,Rs.sw / Rt.sw); - }}); - - 0x3: divu({{ - xc->setMiscReg(Hi,Rs.uw % Rt.uw); - xc->setMiscReg(Lo,Rs.uw / Rt.uw); - }}); - } - } - - 0x4: decode FUNCTION_LO { - format IntOp { - 0x0: add({{ Rd.sw = Rs.sw + Rt.sw;/*Trap on Overflow*/}}); - 0x1: addu({{ Rd.sw = Rs.sw + Rt.sw;}}); - 0x2: sub({{ Rd.sw = Rs.sw - Rt.sw; /*Trap on Overflow*/}}); - 0x3: subu({{ Rd.sw = Rs.sw - Rt.uw;}}); - 0x4: and({{ Rd = Rs & Rt;}}); - 0x5: or({{ Rd = Rs | Rt;}}); - 0x6: xor({{ Rd = Rs ^ Rt;}}); - 0x7: nor({{ Rd = ~(Rs | Rt);}}); - } - } - - 0x5: decode FUNCTION_LO { - format IntOp{ - 0x2: slt({{ Rd.sw = ( Rs.sw < Rt.sw ) ? 1 : 0}}); - 0x3: sltu({{ Rd.uw = ( Rs.uw < Rt.uw ) ? 1 : 0}}); - } - } - - 0x6: decode FUNCTION_LO { - format Trap { - 0x0: tge({{ cond = (Rs.sw >= Rt.sw); }}); - 0x1: tgeu({{ cond = (Rs.uw >= Rt.uw); }}); - 0x2: tlt({{ cond = (Rs.sw < Rt.sw); }}); - 0x3: tltu({{ cond = (Rs.uw >= Rt.uw); }}); - 0x4: teq({{ cond = (Rs.sw == Rt.sw); }}); - 0x6: tne({{ cond = (Rs.sw != Rt.sw); }}); - } - } - } - - 0x1: decode REGIMM_HI { - 0x0: decode REGIMM_LO { - format Branch { - 0x0: bltz({{ cond = (Rs.sw < 0); }}); - 0x1: bgez({{ cond = (Rs.sw >= 0); }}); - } - - format BranchLikely { - //MIPS obsolete instructions - 0x2: bltzl({{ cond = (Rs.sw < 0); }}); - 0x3: bgezl({{ cond = (Rs.sw >= 0); }}); - } - } - - 0x1: decode REGIMM_LO { - format Trap { - 0x0: tgei( {{ cond = (Rs.sw >= INTIMM); }}); - 0x1: tgeiu({{ cond = (Rs.uw >= INTIMM); }}); - 0x2: tlti( {{ cond = (Rs.sw < INTIMM); }}); - 0x3: tltiu({{ cond = (Rs.uw < INTIMM); }}); - 0x4: teqi( {{ cond = (Rs.sw == INTIMM);}}); - 0x6: tnei( {{ cond = (Rs.sw != INTIMM);}}); - } - } - - 0x2: decode REGIMM_LO { - format Branch { - 0x0: bltzal({{ cond = (Rs.sw < 0); }}, IsCall,IsReturn); - 0x1: bgezal({{ cond = (Rs.sw >= 0); }}, IsCall,IsReturn); - } - - format BranchLikely { - //Will be removed in future MIPS releases - 0x2: bltzall({{ cond = (Rs.sw < 0); }}, IsCall, IsReturn); - 0x3: bgezall({{ cond = (Rs.sw >= 0); }}, IsCall, IsReturn); - } - } - - 0x3: decode REGIMM_LO { - format WarnUnimpl { - 0x7: synci(); - } - } - } - - format Jump { - 0x2: j({{ NNPC = (NPC & 0xF0000000) | (JMPTARG << 2);}}); - - 0x3: jal({{ NNPC = (NPC & 0xF0000000) | (JMPTARG << 2); }},IsCall,IsReturn); - } - - format Branch { - 0x4: beq({{ cond = (Rs.sw == Rt.sw); }}); - 0x5: bne({{ cond = (Rs.sw != Rt.sw); }}); - 0x6: blez({{ cond = (Rs.sw <= 0); }}); - 0x7: bgtz({{ cond = (Rs.sw > 0); }}); - } - } - - 0x1: decode OPCODE_LO { - format IntOp { - 0x0: addi({{ Rt.sw = Rs.sw + imm; /*Trap If Overflow*/}}); - 0x1: addiu({{ Rt.sw = Rs.sw + imm;}}); - 0x2: slti({{ Rt.sw = ( Rs.sw < imm) ? 1 : 0 }}); - 0x3: sltiu({{ Rt.sw = ( Rs.sw < imm ) ? 1 : 0 }}); - 0x4: andi({{ Rt.sw = Rs.sw & INTIMM;}}); - 0x5: ori({{ Rt.sw = Rs.sw | INTIMM;}}); - 0x6: xori({{ Rt.sw = Rs.sw ^ INTIMM;}}); - 0x7: lui({{ Rt = INTIMM << 16}}); - } - } - - 0x2: decode OPCODE_LO { - - //Table A-11 MIPS32 COP0 Encoding of rs Field - 0x0: decode RS_MSB { - 0x0: decode RS { - format System { - 0x0: mfc0({{ - //uint64_t reg_num = Rd.uw; - - Rt = xc->readMiscReg(RD << 5 | SEL); - }}); - - 0x4: mtc0({{ - //uint64_t reg_num = Rd.uw; - - xc->setMiscReg(RD << 5 | SEL,Rt); - }}); - - 0x8: mftr({{ - //The contents of the coprocessor 0 register specified by the - //combination of rd and sel are loaded into general register - //rt. Note that not all coprocessor 0 registers support the - //sel field. In those instances, the sel field must be zero. - - //MT Code Needed Here - }}); - - 0xC: mttr({{ - //The contents of the coprocessor 0 register specified by the - //combination of rd and sel are loaded into general register - //rt. Note that not all coprocessor 0 registers support the - //sel field. In those instances, the sel field must be zero. - - //MT Code Needed Here - }}); - - - 0xA: rdpgpr({{ - //Accessing Previous Shadow Set Register Number - //uint64_t prev = xc->readMiscReg(SRSCtl)/*[PSS]*/; - //uint64_t reg_num = Rt.uw; - - //Rd = xc->regs.IntRegFile[prev]; - //Rd = xc->shadowIntRegFile[prev][reg_num]; - }}); - - 0xB: decode RD { - - 0x0: decode SC { - 0x0: dvpe({{ - int idx; - int sel; - getMiscRegIdx(MVPControl,idx,sel); - Rt.sw = xc->readMiscReg(idx,sel); - xc->setMiscReg(idx,sel); - }}); - - 0x1: evpe({{ - int idx; - int sel; - getMiscRegIdx(MVPControl,idx,sel); - Rt.sw = xc->readMiscReg(idx,sel); - xc->setMiscReg(idx,sel,1); - }}); - } - - 0x1: decode SC { - 0x0: dmt({{ - int idx; - int sel; - getMiscRegIdx(VPEControl,idx,sel); - Rt.sw = xc->readMiscReg(idx,sel); - xc->setMiscReg(idx,sel); - }}); - - 0x1: emt({{ - int idx; - int sel; - getMiscRegIdx(VPEControl,idx,sel); - Rt.sw = xc->readMiscReg(idx,sel); - xc->setMiscReg(idx,sel,1); - }}); - } - - 0xC: decode SC { - 0x0: di({{ - int idx; - int sel; - getMiscRegIdx(Status,idx,sel); - Rt.sw = xc->readMiscReg(idx,sel); - xc->setMiscReg(idx,sel); - }}); - - 0x1: ei({{ - int idx; - int sel; - getMiscRegIdx(Status,idx,sel); - Rt.sw = xc->readMiscReg(idx,sel); - xc->setMiscReg(idx,sel,1); - }}); - } - } - - 0xE: wrpgpr({{ - //Accessing Previous Shadow Set Register Number - //uint64_t prev = xc->readMiscReg(SRSCtl/*[PSS]*/); - //uint64_t reg_num = Rd.uw; - - //xc->regs.IntRegFile[prev]; - //xc->shadowIntRegFile[prev][reg_num] = Rt; - }}); - } - } - - //Table A-12 MIPS32 COP0 Encoding of Function Field When rs=CO - 0x1: decode FUNCTION { - format System { - 0x01: tlbr({{ }}); - 0x02: tlbwi({{ }}); - 0x06: tlbwr({{ }}); - 0x08: tlbp({{ }}); - } - - format WarnUnimpl { - 0x18: eret(); - 0x1F: deret(); - 0x20: wait(); - } - } - } - - //Table A-13 MIPS32 COP1 Encoding of rs Field - 0x1: decode RS_MSB { - - 0x0: decode RS_HI { - 0x0: decode RS_LO { - format FloatOp { - 0x0: mfc1({{ /*Rt.uw = Fs.ud<31:0>;*/ }}); - 0x2: cfc1({{ /*Rt.uw = xc->readMiscReg(FPCR[Fs]);*/}}); - 0x3: mfhc1({{ /*Rt.uw = Fs.ud<63:32>*/;}}); - 0x4: mtc1({{ /*Fs = Rt.uw*/}}); - 0x6: ctc1({{ /*xc->setMiscReg(FPCR[Fs],Rt);*/}}); - 0x7: mthc1({{ /*Fs<63:32> = Rt.uw*/}}); - } - } - - 0x1: decode ND { - 0x0: decode TF { - format Branch { - 0x0: bc1f({{ cond = (xc->readMiscReg(FPCR) == 0); }}); - 0x1: bc1t({{ cond = (xc->readMiscReg(FPCR) == 1); }}); - } - } - - 0x1: decode TF { - format BranchLikely { - 0x0: bc1fl({{ cond = (xc->readMiscReg(FPCR) == 0); }}); - 0x1: bc1tl({{ cond = (xc->readMiscReg(FPCR) == 1); }}); - } - } - } - } - - 0x1: decode RS_HI { - 0x2: decode RS_LO { - - //Table A-14 MIPS32 COP1 Encoding of Function Field When rs=S - //(( single-word )) - 0x0: decode RS_HI { - 0x0: decode RS_LO { - format FloatOp { - 0x0: adds({{ Fd.sf = Fs.sf + Ft.sf;}}); - 0x1: subs({{ Fd.sf = Fs.sf - Ft.sf;}}); - 0x2: muls({{ Fd.sf = Fs.sf * Ft.sf;}}); - 0x3: divs({{ Fd.sf = Fs.sf / Ft.sf;}}); - 0x4: sqrts({{ Fd.sf = sqrt(Fs.sf);}}); - 0x5: abss({{ Fd.sf = fabs(Fs.sf);}}); - 0x6: movs({{ Fd.sf = Fs.sf;}}); - 0x7: negs({{ Fd.sf = -1 * Fs.sf;}}); - } - } - - 0x1: decode RS_LO { - //only legal for 64 bit-FP - format Float64Op { - 0x0: round_l_s({{ Fd = convert_and_round(Fs.sf,RND_NEAREST,FP_LONG,FP_SINGLE);}}); - 0x1: trunc_l_s({{ Fd = convert_and_round(Fs.sf,RND_ZERO,FP_LONG,FP_SINGLE);}}); - 0x2: ceil_l_s({{ Fd = convert_and_round(Fs.sf,RND_UP,FP_LONG,FP_SINGLE);}}); - 0x3: floor_l_s({{ Fd = convert_and_round(Fs.sf,RND_DOWN,FP_LONG,FP_SINGLE);}}); - } - - format FloatOp { - 0x4: round_w_s({{ Fd = convert_and_round(Fs.sf,RND_NEAREST,FP_WORD,FP_SINGLE);}}); - 0x5: trunc_w_s({{ Fd = convert_and_round(Fs.sf,RND_ZERO,FP_WORD,FP_SINGLE);}}); - 0x6: ceil_w_s({{ Fd = convert_and_round(Fs.sf,RND_UP,FP_WORD,FP_SINGLE);}}); - 0x7: floor_w_s({{ Fd = convert_and_round(Fs.sf,RND_DOWN,FP_WORD,FP_SINGLE);}}); - } - } - - 0x2: decode RS_LO { - 0x1: decode MOVCF { - format FloatOp { - 0x0: movfs({{if (xc->readMiscReg(FPCR) != CC) Fd = Fs; }}); - 0x1: movts({{if (xc->readMiscReg(FPCR) == CC) Fd = Fs;}}); - } - } - - format BasicOp { - 0x2: movzs({{ if (Rt == 0) Fd = Fs; }}); - 0x3: movns({{ if (Rt != 0) Fd = Fs; }}); - } - - format Float64Op { - 0x5: recips({{ Fd = 1 / Fs; }}); - 0x6: rsqrts({{ Fd = 1 / sqrt((double)Fs.ud);}}); - } - } - - 0x4: decode RS_LO { - - format FloatOp { - 0x1: cvt_d_s({{ int rnd_mode = xc->readMiscReg(FCSR); - Fd = convert_and_round(Fs.sf,rnd_mode,FP_DOUBLE,FP_SINGLE); - }}); - - 0x4: cvt_w_s({{ int rnd_mode = xc->readMiscReg(FCSR); - Fd = convert_and_round(Fs.sf,rnd_mode,FP_WORD,FP_SINGLE); - }}); - } - - //only legal for 64 bit - format Float64Op { - 0x5: cvt_l_s({{ int rnd_mode = xc->readMiscReg(FCSR); - Fd = convert_and_round(Fs.sf,rnd_mode,FP_LONG,FP_SINGLE); - }}); - - 0x6: cvt_ps_s({{ /*Fd.df = Fs.df<31:0> | Ft.df<31:0>;*/ }}); - } - } - } - - //Table A-15 MIPS32 COP1 Encoding of Function Field When rs=D - 0x1: decode RS_HI { - 0x0: decode RS_LO { - format FloatOp { - 0x0: addd({{ Fd.df = Fs.df + Ft.df;}}); - 0x1: subd({{ Fd.df = Fs.df - Ft.df;}}); - 0x2: muld({{ Fd.df = Fs.df * Ft.df;}}); - 0x3: divd({{ Fd.df = Fs.df / Ft.df;}}); - 0x4: sqrtd({{ Fd.df = sqrt(Fs.df);}}); - 0x5: absd({{ Fd.df = fabs(Fs.df);}}); - 0x6: movd({{ Fd.df = Fs.df;}}); - 0x7: negd({{ Fd.df = -1 * Fs.df;}}); - } - } - - 0x1: decode RS_LO { - //only legal for 64 bit - format Float64Op { - 0x0: round_l_d({{ Fd = convert_and_round(Fs.df,RND_NEAREST,FP_LONG,FP_DOUBLE); }}); - 0x1: trunc_l_d({{ Fd = convert_and_round(Fs.df,RND_ZERO,FP_LONG,FP_DOUBLE);}}); - 0x2: ceil_l_d({{ Fd = convert_and_round(Fs.df,RND_UP,FP_LONG,FP_DOUBLE);}}); - 0x3: floor_l_d({{ Fd = convert_and_round(Fs.df,RND_DOWN,FP_LONG,FP_DOUBLE);}}); - } - - format FloatOp { - 0x4: round_w_d({{ Fd = convert_and_round(Fs.df,RND_NEAREST,FP_LONG,FP_DOUBLE); }}); - 0x5: trunc_w_d({{ Fd = convert_and_round(Fs.df,RND_ZERO,FP_LONG,FP_DOUBLE); }}); - 0x6: ceil_w_d({{ Fd = convert_and_round(Fs.df,RND_UP,FP_LONG,FP_DOUBLE); }}); - 0x7: floor_w_d({{ Fd = convert_and_round(Fs.df,RND_DOWN,FP_LONG,FP_DOUBLE); }}); - } - } - - 0x2: decode RS_LO { - 0x1: decode MOVCF { - format FloatOp { - 0x0: movfd({{if (xc->readMiscReg(FPCR) != CC) Fd.df = Fs.df; }}); - 0x1: movtd({{if (xc->readMiscReg(FPCR) == CC) Fd.df = Fs.df; }}); - } - } - - format BasicOp { - 0x2: movzd({{ if (Rt == 0) Fd.df = Fs.df; }}); - 0x3: movnd({{ if (Rt != 0) Fd.df = Fs.df; }}); - } - - format Float64Op { - 0x5: recipd({{ Fd.df = 1 / Fs.df}}); - 0x6: rsqrtd({{ Fd.df = 1 / sqrt(Fs.df) }}); - } - } - - 0x4: decode RS_LO { - format FloatOp { - 0x0: cvt_s_d({{ - int rnd_mode = xc->readMiscReg(FCSR); - Fd = convert_and_round(Fs.df,rnd_mode,FP_SINGLE,FP_DOUBLE); - }}); - - 0x4: cvt_w_d({{ - int rnd_mode = xc->readMiscReg(FCSR); - Fd = convert_and_round(Fs.df,rnd_mode,FP_WORD,FP_DOUBLE); - }}); - } - - //only legal for 64 bit - format Float64Op { - 0x5: cvt_l_d({{ - int rnd_mode = xc->readMiscReg(FCSR); - Fd = convert_and_round(Fs.df,rnd_mode,FP_LONG,FP_DOUBLE); - }}); - } - } - } - - //Table A-16 MIPS32 COP1 Encoding of Function Field When rs=W - 0x4: decode FUNCTION { - format FloatOp { - 0x20: cvt_s({{ - int rnd_mode = xc->readMiscReg(FCSR); - Fd = convert_and_round(Fs.df,rnd_mode,FP_SINGLE,FP_WORD); - }}); - - 0x21: cvt_d({{ - int rnd_mode = xc->readMiscReg(FCSR); - Fd = convert_and_round(Fs.df,rnd_mode,FP_DOUBLE,FP_WORD); - }}); - } - } - - //Table A-16 MIPS32 COP1 Encoding of Function Field When rs=L1 - //Note: "1. Format type L is legal only if 64-bit floating point operations - //are enabled." - 0x5: decode FUNCTION_HI { - format FloatOp { - 0x10: cvt_s_l({{ - int rnd_mode = xc->readMiscReg(FCSR); - Fd = convert_and_round(Fs.df,rnd_mode,FP_SINGLE,FP_LONG); - }}); - - 0x11: cvt_d_l({{ - int rnd_mode = xc->readMiscReg(FCSR); - Fd = convert_and_round(Fs.df,rnd_mode,FP_DOUBLE,FP_LONG); - }}); - } - } - - //Table A-17 MIPS64 COP1 Encoding of Function Field When rs=PS1 - //Note: "1. Format type PS is legal only if 64-bit floating point operations - //are enabled. " - 0x6: decode RS_HI { - 0x0: decode RS_LO { - format Float64Op { - 0x0: addps({{ //Must Check for Exception Here... Supposed to Operate on Upper and - //Lower Halves Independently but we take simulator shortcut - Fd.df = Fs.df + Ft.df; - }}); - - 0x1: subps({{ //Must Check for Exception Here... Supposed to Operate on Upper and - //Lower Halves Independently but we take simulator shortcut - Fd.df = Fs.df - Ft.df; - }}); - - 0x2: mulps({{ //Must Check for Exception Here... Supposed to Operate on Upper and - //Lower Halves Independently but we take simulator shortcut - Fd.df = Fs.df * Ft.df; - }}); - - 0x5: absps({{ //Must Check for Exception Here... Supposed to Operate on Upper and - //Lower Halves Independently but we take simulator shortcut - Fd.df = fabs(Fs.df); - }}); - - 0x6: movps({{ //Must Check for Exception Here... Supposed to Operate on Upper and - //Lower Halves Independently but we take simulator shortcut - //Fd.df = Fs<31:0> | Ft<31:0>; - }}); - - 0x7: negps({{ //Must Check for Exception Here... Supposed to Operate on Upper and - //Lower Halves Independently but we take simulator shortcut - Fd.df = -1 * Fs.df; - }}); - } - } - - 0x2: decode RS_LO { - 0x1: decode MOVCF { - format Float64Op { - 0x0: movfps({{if (xc->readMiscReg(FPCR) != CC) Fd = Fs;}}); - 0x1: movtps({{if (xc->readMiscReg(FPCR) == CC) Fd = Fs;}}); - } - } - - format BasicOp { - 0x2: movzps({{if (xc->readMiscReg(FPCR) != CC) Fd = Fs; }}); - 0x3: movnps({{if (xc->readMiscReg(FPCR) == CC) Fd = Fs; }}); - } - - } - - 0x4: decode RS_LO { - 0x0: Float64Op::cvt_s_pu({{ - int rnd_mode = xc->readMiscReg(FCSR); - Fd = convert_and_round(Fs.df,rnd_mode,FP_DOUBLE,FP_PS_HI); - }}); - } - - 0x5: decode RS_LO { - format Float64Op { - 0x0: cvt_s_pl({{ - int rnd_mode = xc->readMiscReg(FCSR); - Fd = convert_and_round(Fs.df,rnd_mode,FP_SINGLE,FP_PS_LO); - }}); - 0x4: pll({{ /*Fd.df = Fs<31:0> | Ft<31:0>*/}}); - 0x5: plu({{ /*Fd.df = Fs<31:0> | Ft<63:32>*/}}); - 0x6: pul({{ /*Fd.df = Fs<63:32> | Ft<31:0>*/}}); - 0x7: puu({{ /*Fd.df = Fs<63:32 | Ft<63:32>*/}}); - } - } - } - } - } - } - - //Table A-19 MIPS32 COP2 Encoding of rs Field - 0x2: decode RS_MSB { - 0x0: decode RS_HI { - 0x0: decode RS_LO { - format WarnUnimpl { - 0x0: mfc2(); - 0x2: cfc2(); - 0x3: mfhc2(); - 0x4: mtc2(); - 0x6: ctc2(); - 0x7: mftc2(); - } - } - - 0x1: decode ND { - 0x0: decode TF { - format WarnUnimpl { - 0x0: bc2f(); - 0x1: bc2t(); - } - } - - 0x1: decode TF { - format WarnUnimpl { - 0x0: bc2fl(); - 0x1: bc2tl(); - } - } - } - } - } - - //Table A-20 MIPS64 COP1X Encoding of Function Field 1 - //Note: "COP1X instructions are legal only if 64-bit floating point - //operations are enabled." - 0x3: decode FUNCTION_HI { - 0x0: decode FUNCTION_LO { - format LoadMemory2 { - 0x0: lwxc1({{ EA = Rs + Rt; }},{{ /*F_t<31:0> = Mem.sf; */}}); - 0x1: ldxc1({{ EA = Rs + Rt; }},{{ /*F_t<63:0> = Mem.df;*/ }}); - 0x5: luxc1({{ //Need to make EA<2:0> = 0 - EA = Rs + Rt; - }}, - {{ /*F_t<31:0> = Mem.df; */}}); - } - } - - 0x1: decode FUNCTION_LO { - format StoreMemory2 { - 0x0: swxc1({{ EA = Rs + Rt; }},{{ /*Mem.sf = Ft<31:0>; */}}); - 0x1: sdxc1({{ EA = Rs + Rt; }},{{ /*Mem.df = Ft<63:0> */}}); - 0x5: suxc1({{ //Need to make EA<2:0> = 0 - EA = Rs + Rt; - }}, - {{ /*Mem.df = F_t<63:0>;*/}}); - } - - 0x7: WarnUnimpl::prefx(); - } - - format FloatOp { - 0x3: WarnUnimpl::alnv_ps(); - - format BasicOp { - 0x4: decode FUNCTION_LO { - 0x0: madd_s({{ Fd.sf = (Fs.sf * Fs.sf) + Fr.sf; }}); - 0x1: madd_d({{ Fd.df = (Fs.df * Fs.df) + Fr.df; }}); - 0x6: madd_ps({{ - //Must Check for Exception Here... Supposed to Operate on Upper and - //Lower Halves Independently but we take simulator shortcut - Fd.df = (Fs.df * Fs.df) + Fr.df; - }}); - } - - 0x5: decode FUNCTION_LO { - 0x0: msub_s({{ Fd.sf = (Fs.sf * Fs.sf) - Fr.sf; }}); - 0x1: msub_d({{ Fd.df = (Fs.df * Fs.df) - Fr.df; }}); - 0x6: msub_ps({{ - //Must Check for Exception Here... Supposed to Operate on Upper and - //Lower Halves Independently but we take simulator shortcut - Fd.df = (Fs.df * Fs.df) - Fr.df; - }}); - } - - 0x6: decode FUNCTION_LO { - 0x0: nmadd_s({{ Fd.sf = (-1 * Fs.sf * Fs.sf) - Fr.sf; }}); - 0x1: nmadd_d({{ Fd.df = (-1 * Fs.df * Fs.df) + Fr.df; }}); - 0x6: nmadd_ps({{ - //Must Check for Exception Here... Supposed to Operate on Upper and - //Lower Halves Independently but we take simulator shortcut - Fd.df = (-1 * Fs.df * Fs.df) + Fr.df; - }}); - } - - 0x7: decode FUNCTION_LO { - 0x0: nmsub_s({{ Fd.sf = (-1 * Fs.sf * Fs.sf) - Fr.sf; }}); - 0x1: nmsub_d({{ Fd.df = (-1 * Fs.df * Fs.df) - Fr.df; }}); - 0x6: nmsub_ps({{ - //Must Check for Exception Here... Supposed to Operate on Upper and - //Lower Halves Independently but we take simulator shortcut - Fd.df = (-1 * Fs.df * Fs.df) + Fr.df; - }}); - } - } - } - } - - //MIPS obsolete instructions - format BranchLikely { - 0x4: beql({{ cond = (Rs.sw == 0); }}); - 0x5: bnel({{ cond = (Rs.sw != 0); }}); - 0x6: blezl({{ cond = (Rs.sw <= 0); }}); - 0x7: bgtzl({{ cond = (Rs.sw > 0); }}); - } - } - - 0x3: decode OPCODE_LO default FailUnimpl::reserved() { - - //Table A-5 MIPS32 SPECIAL2 Encoding of Function Field - 0x4: decode FUNCTION_HI { - - 0x0: decode FUNCTION_LO { - format IntOp { - 0x0: madd({{ - int64_t temp1 = xc->readMiscReg(Hi) << 32 | xc->readMiscReg(Lo) >> 32; - temp1 = temp1 + (Rs.sw * Rt.sw); - xc->setMiscReg(Hi,temp1<63:32>); - xc->setMiscReg(Lo,temp1<31:0>); - }}); - - 0x1: maddu({{ - int64_t temp1 = xc->readMiscReg(Hi) << 32 | xc->readMiscReg(Lo) >> 32; - temp1 = temp1 + (Rs.uw * Rt.uw); - xc->setMiscReg(Hi,temp1<63:32>); - xc->setMiscReg(Lo,temp1<31:0>); - }}); - - 0x2: mul({{ Rd.sw = Rs.sw * Rt.sw; }}); - - 0x4: msub({{ - int64_t temp1 = xc->readMiscReg(Hi) << 32 | xc->readMiscReg(Lo) >> 32; - temp1 = temp1 - (Rs.sw * Rt.sw); - xc->setMiscReg(Hi,temp1<63:32>); - xc->setMiscReg(Lo,temp1<31:0>); - }}); - - 0x5: msubu({{ - int64_t temp1 = xc->readMiscReg(Hi) << 32 | xc->readMiscReg(Lo) >> 32; - temp1 = temp1 - (Rs.uw * Rt.uw); - xc->setMiscReg(Hi,temp1<63:32>); - xc->setMiscReg(Lo,temp1<31:0>); - }}); - } - } - - 0x4: decode FUNCTION_LO { - format BasicOp { - 0x0: clz({{ - /*int cnt = 0; - int idx = 0; - while ( Rs.uw<idx> != 1) { - cnt++; - idx--; - } - - Rd.uw = cnt;*/ - }}); - - 0x1: clo({{ - /*int cnt = 0; - int idx = 0; - while ( Rs.uw<idx> != 0) { - cnt++; - idx--; - } - - Rd.uw = cnt;*/ - }}); - } - } - - 0x7: decode FUNCTION_LO { - 0x7: WarnUnimpl::sdbbp(); - } - } - - //Table A-6 MIPS32 SPECIAL3 Encoding of Function Field for Release 2 of the Architecture - 0x7: decode FUNCTION_HI { - - 0x0: decode FUNCTION_LO { - format WarnUnimpl { - 0x1: ext(); - 0x4: ins(); - } - } - - 0x1: decode FUNCTION_LO { - format WarnUnimpl { - 0x0: fork(); - 0x1: yield(); - } - } - - - //Table A-10 MIPS32 BSHFL Encoding of sa Field - 0x4: decode SA { - - 0x02: WarnUnimpl::wsbh(); - - format BasicOp { - 0x10: seb({{ Rd.sw = /* sext32(Rt<7>,24) | */ Rt<7:0>}}); - 0x18: seh({{ Rd.sw = /* sext32(Rt<15>,16) | */ Rt<15:0>}}); - } - } - - 0x6: decode FUNCTION_LO { - 0x7: BasicOp::rdhwr({{ /*Rt = xc->hwRegs[RD];*/ }}); - } - } - } - - 0x4: decode OPCODE_LO default FailUnimpl::reserved() { - format LoadMemory { - 0x0: lb({{ Rt.sw = Mem.sb; }}); - 0x1: lh({{ Rt.sw = Mem.sh; }}); - 0x2: lwl({{ Rt.sw = Mem.sw; }});//, WordAlign); - 0x3: lw({{ Rt.sw = Mem.sb; }}); - 0x4: lbu({{ Rt.uw = Mem.ub; }}); - 0x5: lhu({{ Rt.uw = Mem.uh; }}); - 0x6: lwr({{ Rt.uw = Mem.uw; }});//, WordAlign); - } - - 0x7: FailUnimpl::reserved(); - } - - 0x5: decode OPCODE_LO default FailUnimpl::reserved() { - format StoreMemory { - 0x0: sb({{ Mem.ub = Rt<7:0>; }}); - 0x1: sh({{ Mem.uh = Rt<15:0>; }}); - 0x2: swl({{ Mem.ub = Rt<31:0>; }});//,WordAlign); - 0x3: sw({{ Mem.ub = Rt<31:0>; }}); - 0x6: swr({{ Mem.ub = Rt<31:0>; }});//,WordAlign); - } - - format WarnUnimpl { - 0x7: cache(); - } - - } - - 0x6: decode OPCODE_LO default FailUnimpl::reserved() { - 0x0: WarnUnimpl::ll(); - - format LoadMemory { - 0x1: lwc1({{ /*F_t<31:0> = Mem.sf; */}}); - 0x5: ldc1({{ /*F_t<63:0> = Mem.df; */}}); - } - } - - - 0x7: decode OPCODE_LO default FailUnimpl::reserved() { - 0x0: WarnUnimpl::sc(); - - format StoreMemory { - 0x1: swc1({{ //Mem.sf = Ft<31:0>; }}); - 0x5: sdc1({{ //Mem.df = Ft<63:0>; }}); - } - } -} - - diff --git a/arch/mips/isa/formats.isa b/arch/mips/isa/formats.isa deleted file mode 100644 index f7a9e4ce2..000000000 --- a/arch/mips/isa/formats.isa +++ /dev/null @@ -1,35 +0,0 @@ -// -*- mode:c++ -*- - -//Templates from this format are used later -//Include the basic format -##include "m5/arch/mips/isa/formats/basic.isa" - -//Include the basic format -##include "m5/arch/mips/isa/formats/noop.isa" - -//Include utility formats/functions -##include "m5/arch/mips/isa/formats/util.isa" - -//Include the cop0 formats -##include "m5/arch/mips/isa/formats/cop0.isa" - -//Include the integer formats -##include "m5/arch/mips/isa/formats/int.isa" - -//Include the floatOp format -##include "m5/arch/mips/isa/formats/fp.isa" - -//Include the mem format -##include "m5/arch/mips/isa/formats/mem.isa" - -//Include the trap format -##include "m5/arch/mips/isa/formats/trap.isa" - -//Include the branch format -##include "m5/arch/mips/isa/formats/branch.isa" - -//Include the noop format -##include "m5/arch/mips/isa/formats/unimp.isa" - -//Include the noop format -##include "m5/arch/mips/isa/formats/unknown.isa" diff --git a/arch/mips/isa/formats/basic.isa b/arch/mips/isa/formats/basic.isa deleted file mode 100644 index c02af7ddc..000000000 --- a/arch/mips/isa/formats/basic.isa +++ /dev/null @@ -1,66 +0,0 @@ -// -*- mode:c++ -*- - -// Declarations for execute() methods. -def template BasicExecDeclare {{ - Fault execute(%(CPU_exec_context)s *, Trace::InstRecord *) const; -}}; - -// Basic instruction class declaration template. -def template BasicDeclare {{ - /** - * Static instruction class for "%(mnemonic)s". - */ - class %(class_name)s : public %(base_class)s - { - public: - /// Constructor. - %(class_name)s(MachInst machInst); - %(BasicExecDeclare)s - }; -}}; - -// Basic instruction class constructor template. -def template BasicConstructor {{ - inline %(class_name)s::%(class_name)s(MachInst machInst) : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s) - { - %(constructor)s; - } -}}; - -// Basic instruction class execute method template. -def template BasicExecute {{ - Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const - { - Fault fault = NoFault; - - %(fp_enable_check)s; - %(op_decl)s; - %(op_rd)s; - %(code)s; - - if(fault == NoFault) - { - %(op_wb)s; - } - return fault; - } -}}; - -// Basic decode template. -def template BasicDecode {{ - return new %(class_name)s(machInst); -}}; - -// Basic decode template, passing mnemonic in as string arg to constructor. -def template BasicDecodeWithMnemonic {{ - return new %(class_name)s("%(mnemonic)s", machInst); -}}; - -// The most basic instruction format... used only for a few misc. insts -def format BasicOp(code, *flags) {{ - iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecode.subst(iop) - exec_output = BasicExecute.subst(iop) -}}; diff --git a/arch/mips/isa/formats/branch.isa b/arch/mips/isa/formats/branch.isa deleted file mode 100644 index 0d2ad7855..000000000 --- a/arch/mips/isa/formats/branch.isa +++ /dev/null @@ -1,322 +0,0 @@ -// -*- mode:c++ -*- - -//////////////////////////////////////////////////////////////////// -// -// Control transfer instructions -// - -output header {{ - -#include <iostream> - using namespace std; - - /** - * Base class for instructions whose disassembly is not purely a - * function of the machine instruction (i.e., it depends on the - * PC). This class overrides the disassemble() method to check - * the PC and symbol table values before re-using a cached - * disassembly string. This is necessary for branches and jumps, - * where the disassembly string includes the target address (which - * may depend on the PC and/or symbol table). - */ - class PCDependentDisassembly : public MipsStaticInst - { - protected: - /// Cached program counter from last disassembly - mutable Addr cachedPC; - - /// Cached symbol table pointer from last disassembly - mutable const SymbolTable *cachedSymtab; - - /// Constructor - PCDependentDisassembly(const char *mnem, MachInst _machInst, - OpClass __opClass) - : MipsStaticInst(mnem, _machInst, __opClass), - cachedPC(0), cachedSymtab(0) - { - } - - const std::string & - disassemble(Addr pc, const SymbolTable *symtab) const; - }; - - /** - * Base class for branches (PC-relative control transfers), - * conditional or unconditional. - */ - class Branch : public PCDependentDisassembly - { - protected: - /// target address (signed) Displacement . - int32_t disp; - - /// Constructor. - Branch(const char *mnem, MachInst _machInst, OpClass __opClass) - : PCDependentDisassembly(mnem, _machInst, __opClass), - disp(OFFSET << 2) - { - //If Bit 17 is 1 then Sign Extend - if ( (disp & 0x00020000) > 0 ) { - disp |= 0xFFFE0000; - } - } - - Addr branchTarget(Addr branchPC) const; - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; - - /** - * Base class for branch likely branches (PC-relative control transfers), - */ - class BranchLikely : public PCDependentDisassembly - { - protected: - /// target address (signed) Displacement . - int32_t disp; - - /// Constructor. - BranchLikely(const char *mnem, MachInst _machInst, OpClass __opClass) - : PCDependentDisassembly(mnem, _machInst, __opClass), - disp(OFFSET << 2) - { - - } - - Addr branchTarget(Addr branchPC) const; - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; - - /** - * Base class for jumps (register-indirect control transfers). In - * the Mips ISA, these are always unconditional. - */ - class Jump : public PCDependentDisassembly - { - protected: - - /// Displacement to target address (signed). - int32_t disp; - - uint32_t target; - - public: - /// Constructor - Jump(const char *mnem, MachInst _machInst, OpClass __opClass) - : PCDependentDisassembly(mnem, _machInst, __opClass), - disp(JMPTARG << 2) - { - } - - Addr branchTarget(ExecContext *xc) const; - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; -}}; - -output decoder {{ - Addr - Branch::branchTarget(Addr branchPC) const - { - return branchPC + 4 + disp; - } - - Addr - BranchLikely::branchTarget(Addr branchPC) const - { - return branchPC + 4 + disp; - } - - Addr - Jump::branchTarget(ExecContext *xc) const - { - Addr NPC = xc->readPC() + 4; - uint64_t Rb = xc->readIntReg(_srcRegIdx[0]); - return (Rb & ~3) | (NPC & 1); - } - - const std::string & - PCDependentDisassembly::disassemble(Addr pc, - const SymbolTable *symtab) const - { - if (!cachedDisassembly || - pc != cachedPC || symtab != cachedSymtab) - { - if (cachedDisassembly) - delete cachedDisassembly; - - cachedDisassembly = - new std::string(generateDisassembly(pc, symtab)); - cachedPC = pc; - cachedSymtab = symtab; - } - - return *cachedDisassembly; - } - - std::string - Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - std::stringstream ss; - - ccprintf(ss, "%-10s ", mnemonic); - - // There's only one register arg (RA), but it could be - // either a source (the condition for conditional - // branches) or a destination (the link reg for - // unconditional branches) - if (_numSrcRegs == 1) { - printReg(ss, _srcRegIdx[0]); - ss << ","; - } else if(_numSrcRegs == 2) { - printReg(ss, _srcRegIdx[0]); - ss << ","; - printReg(ss, _srcRegIdx[1]); - ss << ","; - } - - Addr target = pc + 8 + disp; - - std::string str; - if (symtab && symtab->findSymbol(target, str)) - ss << str; - else - ccprintf(ss, "0x%x", target); - - return ss.str(); - } - - std::string - BranchLikely::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - std::stringstream ss; - - ccprintf(ss, "%-10s ", mnemonic); - - // There's only one register arg (RA), but it could be - // either a source (the condition for conditional - // branches) or a destination (the link reg for - // unconditional branches) - if (_numSrcRegs > 0) { - printReg(ss, _srcRegIdx[0]); - ss << ","; - } - else if (_numDestRegs > 0) { - printReg(ss, _destRegIdx[0]); - ss << ","; - } - - Addr target = pc + 4 + disp; - - std::string str; - if (symtab && symtab->findSymbol(target, str)) - ss << str; - else - ccprintf(ss, "0x%x", target); - - return ss.str(); - } - - std::string - Jump::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - std::stringstream ss; - - ccprintf(ss, "%-10s ", mnemonic); - - if ( mnemonic == "jal" ) { - Addr npc = pc + 4; - ccprintf(ss,"0x%x",(npc & 0xF0000000) | disp); - } else if (_numSrcRegs == 0) { - std::string str; - if (symtab && symtab->findSymbol(disp, str)) - ss << str; - else - ccprintf(ss, "0x%x", disp); - } else if (_numSrcRegs == 1) { - printReg(ss, _srcRegIdx[0]); - } else if(_numSrcRegs == 2) { - printReg(ss, _srcRegIdx[0]); - ss << ","; - printReg(ss, _srcRegIdx[1]); - } else { - panic(">= 3 Source Registers!!!"); - } - - return ss.str(); - } -}}; - -def format Branch(code,*flags) {{ - #Add Link Code if Link instruction - strlen = len(name) - if name[strlen-2:] == 'al': - code += 'r31 = NNPC;\n' - - #Condition code - code = 'bool cond;\n' + code - code += 'if (cond) {\n' - code += ' NNPC = NPC + disp;\n' - code += '} else {\n' - code += ' NNPC = NNPC;\n' - code += '} \n' - - code += 'cout << hex << "NPC: " << NPC << " + " << disp << " = " << NNPC << endl;' - - iop = InstObjParams(name, Name, 'Branch', CodeBlock(code), - ('IsDirectControl', 'IsCondControl')) - - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecode.subst(iop) - exec_output = BasicExecute.subst(iop) -}}; - - -def format BranchLikely(code,*flags) {{ - #Add Link Code if Link instruction - strlen = len(name) - if name[strlen-3:] == 'all': - code += 'r31 = NNPC;\n' - - #Condition code - code = 'bool cond;\n' + code - code += 'if (cond) {' - code += 'NNPC = NPC + disp;\n' - code += '} \n' - - - iop = InstObjParams(name, Name, 'Branch', CodeBlock(code), - ('IsDirectControl', 'IsCondControl','IsCondDelaySlot')) - - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecode.subst(iop) - exec_output = BasicExecute.subst(iop) -}}; - -def format Jump(code,*flags) {{ - #Add Link Code if Link instruction - strlen = len(name) - if strlen > 1 and name[1:] == 'al': - code = 'r31 = NNPC;\n' + code - - #code += 'if(NNPC == 0x80000638) { NNPC = r31; cout << "SKIPPING JUMP TO SIM_GET_MEM_CONF" << endl;}' - #code += 'target = NNPC;' - - iop = InstObjParams(name, Name, 'Jump', CodeBlock(code),\ - ('IsIndirectControl', 'IsUncondControl')) - - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecode.subst(iop) - exec_output = BasicExecute.subst(iop) -}}; - - - - diff --git a/arch/mips/isa/formats/fp.isa b/arch/mips/isa/formats/fp.isa deleted file mode 100644 index 34b71acf7..000000000 --- a/arch/mips/isa/formats/fp.isa +++ /dev/null @@ -1,49 +0,0 @@ -// -*- mode:c++ -*- - -//////////////////////////////////////////////////////////////////// -// -// Floating Point operate instructions -// - -output header {{ - /** - * Base class for FP operations. - */ - class FPOp : public MipsStaticInst - { - protected: - - /// Constructor - FPOp(const char *mnem, MachInst _machInst, OpClass __opClass) : MipsStaticInst(mnem, _machInst, __opClass) - { - } - - std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; -}}; - -output decoder {{ - std::string FPOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - return "Disassembly of integer instruction\n"; - } -}}; - - -// Primary format for integer operate instructions: -def format FloatOp(code, *flags) {{ - iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecode.subst(iop) - exec_output = BasicExecute.subst(iop) -}}; - -// Primary format for integer operate instructions: -def format Float64Op(code, *flags) {{ - iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecode.subst(iop) - exec_output = BasicExecute.subst(iop) -}}; diff --git a/arch/mips/isa/formats/int.isa b/arch/mips/isa/formats/int.isa deleted file mode 100644 index a47844bee..000000000 --- a/arch/mips/isa/formats/int.isa +++ /dev/null @@ -1,130 +0,0 @@ -// -*- mode:c++ -*- - -//////////////////////////////////////////////////////////////////// -// -// Integer operate instructions -// - -//Outputs to decoder.hh -output header {{ -#include <iostream> - using namespace std; - /** - * Base class for integer operations. - */ - class IntOp : public MipsStaticInst - { - protected: - - /// Constructor - IntOp(const char *mnem, MachInst _machInst, OpClass __opClass) : - MipsStaticInst(mnem, _machInst, __opClass) - { - } - - std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; - - class IntImmOp : public MipsStaticInst - { - protected: - - int32_t imm; - - /// Constructor - IntImmOp(const char *mnem, MachInst _machInst, OpClass __opClass) : - MipsStaticInst(mnem, _machInst, __opClass),imm(INTIMM) - { - //If Bit 15 is 1 then Sign Extend - int32_t temp = imm & 0x00008000; - - if (temp > 0 && mnemonic != "lui") { - imm |= 0xFFFF0000; - } - } - - std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; - - - }; - -}}; - -//Outputs to decoder.cc -output decoder {{ - std::string IntOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - std::stringstream ss; - - ccprintf(ss, "%-10s ", mnemonic); - - // just print the first dest... if there's a second one, - // it's generally implicit - if (_numDestRegs > 0) { - printReg(ss, _destRegIdx[0]); - } - - ss << ","; - - // just print the first two source regs... if there's - // a third one, it's a read-modify-write dest (Rc), - // e.g. for CMOVxx - if (_numSrcRegs > 0) { - printReg(ss, _srcRegIdx[0]); - } - - if (_numSrcRegs > 1) { - ss << ","; - printReg(ss, _srcRegIdx[1]); - } - - return ss.str(); - } - - std::string IntImmOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - std::stringstream ss; - - ccprintf(ss, "%-10s ", mnemonic); - - if (_numDestRegs > 0) { - printReg(ss, _destRegIdx[0]); - } - - ss << ","; - - if (_numSrcRegs > 0) { - printReg(ss, _srcRegIdx[0]); - ss << ","; - } - - if( mnemonic == "lui") - ccprintf(ss, "%08p ", imm); - else - ss << (int) imm; - - return ss.str(); - } - -}}; - -//Used by decoder.isa -def format IntOp(code, *opt_flags) {{ - orig_code = code - cblk = CodeBlock(code) - - # Figure out if we are creating a IntImmOp or a IntOp - # by looking at the instruction name - iop = InstObjParams(name, Name, 'IntOp', cblk, opt_flags) - strlen = len(name) - if name[strlen-1] == 'i' or name[strlen-2:] == 'iu': - iop = InstObjParams(name, Name, 'IntImmOp', cblk, opt_flags) - - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = OperateNopCheckDecode.subst(iop) - exec_output = BasicExecute.subst(iop) -}}; - - - diff --git a/arch/mips/isa/formats/mem.isa b/arch/mips/isa/formats/mem.isa deleted file mode 100644 index 8a07e63d4..000000000 --- a/arch/mips/isa/formats/mem.isa +++ /dev/null @@ -1,469 +0,0 @@ -// -*- mode:c++ -*- - -// Copyright (c) 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. - -output header {{ - /** - * Base class for general Mips memory-format instructions. - */ - class Memory : public MipsStaticInst - { - protected: - - /// Memory request flags. See mem_req_base.hh. - unsigned memAccessFlags; - /// Pointer to EAComp object. - const StaticInstPtr eaCompPtr; - /// Pointer to MemAcc object. - const StaticInstPtr memAccPtr; - - /// Displacement for EA calculation (signed). - int32_t disp; - - /// Constructor - Memory(const char *mnem, MachInst _machInst, OpClass __opClass, - StaticInstPtr _eaCompPtr = nullStaticInstPtr, - StaticInstPtr _memAccPtr = nullStaticInstPtr) - : MipsStaticInst(mnem, _machInst, __opClass), - memAccessFlags(0), eaCompPtr(_eaCompPtr), memAccPtr(_memAccPtr), - disp(OFFSET) - { - //If Bit 15 is 1 then Sign Extend - int32_t temp = disp & 0x00008000; - - if (temp > 0) { - disp |= 0xFFFF0000; - } - } - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - - public: - - const StaticInstPtr &eaCompInst() const { return eaCompPtr; } - const StaticInstPtr &memAccInst() const { return memAccPtr; } - }; - -}}; - - -output decoder {{ - std::string - Memory::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - return csprintf("%-10s %c%d,%d(r%d)", mnemonic, - flags[IsFloating] ? 'f' : 'r', RT, disp, RS); - } - -}}; - -def format LoadAddress(code) {{ - iop = InstObjParams(name, Name, 'MemoryDisp32', CodeBlock(code)) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecode.subst(iop) - exec_output = BasicExecute.subst(iop) -}}; - - -def template LoadStoreDeclare {{ - /** - * Static instruction class for "%(mnemonic)s". - */ - class %(class_name)s : public %(base_class)s - { - protected: - - /** - * "Fake" effective address computation class for "%(mnemonic)s". - */ - class EAComp : public %(base_class)s - { - public: - /// Constructor - EAComp(MachInst machInst); - - %(BasicExecDeclare)s - }; - - /** - * "Fake" memory access instruction class for "%(mnemonic)s". - */ - class MemAcc : public %(base_class)s - { - public: - /// Constructor - MemAcc(MachInst machInst); - - %(BasicExecDeclare)s - }; - - public: - - /// Constructor. - %(class_name)s(MachInst machInst); - - %(BasicExecDeclare)s - - %(InitiateAccDeclare)s - - %(CompleteAccDeclare)s - }; -}}; - - -def template InitiateAccDeclare {{ - Fault initiateAcc(%(CPU_exec_context)s *, Trace::InstRecord *) const; -}}; - - -def template CompleteAccDeclare {{ - Fault completeAcc(uint8_t *, %(CPU_exec_context)s *, Trace::InstRecord *) const; -}}; - - -def template LoadStoreConstructor {{ - /** TODO: change op_class to AddrGenOp or something (requires - * creating new member of OpClass enum in op_class.hh, updating - * config files, etc.). */ - inline %(class_name)s::EAComp::EAComp(MachInst machInst) - : %(base_class)s("%(mnemonic)s (EAComp)", machInst, IntAluOp) - { - %(ea_constructor)s; - } - - inline %(class_name)s::MemAcc::MemAcc(MachInst machInst) - : %(base_class)s("%(mnemonic)s (MemAcc)", machInst, %(op_class)s) - { - %(memacc_constructor)s; - } - - inline %(class_name)s::%(class_name)s(MachInst machInst) - : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, - new EAComp(machInst), new MemAcc(machInst)) - { - %(constructor)s; - } -}}; - - -def template EACompExecute {{ - Fault - %(class_name)s::EAComp::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Addr EA; - Fault fault = NoFault; - - %(fp_enable_check)s; - %(op_decl)s; - %(op_rd)s; - %(code)s; - - if (fault == NoFault) { - %(op_wb)s; - xc->setEA(EA); - } - - return fault; - } -}}; - -def template LoadMemAccExecute {{ - Fault - %(class_name)s::MemAcc::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Addr EA; - Fault fault = NoFault; - - %(fp_enable_check)s; - %(op_decl)s; - %(op_rd)s; - EA = xc->getEA(); - - if (fault == NoFault) { - fault = xc->read(EA, (uint%(mem_acc_size)d_t&)Mem, memAccessFlags); - %(code)s; - } - - if (fault == NoFault) { - %(op_wb)s; - } - - return fault; - } -}}; - - -def template LoadExecute {{ - Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Addr EA; - Fault fault = NoFault; - - %(fp_enable_check)s; - %(op_decl)s; - %(op_rd)s; - %(ea_code)s; - - if (fault == NoFault) { - fault = xc->read(EA, (uint%(mem_acc_size)d_t&)Mem, memAccessFlags); - %(memacc_code)s; - } - - if (fault == NoFault) { - %(op_wb)s; - } - - return fault; - } -}}; - - -def template LoadInitiateAcc {{ - Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Addr EA; - Fault fault = NoFault; - - %(fp_enable_check)s; - %(op_src_decl)s; - %(op_rd)s; - %(ea_code)s; - - if (fault == NoFault) { - fault = xc->read(EA, (uint%(mem_acc_size)d_t &)Mem, memAccessFlags); - } - - return fault; - } -}}; - - -def template LoadCompleteAcc {{ - Fault %(class_name)s::completeAcc(uint8_t *data, - %(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Fault fault = NoFault; - - %(fp_enable_check)s; - %(op_src_decl)s; - %(op_dest_decl)s; - - memcpy(&Mem, data, sizeof(Mem)); - - if (fault == NoFault) { - %(memacc_code)s; - } - - if (fault == NoFault) { - %(op_wb)s; - } - - return fault; - } -}}; - - -def template StoreMemAccExecute {{ - Fault - %(class_name)s::MemAcc::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Addr EA; - Fault fault = NoFault; - uint64_t write_result = 0; - - %(fp_enable_check)s; - %(op_decl)s; - %(op_rd)s; - EA = xc->getEA(); - - if (fault == NoFault) { - %(code)s; - } - - if (fault == NoFault) { - fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA, - memAccessFlags, &write_result); - if (traceData) { traceData->setData(Mem); } - } - - if (fault == NoFault) { - %(postacc_code)s; - } - - if (fault == NoFault) { - %(op_wb)s; - } - - return fault; - } -}}; - - -def template StoreExecute {{ - Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Addr EA; - Fault fault = NoFault; - uint64_t write_result = 0; - - %(fp_enable_check)s; - %(op_decl)s; - %(op_rd)s; - %(ea_code)s; - - if (fault == NoFault) { - %(memacc_code)s; - } - - if (fault == NoFault) { - fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA, - memAccessFlags, &write_result); - if (traceData) { traceData->setData(Mem); } - } - - if (fault == NoFault) { - %(postacc_code)s; - } - - if (fault == NoFault) { - %(op_wb)s; - } - - return fault; - } -}}; - -def template StoreInitiateAcc {{ - Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Addr EA; - Fault fault = NoFault; - uint64_t write_result = 0; - - %(fp_enable_check)s; - %(op_src_decl)s; - %(op_dest_decl)s; - %(op_rd)s; - %(ea_code)s; - - if (fault == NoFault) { - %(memacc_code)s; - } - - if (fault == NoFault) { - fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA, - memAccessFlags, &write_result); - if (traceData) { traceData->setData(Mem); } - } - - return fault; - } -}}; - - -def template StoreCompleteAcc {{ - Fault %(class_name)s::completeAcc(uint8_t *data, - %(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Fault fault = NoFault; - uint64_t write_result = 0; - - %(fp_enable_check)s; - %(op_dest_decl)s; - - memcpy(&write_result, data, sizeof(write_result)); - - if (fault == NoFault) { - %(postacc_code)s; - } - - if (fault == NoFault) { - %(op_wb)s; - } - - return fault; - } -}}; - -// load instructions use Rt as dest, so check for -// Rt == 31 to detect nops -def template LoadNopCheckDecode {{ - { - MipsStaticInst *i = new %(class_name)s(machInst); - if (RT == 0) { - i = makeNop(i); - } - return i; - } -}}; - -def format LoadMemory(memacc_code, ea_code = {{ EA = Rs + disp; }}, - mem_flags = [], inst_flags = []) {{ - (header_output, decoder_output, decode_block, exec_output) = \ - LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, - decode_template = LoadNopCheckDecode, - exec_template_base = 'Load') -}}; - - -def format StoreMemory(memacc_code, ea_code = {{ EA = Rs + disp; }}, - mem_flags = [], inst_flags = []) {{ - (header_output, decoder_output, decode_block, exec_output) = \ - LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, - exec_template_base = 'Store') -}}; - -//FP loads are offloaded to these formats for now ... -def format LoadMemory2(ea_code = {{ EA = Rs + disp; }}, memacc_code = {{ }}, - mem_flags = [], inst_flags = []) {{ - (header_output, decoder_output, decode_block, exec_output) = \ - LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, - decode_template = LoadNopCheckDecode, - exec_template_base = 'Load') -}}; - - -//FP stores are offloaded to these formats for now ... -def format StoreMemory2(ea_code = {{ EA = Rs + disp; }},memacc_code = {{ }}, - mem_flags = [], inst_flags = []) {{ - (header_output, decoder_output, decode_block, exec_output) = \ - LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, - decode_template = LoadNopCheckDecode, - exec_template_base = 'Store') -}}; - diff --git a/arch/mips/isa/formats/noop.isa b/arch/mips/isa/formats/noop.isa deleted file mode 100644 index d35179005..000000000 --- a/arch/mips/isa/formats/noop.isa +++ /dev/null @@ -1,90 +0,0 @@ -// -*- mode:c++ -*- - -//////////////////////////////////////////////////////////////////// -// -// Nop -// - -output header {{ - /** - * Static instruction class for no-ops. This is a leaf class. - */ - class Nop : public MipsStaticInst - { - /// Disassembly of original instruction. - const std::string originalDisassembly; - - public: - /// Constructor - Nop(const std::string _originalDisassembly, MachInst _machInst) - : MipsStaticInst("nop", _machInst, No_OpClass), - originalDisassembly(_originalDisassembly) - { - flags[IsNop] = true; - } - - ~Nop() { } - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - - %(BasicExecDeclare)s - }; -}}; - -output decoder {{ - std::string Nop::generateDisassembly(Addr pc, - const SymbolTable *symtab) const - { -#ifdef SS_COMPATIBLE_DISASSEMBLY - return originalDisassembly; -#else - return csprintf("%-10s (%s)", "nop", originalDisassembly); -#endif - } - - /// Helper function for decoding nops. Substitute Nop object - /// for original inst passed in as arg (and delete latter). - inline - MipsStaticInst * - makeNop(MipsStaticInst *inst) - { - MipsStaticInst *nop = new Nop(inst->disassemble(0), inst->machInst); - delete inst; - return nop; - } -}}; - -output exec {{ - Fault - Nop::execute(%(CPU_exec_context)s *, Trace::InstRecord *) const - { - return NoFault; - } -}}; - -// integer & FP operate instructions use RT as dest, so check for -// RT == 0 to detect nops -def template OperateNopCheckDecode {{ - { - MipsStaticInst *i = new %(class_name)s(machInst); - - //if (RD == 0) { - // i = makeNop(i); - //} - - return i; - } -}}; - - -// Like BasicOperate format, but generates NOP if RC/FC == 31 -def format BasicOperateWithNopCheck(code, *opt_args) {{ - iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), - opt_args) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = OperateNopCheckDecode.subst(iop) - exec_output = BasicExecute.subst(iop) -}}; - diff --git a/arch/mips/isa/formats/tlbop.isa b/arch/mips/isa/formats/tlbop.isa deleted file mode 100644 index f5e4076f2..000000000 --- a/arch/mips/isa/formats/tlbop.isa +++ /dev/null @@ -1,53 +0,0 @@ -//////////////////////////////////////////////////////////////////// -// -// TlbOp instructions -// - -output header {{ - /** - * Base class for integer operations. - */ - class TlbOp : public MipsStaticInst - { - protected: - - /// Constructor - TlbOp(const char *mnem, MachInst _machInst, OpClass __opClass) : MipsStaticInst(mnem, _machInst, __opClass) - { - } - - std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; -}}; - -output decoder {{ - std::string TlbOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - return "Disassembly of integer instruction\n"; - } -}}; - -def template TlbOpExecute {{ - Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const - { - //Call into the trap handler with the appropriate fault - return No_Fault; - } - - //Write the resulting state to the execution context - %(op_wb)s; - - return No_Fault; - } -}}; - -// Primary format for integer operate instructions: -def format TlbOp(code, *opt_flags) {{ - orig_code = code - cblk = CodeBlock(code) - iop = InstObjParams(name, Name, 'MipsStaticInst', cblk, opt_flags) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecodeWithMnemonic.subst(iop) - exec_output = TlbOpExecute.subst(iop) -}}; diff --git a/arch/mips/isa/formats/trap.isa b/arch/mips/isa/formats/trap.isa deleted file mode 100644 index 6884d4fa8..000000000 --- a/arch/mips/isa/formats/trap.isa +++ /dev/null @@ -1,52 +0,0 @@ -//////////////////////////////////////////////////////////////////// -// -// Trap instructions -// - -output header {{ - /** - * Base class for integer operations. - */ - class Trap : public MipsStaticInst - { - protected: - - /// Constructor - Trap(const char *mnem, MachInst _machInst, OpClass __opClass) : MipsStaticInst(mnem, _machInst, __opClass) - { - } - - std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; -}}; - -output decoder {{ - std::string Trap::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - return "Disassembly of integer instruction\n"; - } -}}; - -def template TrapExecute {{ - Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const - { - //Call into the trap handler with the appropriate fault - return No_Fault; - } - - //Write the resulting state to the execution context - %(op_wb)s; - - return No_Fault; - } -}}; - -// Primary format for integer operate instructions: -def format Trap(code, *flags) {{ - code = 'bool cond;\n' + code; - iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecode.subst(iop) - exec_output = BasicExecute.subst(iop) -}}; diff --git a/arch/mips/isa/formats/unimp.isa b/arch/mips/isa/formats/unimp.isa deleted file mode 100644 index adbd5b5b1..000000000 --- a/arch/mips/isa/formats/unimp.isa +++ /dev/null @@ -1,165 +0,0 @@ -// -*- mode:c++ -*- - -// Copyright (c) 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. - -output header {{ - /** - * Static instruction class for unimplemented instructions that - * cause simulator termination. Note that these are recognized - * (legal) instructions that the simulator does not support; the - * 'Unknown' class is used for unrecognized/illegal instructions. - * This is a leaf class. - */ - class FailUnimplemented : public MipsStaticInst - { - public: - /// Constructor - FailUnimplemented(const char *_mnemonic, MachInst _machInst) - : MipsStaticInst(_mnemonic, _machInst, No_OpClass) - { - // don't call execute() (which panics) if we're on a - // speculative path - flags[IsNonSpeculative] = true; - } - - %(BasicExecDeclare)s - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; - - /** - * Base class for unimplemented instructions that cause a warning - * to be printed (but do not terminate simulation). This - * implementation is a little screwy in that it will print a - * warning for each instance of a particular unimplemented machine - * instruction, not just for each unimplemented opcode. Should - * probably make the 'warned' flag a static member of the derived - * class. - */ - class WarnUnimplemented : public MipsStaticInst - { - private: - /// Have we warned on this instruction yet? - mutable bool warned; - - public: - /// Constructor - WarnUnimplemented(const char *_mnemonic, MachInst _machInst) - : MipsStaticInst(_mnemonic, _machInst, No_OpClass), warned(false) - { - // don't call execute() (which panics) if we're on a - // speculative path - flags[IsNonSpeculative] = true; - } - - %(BasicExecDeclare)s - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; -}}; - -output decoder {{ - std::string - FailUnimplemented::generateDisassembly(Addr pc, - const SymbolTable *symtab) const - { - return csprintf("%-10s (unimplemented)", mnemonic); - } - - std::string - WarnUnimplemented::generateDisassembly(Addr pc, - const SymbolTable *symtab) const - { -#ifdef SS_COMPATIBLE_DISASSEMBLY - return csprintf("%-10s", mnemonic); -#else - return csprintf("%-10s (unimplemented)", mnemonic); -#endif - } -}}; - -output exec {{ - Fault - FailUnimplemented::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - panic("attempt to execute unimplemented instruction '%s' " - "(inst 0x%08x, opcode 0x%x)", mnemonic, machInst, OPCODE); - return UnimplementedOpcodeFault; - } - - Fault - WarnUnimplemented::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - if (!warned) { - warn("instruction '%s' unimplemented\n", mnemonic); - warned = true; - } - - return NoFault; - } -}}; - - -def format FailUnimpl() {{ - iop = InstObjParams(name, 'FailUnimplemented') - decode_block = BasicDecodeWithMnemonic.subst(iop) -}}; - -def format WarnUnimpl() {{ - iop = InstObjParams(name, 'WarnUnimplemented') - decode_block = BasicDecodeWithMnemonic.subst(iop) -}}; - -output header {{ - /** - * Static instruction class for unknown (illegal) instructions. - * These cause simulator termination if they are executed in a - * non-speculative mode. This is a leaf class. - */ - class Unknown : public MipsStaticInst - { - public: - /// Constructor - Unknown(MachInst _machInst) - : MipsStaticInst("unknown", _machInst, No_OpClass) - { - // don't call execute() (which panics) if we're on a - // speculative path - flags[IsNonSpeculative] = true; - } - - %(BasicExecDeclare)s - - std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const; - }; -}}; - diff --git a/arch/mips/isa/formats/unknown.isa b/arch/mips/isa/formats/unknown.isa deleted file mode 100644 index 4601b3684..000000000 --- a/arch/mips/isa/formats/unknown.isa +++ /dev/null @@ -1,52 +0,0 @@ -// -*- mode:c++ -*- - -// Copyright (c) 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. - -output decoder {{ - std::string - Unknown::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - return csprintf("%-10s (inst 0x%x, opcode 0x%x)", - "unknown", machInst, OPCODE); - } -}}; - -output exec {{ - Fault - Unknown::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - panic("attempt to execute unknown instruction " - "(inst 0x%08x, opcode 0x%x)", machInst, OPCODE); - return UnimplementedOpcodeFault; - } -}}; - -def format Unknown() {{ - decode_block = 'return new Unknown(machInst);\n' -}}; - diff --git a/arch/mips/isa/formats/util.isa b/arch/mips/isa/formats/util.isa deleted file mode 100644 index db4bf204a..000000000 --- a/arch/mips/isa/formats/util.isa +++ /dev/null @@ -1,148 +0,0 @@ -// -*- mode:c++ -*- - -let {{ -def LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, - postacc_code = '', base_class = 'Memory', - decode_template = BasicDecode, exec_template_base = ''): - # Make sure flags are in lists (convert to lists if not). - mem_flags = makeList(mem_flags) - inst_flags = makeList(inst_flags) - - # add hook to get effective addresses into execution trace output. - ea_code += '\nif (traceData) { traceData->setAddr(EA); }\n' - - # generate code block objects - ea_cblk = CodeBlock(ea_code) - memacc_cblk = CodeBlock(memacc_code) - postacc_cblk = CodeBlock(postacc_code) - - # Some CPU models execute the memory operation as an atomic unit, - # while others want to separate them into an effective address - # computation and a memory access operation. As a result, we need - # to generate three StaticInst objects. Note that the latter two - # are nested inside the larger "atomic" one. - - # generate InstObjParams for EAComp object - ea_iop = InstObjParams(name, Name, base_class, ea_cblk, inst_flags) - - # generate InstObjParams for MemAcc object - memacc_iop = InstObjParams(name, Name, base_class, memacc_cblk, inst_flags) - # in the split execution model, the MemAcc portion is responsible - # for the post-access code. - memacc_iop.postacc_code = postacc_cblk.code - - # generate InstObjParams for InitiateAcc, CompleteAcc object - # The code used depends on the template being used - if (exec_template_base == 'Load'): - initiateacc_cblk = CodeBlock(ea_code + memacc_code) - completeacc_cblk = CodeBlock(memacc_code + postacc_code) - elif (exec_template_base == 'Store'): - initiateacc_cblk = CodeBlock(ea_code + memacc_code) - completeacc_cblk = CodeBlock(postacc_code) - else: - initiateacc_cblk = '' - completeacc_cblk = '' - - initiateacc_iop = InstObjParams(name, Name, base_class, initiateacc_cblk, - inst_flags) - - completeacc_iop = InstObjParams(name, Name, base_class, completeacc_cblk, - inst_flags) - - if (exec_template_base == 'Load'): - initiateacc_iop.ea_code = ea_cblk.code - initiateacc_iop.memacc_code = memacc_cblk.code - completeacc_iop.memacc_code = memacc_cblk.code - completeacc_iop.postacc_code = postacc_cblk.code - elif (exec_template_base == 'Store'): - initiateacc_iop.ea_code = ea_cblk.code - initiateacc_iop.memacc_code = memacc_cblk.code - completeacc_iop.postacc_code = postacc_cblk.code - - # generate InstObjParams for unified execution - cblk = CodeBlock(ea_code + memacc_code + postacc_code) - iop = InstObjParams(name, Name, base_class, cblk, inst_flags) - - iop.ea_constructor = ea_cblk.constructor - iop.ea_code = ea_cblk.code - iop.memacc_constructor = memacc_cblk.constructor - iop.memacc_code = memacc_cblk.code - iop.postacc_code = postacc_cblk.code - - if mem_flags: - s = '\n\tmemAccessFlags = ' + string.join(mem_flags, '|') + ';' - iop.constructor += s - memacc_iop.constructor += s - - # select templates - memAccExecTemplate = eval(exec_template_base + 'MemAccExecute') - fullExecTemplate = eval(exec_template_base + 'Execute') - initiateAccTemplate = eval(exec_template_base + 'InitiateAcc') - completeAccTemplate = eval(exec_template_base + 'CompleteAcc') - - # (header_output, decoder_output, decode_block, exec_output) - return (LoadStoreDeclare.subst(iop), LoadStoreConstructor.subst(iop), - decode_template.subst(iop), - EACompExecute.subst(ea_iop) - + memAccExecTemplate.subst(memacc_iop) - + fullExecTemplate.subst(iop) - + initiateAccTemplate.subst(initiateacc_iop) - + completeAccTemplate.subst(completeacc_iop)) -}}; - - -output exec {{ - -using namespace MipsISA; - - - /// CLEAR ALL CPU INST/EXE HAZARDS - inline void - clear_exe_inst_hazards() - { - //CODE HERE - } - - - /// Check "FP enabled" machine status bit. Called when executing any FP - /// instruction in full-system mode. - /// @retval Full-system mode: NoFault if FP is enabled, FenFault - /// if not. Non-full-system mode: always returns NoFault. -#if FULL_SYSTEM - inline Fault checkFpEnableFault(%(CPU_exec_context)s *xc) - { - Fault fault = NoFault; // dummy... this ipr access should not fault - if (!Mips34k::ICSR_FPE(xc->readIpr(MipsISA::IPR_ICSR, fault))) { - fault = FloatEnableFault; - } - return fault; - } -#else - inline Fault checkFpEnableFault(%(CPU_exec_context)s *xc) - { - return NoFault; - } -#endif - - double convert_and_round(float w, int x, int y, int z) - { - double temp = .34000; - - return temp; - } - - enum FPTypes{ - FP_SINGLE, - FP_DOUBLE, - FP_LONG, - FP_PS_LO, - FP_PS_HI, - FP_WORD, - RND_NEAREST, - RND_ZERO, - RND_UP, - RND_DOWN - }; -}}; - - diff --git a/arch/mips/isa/includes.isa b/arch/mips/isa/includes.isa deleted file mode 100644 index da919be00..000000000 --- a/arch/mips/isa/includes.isa +++ /dev/null @@ -1,39 +0,0 @@ -//////////////////////////////////////////////////////////////////// -// -// Output include file directives. -// - -output header {{ -#include <sstream> -#include <iostream> -#include <iomanip> - -#include "cpu/static_inst.hh" -#include "mem/mem_req.hh" // some constructors use MemReq flags -}}; - -output decoder {{ -#include "base/cprintf.hh" -#include "base/loader/symtab.hh" -#include "cpu/exec_context.hh" // for Jump::branchTarget() - -#include <math.h> -#if defined(linux) -#include <fenv.h> -#endif -}}; - -output exec {{ -#include <math.h> -#if defined(linux) -#include <fenv.h> -#endif - -#ifdef FULL_SYSTEM -//#include "arch/alpha/pseudo_inst.hh" -#endif -#include "cpu/base.hh" -#include "cpu/exetrace.hh" -#include "sim/sim_exit.hh" -}}; - diff --git a/arch/mips/isa/main.isa b/arch/mips/isa/main.isa deleted file mode 100644 index 411e398b4..000000000 --- a/arch/mips/isa/main.isa +++ /dev/null @@ -1,52 +0,0 @@ -// -*- mode:c++ -*- - -// Copyright (c) 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. - -##include "m5/arch/mips/isa/includes.isa" - -//////////////////////////////////////////////////////////////////// -// -// Namespace statement. Everything below this line will be in the -// MipsISAInst namespace. -// - -namespace MipsISA; - -//Include the bitfield definitions -##include "m5/arch/mips/isa/bitfields.isa" - -//Include the operand_types and operand definitions -##include "m5/arch/mips/isa/operands.isa" - -//Include the base class for mips instructions, and some support code -##include "m5/arch/mips/isa/base.isa" - -//Include the definitions for the instruction formats -##include "m5/arch/mips/isa/formats.isa" - -//Include the decoder definition -##include "m5/arch/mips/isa/decoder.isa" diff --git a/arch/mips/isa/operands.isa b/arch/mips/isa/operands.isa deleted file mode 100644 index 13870337b..000000000 --- a/arch/mips/isa/operands.isa +++ /dev/null @@ -1,33 +0,0 @@ -def operand_types {{ - 'sb' : ('signed int', 8), - 'ub' : ('unsigned int', 8), - 'sh' : ('signed int', 16), - 'uh' : ('unsigned int', 16), - 'sw' : ('signed int', 32), - 'uw' : ('unsigned int', 32), - 'sd' : ('signed int', 64), - 'ud' : ('unsigned int', 64), - 'sf' : ('float', 32), - 'df' : ('float', 64), - 'qf' : ('float', 128) -}}; - -def operands {{ - 'Rd': ('IntReg', 'uw', 'RD', 'IsInteger', 1), - 'Rs': ('IntReg', 'uw', 'RS', 'IsInteger', 2), - 'Rt': ('IntReg', 'uw', 'RT', 'IsInteger', 3), - 'r31': ('IntReg', 'uw','R31','IsInteger', 4), - 'R0': ('IntReg', 'uw','R0', 'IsInteger', 5), - - 'IntImm': ('IntReg', 'uw', 'INTIMM', 'IsInteger', 3), - - 'Fd': ('FloatReg', 'sf', 'FD', 'IsFloating', 1), - 'Fs': ('FloatReg', 'sf', 'FS', 'IsFloating', 2), - 'Ft': ('FloatReg', 'sf', 'FT', 'IsFloating', 3), - 'Fr': ('FloatReg', 'sf', 'FR', 'IsFloating', 3), - - 'Mem': ('Mem', 'ud', None, ('IsMemRef', 'IsLoad', 'IsStore'), 4), - - 'NPC': ('NPC', 'uw', None, ( None, None, 'IsControl' ), 4), - 'NNPC':('NNPC', 'uw', None, ( None, None, 'IsControl' ), 4) -}}; diff --git a/arch/mips/isa_traits.cc b/arch/mips/isa_traits.cc deleted file mode 100644 index d01fa6bd4..000000000 --- a/arch/mips/isa_traits.cc +++ /dev/null @@ -1,403 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include "arch/mips/isa_traits.hh" -#include "config/full_system.hh" -#include "cpu/static_inst.hh" -#include "sim/serialize.hh" - -using namespace MipsISA; - - -//Function now Obsolete in current state. -//If anyting this should return the correct miscreg index -//but that is handled implicitly with enums anyway -void -MipsISA::getMiscRegIdx(int reg_name,int &idx, int &sel) -{ - switch(reg_name) - { - case Index: idx = 0; sel = 0; break; //0-0 Index into the TLB array - case MVPControl: idx = 0; sel = 1; break; //0-1 Per-processor register containing global - case MVPConf0: idx = 0; sel = 2; break; //0-2 Per-processor register containing global - case MVPConf1: idx = 0; sel = 3; break; //0-3 Per-processor register containing global - case Random: idx = 1; sel = 3; break; //1-0 Randomly generated index into the TLB array - case VPEControl: idx = 1; sel = 1; break; //1-1 Per-VPE register containing relatively volatile - //thread configuration data - case VPEConf0: idx = 1; sel = 2; break; //1-2 Per-VPE multi-thread configuration - //information - case VPEConf1: idx = 1; sel = 3; break; //1-3 Per-VPE multi-thread configuration - //information - case YQMask: idx = 1; sel = 4; break; //Per-VPE register defining which YIELD - //qualifier bits may be used without generating - //an exception - case VPESchedule: idx = 1; sel = 5; break; - case VPEScheFBack: idx = 1; sel = 6; break; - case VPEOpt: idx = 1; sel = 7; break; - case EntryLo0: idx = 1; sel = 5; break; - case TCStatus: idx = 1; sel = 5; break; - case TCBind: idx = 1; sel = 5; break; - case TCRestart: idx = 1; sel = 5; break; - case TCHalt: idx = 1; sel = 5; break; - case TCContext: idx = 1; sel = 5; break; - case TCSchedule: idx = 1; sel = 5; break; - case TCScheFBack: panic("Accessing Unimplemented CP0 Register"); break; - case EntryLo1: panic("Accessing Unimplemented CP0 Register"); break; - case Context: panic("Accessing Unimplemented CP0 Register"); break; - case ContextConfig: panic("Accessing Unimplemented CP0 Register"); break; - //case PageMask: panic("Accessing Unimplemented CP0 Register"); break; - case PageGrain: panic("Accessing Unimplemented CP0 Register"); break; - case Wired: panic("Accessing Unimplemented CP0 Register"); break; - case SRSConf0: panic("Accessing Unimplemented CP0 Register"); break; - case SRSConf1: panic("Accessing Unimplemented CP0 Register"); break; - case SRSConf2: panic("Accessing Unimplemented CP0 Register"); break; - case SRSConf3: panic("Accessing Unimplemented CP0 Register"); break; - case SRSConf4: panic("Accessing Unimplemented CP0 Register"); break; - case BadVAddr: panic("Accessing Unimplemented CP0 Register"); break; - case Count: panic("Accessing Unimplemented CP0 Register"); break; - case EntryHi: panic("Accessing Unimplemented CP0 Register"); break; - case Compare: panic("Accessing Unimplemented CP0 Register"); break; - case Status: idx = 12; sel = 0; break; //12-0 Processor status and control - case IntCtl: idx = 12; sel = 1; break; //12-1 Interrupt system status and control - case SRSCtl: idx = 12; sel = 2; break; //12-2 Shadow register set status and control - case SRSMap: idx = 12; sel = 3; break; //12-3 Shadow set IPL mapping - case Cause: idx = 13; sel = 0; break; //13-0 Cause of last general exception - case EPC: idx = 14; sel = 0; break; //14-0 Program counter at last exception - case PrId: idx = 15; sel = 0; break; //15-0 Processor identification and revision - case EBase: idx = 15; sel = 1; break; //15-1 Exception vector base register - case Config: panic("Accessing Unimplemented CP0 Register"); break; - case Config1: panic("Accessing Unimplemented CP0 Register"); break; - case Config2: panic("Accessing Unimplemented CP0 Register"); break; - case Config3: panic("Accessing Unimplemented CP0 Register"); break; - case LLAddr: panic("Accessing Unimplemented CP0 Register"); break; - case WatchLo: panic("Accessing Unimplemented CP0 Register"); break; - case WatchHi: panic("Accessing Unimplemented CP0 Register"); break; - case Debug: panic("Accessing Unimplemented CP0 Register"); break; - case TraceControl1: panic("Accessing Unimplemented CP0 Register"); break; - case TraceControl2: panic("Accessing Unimplemented CP0 Register"); break; - case UserTraceData: panic("Accessing Unimplemented CP0 Register"); break; - case TraceBPC: panic("Accessing Unimplemented CP0 Register"); break; - case DEPC: panic("Accessing Unimplemented CP0 Register"); break; - case PerfCnt: panic("Accessing Unimplemented CP0 Register"); break; - case ErrCtl: panic("Accessing Unimplemented CP0 Register"); break; - case CacheErr0: panic("Accessing Unimplemented CP0 Register"); break; - case CacheErr1: panic("Accessing Unimplemented CP0 Register"); break; - case CacheErr2: panic("Accessing Unimplemented CP0 Register"); break; - case CacheErr3: panic("Accessing Unimplemented CP0 Register"); break; - case TagLo: panic("Accessing Unimplemented CP0 Register"); break; - case DataLo: panic("Accessing Unimplemented CP0 Register"); break; - case TagHi: panic("Accessing Unimplemented CP0 Register"); break; - case DataHi: panic("Accessing Unimplemented CP0 Register"); break; - case ErrorEPC: panic("Accessing Unimplemented CP0 Register"); break; - - default: - panic("Accessing Unimplemented Misc. Register"); - } -} - -void RegFile::coldReset() -{ - //CP0 Random Reg: - //Randomly generated index into the TLB array - miscRegs[Random] = 0x0000003f; - - //CP0 Wired Reg. - miscRegs[Wired] = 0x0000000; - - //CP0 HWRENA - miscRegs[HWRena] = 0x0000000; - - //CP0 Status Reg. - miscRegs[Status] = 0x0400004; - - //CP0 INTCNTL - miscRegs[IntCtl] = 0xfc00000; - - //CP0 SRSCNTL - miscRegs[SRSCtl] = 0x0c00000; - - //CP0 SRSMAP - miscRegs[SRSMap] = 0x0000000; - - //CP0 Cause - miscRegs[Cause] = 0x0000000; - - //CP0 Processor ID - miscRegs[PrId] = 0x0019300; - - //CP0 EBASE - miscRegs[EBase] = 0x8000000; - - //CP0 Config Reg. - miscRegs[Config] = 0x80040482; - - //CP0 Config 1 Reg. - miscRegs[Config1] = 0xfee3719e; - - //CP0 Config 2 Reg. - miscRegs[Config2] = 0x8000000; - - //CP0 Config 3 Reg. - miscRegs[Config3] = 0x0000020; - - //CP0 Config 7 Reg. - miscRegs[Config7] = 0x0000000; - - //CP0 Debug - miscRegs[Debug] = 0x0201800; - - //CP0 PERFCNTL1 - miscRegs[PerfCnt0] = 0x0000000; - - //CP0 PERFCNTL2 - miscRegs[PerfCnt1] = 0x0000000; - -} - -void RegFile::createCP0Regs() -{ -//Resize Coprocessor Register Banks to -// the number specified in MIPS32K VOL.III -// Chapter 8 - /* - //Cop-0 Regs. Bank 0: Index, - miscRegs[0].resize(4); - - //Cop-0 Regs. Bank 1: - miscRegs[1].resize(8); - - //Cop-0 Regs. Bank 2: - miscRegs[2].resize(8); - - //Cop-0 Regs. Bank 3: - miscRegs[3].resize(1); - - //Cop-0 Regs. Bank 4: - miscRegs[4].resize(2); - - //Cop-0 Regs. Bank 5: - miscRegs[5].resize(2); - - //Cop-0 Regs. Bank 6: - miscRegs[6].resize(6); - - //Cop-0 Regs. Bank 7: - miscRegs[7].resize(1); - - //Cop-0 Regs. Bank 8: - miscRegs[8].resize(1); - - //Cop-0 Regs. Bank 9: - miscRegs[9].resize(1); - - //Cop-0 Regs. Bank 10: - miscRegs[10].resize(1); - - //Cop-0 Regs. Bank 11: - miscRegs[11].resize(1); - - //Cop-0 Regs. Bank 12: - miscRegs[12].resize(4); - - //Cop-0 Regs. Bank 13: - miscRegs[13].resize(1); - - //Cop-0 Regs. Bank 14: - miscRegs[14].resize(1); - - //Cop-0 Regs. Bank 15: - miscRegs[15].resize(2); - - //Cop-0 Regs. Bank 16: - miscRegs[16].resize(4); - - //Cop-0 Regs. Bank 17: - miscRegs[17].resize(1); - - //Cop-0 Regs. Bank 18: - miscRegs[18].resize(8); - - //Cop-0 Regs. Bank 19: - miscRegs[19].resize(8); - - //Cop-0 Regs. Bank 20: - miscRegs[20].resize(1); - - //Cop-0 Regs. Bank 21: - //miscRegs[21].resize(1); - //Reserved for future extensions - - //Cop-0 Regs. Bank 22: - //miscRegs[22].resize(4); - //Available for implementation dependent use - - //Cop-0 Regs. Bank 23: - miscRegs[23].resize(5); - - //Cop-0 Regs. Bank 24: - miscRegs[24].resize(1); - - //Cop-0 Regs. Bank 25: - miscRegs[25].resize(8); - - //Cop-0 Regs. Bank 26: - miscRegs[26].resize(1); - - //Cop-0 Regs. Bank 27: - miscRegs[27].resize(4); - - //Cop-0 Regs. Bank 28: - miscRegs[28].resize(8); - - //Cop-0 Regs. Bank 29: - miscRegs[29].resize(8); - - //Cop-0 Regs. Bank 30: - miscRegs[30].resize(1); - - //Cop-0 Regs. Bank 31: - miscRegs[31].resize(1);*/ - -} - - -const Addr MipsISA::PageShift = 13; -const Addr MipsISA::PageBytes = ULL(1) << PageShift; -const Addr MipsISA::PageMask = ~(PageBytes - 1); -const Addr MipsISA::PageOffset = PageBytes - 1; - -#if FULL_SYSTEM - -//////////////////////////////////////////////////////////////////////// -// -// Translation stuff -// - -const Addr MipsISA::PteShift = 3; -const Addr MipsISA::NPtePageShift = PageShift - PteShift; -const Addr MipsISA::NPtePage = ULL(1) << NPtePageShift; -const Addr MipsISA::PteMask = NPtePage - 1; - -// User Virtual -const Addr MipsISA::USegBase = ULL(0x0); -const Addr MipsISA::USegEnd = ULL(0x000003ffffffffff); - -// Kernel Direct Mapped -const Addr MipsISA::K0SegBase = ULL(0xfffffc0000000000); -const Addr MipsISA::K0SegEnd = ULL(0xfffffdffffffffff); - -// Kernel Virtual -const Addr MipsISA::K1SegBase = ULL(0xfffffe0000000000); -const Addr MipsISA::K1SegEnd = ULL(0xffffffffffffffff); - -#endif - -// Mips UNOP (sll r0,r0,r0) -const MachInst MipsISA::NoopMachInst = 0x00000000; - -static inline Addr -TruncPage(Addr addr) -{ return addr & ~(MipsISA::PageBytes - 1); } - -static inline Addr -RoundPage(Addr addr) -{ return (addr + MipsISA::PageBytes - 1) & ~(MipsISA::PageBytes - 1); } - -void -RegFile::serialize(std::ostream &os) -{ - SERIALIZE_ARRAY(intRegFile, NumIntRegs); - SERIALIZE_ARRAY(floatRegFile.q, NumFloatRegs); - //SERIALIZE_SCALAR(miscRegs.fpcr); - //SERIALIZE_SCALAR(miscRegs.uniq); - //SERIALIZE_SCALAR(miscRegs.lock_flag); - //SERIALIZE_SCALAR(miscRegs.lock_addr); - SERIALIZE_SCALAR(pc); - SERIALIZE_SCALAR(npc); - SERIALIZE_SCALAR(nnpc); -#if FULL_SYSTEM - SERIALIZE_ARRAY(palregs, NumIntRegs); - SERIALIZE_ARRAY(ipr, NumInternalProcRegs); - SERIALIZE_SCALAR(intrflag); - SERIALIZE_SCALAR(pal_shadow); -#endif -} - - -void -RegFile::unserialize(Checkpoint *cp, const std::string §ion) -{ - UNSERIALIZE_ARRAY(intRegFile, NumIntRegs); - UNSERIALIZE_ARRAY(floatRegFile.q, NumFloatRegs); - //UNSERIALIZE_SCALAR(miscRegs.fpcr); - //UNSERIALIZE_SCALAR(miscRegs.uniq); - //UNSERIALIZE_SCALAR(miscRegs.lock_flag); - //UNSERIALIZE_SCALAR(miscRegs.lock_addr); - UNSERIALIZE_SCALAR(pc); - UNSERIALIZE_SCALAR(npc); - UNSERIALIZE_SCALAR(nnpc); -#if FULL_SYSTEM - UNSERIALIZE_ARRAY(palregs, NumIntRegs); - UNSERIALIZE_ARRAY(ipr, NumInternalProcRegs); - UNSERIALIZE_SCALAR(intrflag); - UNSERIALIZE_SCALAR(pal_shadow); -#endif -} - - -#if FULL_SYSTEM -void -PTE::serialize(std::ostream &os) -{ - SERIALIZE_SCALAR(tag); - SERIALIZE_SCALAR(ppn); - SERIALIZE_SCALAR(xre); - SERIALIZE_SCALAR(xwe); - SERIALIZE_SCALAR(asn); - SERIALIZE_SCALAR(asma); - SERIALIZE_SCALAR(fonr); - SERIALIZE_SCALAR(fonw); - SERIALIZE_SCALAR(valid); -} - - -void -PTE::unserialize(Checkpoint *cp, const std::string §ion) -{ - UNSERIALIZE_SCALAR(tag); - UNSERIALIZE_SCALAR(ppn); - UNSERIALIZE_SCALAR(xre); - UNSERIALIZE_SCALAR(xwe); - UNSERIALIZE_SCALAR(asn); - UNSERIALIZE_SCALAR(asma); - UNSERIALIZE_SCALAR(fonr); - UNSERIALIZE_SCALAR(fonw); - UNSERIALIZE_SCALAR(valid); -} - -#endif //FULL_SYSTEM diff --git a/arch/mips/isa_traits.hh b/arch/mips/isa_traits.hh deleted file mode 100644 index 1dfa0dc7a..000000000 --- a/arch/mips/isa_traits.hh +++ /dev/null @@ -1,546 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __ARCH_MIPS_ISA_TRAITS_HH__ -#define __ARCH_MIPS_ISA_TRAITS_HH__ - -//#include "arch/mips/misc_regfile.hh" -#include "base/misc.hh" -#include "config/full_system.hh" -#include "sim/host.hh" -#include "sim/faults.hh" - -#include <vector> - -class FastCPU; -class FullCPU; -class Checkpoint; - -namespace LittleEndianGuest {}; -using namespace LittleEndianGuest; - -#define TARGET_MIPS - -class StaticInst; -class StaticInstPtr; - -namespace MIPS34K { -int DTB_ASN_ASN(uint64_t reg); -int ITB_ASN_ASN(uint64_t reg); -}; - -namespace MipsISA -{ - typedef uint32_t MachInst; -// typedef uint64_t Addr; - typedef uint8_t RegIndex; - - enum { - MemoryEnd = 0xffffffffffffffffULL, - - NumIntRegs = 32, - NumFloatRegs = 32, - NumMiscRegs = 258, //account for hi,lo regs - - MaxRegsOfAnyType = 32, - // Static instruction parameters - MaxInstSrcRegs = 3, - MaxInstDestRegs = 2, - - // semantically meaningful register indices - ZeroReg = 0, // architecturally meaningful - // the rest of these depend on the ABI - StackPointerReg = 30, - GlobalPointerReg = 29, - ProcedureValueReg = 27, - ReturnAddressReg = 26, - ReturnValueReg = 0, - FramePointerReg = 15, - ArgumentReg0 = 16, - ArgumentReg1 = 17, - ArgumentReg2 = 18, - ArgumentReg3 = 19, - ArgumentReg4 = 20, - ArgumentReg5 = 21, - - LogVMPageSize = 13, // 8K bytes - VMPageSize = (1 << LogVMPageSize), - - BranchPredAddrShiftAmt = 2, // instructions are 4-byte aligned - - WordBytes = 4, - HalfwordBytes = 2, - ByteBytes = 1, - DepNA = 0, - }; - - // These enumerate all the registers for dependence tracking. - enum DependenceTags { - // 0..31 are the integer regs 0..31 - // 32..63 are the FP regs 0..31, i.e. use (reg + FP_Base_DepTag) - FP_Base_DepTag = 32, - Ctrl_Base_DepTag = 64, - Fpcr_DepTag = 64, // floating point control register - Uniq_DepTag = 65, - IPR_Base_DepTag = 66, - MiscReg_DepTag = 67 - }; - - typedef uint64_t IntReg; - typedef IntReg IntRegFile[NumIntRegs]; - - // floating point register file entry type - typedef union { - uint64_t q; - double d; - } FloatReg; - - typedef union { - uint64_t q[NumFloatRegs]; // integer qword view - double d[NumFloatRegs]; // double-precision floating point view - } FloatRegFile; - - // cop-0/cop-1 system control register file - typedef uint64_t MiscReg; -//typedef MiscReg MiscRegFile[NumMiscRegs]; - class MiscRegFile { - public: - MiscReg - protected: - uint64_t fpcr; // floating point condition codes - uint64_t uniq; // process-unique register - bool lock_flag; // lock flag for LL/SC - Addr lock_addr; // lock address for LL/SC - - MiscReg miscRegFile[NumMiscRegs]; - - public: - //These functions should be removed once the simplescalar cpu model - //has been replaced. - int getInstAsid(); - int getDataAsid(); - - MiscReg readReg(int misc_reg) - { return miscRegFile[misc_reg]; } - - MiscReg readRegWithEffect(int misc_reg, Fault &fault, ExecContext *xc) - { return miscRegFile[misc_reg];} - - Fault setReg(int misc_reg, const MiscReg &val) - { miscRegFile[misc_reg] = val; return NoFault; } - - Fault setRegWithEffect(int misc_reg, const MiscReg &val, - ExecContext *xc) - { miscRegFile[misc_reg] = val; return NoFault; } - -#if FULL_SYSTEM - void clearIprs() { }; - - protected: - InternalProcReg ipr[NumInternalProcRegs]; // Internal processor regs - - private: - MiscReg readIpr(int idx, Fault &fault, ExecContext *xc) { } - - Fault setIpr(int idx, uint64_t val, ExecContext *xc) { } -#endif - friend class RegFile; - }; - - enum MiscRegTags { - //Coprocessor 0 Registers - //Reference MIPS32 Arch. for Programmers, Vol. III, Ch.8 - //(Register Number-Register Select) Summary of Register - //------------------------------------------------------ - Index = 0, //0-0 Index into the TLB array - - MVPControl = 1, //0-1 Per-processor register containing global - //MIPS® MT configuration data - - MVPConf0 = 2, //0-2 Per-processor register containing global - //MIPS® MT configuration data - - MVPConf1 = 3, //0-3 Per-processor register containing global - //MIPS® MT configuration data - - Random = 8, //1-0 Randomly generated index into the TLB array - - VPEControl = 9, //1-1 Per-VPE register containing relatively volatile - //thread configuration data - - VPEConf0 = 10, //1-2 Per-VPE multi-thread configuration - //information - - - VPEConf1 = 11, //1-2 Per-VPE multi-thread configuration - //information - - YQMask = 12, //Per-VPE register defining which YIELD - //qualifier bits may be used without generating - //an exception - - VPESchedule = 13, - VPEScheFBack = 14, - VPEOpt = 15, - EntryLo0 = 16, // Bank 3: 16 - 23 - TCStatus = 17, - TCBind = 18, - TCRestart = 19, - TCHalt = 20, - TCContext = 21, - TCSchedule = 22, - TCScheFBack = 23, - - EntryLo1 = 24,// Bank 4: 24 - 31 - - Context = 32, // Bank 5: 32 - 39 - ContextConfig = 33, - - //PageMask = 40, //Bank 6: 40 - 47 - PageGrain = 41, - - Wired = 48, //Bank 7:48 - 55 - SRSConf0 = 49, - SRSConf1 = 50, - SRSConf2 = 51, - SRSConf3 = 52, - SRSConf4 = 53, - BadVAddr = 54, - - HWRena = 56,//Bank 8:56 - 63 - - Count = 64, //Bank 9:64 - 71 - - EntryHi = 72,//Bank 10:72 - 79 - - Compare = 80,//Bank 11:80 - 87 - - Status = 88,//Bank 12:88 - 96 //12-0 Processor status and control - IntCtl = 89, //12-1 Interrupt system status and control - SRSCtl = 90, //12-2 Shadow register set status and control - SRSMap = 91, //12-3 Shadow set IPL mapping - - Cause = 97,//97-104 //13-0 Cause of last general exception - - EPC = 105,//105-112 //14-0 Program counter at last exception - - PRId = 113//113-120, //15-0 Processor identification and revision - EBase = 114, //15-1 Exception vector base register - - Config = 121,//Bank 16: 121-128 - Config1 = 122, - Config2 = 123, - Config3 = 124, - Config6 = 127, - Config7 = 128, - - - LLAddr = 129,//Bank 17: 129-136 - - WatchLo0 = 137,//Bank 18: 137-144 - WatchLo1 = 138, - WatchLo2 = 139, - WatchLo3 = 140, - WatchLo4 = 141, - WatchLo5 = 142, - WatchLo6 = 143, - WatchLo7 = 144, - - WatchHi0 = 145,//Bank 19: 145-152 - WatchHi1 = 146, - WatchHi2 = 147, - WatchHi3 = 148, - WatchHi4 = 149, - WatchHi5 = 150, - WatchHi6 = 151, - WatchHi7 = 152, - - XCContext64 = 153,//Bank 20: 153-160 - - //Bank 21: 161-168 - - //Bank 22: 169-176 - - Debug = 177, //Bank 23: 177-184 - TraceControl1 = 178, - TraceControl2 = 179, - UserTraceData = 180, - TraceBPC = 181, - - DEPC = 185,//Bank 24: 185-192 - - PerfCnt0 = 193,//Bank 25: 193 - 200 - PerfCnt1 = 194, - PerfCnt2 = 195, - PerfCnt3 = 196, - PerfCnt4 = 197, - PerfCnt5 = 198, - PerfCnt6 = 199, - PerfCnt7 = 200, - - ErrCtl = 201, //Bank 26: 201 - 208 - - CacheErr0 = 209, //Bank 27: 209 - 216 - CacheErr1 = 210, - CacheErr2 = 211, - CacheErr3 = 212, - - TagLo0 = 217,//Bank 28: 217 - 224 - DataLo1 = 218, - TagLo2 = 219, - DataLo3 = 220, - TagLo4 = 221, - DataLo5 = 222, - TagLo6 = 223, - DataLo7 = 234, - - TagHi0 = 233,//Bank 29: 233 - 240 - DataHi1 = 234, - TagHi2 = 235, - DataHi3 = 236, - TagHi4 = 237, - DataHi5 = 238, - TagHi6 = 239, - DataHi7 = 240, - - - ErrorEPC = 249,//Bank 30: 241 - 248 - - DESAVE = 257,//Bank 31: 249-256 - - //More Misc. Regs - Hi, - Lo, - FCSR, - FPCR, - - //Alpha Regs, but here now, for - //compiling sake - UNIQ, - LockAddr, - LockFlag - }; - -extern const Addr PageShift; -extern const Addr PageBytes; -extern const Addr PageMask; -extern const Addr PageOffset; - -#if FULL_SYSTEM - - typedef uint64_t InternalProcReg; - -#include "arch/mips/isa_fullsys_traits.hh" - -#else - enum { - NumInternalProcRegs = 0 - }; -#endif - - enum { - TotalNumRegs = - NumIntRegs + NumFloatRegs + NumMiscRegs + NumInternalProcRegs - }; - - enum { - TotalDataRegs = NumIntRegs + NumFloatRegs - }; - - typedef union { - IntReg intreg; - FloatReg fpreg; - MiscReg ctrlreg; - } AnyReg; - - struct RegFile { - IntRegFile intRegFile; // (signed) integer register file - FloatRegFile floatRegFile; // floating point register file - MiscRegFile miscRegs; // control register file - - - Addr pc; // program counter - Addr npc; // next-cycle program counter - Addr nnpc; // next-next-cycle program counter - // used to implement branch delay slot - // not real register - - MiscReg hi; // MIPS HI Register - MiscReg lo; // MIPS LO Register - - -#if FULL_SYSTEM - IntReg palregs[NumIntRegs]; // PAL shadow registers - InternalProcReg ipr[NumInternalProcRegs]; // internal processor regs - int intrflag; // interrupt flag - bool pal_shadow; // using pal_shadow registers - inline int instAsid() { return MIPS34K::ITB_ASN_ASN(ipr[IPR_ITB_ASN]); } - inline int dataAsid() { return MIPS34K::DTB_ASN_ASN(ipr[IPR_DTB_ASN]); } -#endif // FULL_SYSTEM - - //void initCP0Regs(); - void serialize(std::ostream &os); - void unserialize(Checkpoint *cp, const std::string §ion); - - void createCP0Regs(); - void coldReset(); - }; - - StaticInstPtr decodeInst(MachInst); - - // return a no-op instruction... used for instruction fetch faults - extern const MachInst NoopMachInst; - - enum annotes { - ANNOTE_NONE = 0, - // An impossible number for instruction annotations - ITOUCH_ANNOTE = 0xffffffff, - }; - - void getMiscRegIdx(int reg_name,int &idx, int &sel); - - - static inline bool isCallerSaveIntegerRegister(unsigned int reg) { - panic("register classification not implemented"); - return (reg >= 1 && reg <= 8 || reg >= 22 && reg <= 25 || reg == 27); - } - - static inline bool isCalleeSaveIntegerRegister(unsigned int reg) { - panic("register classification not implemented"); - return (reg >= 9 && reg <= 15); - } - - static inline bool isCallerSaveFloatRegister(unsigned int reg) { - panic("register classification not implemented"); - return false; - } - - static inline bool isCalleeSaveFloatRegister(unsigned int reg) { - panic("register classification not implemented"); - return false; - } - - static inline Addr alignAddress(const Addr &addr, - unsigned int nbytes) { - return (addr & ~(nbytes - 1)); - } - - // Instruction address compression hooks - static inline Addr realPCToFetchPC(const Addr &addr) { - return addr; - } - - static inline Addr fetchPCToRealPC(const Addr &addr) { - return addr; - } - - // the size of "fetched" instructions (not necessarily the size - // of real instructions for PISA) - static inline size_t fetchInstSize() { - return sizeof(MachInst); - } - - static inline MachInst makeRegisterCopy(int dest, int src) { - panic("makeRegisterCopy not implemented"); - return 0; - } - - // Machine operations - - void saveMachineReg(AnyReg &savereg, const RegFile ®_file, - int regnum); - - void restoreMachineReg(RegFile ®s, const AnyReg ®, - int regnum); - -#if 0 - static void serializeSpecialRegs(const Serializable::Proxy &proxy, - const RegFile ®s); - - static void unserializeSpecialRegs(const IniFile *db, - const std::string &category, - ConfigNode *node, - RegFile ®s); -#endif - - /** - * Function to insure ISA semantics about 0 registers. - * @param xc The execution context. - */ - template <class XC> - void zeroRegisters(XC *xc); - - const Addr MaxAddr = (Addr)-1; -}; - -#if !FULL_SYSTEM -class SyscallReturn { - public: - template <class T> - SyscallReturn(T v, bool s) - { - retval = (uint64_t)v; - success = s; - } - - template <class T> - SyscallReturn(T v) - { - success = (v >= 0); - retval = (uint64_t)v; - } - - ~SyscallReturn() {} - - SyscallReturn& operator=(const SyscallReturn& s) { - retval = s.retval; - success = s.success; - return *this; - } - - bool successful() { return success; } - uint64_t value() { return retval; } - - - private: - uint64_t retval; - bool success; -}; - -#endif - - -#if FULL_SYSTEM -//typedef TheISA::InternalProcReg InternalProcReg; -//const int NumInternalProcRegs = TheISA::NumInternalProcRegs; -//const int NumInterruptLevels = TheISA::NumInterruptLevels; - -#include "arch/mips/mips34k.hh" -#endif - -#endif // __ARCH_MIPS_ISA_TRAITS_HH__ diff --git a/arch/mips/linux_process.cc b/arch/mips/linux_process.cc deleted file mode 100644 index 1d4f62350..000000000 --- a/arch/mips/linux_process.cc +++ /dev/null @@ -1,588 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include "arch/mips/common_syscall_emul.hh" -#include "arch/mips/linux_process.hh" -#include "arch/mips/isa_traits.hh" - -#include "base/trace.hh" -#include "cpu/exec_context.hh" -#include "kern/linux/linux.hh" -#include "mem/functional/functional.hh" - -#include "sim/process.hh" -#include "sim/syscall_emul.hh" - -using namespace std; -using namespace MipsISA; - -/// Target uname() handler. -static SyscallReturn -unameFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - TypedBufferArg<Linux::utsname> name(xc->getSyscallArg(0)); - - strcpy(name->sysname, "Linux"); - strcpy(name->nodename, "m5.eecs.umich.edu"); - strcpy(name->release, "2.4.20"); - strcpy(name->version, "#1 Mon Aug 18 11:32:15 EDT 2003"); - strcpy(name->machine, "mips"); - - name.copyOut(xc->mem); - return 0; -} - -/// Target osf_getsysyinfo() handler. Even though this call is -/// borrowed from Tru64, the subcases that get used appear to be -/// different in practice from those used by Tru64 processes. -static SyscallReturn -osf_getsysinfoFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - unsigned op = xc->getSyscallArg(0); - // unsigned nbytes = xc->getSyscallArg(2); - - switch (op) { - - case 45: { // GSI_IEEE_FP_CONTROL - TypedBufferArg<uint64_t> fpcr(xc->getSyscallArg(1)); - // I don't think this exactly matches the HW FPCR - *fpcr = 0; - fpcr.copyOut(xc->mem); - return 0; - } - - default: - cerr << "osf_getsysinfo: unknown op " << op << endl; - abort(); - break; - } - - return 1; -} - -/// Target osf_setsysinfo() handler. -static SyscallReturn -osf_setsysinfoFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - unsigned op = xc->getSyscallArg(0); - // unsigned nbytes = xc->getSyscallArg(2); - - switch (op) { - - case 14: { // SSI_IEEE_FP_CONTROL - TypedBufferArg<uint64_t> fpcr(xc->getSyscallArg(1)); - // I don't think this exactly matches the HW FPCR - fpcr.copyIn(xc->mem); - DPRINTFR(SyscallVerbose, "osf_setsysinfo(SSI_IEEE_FP_CONTROL): " - " setting FPCR to 0x%x\n", gtoh(*(uint64_t*)fpcr)); - return 0; - } - - default: - cerr << "osf_setsysinfo: unknown op " << op << endl; - abort(); - break; - } - - return 1; -} - - -SyscallDesc MipsLinuxProcess::syscallDescs[] = { - /* 0 */ SyscallDesc("osf_syscall", unimplementedFunc), - /* 1 */ SyscallDesc("exit", exitFunc), - /* 2 */ SyscallDesc("fork", unimplementedFunc), - /* 3 */ SyscallDesc("read", readFunc), - /* 4 */ SyscallDesc("write", writeFunc), - /* 5 */ SyscallDesc("osf_old_open", unimplementedFunc), - /* 6 */ SyscallDesc("close", closeFunc), - /* 7 */ SyscallDesc("osf_wait4", unimplementedFunc), - /* 8 */ SyscallDesc("osf_old_creat", unimplementedFunc), - /* 9 */ SyscallDesc("link", unimplementedFunc), - /* 10 */ SyscallDesc("unlink", unlinkFunc), - /* 11 */ SyscallDesc("osf_execve", unimplementedFunc), - /* 12 */ SyscallDesc("chdir", unimplementedFunc), - /* 13 */ SyscallDesc("fchdir", unimplementedFunc), - /* 14 */ SyscallDesc("mknod", unimplementedFunc), - /* 15 */ SyscallDesc("chmod", chmodFunc<Linux>), - /* 16 */ SyscallDesc("chown", chownFunc), - /* 17 */ SyscallDesc("brk", obreakFunc), - /* 18 */ SyscallDesc("osf_getfsstat", unimplementedFunc), - /* 19 */ SyscallDesc("lseek", lseekFunc), - /* 20 */ SyscallDesc("getxpid", getpidFunc), - /* 21 */ SyscallDesc("osf_mount", unimplementedFunc), - /* 22 */ SyscallDesc("umount", unimplementedFunc), - /* 23 */ SyscallDesc("setuid", setuidFunc), - /* 24 */ SyscallDesc("getxuid", getuidFunc), - /* 25 */ SyscallDesc("exec_with_loader", unimplementedFunc), - /* 26 */ SyscallDesc("osf_ptrace", unimplementedFunc), - /* 27 */ SyscallDesc("osf_nrecvmsg", unimplementedFunc), - /* 28 */ SyscallDesc("osf_nsendmsg", unimplementedFunc), - /* 29 */ SyscallDesc("osf_nrecvfrom", unimplementedFunc), - /* 30 */ SyscallDesc("osf_naccept", unimplementedFunc), - /* 31 */ SyscallDesc("osf_ngetpeername", unimplementedFunc), - /* 32 */ SyscallDesc("osf_ngetsockname", unimplementedFunc), - /* 33 */ SyscallDesc("access", unimplementedFunc), - /* 34 */ SyscallDesc("osf_chflags", unimplementedFunc), - /* 35 */ SyscallDesc("osf_fchflags", unimplementedFunc), - /* 36 */ SyscallDesc("sync", unimplementedFunc), - /* 37 */ SyscallDesc("kill", unimplementedFunc), - /* 38 */ SyscallDesc("osf_old_stat", unimplementedFunc), - /* 39 */ SyscallDesc("setpgid", unimplementedFunc), - /* 40 */ SyscallDesc("osf_old_lstat", unimplementedFunc), - /* 41 */ SyscallDesc("dup", unimplementedFunc), - /* 42 */ SyscallDesc("pipe", unimplementedFunc), - /* 43 */ SyscallDesc("osf_set_program_attributes", unimplementedFunc), - /* 44 */ SyscallDesc("osf_profil", unimplementedFunc), - /* 45 */ SyscallDesc("open", openFunc<Linux>), - /* 46 */ SyscallDesc("osf_old_sigaction", unimplementedFunc), - /* 47 */ SyscallDesc("getxgid", getgidFunc), - /* 48 */ SyscallDesc("osf_sigprocmask", ignoreFunc), - /* 49 */ SyscallDesc("osf_getlogin", unimplementedFunc), - /* 50 */ SyscallDesc("osf_setlogin", unimplementedFunc), - /* 51 */ SyscallDesc("acct", unimplementedFunc), - /* 52 */ SyscallDesc("sigpending", unimplementedFunc), - /* 53 */ SyscallDesc("osf_classcntl", unimplementedFunc), - /* 54 */ SyscallDesc("ioctl", ioctlFunc<Linux>), - /* 55 */ SyscallDesc("osf_reboot", unimplementedFunc), - /* 56 */ SyscallDesc("osf_revoke", unimplementedFunc), - /* 57 */ SyscallDesc("symlink", unimplementedFunc), - /* 58 */ SyscallDesc("readlink", unimplementedFunc), - /* 59 */ SyscallDesc("execve", unimplementedFunc), - /* 60 */ SyscallDesc("umask", unimplementedFunc), - /* 61 */ SyscallDesc("chroot", unimplementedFunc), - /* 62 */ SyscallDesc("osf_old_fstat", unimplementedFunc), - /* 63 */ SyscallDesc("getpgrp", unimplementedFunc), - /* 64 */ SyscallDesc("getpagesize", getpagesizeFunc), - /* 65 */ SyscallDesc("osf_mremap", unimplementedFunc), - /* 66 */ SyscallDesc("vfork", unimplementedFunc), - /* 67 */ SyscallDesc("stat", statFunc<Linux>), - /* 68 */ SyscallDesc("lstat", lstatFunc<Linux>), - /* 69 */ SyscallDesc("osf_sbrk", unimplementedFunc), - /* 70 */ SyscallDesc("osf_sstk", unimplementedFunc), - /* 71 */ SyscallDesc("mmap", mmapFunc<Linux>), - /* 72 */ SyscallDesc("osf_old_vadvise", unimplementedFunc), - /* 73 */ SyscallDesc("munmap", munmapFunc), - /* 74 */ SyscallDesc("mprotect", ignoreFunc), - /* 75 */ SyscallDesc("madvise", unimplementedFunc), - /* 76 */ SyscallDesc("vhangup", unimplementedFunc), - /* 77 */ SyscallDesc("osf_kmodcall", unimplementedFunc), - /* 78 */ SyscallDesc("osf_mincore", unimplementedFunc), - /* 79 */ SyscallDesc("getgroups", unimplementedFunc), - /* 80 */ SyscallDesc("setgroups", unimplementedFunc), - /* 81 */ SyscallDesc("osf_old_getpgrp", unimplementedFunc), - /* 82 */ SyscallDesc("setpgrp", unimplementedFunc), - /* 83 */ SyscallDesc("osf_setitimer", unimplementedFunc), - /* 84 */ SyscallDesc("osf_old_wait", unimplementedFunc), - /* 85 */ SyscallDesc("osf_table", unimplementedFunc), - /* 86 */ SyscallDesc("osf_getitimer", unimplementedFunc), - /* 87 */ SyscallDesc("gethostname", gethostnameFunc), - /* 88 */ SyscallDesc("sethostname", unimplementedFunc), - /* 89 */ SyscallDesc("getdtablesize", unimplementedFunc), - /* 90 */ SyscallDesc("dup2", unimplementedFunc), - /* 91 */ SyscallDesc("fstat", fstatFunc<Linux>), - /* 92 */ SyscallDesc("fcntl", fcntlFunc), - /* 93 */ SyscallDesc("osf_select", unimplementedFunc), - /* 94 */ SyscallDesc("poll", unimplementedFunc), - /* 95 */ SyscallDesc("fsync", unimplementedFunc), - /* 96 */ SyscallDesc("setpriority", unimplementedFunc), - /* 97 */ SyscallDesc("socket", unimplementedFunc), - /* 98 */ SyscallDesc("connect", unimplementedFunc), - /* 99 */ SyscallDesc("accept", unimplementedFunc), - /* 100 */ SyscallDesc("getpriority", unimplementedFunc), - /* 101 */ SyscallDesc("send", unimplementedFunc), - /* 102 */ SyscallDesc("recv", unimplementedFunc), - /* 103 */ SyscallDesc("sigreturn", unimplementedFunc), - /* 104 */ SyscallDesc("bind", unimplementedFunc), - /* 105 */ SyscallDesc("setsockopt", unimplementedFunc), - /* 106 */ SyscallDesc("listen", unimplementedFunc), - /* 107 */ SyscallDesc("osf_plock", unimplementedFunc), - /* 108 */ SyscallDesc("osf_old_sigvec", unimplementedFunc), - /* 109 */ SyscallDesc("osf_old_sigblock", unimplementedFunc), - /* 110 */ SyscallDesc("osf_old_sigsetmask", unimplementedFunc), - /* 111 */ SyscallDesc("sigsuspend", unimplementedFunc), - /* 112 */ SyscallDesc("osf_sigstack", ignoreFunc), - /* 113 */ SyscallDesc("recvmsg", unimplementedFunc), - /* 114 */ SyscallDesc("sendmsg", unimplementedFunc), - /* 115 */ SyscallDesc("osf_old_vtrace", unimplementedFunc), - /* 116 */ SyscallDesc("osf_gettimeofday", unimplementedFunc), - /* 117 */ SyscallDesc("osf_getrusage", unimplementedFunc), - /* 118 */ SyscallDesc("getsockopt", unimplementedFunc), - /* 119 */ SyscallDesc("numa_syscalls", unimplementedFunc), - /* 120 */ SyscallDesc("readv", unimplementedFunc), - /* 121 */ SyscallDesc("writev", writevFunc<Linux>), - /* 122 */ SyscallDesc("osf_settimeofday", unimplementedFunc), - /* 123 */ SyscallDesc("fchown", fchownFunc), - /* 124 */ SyscallDesc("fchmod", fchmodFunc<Linux>), - /* 125 */ SyscallDesc("recvfrom", unimplementedFunc), - /* 126 */ SyscallDesc("setreuid", unimplementedFunc), - /* 127 */ SyscallDesc("setregid", unimplementedFunc), - /* 128 */ SyscallDesc("rename", renameFunc), - /* 129 */ SyscallDesc("truncate", unimplementedFunc), - /* 130 */ SyscallDesc("ftruncate", unimplementedFunc), - /* 131 */ SyscallDesc("flock", unimplementedFunc), - /* 132 */ SyscallDesc("setgid", unimplementedFunc), - /* 133 */ SyscallDesc("sendto", unimplementedFunc), - /* 134 */ SyscallDesc("shutdown", unimplementedFunc), - /* 135 */ SyscallDesc("socketpair", unimplementedFunc), - /* 136 */ SyscallDesc("mkdir", unimplementedFunc), - /* 137 */ SyscallDesc("rmdir", unimplementedFunc), - /* 138 */ SyscallDesc("osf_utimes", unimplementedFunc), - /* 139 */ SyscallDesc("osf_old_sigreturn", unimplementedFunc), - /* 140 */ SyscallDesc("osf_adjtime", unimplementedFunc), - /* 141 */ SyscallDesc("getpeername", unimplementedFunc), - /* 142 */ SyscallDesc("osf_gethostid", unimplementedFunc), - /* 143 */ SyscallDesc("osf_sethostid", unimplementedFunc), - /* 144 */ SyscallDesc("getrlimit", getrlimitFunc<Linux>), - /* 145 */ SyscallDesc("setrlimit", ignoreFunc), - /* 146 */ SyscallDesc("osf_old_killpg", unimplementedFunc), - /* 147 */ SyscallDesc("setsid", unimplementedFunc), - /* 148 */ SyscallDesc("quotactl", unimplementedFunc), - /* 149 */ SyscallDesc("osf_oldquota", unimplementedFunc), - /* 150 */ SyscallDesc("getsockname", unimplementedFunc), - /* 151 */ SyscallDesc("osf_pread", unimplementedFunc), - /* 152 */ SyscallDesc("osf_pwrite", unimplementedFunc), - /* 153 */ SyscallDesc("osf_pid_block", unimplementedFunc), - /* 154 */ SyscallDesc("osf_pid_unblock", unimplementedFunc), - /* 155 */ SyscallDesc("osf_signal_urti", unimplementedFunc), - /* 156 */ SyscallDesc("sigaction", ignoreFunc), - /* 157 */ SyscallDesc("osf_sigwaitprim", unimplementedFunc), - /* 158 */ SyscallDesc("osf_nfssvc", unimplementedFunc), - /* 159 */ SyscallDesc("osf_getdirentries", unimplementedFunc), - /* 160 */ SyscallDesc("osf_statfs", unimplementedFunc), - /* 161 */ SyscallDesc("osf_fstatfs", unimplementedFunc), - /* 162 */ SyscallDesc("unknown #162", unimplementedFunc), - /* 163 */ SyscallDesc("osf_async_daemon", unimplementedFunc), - /* 164 */ SyscallDesc("osf_getfh", unimplementedFunc), - /* 165 */ SyscallDesc("osf_getdomainname", unimplementedFunc), - /* 166 */ SyscallDesc("setdomainname", unimplementedFunc), - /* 167 */ SyscallDesc("unknown #167", unimplementedFunc), - /* 168 */ SyscallDesc("unknown #168", unimplementedFunc), - /* 169 */ SyscallDesc("osf_exportfs", unimplementedFunc), - /* 170 */ SyscallDesc("unknown #170", unimplementedFunc), - /* 171 */ SyscallDesc("unknown #171", unimplementedFunc), - /* 172 */ SyscallDesc("unknown #172", unimplementedFunc), - /* 173 */ SyscallDesc("unknown #173", unimplementedFunc), - /* 174 */ SyscallDesc("unknown #174", unimplementedFunc), - /* 175 */ SyscallDesc("unknown #175", unimplementedFunc), - /* 176 */ SyscallDesc("unknown #176", unimplementedFunc), - /* 177 */ SyscallDesc("unknown #177", unimplementedFunc), - /* 178 */ SyscallDesc("unknown #178", unimplementedFunc), - /* 179 */ SyscallDesc("unknown #179", unimplementedFunc), - /* 180 */ SyscallDesc("unknown #180", unimplementedFunc), - /* 181 */ SyscallDesc("osf_alt_plock", unimplementedFunc), - /* 182 */ SyscallDesc("unknown #182", unimplementedFunc), - /* 183 */ SyscallDesc("unknown #183", unimplementedFunc), - /* 184 */ SyscallDesc("osf_getmnt", unimplementedFunc), - /* 185 */ SyscallDesc("unknown #185", unimplementedFunc), - /* 186 */ SyscallDesc("unknown #186", unimplementedFunc), - /* 187 */ SyscallDesc("osf_alt_sigpending", unimplementedFunc), - /* 188 */ SyscallDesc("osf_alt_setsid", unimplementedFunc), - /* 189 */ SyscallDesc("unknown #189", unimplementedFunc), - /* 190 */ SyscallDesc("unknown #190", unimplementedFunc), - /* 191 */ SyscallDesc("unknown #191", unimplementedFunc), - /* 192 */ SyscallDesc("unknown #192", unimplementedFunc), - /* 193 */ SyscallDesc("unknown #193", unimplementedFunc), - /* 194 */ SyscallDesc("unknown #194", unimplementedFunc), - /* 195 */ SyscallDesc("unknown #195", unimplementedFunc), - /* 196 */ SyscallDesc("unknown #196", unimplementedFunc), - /* 197 */ SyscallDesc("unknown #197", unimplementedFunc), - /* 198 */ SyscallDesc("unknown #198", unimplementedFunc), - /* 199 */ SyscallDesc("osf_swapon", unimplementedFunc), - /* 200 */ SyscallDesc("msgctl", unimplementedFunc), - /* 201 */ SyscallDesc("msgget", unimplementedFunc), - /* 202 */ SyscallDesc("msgrcv", unimplementedFunc), - /* 203 */ SyscallDesc("msgsnd", unimplementedFunc), - /* 204 */ SyscallDesc("semctl", unimplementedFunc), - /* 205 */ SyscallDesc("semget", unimplementedFunc), - /* 206 */ SyscallDesc("semop", unimplementedFunc), - /* 207 */ SyscallDesc("osf_utsname", unimplementedFunc), - /* 208 */ SyscallDesc("lchown", unimplementedFunc), - /* 209 */ SyscallDesc("osf_shmat", unimplementedFunc), - /* 210 */ SyscallDesc("shmctl", unimplementedFunc), - /* 211 */ SyscallDesc("shmdt", unimplementedFunc), - /* 212 */ SyscallDesc("shmget", unimplementedFunc), - /* 213 */ SyscallDesc("osf_mvalid", unimplementedFunc), - /* 214 */ SyscallDesc("osf_getaddressconf", unimplementedFunc), - /* 215 */ SyscallDesc("osf_msleep", unimplementedFunc), - /* 216 */ SyscallDesc("osf_mwakeup", unimplementedFunc), - /* 217 */ SyscallDesc("msync", unimplementedFunc), - /* 218 */ SyscallDesc("osf_signal", unimplementedFunc), - /* 219 */ SyscallDesc("osf_utc_gettime", unimplementedFunc), - /* 220 */ SyscallDesc("osf_utc_adjtime", unimplementedFunc), - /* 221 */ SyscallDesc("unknown #221", unimplementedFunc), - /* 222 */ SyscallDesc("osf_security", unimplementedFunc), - /* 223 */ SyscallDesc("osf_kloadcall", unimplementedFunc), - /* 224 */ SyscallDesc("unknown #224", unimplementedFunc), - /* 225 */ SyscallDesc("unknown #225", unimplementedFunc), - /* 226 */ SyscallDesc("unknown #226", unimplementedFunc), - /* 227 */ SyscallDesc("unknown #227", unimplementedFunc), - /* 228 */ SyscallDesc("unknown #228", unimplementedFunc), - /* 229 */ SyscallDesc("unknown #229", unimplementedFunc), - /* 230 */ SyscallDesc("unknown #230", unimplementedFunc), - /* 231 */ SyscallDesc("unknown #231", unimplementedFunc), - /* 232 */ SyscallDesc("unknown #232", unimplementedFunc), - /* 233 */ SyscallDesc("getpgid", unimplementedFunc), - /* 234 */ SyscallDesc("getsid", unimplementedFunc), - /* 235 */ SyscallDesc("sigaltstack", ignoreFunc), - /* 236 */ SyscallDesc("osf_waitid", unimplementedFunc), - /* 237 */ SyscallDesc("osf_priocntlset", unimplementedFunc), - /* 238 */ SyscallDesc("osf_sigsendset", unimplementedFunc), - /* 239 */ SyscallDesc("osf_set_speculative", unimplementedFunc), - /* 240 */ SyscallDesc("osf_msfs_syscall", unimplementedFunc), - /* 241 */ SyscallDesc("osf_sysinfo", unimplementedFunc), - /* 242 */ SyscallDesc("osf_uadmin", unimplementedFunc), - /* 243 */ SyscallDesc("osf_fuser", unimplementedFunc), - /* 244 */ SyscallDesc("osf_proplist_syscall", unimplementedFunc), - /* 245 */ SyscallDesc("osf_ntp_adjtime", unimplementedFunc), - /* 246 */ SyscallDesc("osf_ntp_gettime", unimplementedFunc), - /* 247 */ SyscallDesc("osf_pathconf", unimplementedFunc), - /* 248 */ SyscallDesc("osf_fpathconf", unimplementedFunc), - /* 249 */ SyscallDesc("unknown #249", unimplementedFunc), - /* 250 */ SyscallDesc("osf_uswitch", unimplementedFunc), - /* 251 */ SyscallDesc("osf_usleep_thread", unimplementedFunc), - /* 252 */ SyscallDesc("osf_audcntl", unimplementedFunc), - /* 253 */ SyscallDesc("osf_audgen", unimplementedFunc), - /* 254 */ SyscallDesc("sysfs", unimplementedFunc), - /* 255 */ SyscallDesc("osf_subsys_info", unimplementedFunc), - /* 256 */ SyscallDesc("osf_getsysinfo", osf_getsysinfoFunc), - /* 257 */ SyscallDesc("osf_setsysinfo", osf_setsysinfoFunc), - /* 258 */ SyscallDesc("osf_afs_syscall", unimplementedFunc), - /* 259 */ SyscallDesc("osf_swapctl", unimplementedFunc), - /* 260 */ SyscallDesc("osf_memcntl", unimplementedFunc), - /* 261 */ SyscallDesc("osf_fdatasync", unimplementedFunc), - /* 262 */ SyscallDesc("unknown #262", unimplementedFunc), - /* 263 */ SyscallDesc("unknown #263", unimplementedFunc), - /* 264 */ SyscallDesc("unknown #264", unimplementedFunc), - /* 265 */ SyscallDesc("unknown #265", unimplementedFunc), - /* 266 */ SyscallDesc("unknown #266", unimplementedFunc), - /* 267 */ SyscallDesc("unknown #267", unimplementedFunc), - /* 268 */ SyscallDesc("unknown #268", unimplementedFunc), - /* 269 */ SyscallDesc("unknown #269", unimplementedFunc), - /* 270 */ SyscallDesc("unknown #270", unimplementedFunc), - /* 271 */ SyscallDesc("unknown #271", unimplementedFunc), - /* 272 */ SyscallDesc("unknown #272", unimplementedFunc), - /* 273 */ SyscallDesc("unknown #273", unimplementedFunc), - /* 274 */ SyscallDesc("unknown #274", unimplementedFunc), - /* 275 */ SyscallDesc("unknown #275", unimplementedFunc), - /* 276 */ SyscallDesc("unknown #276", unimplementedFunc), - /* 277 */ SyscallDesc("unknown #277", unimplementedFunc), - /* 278 */ SyscallDesc("unknown #278", unimplementedFunc), - /* 279 */ SyscallDesc("unknown #279", unimplementedFunc), - /* 280 */ SyscallDesc("unknown #280", unimplementedFunc), - /* 281 */ SyscallDesc("unknown #281", unimplementedFunc), - /* 282 */ SyscallDesc("unknown #282", unimplementedFunc), - /* 283 */ SyscallDesc("unknown #283", unimplementedFunc), - /* 284 */ SyscallDesc("unknown #284", unimplementedFunc), - /* 285 */ SyscallDesc("unknown #285", unimplementedFunc), - /* 286 */ SyscallDesc("unknown #286", unimplementedFunc), - /* 287 */ SyscallDesc("unknown #287", unimplementedFunc), - /* 288 */ SyscallDesc("unknown #288", unimplementedFunc), - /* 289 */ SyscallDesc("unknown #289", unimplementedFunc), - /* 290 */ SyscallDesc("unknown #290", unimplementedFunc), - /* 291 */ SyscallDesc("unknown #291", unimplementedFunc), - /* 292 */ SyscallDesc("unknown #292", unimplementedFunc), - /* 293 */ SyscallDesc("unknown #293", unimplementedFunc), - /* 294 */ SyscallDesc("unknown #294", unimplementedFunc), - /* 295 */ SyscallDesc("unknown #295", unimplementedFunc), - /* 296 */ SyscallDesc("unknown #296", unimplementedFunc), - /* 297 */ SyscallDesc("unknown #297", unimplementedFunc), - /* 298 */ SyscallDesc("unknown #298", unimplementedFunc), - /* 299 */ SyscallDesc("unknown #299", unimplementedFunc), -/* - * Linux-specific system calls begin at 300 - */ - /* 300 */ SyscallDesc("bdflush", unimplementedFunc), - /* 301 */ SyscallDesc("sethae", unimplementedFunc), - /* 302 */ SyscallDesc("mount", unimplementedFunc), - /* 303 */ SyscallDesc("old_adjtimex", unimplementedFunc), - /* 304 */ SyscallDesc("swapoff", unimplementedFunc), - /* 305 */ SyscallDesc("getdents", unimplementedFunc), - /* 306 */ SyscallDesc("create_module", unimplementedFunc), - /* 307 */ SyscallDesc("init_module", unimplementedFunc), - /* 308 */ SyscallDesc("delete_module", unimplementedFunc), - /* 309 */ SyscallDesc("get_kernel_syms", unimplementedFunc), - /* 310 */ SyscallDesc("syslog", unimplementedFunc), - /* 311 */ SyscallDesc("reboot", unimplementedFunc), - /* 312 */ SyscallDesc("clone", unimplementedFunc), - /* 313 */ SyscallDesc("uselib", unimplementedFunc), - /* 314 */ SyscallDesc("mlock", unimplementedFunc), - /* 315 */ SyscallDesc("munlock", unimplementedFunc), - /* 316 */ SyscallDesc("mlockall", unimplementedFunc), - /* 317 */ SyscallDesc("munlockall", unimplementedFunc), - /* 318 */ SyscallDesc("sysinfo", unimplementedFunc), - /* 319 */ SyscallDesc("_sysctl", unimplementedFunc), - /* 320 */ SyscallDesc("was sys_idle", unimplementedFunc), - /* 321 */ SyscallDesc("oldumount", unimplementedFunc), - /* 322 */ SyscallDesc("swapon", unimplementedFunc), - /* 323 */ SyscallDesc("times", ignoreFunc), - /* 324 */ SyscallDesc("personality", unimplementedFunc), - /* 325 */ SyscallDesc("setfsuid", unimplementedFunc), - /* 326 */ SyscallDesc("setfsgid", unimplementedFunc), - /* 327 */ SyscallDesc("ustat", unimplementedFunc), - /* 328 */ SyscallDesc("statfs", unimplementedFunc), - /* 329 */ SyscallDesc("fstatfs", unimplementedFunc), - /* 330 */ SyscallDesc("sched_setparam", unimplementedFunc), - /* 331 */ SyscallDesc("sched_getparam", unimplementedFunc), - /* 332 */ SyscallDesc("sched_setscheduler", unimplementedFunc), - /* 333 */ SyscallDesc("sched_getscheduler", unimplementedFunc), - /* 334 */ SyscallDesc("sched_yield", unimplementedFunc), - /* 335 */ SyscallDesc("sched_get_priority_max", unimplementedFunc), - /* 336 */ SyscallDesc("sched_get_priority_min", unimplementedFunc), - /* 337 */ SyscallDesc("sched_rr_get_interval", unimplementedFunc), - /* 338 */ SyscallDesc("afs_syscall", unimplementedFunc), - /* 339 */ SyscallDesc("uname", unameFunc), - /* 340 */ SyscallDesc("nanosleep", unimplementedFunc), - /* 341 */ SyscallDesc("mremap", unimplementedFunc), - /* 342 */ SyscallDesc("nfsservctl", unimplementedFunc), - /* 343 */ SyscallDesc("setresuid", unimplementedFunc), - /* 344 */ SyscallDesc("getresuid", unimplementedFunc), - /* 345 */ SyscallDesc("pciconfig_read", unimplementedFunc), - /* 346 */ SyscallDesc("pciconfig_write", unimplementedFunc), - /* 347 */ SyscallDesc("query_module", unimplementedFunc), - /* 348 */ SyscallDesc("prctl", unimplementedFunc), - /* 349 */ SyscallDesc("pread", unimplementedFunc), - /* 350 */ SyscallDesc("pwrite", unimplementedFunc), - /* 351 */ SyscallDesc("rt_sigreturn", unimplementedFunc), - /* 352 */ SyscallDesc("rt_sigaction", ignoreFunc), - /* 353 */ SyscallDesc("rt_sigprocmask", unimplementedFunc), - /* 354 */ SyscallDesc("rt_sigpending", unimplementedFunc), - /* 355 */ SyscallDesc("rt_sigtimedwait", unimplementedFunc), - /* 356 */ SyscallDesc("rt_sigqueueinfo", unimplementedFunc), - /* 357 */ SyscallDesc("rt_sigsuspend", unimplementedFunc), - /* 358 */ SyscallDesc("select", unimplementedFunc), - /* 359 */ SyscallDesc("gettimeofday", gettimeofdayFunc<Linux>), - /* 360 */ SyscallDesc("settimeofday", unimplementedFunc), - /* 361 */ SyscallDesc("getitimer", unimplementedFunc), - /* 362 */ SyscallDesc("setitimer", unimplementedFunc), - /* 363 */ SyscallDesc("utimes", utimesFunc<Linux>), - /* 364 */ SyscallDesc("getrusage", getrusageFunc<Linux>), - /* 365 */ SyscallDesc("wait4", unimplementedFunc), - /* 366 */ SyscallDesc("adjtimex", unimplementedFunc), - /* 367 */ SyscallDesc("getcwd", unimplementedFunc), - /* 368 */ SyscallDesc("capget", unimplementedFunc), - /* 369 */ SyscallDesc("capset", unimplementedFunc), - /* 370 */ SyscallDesc("sendfile", unimplementedFunc), - /* 371 */ SyscallDesc("setresgid", unimplementedFunc), - /* 372 */ SyscallDesc("getresgid", unimplementedFunc), - /* 373 */ SyscallDesc("dipc", unimplementedFunc), - /* 374 */ SyscallDesc("pivot_root", unimplementedFunc), - /* 375 */ SyscallDesc("mincore", unimplementedFunc), - /* 376 */ SyscallDesc("pciconfig_iobase", unimplementedFunc), - /* 377 */ SyscallDesc("getdents64", unimplementedFunc), - /* 378 */ SyscallDesc("gettid", unimplementedFunc), - /* 379 */ SyscallDesc("readahead", unimplementedFunc), - /* 380 */ SyscallDesc("security", unimplementedFunc), - /* 381 */ SyscallDesc("tkill", unimplementedFunc), - /* 382 */ SyscallDesc("setxattr", unimplementedFunc), - /* 383 */ SyscallDesc("lsetxattr", unimplementedFunc), - /* 384 */ SyscallDesc("fsetxattr", unimplementedFunc), - /* 385 */ SyscallDesc("getxattr", unimplementedFunc), - /* 386 */ SyscallDesc("lgetxattr", unimplementedFunc), - /* 387 */ SyscallDesc("fgetxattr", unimplementedFunc), - /* 388 */ SyscallDesc("listxattr", unimplementedFunc), - /* 389 */ SyscallDesc("llistxattr", unimplementedFunc), - /* 390 */ SyscallDesc("flistxattr", unimplementedFunc), - /* 391 */ SyscallDesc("removexattr", unimplementedFunc), - /* 392 */ SyscallDesc("lremovexattr", unimplementedFunc), - /* 393 */ SyscallDesc("fremovexattr", unimplementedFunc), - /* 394 */ SyscallDesc("futex", unimplementedFunc), - /* 395 */ SyscallDesc("sched_setaffinity", unimplementedFunc), - /* 396 */ SyscallDesc("sched_getaffinity", unimplementedFunc), - /* 397 */ SyscallDesc("tuxcall", unimplementedFunc), - /* 398 */ SyscallDesc("io_setup", unimplementedFunc), - /* 399 */ SyscallDesc("io_destroy", unimplementedFunc), - /* 400 */ SyscallDesc("io_getevents", unimplementedFunc), - /* 401 */ SyscallDesc("io_submit", unimplementedFunc), - /* 402 */ SyscallDesc("io_cancel", unimplementedFunc), - /* 403 */ SyscallDesc("unknown #403", unimplementedFunc), - /* 404 */ SyscallDesc("unknown #404", unimplementedFunc), - /* 405 */ SyscallDesc("exit_group", exitFunc), // exit all threads... - /* 406 */ SyscallDesc("lookup_dcookie", unimplementedFunc), - /* 407 */ SyscallDesc("sys_epoll_create", unimplementedFunc), - /* 408 */ SyscallDesc("sys_epoll_ctl", unimplementedFunc), - /* 409 */ SyscallDesc("sys_epoll_wait", unimplementedFunc), - /* 410 */ SyscallDesc("remap_file_pages", unimplementedFunc), - /* 411 */ SyscallDesc("set_tid_address", unimplementedFunc), - /* 412 */ SyscallDesc("restart_syscall", unimplementedFunc), - /* 413 */ SyscallDesc("fadvise64", unimplementedFunc), - /* 414 */ SyscallDesc("timer_create", unimplementedFunc), - /* 415 */ SyscallDesc("timer_settime", unimplementedFunc), - /* 416 */ SyscallDesc("timer_gettime", unimplementedFunc), - /* 417 */ SyscallDesc("timer_getoverrun", unimplementedFunc), - /* 418 */ SyscallDesc("timer_delete", unimplementedFunc), - /* 419 */ SyscallDesc("clock_settime", unimplementedFunc), - /* 420 */ SyscallDesc("clock_gettime", unimplementedFunc), - /* 421 */ SyscallDesc("clock_getres", unimplementedFunc), - /* 422 */ SyscallDesc("clock_nanosleep", unimplementedFunc), - /* 423 */ SyscallDesc("semtimedop", unimplementedFunc), - /* 424 */ SyscallDesc("tgkill", unimplementedFunc), - /* 425 */ SyscallDesc("stat64", unimplementedFunc), - /* 426 */ SyscallDesc("lstat64", lstat64Func<Linux>), - /* 427 */ SyscallDesc("fstat64", fstat64Func<Linux>), - /* 428 */ SyscallDesc("vserver", unimplementedFunc), - /* 429 */ SyscallDesc("mbind", unimplementedFunc), - /* 430 */ SyscallDesc("get_mempolicy", unimplementedFunc), - /* 431 */ SyscallDesc("set_mempolicy", unimplementedFunc), - /* 432 */ SyscallDesc("mq_open", unimplementedFunc), - /* 433 */ SyscallDesc("mq_unlink", unimplementedFunc), - /* 434 */ SyscallDesc("mq_timedsend", unimplementedFunc), - /* 435 */ SyscallDesc("mq_timedreceive", unimplementedFunc), - /* 436 */ SyscallDesc("mq_notify", unimplementedFunc), - /* 437 */ SyscallDesc("mq_getsetattr", unimplementedFunc), - /* 438 */ SyscallDesc("waitid", unimplementedFunc), - /* 439 */ SyscallDesc("add_key", unimplementedFunc), - /* 440 */ SyscallDesc("request_key", unimplementedFunc), - /* 441 */ SyscallDesc("keyctl", unimplementedFunc) -}; - -MipsLinuxProcess::MipsLinuxProcess(const std::string &name, - ObjectFile *objFile, - int stdin_fd, - int stdout_fd, - int stderr_fd, - std::vector<std::string> &argv, - std::vector<std::string> &envp) - : LiveProcess(name, objFile, stdin_fd, stdout_fd, stderr_fd, argv, envp), - Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc)) -{ - init_regs->intRegFile[0] = 0; -} - - - -SyscallDesc* -MipsLinuxProcess::getDesc(int callnum) -{ - if (callnum < 0 || callnum > Num_Syscall_Descs) - return NULL; - return &syscallDescs[callnum]; -} diff --git a/arch/mips/linux_process.hh b/arch/mips/linux_process.hh deleted file mode 100644 index 5408a6c44..000000000 --- a/arch/mips/linux_process.hh +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2003-2004 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. - */ - -#ifndef __MIPS_LINUX_PROCESS_HH__ -#define __MIPS_LINUX_PROCESS_HH__ - -#include "sim/process.hh" - - -/// A process with emulated Mips/Linux syscalls. -class MipsLinuxProcess : public LiveProcess -{ - public: - /// Constructor. - MipsLinuxProcess(const std::string &name, - ObjectFile *objFile, - int stdin_fd, int stdout_fd, int stderr_fd, - std::vector<std::string> &argv, - std::vector<std::string> &envp); - - virtual SyscallDesc* getDesc(int callnum); - - /// The target system's hostname. - static const char *hostname; - - /// Array of syscall descriptors, indexed by call number. - static SyscallDesc syscallDescs[]; - - const int Num_Syscall_Descs; -}; - - -#endif // __MIPS_LINUX_PROCESS_HH__ diff --git a/arch/mips/process.cc b/arch/mips/process.cc deleted file mode 100644 index 6de44fe9f..000000000 --- a/arch/mips/process.cc +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2003-2004 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. - */ - -#include "arch/mips/process.hh" - -namespace MipsISA -{ - -LiveProcess * -createProcess(const string &nm, ObjectFile * objFile, - int stdin_fd, int stdout_fd, int stderr_fd, - vector<string> &argv, vector<string> &envp) -{ - LiveProcess * process = NULL; - if (objFile->getArch() != ObjectFile::MIPS) - fatal("Object file does not match architecture."); - switch (objFile->getOpSys()) { - case ObjectFile::Linux: - process = new MipsLinuxProcess(nm, objFile, - stdin_fd, stdout_fd, stderr_fd, - argv, envp); - break; - - default: - fatal("Unknown/unsupported operating system."); - } - return process; -} - -} // namespace MipsISA - diff --git a/arch/mips/process.hh b/arch/mips/process.hh deleted file mode 100644 index ab4323107..000000000 --- a/arch/mips/process.hh +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2003-2004 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. - */ - -#ifndef __MIPS_PROCESS_HH__ -#define __MIPS_PROCESS_HH__ - -#include "arch/mips/linux_process.hh" -#include "base/loader/object_file.hh" - -namespace MipsISA -{ - -LiveProcess * -createProcess(const string &nm, ObjectFile * objFile, - int stdin_fd, int stdout_fd, int stderr_fd, - vector<string> &argv, vector<string> &envp); - -} // namespace MipsISA - -#endif // __MIPS_PROCESS_HH__ diff --git a/arch/mips/stacktrace.hh b/arch/mips/stacktrace.hh deleted file mode 100644 index 1d8d97a79..000000000 --- a/arch/mips/stacktrace.hh +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __ARCH_ALPHA_STACKTRACE_HH__ -#define __ARCH_ALPHA_STACKTRACE_HH__ - -#include "base/trace.hh" -#include "cpu/static_inst.hh" - -class ExecContext; -class StackTrace; - -class ProcessInfo -{ - private: - ExecContext *xc; - - int thread_info_size; - int task_struct_size; - int task_off; - int pid_off; - int name_off; - - public: - ProcessInfo(ExecContext *_xc); - - Addr task(Addr ksp) const; - int pid(Addr ksp) const; - std::string name(Addr ksp) const; -}; - -class StackTrace -{ - protected: - typedef TheISA::MachInst MachInst; - private: - ExecContext *xc; - std::vector<Addr> stack; - - private: - bool isEntry(Addr addr); - bool decodePrologue(Addr sp, Addr callpc, Addr func, int &size, Addr &ra); - bool decodeSave(MachInst inst, int ®, int &disp); - bool decodeStack(MachInst inst, int &disp); - - void trace(ExecContext *xc, bool is_call); - - public: - StackTrace(); - StackTrace(ExecContext *xc, StaticInstPtr inst); - ~StackTrace(); - - void clear() - { - xc = 0; - stack.clear(); - } - - bool valid() const { return xc != NULL; } - bool trace(ExecContext *xc, StaticInstPtr inst); - - public: - const std::vector<Addr> &getstack() const { return stack; } - - static const int user = 1; - static const int console = 2; - static const int unknown = 3; - -#if TRACING_ON - private: - void dump(); - - public: - void dprintf() { if (DTRACE(Stack)) dump(); } -#else - public: - void dprintf() {} -#endif -}; - -inline bool -StackTrace::trace(ExecContext *xc, StaticInstPtr inst) -{ - if (!inst->isCall() && !inst->isReturn()) - return false; - - if (valid()) - clear(); - - trace(xc, !inst->isReturn()); - return true; -} - -#endif // __ARCH_ALPHA_STACKTRACE_HH__ diff --git a/arch/sparc/SConscript b/arch/sparc/SConscript deleted file mode 100644 index edff5821e..000000000 --- a/arch/sparc/SConscript +++ /dev/null @@ -1,82 +0,0 @@ -# -*- mode:python -*- - -# 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. - -import os -import sys -from os.path import isdir - -# Import build environment variable from SConstruct. -Import('env') - -################################################### -# -# Define needed sources. -# -################################################### - -# Base sources used by all configurations. -base_sources = Split(''' - faults.cc - isa_traits.cc - ''') - -# Full-system sources -full_system_sources = Split(''' - tlb.cc - arguments.cc - ev5.cc - osfpal.cc - stacktrace.cc - vtophys.cc - ''') - -# Syscall emulation (non-full-system) sources -syscall_emulation_sources = Split(''' - common_syscall_emul.cc - linux_process.cc - process.cc - ''') - -sources = base_sources - -if env['FULL_SYSTEM']: - sources += full_system_sources -else: - sources += syscall_emulation_sources - -# Convert file names to SCons File objects. This takes care of the -# path relative to the top of the directory tree. -sources = [File(s) for s in sources] - -# Add in files generated by the ISA description. -isa_desc_files = env.ISADesc('isa/main.isa') -# Only non-header files need to be compiled. -isa_desc_sources = [f for f in isa_desc_files if not f.path.endswith('.hh')] -sources += isa_desc_sources - -Return('sources') diff --git a/arch/sparc/faults.cc b/arch/sparc/faults.cc deleted file mode 100644 index b48fc600b..000000000 --- a/arch/sparc/faults.cc +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include "arch/sparc/faults.hh" -#include "cpu/exec_context.hh" -#include "cpu/base.hh" -#include "base/trace.hh" - -namespace SparcISA -{ - -FaultName InternalProcessorError::_name = "intprocerr"; -TrapType InternalProcessorError::_trapType = 0x029; -FaultPriority InternalProcessorError::_priority = 4; -FaultStat InternalProcessorError::_count; - -FaultName MemAddressNotAligned::_name = "unalign"; -TrapType MemAddressNotAligned::_trapType = 0x034; -FaultPriority MemAddressNotAligned::_priority = 10; -FaultStat MemAddressNotAligned::_count; - -FaultName PowerOnReset::_name = "pow_reset"; -TrapType PowerOnReset::_trapType = 0x001; -FaultPriority PowerOnReset::_priority = 0; -FaultStat PowerOnReset::_count; - -FaultName WatchDogReset::_name = "watch_dog_reset"; -TrapType WatchDogReset::_trapType = 0x002; -FaultPriority WatchDogReset::_priority = 1; -FaultStat WatchDogReset::_count; - -FaultName ExternallyInitiatedReset::_name = "extern_reset"; -TrapType ExternallyInitiatedReset::_trapType = 0x003; -FaultPriority ExternallyInitiatedReset::_priority = 1; -FaultStat ExternallyInitiatedReset::_count; - -FaultName SoftwareInitiatedReset::_name = "software_reset"; -TrapType SoftwareInitiatedReset::_trapType = 0x004; -FaultPriority SoftwareInitiatedReset::_priority = 1; -FaultStat SoftwareInitiatedReset::_count; - -FaultName REDStateException::_name = "red_counte"; -TrapType REDStateException::_trapType = 0x005; -FaultPriority REDStateException::_priority = 1; -FaultStat REDStateException::_count; - -FaultName InstructionAccessException::_name = "inst_access"; -TrapType InstructionAccessException::_trapType = 0x008; -FaultPriority InstructionAccessException::_priority = 5; -FaultStat InstructionAccessException::_count; - -FaultName InstructionAccessMMUMiss::_name = "inst_mmu"; -TrapType InstructionAccessMMUMiss::_trapType = 0x009; -FaultPriority InstructionAccessMMUMiss::_priority = 2; -FaultStat InstructionAccessMMUMiss::_count; - -FaultName InstructionAccessError::_name = "inst_error"; -TrapType InstructionAccessError::_trapType = 0x00A; -FaultPriority InstructionAccessError::_priority = 3; -FaultStat InstructionAccessError::_count; - -FaultName IllegalInstruction::_name = "illegal_inst"; -TrapType IllegalInstruction::_trapType = 0x010; -FaultPriority IllegalInstruction::_priority = 7; -FaultStat IllegalInstruction::_count; - -FaultName PrivelegedOpcode::_name = "priv_opcode"; -TrapType PrivelegedOpcode::_trapType = 0x011; -FaultPriority PrivelegedOpcode::_priority = 6; -FaultStat PrivelegedOpcode::_count; - -FaultName UnimplementedLDD::_name = "unimp_ldd"; -TrapType UnimplementedLDD::_trapType = 0x012; -FaultPriority UnimplementedLDD::_priority = 6; -FaultStat UnimplementedLDD::_count; - -FaultName UnimplementedSTD::_name = "unimp_std"; -TrapType UnimplementedSTD::_trapType = 0x013; -FaultPriority UnimplementedSTD::_priority = 6; -FaultStat UnimplementedSTD::_count; - -FaultName FpDisabled::_name = "fp_disabled"; -TrapType FpDisabled::_trapType = 0x020; -FaultPriority FpDisabled::_priority = 8; -FaultStat FpDisabled::_count; - -FaultName FpExceptionIEEE754::_name = "fp_754"; -TrapType FpExceptionIEEE754::_trapType = 0x021; -FaultPriority FpExceptionIEEE754::_priority = 11; -FaultStat FpExceptionIEEE754::_count; - -FaultName FpExceptionOther::_name = "fp_other"; -TrapType FpExceptionOther::_trapType = 0x022; -FaultPriority FpExceptionOther::_priority = 11; -FaultStat FpExceptionOther::_count; - -FaultName TagOverflow::_name = "tag_overflow"; -TrapType TagOverflow::_trapType = 0x023; -FaultPriority TagOverflow::_priority = 14; -FaultStat TagOverflow::_count; - -FaultName DivisionByZero::_name = "div_by_zero"; -TrapType DivisionByZero::_trapType = 0x028; -FaultPriority DivisionByZero::_priority = 15; -FaultStat DivisionByZero::_count; - -FaultName DataAccessException::_name = "data_access"; -TrapType DataAccessException::_trapType = 0x030; -FaultPriority DataAccessException::_priority = 12; -FaultStat DataAccessException::_count; - -FaultName DataAccessMMUMiss::_name = "data_mmu"; -TrapType DataAccessMMUMiss::_trapType = 0x031; -FaultPriority DataAccessMMUMiss::_priority = 12; -FaultStat DataAccessMMUMiss::_count; - -FaultName DataAccessError::_name = "data_error"; -TrapType DataAccessError::_trapType = 0x032; -FaultPriority DataAccessError::_priority = 12; -FaultStat DataAccessError::_count; - -FaultName DataAccessProtection::_name = "data_protection"; -TrapType DataAccessProtection::_trapType = 0x033; -FaultPriority DataAccessProtection::_priority = 12; -FaultStat DataAccessProtection::_count; - -FaultName LDDFMemAddressNotAligned::_name = "unalign_lddf"; -TrapType LDDFMemAddressNotAligned::_trapType = 0x035; -FaultPriority LDDFMemAddressNotAligned::_priority = 10; -FaultStat LDDFMemAddressNotAligned::_count; - -FaultName STDFMemAddressNotAligned::_name = "unalign_stdf"; -TrapType STDFMemAddressNotAligned::_trapType = 0x036; -FaultPriority STDFMemAddressNotAligned::_priority = 10; -FaultStat STDFMemAddressNotAligned::_count; - -FaultName PrivelegedAction::_name = "priv_action"; -TrapType PrivelegedAction::_trapType = 0x037; -FaultPriority PrivelegedAction::_priority = 11; -FaultStat PrivelegedAction::_count; - -FaultName LDQFMemAddressNotAligned::_name = "unalign_ldqf"; -TrapType LDQFMemAddressNotAligned::_trapType = 0x038; -FaultPriority LDQFMemAddressNotAligned::_priority = 10; -FaultStat LDQFMemAddressNotAligned::_count; - -FaultName STQFMemAddressNotAligned::_name = "unalign_stqf"; -TrapType STQFMemAddressNotAligned::_trapType = 0x039; -FaultPriority STQFMemAddressNotAligned::_priority = 10; -FaultStat STQFMemAddressNotAligned::_count; - -FaultName AsyncDataError::_name = "async_data"; -TrapType AsyncDataError::_trapType = 0x040; -FaultPriority AsyncDataError::_priority = 2; -FaultStat AsyncDataError::_count; - -//The enumerated faults - -FaultName CleanWindow::_name = "clean_win"; -TrapType CleanWindow::_baseTrapType = 0x024; -FaultPriority CleanWindow::_priority = 10; -FaultStat CleanWindow::_count; - -FaultName InterruptLevelN::_name = "interrupt_n"; -TrapType InterruptLevelN::_baseTrapType = 0x041; -FaultStat InterruptLevelN::_count; - -FaultName SpillNNormal::_name = "spill_n_normal"; -TrapType SpillNNormal::_baseTrapType = 0x080; -FaultPriority SpillNNormal::_priority = 9; -FaultStat SpillNNormal::_count; - -FaultName SpillNOther::_name = "spill_n_other"; -TrapType SpillNOther::_baseTrapType = 0x0A0; -FaultPriority SpillNOther::_priority = 9; -FaultStat SpillNOther::_count; - -FaultName FillNNormal::_name = "fill_n_normal"; -TrapType FillNNormal::_baseTrapType = 0x0C0; -FaultPriority FillNNormal::_priority = 9; -FaultStat FillNNormal::_count; - -FaultName FillNOther::_name = "fill_n_other"; -TrapType FillNOther::_baseTrapType = 0x0E0; -FaultPriority FillNOther::_priority = 9; -FaultStat FillNOther::_count; - -FaultName TrapInstruction::_name = "trap_inst_n"; -TrapType TrapInstruction::_baseTrapType = 0x100; -FaultPriority TrapInstruction::_priority = 16; -FaultStat TrapInstruction::_count; - - - -#if FULL_SYSTEM - -void SparcFault::invoke(ExecContext * xc) -{ - FaultBase::invoke(xc); - countStat()++; - - //Use the SPARC trap state machine - /*// exception restart address - if (setRestartAddress() || !xc->inPalMode()) - xc->setMiscReg(AlphaISA::IPR_EXC_ADDR, xc->regs.pc); - - if (skipFaultingInstruction()) { - // traps... skip faulting instruction. - xc->setMiscReg(AlphaISA::IPR_EXC_ADDR, - xc->readMiscReg(AlphaISA::IPR_EXC_ADDR) + 4); - } - - if (!xc->inPalMode()) - AlphaISA::swap_palshadow(&(xc->regs), true); - - xc->regs.pc = xc->readMiscReg(AlphaISA::IPR_PAL_BASE) + vect(); - xc->regs.npc = xc->regs.pc + sizeof(MachInst);*/ -} - -#endif - -} // namespace SparcISA - diff --git a/arch/sparc/faults.hh b/arch/sparc/faults.hh deleted file mode 100644 index 318b1ad5a..000000000 --- a/arch/sparc/faults.hh +++ /dev/null @@ -1,587 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __ALPHA_FAULTS_HH__ -#define __ALPHA_FAULTS_HH__ - -#include "sim/faults.hh" - -// The design of the "name" and "vect" functions is in sim/faults.hh - -namespace SparcISA -{ - -typedef const uint32_t TrapType; -typedef const uint32_t FaultPriority; - -class SparcFault : public FaultBase -{ - public: -#if FULL_SYSTEM - void invoke(ExecContext * xc); -#endif - virtual TrapType trapType() = 0; - virtual FaultPriority priority() = 0; - virtual FaultStat & countStat() = 0; -}; - -class InternalProcessorError : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} - bool isMachineCheckFault() {return true;} -}; - -class MemAddressNotAligned : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} - bool isAlignmentFault() {return true;} -}; - -static inline Fault genMachineCheckFault() -{ - return new InternalProcessorError; -} - -static inline Fault genAlignmentFault() -{ - return new MemAddressNotAligned; -} - -class PowerOnReset : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class WatchDogReset : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class ExternallyInitiatedReset : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class SoftwareInitiatedReset : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class REDStateException : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class InstructionAccessException : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class InstructionAccessMMUMiss : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class InstructionAccessError : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class IllegalInstruction : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class PrivelegedOpcode : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class UnimplementedLDD : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class UnimplementedSTD : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class FpDisabled : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class FpExceptionIEEE754 : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class FpExceptionOther : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class TagOverflow : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class DivisionByZero : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class DataAccessException : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class DataAccessMMUMiss : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class DataAccessError : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class DataAccessProtection : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class LDDFMemAddressNotAligned : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class STDFMemAddressNotAligned : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class PrivelegedAction : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class LDQFMemAddressNotAligned : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class STQFMemAddressNotAligned : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class AsyncDataError : public SparcFault -{ - private: - static FaultName _name; - static TrapType _trapType; - static FaultPriority _priority; - static FaultStat _count; - public: - FaultName name() {return _name;} - TrapType trapType() {return _trapType;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class EnumeratedFault : public SparcFault -{ - protected: - uint32_t _n; - virtual TrapType baseTrapType() = 0; - public: - EnumeratedFault(uint32_t n) : SparcFault() {_n = n;} - TrapType trapType() {return baseTrapType() + _n;} -}; - -class CleanWindow : public EnumeratedFault -{ - private: - static FaultName _name; - static TrapType _baseTrapType; - static FaultPriority _priority; - static FaultStat _count; - TrapType baseTrapType() {return _baseTrapType;} - public: - CleanWindow(uint32_t n) : EnumeratedFault(n) {;} - FaultName name() {return _name;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class InterruptLevelN : public EnumeratedFault -{ - private: - static FaultName _name; - static TrapType _baseTrapType; - static FaultStat _count; - TrapType baseTrapType() {return _baseTrapType;} - public: - InterruptLevelN(uint32_t n) : EnumeratedFault(n) {;} - FaultName name() {return _name;} - FaultPriority priority() {return 32 - _n;} - FaultStat & countStat() {return _count;} -}; - -class SpillNNormal : public EnumeratedFault -{ - private: - static FaultName _name; - static TrapType _baseTrapType; - static FaultPriority _priority; - static FaultStat _count; - TrapType baseTrapType() {return _baseTrapType;} - public: - SpillNNormal(uint32_t n) : EnumeratedFault(n) {;} - FaultName name() {return _name;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class SpillNOther : public EnumeratedFault -{ - private: - static FaultName _name; - static TrapType _baseTrapType; - static FaultPriority _priority; - static FaultStat _count; - TrapType baseTrapType() {return _baseTrapType;} - public: - SpillNOther(uint32_t n) : EnumeratedFault(n) {;} - FaultName name() {return _name;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class FillNNormal : public EnumeratedFault -{ - private: - static FaultName _name; - static TrapType _baseTrapType; - static FaultPriority _priority; - static FaultStat _count; - TrapType baseTrapType() {return _baseTrapType;} - public: - FillNNormal(uint32_t n) : EnumeratedFault(n) {;} - FaultName name() {return _name;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class FillNOther : public EnumeratedFault -{ - private: - static FaultName _name; - static TrapType _baseTrapType; - static FaultPriority _priority; - static FaultStat _count; - TrapType baseTrapType() {return _baseTrapType;} - public: - FillNOther(uint32_t n) : EnumeratedFault(n) {;} - FaultName name() {return _name;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -class TrapInstruction : public EnumeratedFault -{ - private: - static FaultName _name; - static TrapType _baseTrapType; - static FaultPriority _priority; - static FaultStat _count; - TrapType baseTrapType() {return _baseTrapType;} - public: - TrapInstruction(uint32_t n) : EnumeratedFault(n) {;} - FaultName name() {return _name;} - FaultPriority priority() {return _priority;} - FaultStat & countStat() {return _count;} -}; - -} // SparcISA namespace - -#endif // __FAULTS_HH__ diff --git a/arch/sparc/isa/base.isa b/arch/sparc/isa/base.isa deleted file mode 100644 index 992504369..000000000 --- a/arch/sparc/isa/base.isa +++ /dev/null @@ -1,129 +0,0 @@ -//////////////////////////////////////////////////////////////////// -// -// Base class for sparc instructions, and some support functions -// - -output header {{ - - struct condCodes - { - uint8_t c:1; - uint8_t v:1; - uint8_t z:1; - uint8_t n:1; - } - - enum condTest - { - Always=0x8, - Never=0x0, - NotEqual=0x9, - Equal=0x1, - Greater=0xA, - LessOrEqual=0x2, - GreaterOrEqual=0xB, - Less=0x3, - GreaterUnsigned=0xC, - LessOrEqualUnsigned=0x4, - CarryClear=0xD, - CarrySet=0x5, - Positive=0xE, - Negative=0x6, - OverflowClear=0xF, - OverflowSet=0x7 - } - - /** - * Base class for all SPARC static instructions. - */ - class SparcStaticInst : public StaticInst - { - protected: - // Constructor. - SparcStaticInst(const char *mnem, - MachInst _machInst, OpClass __opClass) - : StaticInst(mnem, _machInst, __opClass) - { - } - - std::string generateDisassembly(Addr pc, - const SymbolTable *symtab) const; - }; - - bool passesCondition(condCodes codes, condTest condition); -}}; - -output decoder {{ - - std::string SparcStaticInst::generateDisassembly(Addr pc, - const SymbolTable *symtab) const - { - std::stringstream ss; - - ccprintf(ss, "%-10s ", mnemonic); - - // just print the first two source regs... if there's - // a third one, it's a read-modify-write dest (Rc), - // e.g. for CMOVxx - if(_numSrcRegs > 0) - { - printReg(ss, _srcRegIdx[0]); - } - if(_numSrcRegs > 1) - { - ss << ","; - printReg(ss, _srcRegIdx[1]); - } - - // just print the first dest... if there's a second one, - // it's generally implicit - if(_numDestRegs > 0) - { - if(_numSrcRegs > 0) - ss << ","; - printReg(ss, _destRegIdx[0]); - } - - return ss.str(); - } - - bool passesCondition(condCodes codes, condTest condition) - { - switch(condition) - { - case Always: - return true; - case Never: - return false; - case NotEqual: - return !codes.z; - case Equal: - return codes.z; - case Greater: - return !(codes.z | (codes.n ^ codes.v)); - case LessOrEqual: - return codes.z | (codes.n ^ codes.v); - case GreaterOrEqual: - return !(codes.n ^ codes.v); - case Less: - return (codes.n ^ codes.v); - case GreaterUnsigned: - return !(codes.c | codes.z); - case LessOrEqualUnsigned: - return (codes.c | codes.z); - case CarryClear: - return !codes.c; - case CarrySet: - return codes.c; - case Positive: - return !codes.n; - case Negative: - return codes.n; - case OverflowClear: - return !codes.v; - case OverflowSet: - return codes.v; - } - } -}}; - diff --git a/arch/sparc/isa/bitfields.isa b/arch/sparc/isa/bitfields.isa deleted file mode 100644 index b0ac57575..000000000 --- a/arch/sparc/isa/bitfields.isa +++ /dev/null @@ -1,50 +0,0 @@ -//////////////////////////////////////////////////////////////////// -// -// Bitfield definitions. -// - -// Bitfields are shared liberally between instruction formats, so they are -// simply defined alphabetically - -def bitfield A <29>; -def bitfield CC02 <20>; -def bitfield CC03 <25>; -def bitfield CC04 <11>; -def bitfield CC12 <21>; -def bitfield CC13 <26>; -def bitfield CC14 <12>; -def bitfield CC2 <18>; -def bitfield CMASK <6:4>; -def bitfield COND2 <28:25>; -def bitfield COND4 <17:14>; -def bitfield D16HI <21:20>; -def bitfield D16LO <13:0>; -def bitfield DISP19 <18:0>; -def bitfield DISP22 <21:0>; -def bitfield DISP30 <29:0>; -def bitfield FCN <29:26>; -def bitfield I <13>; -def bitfield IMM_ASI <12:5>; -def bitfield IMM22 <21:0>; -def bitfield MMASK <3:0>; -def bitfield OP <31:30>; -def bitfield OP2 <24:22>; -def bitfield OP3 <24:19>; -def bitfield OPF <13:5>; -def bitfield OPF_CC <13:11>; -def bitfield OPF_LOW5 <9:5>; -def bitfield OPF_LOW6 <10:5>; -def bitfield P <19>; -def bitfield RCOND2 <27:25>; -def bitfield RCOND3 <12:10>; -def bitfield RCOND4 <12:10>; -def bitfield RD <29:25>; -def bitfield RS1 <18:14>; -def bitfield RS2 <4:0>; -def bitfield SHCNT32 <4:0>; -def bitfield SHCNT64 <5:0>; -def bitfield SIMM10 <9:0>; -def bitfield SIMM11 <10:0>; -def bitfield SIMM13 <12:0>; -def bitfield SW_TRAP <6:0>; -def bitfield X <12>; diff --git a/arch/sparc/isa/decoder.isa b/arch/sparc/isa/decoder.isa deleted file mode 100644 index eb458211b..000000000 --- a/arch/sparc/isa/decoder.isa +++ /dev/null @@ -1,662 +0,0 @@ -//////////////////////////////////////////////////////////////////// -// -// The actual decoder specification -// - -decode OP default Trap::unknown({{IllegalInstruction}}) { - - 0x0: decode OP2 { - 0x0: Trap::illtrap({{illegal_instruction}}); //ILLTRAP - 0x1: Branch::bpcc({{ - switch((CC12 << 1) | CC02) - { - case 1: - case 3: - fault = new IllegalInstruction; - case 0: - if(passesCondition(xc->regs.MiscRegs.ccrFields.icc, COND2)) - ;//branchHere - break; - case 2: - if(passesCondition(xc->regs.MiscRegs.ccrFields.xcc, COND2)) - ;//branchHere - break; - } - }});//BPcc - 0x2: Branch::bicc({{ - if(passesCondition(xc->regs.MiscRegs.ccrFields.icc, COND2)) - ;//branchHere - }});//Bicc - 0x3: Branch::bpr({{ - switch(RCOND) - { - case 0: - case 4: - fault = new IllegalInstruction; - case 1: - if(Rs1 == 0) - ;//branchHere - break; - case 2: - if(Rs1 <= 0) - ;//branchHere - break; - case 3: - if(Rs1 < 0) - ;//branchHere - break; - case 5: - if(Rs1 != 0) - ;//branchHere - break; - case 6: - if(Rs1 > 0) - ;//branchHere - break; - case 7: - if(Rs1 >= 0) - ;//branchHere - break; - } - }}); //BPr - //SETHI (or NOP if rd == 0 and imm == 0) - 0x4: IntegerOp::sethi({{Rd = (IMM22 << 10) & 0xFFFFFC00;}}); - 0x5: Trap::fbpfcc({{throw fp_disabled;}}); //FBPfcc - 0x6: Trap::fbfcc({{throw fp_disabled;}}); //FBfcc - } - 0x1: Branch::call({{ - //branch here - Rd = xc->pc; - }}); - 0x2: decode OP3 { - format IntegerOp { - 0x00: add({{ - int64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - Rd = Rs1.sdw + val2; - }});//ADD - 0x01: and({{ - uint64_t val2 = (I ? SIMM13.sdw : Rs2.udw); - Rd = Rs1.udw & val2; - }});//AND - 0x02: or({{ - uint64_t val2 = (I ? SIMM13.sdw : Rs2.udw); - Rd = Rs1.udw | val2; - }});//OR - 0x03: xor({{ - uint64_t val2 = (I ? SIMM13.sdw : Rs2.udw); - Rd = Rs1.udw ^ val2; - }});//XOR - 0x04: sub({{ - int64_t val2 = ~((uint64_t)(I ? SIMM13.sdw : Rs2.udw))+1; - Rd = Rs1.sdw + val2; - }});//SUB - 0x05: andn({{ - uint64_t val2 = (I ? SIMM13.sdw : Rs2.udw); - Rd = Rs1.udw & ~val2; - }});//ANDN - 0x06: orn({{ - uint64_t val2 = (I ? SIMM13.sdw : Rs2.udw); - Rd = Rs1.udw | ~val2; - }});//ORN - 0x07: xnor({{ - uint64_t val2 = (I ? SIMM13.sdw : Rs2.udw); - Rd = ~(Rs1.udw ^ val2); - }});//XNOR - 0x08: addc({{ - int64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - int64_t carryin = xc->regs.MiscRegs.ccrfields.iccfields.c; - Rd = Rs1.sdw + val2 + carryin; - }});//ADDC - 0x09: mulx({{ - int64_t val2 = (I ? SIMM13.sdw : Rs2); - Rd = Rs1 * val2; - }});//MULX - 0x0A: umul({{ - uint64_t resTemp, val2 = (I ? SIMM13.sdw : Rs2.udw); - Rd = resTemp = Rs1.udw<31:0> * val2<31:0>; - xc->regs.MiscRegs.yFields.value = resTemp<63:32>; - }});//UMUL - 0x0B: smul({{ - int64_t resTemp, val2 = (I ? SIMM13.sdw : Rs2.sdw); - rd.sdw = resTemp = Rs1.sdw<31:0> * val2<31:0>; - xc->regs.MiscRegs.yFields.value = resTemp<63:32>; - }});//SMUL - 0x0C: subc({{ - int64_t val2 = ~((int64_t)(I ? SIMM13.sdw : Rs2.sdw))+1; - int64_t carryin = xc->regs.MiscRegs.ccrfields.iccfields.c; - Rd.sdw = Rs1.sdw + val2 + carryin; - }});//SUBC - 0x0D: udivx({{ - uint64_t val2 = (I ? SIMM13.sdw : Rs2.udw); - if(val2 == 0) throw division_by_zero; - Rd.udw = Rs1.udw / val2; - }});//UDIVX - 0x0E: udiv({{ - uint32_t resTemp, val2 = (I ? SIMM13.sw : Rs2.udw<31:0>); - if(val2 == 0) - fault = new DivisionByZero; - resTemp = (uint64_t)((xc->regs.MiscRegs.yFields.value << 32) - | Rs1.udw<31:0>) / val2; - int32_t overflow = (resTemp<63:32> != 0); - if(overflow) - rd.udw = resTemp = 0xFFFFFFFF; - else - rd.udw = resTemp; - }}); //UDIV - 0x0F: sdiv({{ - int32_t resTemp, val2 = (I ? SIMM13.sw : Rs2.sdw<31:0>); - if(val2 == 0) - fault = new DivisionByZero; - - Rd.sdw = (int64_t)((xc->regs.MiscRegs.yFields.value << 32) | - Rs1.sdw<31:0>) / val2; - resTemp = Rd.sdw; - int32_t overflow = (resTemp<63:31> != 0); - int32_t underflow = - (resTemp<63:> && resTemp<62:31> != 0xFFFFFFFF); - if(overflow) - rd.udw = resTemp = 0x7FFFFFFF; - else if(underflow) - rd.udw = resTemp = 0xFFFFFFFF80000000; - else - rd.udw = resTemp; - }});//SDIV - } - format IntegerOpCc { - 0x10: addcc({{ - int64_t resTemp, val2 = (I ? SIMM13.sdw : Rs2); - Rd = resTemp = Rs1 + val2;}}, - {{((Rs1 & 0xFFFFFFFF + val2 & 0xFFFFFFFF) >> 31)}}, - {{Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>}}, - {{((Rs1 >> 1) + (val2 >> 1) + (Rs1 & val2 & 0x1))<63:>}}, - {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}} - );//ADDcc - 0x11: andcc({{ - int64_t val2 = (I ? SIMM13.sdw : Rs2); - Rd = Rs1 & val2;}}, - {{0}},{{0}},{{0}},{{0}});//ANDcc - 0x12: orcc({{ - int64_t val2 = (I ? SIMM13.sdw : Rs2); - Rd = Rs1 | val2;}}, - {{0}},{{0}},{{0}},{{0}});//ORcc - 0x13: xorcc({{ - int64_t val2 = (I ? SIMM13.sdw : Rs2); - Rd = Rs1 ^ val2;}}, - {{0}},{{0}},{{0}},{{0}});//XORcc - 0x14: subcc({{ - int64_t resTemp, val2 = (int64_t)(I ? SIMM13.sdw : Rs2); - Rd = resTemp = Rs1 - val2;}}, - {{((Rs1 & 0xFFFFFFFF + (~val2) & 0xFFFFFFFF + 1) >> 31)}}, - {{Rs1<31:> != val2<31:> && Rs1<31:> != resTemp<31:>}}, - {{((Rs1 >> 1) + (~val2) >> 1) + - ((Rs1 | ~val2) & 0x1))<63:>}}, - {{Rs1<63:> != val2<63:> && Rs1<63:> != resTemp<63:>}} - );//SUBcc - 0x15: andncc({{ - int64_t val2 = (I ? SIMM13.sdw : Rs2); - Rd = Rs1 & ~val2;}}, - {{0}},{{0}},{{0}},{{0}});//ANDNcc - 0x16: orncc({{ - int64_t val2 = (I ? SIMM13.sdw : Rs2); - Rd = Rs1 | ~val2;}}, - {{0}},{{0}},{{0}},{{0}});//ORNcc - 0x17: xnorcc({{ - int64_t val2 = (I ? SIMM13.sdw : Rs2); - Rd = ~(Rs1 ^ val2);}}, - {{0}},{{0}},{{0}},{{0}});//XNORcc - 0x18: addccc({{ - int64_t resTemp, val2 = (I ? SIMM13.sdw : Rs2); - int64_t carryin = xc->regs.MiscRegs.ccrfields.iccfields.c; - Rd = resTemp = Rs1 + val2 + carryin;}}, - {{((Rs1 & 0xFFFFFFFF + val2 & 0xFFFFFFFF) >> 31 - + carryin)}}, - {{Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>}}, - {{((Rs1 >> 1) + (val2 >> 1) + - ((Rs1 & val2) | (carryin & (Rs1 | val2)) & 0x1))<63:>}}, - {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}} - );//ADDCcc - 0x1A: umulcc({{ - uint64_t resTemp, val2 = (I ? SIMM13.sdw : Rs2); - Rd = resTemp = Rs1.udw<31:0> * val2<31:0>; - xc->regs.MiscRegs.yFields.value = resTemp<63:32>;}}, - {{0}},{{0}},{{0}},{{0}});//UMULcc - 0x1B: smulcc({{ - int64_t resTemp, val2 = (I ? SIMM13.sdw : Rs2); - Rd = resTemp = Rs1.sdw<31:0> * val2<31:0>; - xc->regs.MiscRegs.yFields.value = resTemp<63:32>;}} - ,{{0}},{{0}},{{0}},{{0}});//SMULcc - 0x1C: subccc({{ - int64_t resTemp, val2 = (int64_t)(I ? SIMM13.sdw : Rs2); - int64_t carryin = xc->regs.MiscRegs.ccrfields.iccfields.c; - Rd = resTemp = Rs1 + ~(val2 + carryin) + 1;}}, - {{((Rs1 & 0xFFFFFFFF + (~(val2 + carryin)) & 0xFFFFFFFF + 1) >> 31)}}, - {{Rs1<31:> != val2<31:> && Rs1<31:> != resTemp<31:>}}, - {{((Rs1 >> 1) + (~(val2 + carryin)) >> 1) + ((Rs1 | ~(val2+carryin)) & 0x1))<63:>}}, - {{Rs1<63:> != val2<63:> && Rs1<63:> != resTemp<63:>}} - );//SUBCcc - 0x1D: udivxcc({{ - uint64_t val2 = (I ? SIMM13.sdw : Rs2.udw); - if(val2 == 0) throw division_by_zero; - Rd.udw = Rs1.udw / val2;}} - ,{{0}},{{0}},{{0}},{{0}});//UDIVXcc - 0x1E: udivcc({{ - uint32_t resTemp, val2 = (I ? SIMM13.sw : Rs2.udw<31:0>); - if(val2 == 0) throw division_by_zero; - resTemp = (uint64_t)((xc->regs.MiscRegs.yFields.value << 32) | Rs1.udw<31:0>) / val2; - int32_t overflow = (resTemp<63:32> != 0); - if(overflow) rd.udw = resTemp = 0xFFFFFFFF; - else rd.udw = resTemp;}}, - {{0}}, - {{overflow}}, - {{0}}, - {{0}} - );//UDIVcc - 0x1F: sdivcc({{ - int32_t resTemp, val2 = (I ? SIMM13.sw : Rs2.sdw<31:0>); - if(val2 == 0) throw division_by_zero; - Rd.sdw = resTemp = (int64_t)((xc->regs.MiscRegs.yFields.value << 32) | Rs1.sdw<31:0>) / val2; - int32_t overflow = (resTemp<63:31> != 0); - int32_t underflow = (resTemp<63:> && resTemp<62:31> != 0xFFFFFFFF); - if(overflow) rd.udw = resTemp = 0x7FFFFFFF; - else if(underflow) rd.udw = resTemp = 0xFFFFFFFF80000000; - else rd.udw = resTemp;}}, - {{0}}, - {{overflow || underflow}}, - {{0}}, - {{0}} - );//SDIVcc - 0x20: taddcc({{ - int64_t resTemp, val2 = (I ? SIMM13.sdw : Rs2); - Rd = resTemp = Rs1 + val2; - int32_t overflow = Rs1<1:0> || val2<1:0> || (Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>);}}, - {{((Rs1 & 0xFFFFFFFF + val2 & 0xFFFFFFFF) >> 31)}}, - {{overflow}}, - {{((Rs1 >> 1) + (val2 >> 1) + (Rs1 & val2 & 0x1))<63:>}}, - {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}} - );//TADDcc - 0x21: tsubcc({{ - int64_t resTemp, val2 = (I ? SIMM13.sdw : Rs2); - Rd = resTemp = Rs1 + val2; - int32_t overflow = Rs1<1:0> || val2<1:0> || (Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>);}}, - {{(Rs1 & 0xFFFFFFFF + val2 & 0xFFFFFFFF) >> 31)}}, - {{overflow}}, - {{((Rs1 >> 1) + (val2 >> 1) + (Rs1 & val2 & 0x1))<63:>}}, - {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}} - );//TSUBcc - 0x22: taddcctv({{ - int64_t resTemp, val2 = (I ? SIMM13.sdw : Rs2); - Rd = resTemp = Rs1 + val2; - int32_t overflow = Rs1<1:0> || val2<1:0> || (Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>); - if(overflow) throw tag_overflow;}}, - {{((Rs1 & 0xFFFFFFFF + val2 & 0xFFFFFFFF) >> 31)}}, - {{overflow}}, - {{((Rs1 >> 1) + (val2 >> 1) + (Rs1 & val2 & 0x1))<63:>}}, - {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}} - );//TADDccTV - 0x23: tsubcctv({{ - int64_t resTemp, val2 = (I ? SIMM13.sdw : Rs2); - Rd = resTemp = Rs1 + val2; - int32_t overflow = Rs1<1:0> || val2<1:0> || (Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>); - if(overflow) throw tag_overflow;}}, - {{((Rs1 & 0xFFFFFFFF + val2 & 0xFFFFFFFF) >> 31)}}, - {{overflow}}, - {{((Rs1 >> 1) + (val2 >> 1) + (Rs1 & val2 & 0x1))<63:>}}, - {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}} - );//TSUBccTV - 0x24: mulscc({{ - int64_t resTemp, multiplicand = (I ? SIMM13.sdw : Rs2); - int32_t multiplier = Rs1<31:0>; - int32_t savedLSB = Rs1<0:>; - multiplier = multipler<31:1> | - ((xc->regs.MiscRegs.ccrFields.iccFields.n - ^ xc->regs.MiscRegs.ccrFields.iccFields.v) << 32); - if(!xc->regs.MiscRegs.yFields.value<0:>) - multiplicand = 0; - Rd = resTemp = multiplicand + multiplier; - xc->regs.MiscRegs.yFields.value = xc->regs.MiscRegs.yFields.value<31:1> | (savedLSB << 31);}}, - {{((multiplicand & 0xFFFFFFFF + multiplier & 0xFFFFFFFF) >> 31)}}, - {{multiplicand<31:> == multiplier<31:> && multiplier<31:> != resTemp<31:>}}, - {{((multiplicand >> 1) + (multiplier >> 1) + (multiplicand & multiplier & 0x1))<63:>}}, - {{multiplicand<63:> == multiplier<63:> && multiplier<63:> != resTemp<63:>}} - );//MULScc - } - format IntegerOp - { - 0x25: decode X { - 0x0: sll({{Rd = Rs1 << (I ? SHCNT32 : Rs2<4:0>);}}); //SLL - 0x1: sllx({{Rd = Rs1 << (I ? SHCNT64 : Rs2<5:0>);}}); //SLLX - } - 0x26: decode X { - 0x0: srl({{Rd = Rs1.udw<31:0> >> (I ? SHCNT32 : Rs2<4:0>);}}); //SRL - 0x1: srlx({{Rd = Rs1.udw >> (I ? SHCNT64 : Rs2<5:0>);}});//SRLX - } - 0x27: decode X { - 0x0: sra({{Rd = Rs1.sdw<31:0> >> (I ? SHCNT32 : Rs2<4:0>);}}); //SRA - 0x1: srax({{Rd = Rs1.sdw >> (I ? SHCNT64 : Rs2<5:0>);}});//SRAX - } - 0x28: decode RS1 { - 0x0: rdy({{Rd = xc->regs.MiscRegs.yFields.value;}}); //RDY - 0x2: rdccr({{Rd = xc->regs.MiscRegs.ccr;}}); //RDCCR - 0x3: rdasi({{Rd = xc->regs.MiscRegs.asi;}}); //RDASI - 0x4: rdtick({{ - if(xc->regs.MiscRegs.pstateFields.priv == 0 && - xc->regs.MiscRegs.tickFields.npt == 1) - throw privileged_action; - Rd = xc->regs.MiscRegs.tick; - }});//RDTICK - 0x5: rdpc({{Rd = xc->regs.pc;}}); //RDPC - 0x6: rdfprs({{Rd = xc->regs.MiscRegs.fprs;}}); //RDFPRS - 0xF: decode I { - 0x0: Noop::membar({{//Membar isn't needed yet}}); //MEMBAR - 0x1: Noop::stbar({{//Stbar isn/'t needed yet}}); //STBAR - } - } - - 0x2A: decode RS1 { - 0x0: rdprtpc({{checkPriv Rd = xc->regs.MiscRegs.tpc[xc->regs.MiscRegs.tl];}}); - 0x1: rdprtnpc({{checkPriv Rd = xc->regs.MiscRegs.tnpc[xc->regs.MiscRegs.tl];}}); - 0x2: rdprtstate({{checkPriv Rd = xc->regs.MiscRegs.tstate[xc->regs.MiscRegs.tl];}}); - 0x3: rdprtt({{checkPriv Rd = xc->regs.MiscRegs.tt[xc->regs.MiscRegs.tl];}}); - 0x4: rdprtick({{checkPriv Rd = xc->regs.MiscRegs.tick;}}); - 0x5: rdprtba({{checkPriv Rd = xc->regs.MiscRegs.tba;}}); - 0x6: rdprpstate({{checkPriv Rd = xc->regs.MiscRegs.pstate;}}); - 0x7: rdprtl({{checkPriv Rd = xc->regs.MiscRegs.tl;}}); - 0x8: rdprpil({{checkPriv Rd = xc->regs.MiscRegs.pil;}}); - 0x9: rdprcwp({{checkPriv Rd = xc->regs.MiscRegs.cwp;}}); - 0xA: rdprcansave({{checkPriv Rd = xc->regs.MiscRegs.cansave;}}); - 0xB: rdprcanrestore({{checkPriv Rd = xc->regs.MiscRegs.canrestore;}}); - 0xC: rdprcleanwin({{checkPriv Rd = xc->regs.MiscRegs.cleanwin;}}); - 0xD: rdprotherwin({{checkPriv Rd = xc->regs.MiscRegs.otherwin;}}); - 0xE: rdprwstate({{checkPriv Rd = xc->regs.MiscRegs.wstate;}}); - 0xF: rdprfq({{throw illegal_instruction;}}); //The floating point queue isn't implemented right now. - } - 0x2B: BasicOperate::flushw({{\\window toilet}}); //FLUSHW - 0x2C: movcc({{ - ccBank = (CC24 << 2) | (CC14 << 1) | (CC04 << 0); - switch(ccBank) - { - case 0: case 1: case 2: case 3: - throw fp_disabled; - break; - case 5: case 7: - throw illegal_instruction; - break; - case 4: - if(passesCondition(xc->regs.MiscRegs.ccrFields.icc, COND4)) - Rd = (I ? SIMM11.sdw : RS2); - break; - case 6: - if(passesCondition(xc->regs.MiscRegs.ccrFields.xcc, COND4)) - Rd = (I ? SIMM11.sdw : RS2); - break; - } - }});//MOVcc - 0x2D: sdivx({{ - int64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - if(val2 == 0) throw division_by_zero; - Rd.sdw = Rs1.sdw / val2; - }});//SDIVX - 0x2E: decode RS1 { - 0x0: IntegerOp::popc({{ - int64_t count = 0, val2 = (I ? SIMM13.sdw : Rs2.sdw); - uint8_t oneBits[] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4} - for(unsigned int x = 0; x < 16; x++) - { - count += oneBits[val2 & 0xF]; - val2 >> 4; - } - }});//POPC - } - 0x2F: movr({{ - uint64_t val2 = (I ? SIMM10.sdw : Rs2.sdw); - switch(RCOND) - { - case 0: case 4: - throw illegal_instruction; - break; - case 1: - if(Rs1 == 0) Rd = val2; - break; - case 2: - if(Rs1 <= 0) Rd = val2; - break; - case 3: - if(Rs1 = 0) Rd = val2; - break; - case 5: - if(Rs1 != 0) Rd = val2; - break; - case 6: - if(Rs1 > 0) Rd = val2; - break; - case 7: - if(Rs1 >= 0) Rd = val2; - break; - } - }});//MOVR - 0x30: decode RD { - 0x0: wry({{ - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.y = Rs1 ^ val2; - }});//WRY - 0x2: wrccr({{ - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.ccr = Rs1 ^ val2; - }});//WRCCR - 0x3: wrasi({{ - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.asi = Rs1 ^ val2; - }});//WRASI - 0x6: wrfprs({{ - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.asi = Rs1 ^ val2; - }});//WRFPRS - 0xF: Trap::sir({{software_initiated_reset}}); //SIR - } - 0x31: decode FCN { - 0x0: BasicOperate::saved({{\\Boogy Boogy}}); //SAVED - 0x1: BasicOperate::restored({{\\Boogy Boogy}}); //RESTORED - } - 0x32: decode RD { - 0x0: wrprtpc({{checkPriv - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.tpc[xc->regs.MiscRegs.tl] = Rs1 ^ val2; - }}); - 0x1: wrprtnpc({{checkPriv - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.tnpc[xc->regs.MiscRegs.tl] = Rs1 ^ val2; - }}); - 0x2: wrprtstate({{checkPriv - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.tstate[xc->regs.MiscRegs.tl] = Rs1 ^ val2; - }}); - 0x3: wrprtt({{checkPriv - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.tt[xc->regs.MiscRegs.tl] = Rs1 ^ val2; - }}); - 0x4: wrprtick({{checkPriv - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.tick = Rs1 ^ val2; - }}); - 0x5: wrprtba({{checkPriv - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.tba = Rs1 ^ val2; - }}); - 0x6: wrprpstate({{checkPriv - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.pstate = Rs1 ^ val2; - }}); - 0x7: wrprtl({{checkPriv - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.tl = Rs1 ^ val2; - }}); - 0x8: wrprpil({{checkPriv - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.pil = Rs1 ^ val2; - }}); - 0x9: wrprcwp({{checkPriv - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.cwp = Rs1 ^ val2; - }}); - 0xA: wrprcansave({{checkPriv - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.cansave = Rs1 ^ val2; - }}); - 0xB: wrprcanrestore({{checkPriv - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.canrestore = Rs1 ^ val2; - }}); - 0xC: wrprcleanwin({{checkPriv - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.cleanwin = Rs1 ^ val2; - }}); - 0xD: wrprotherwin({{checkPriv - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.otherwin = Rs1 ^ val2; - }}); - 0xE: wrprwstate({{checkPriv - uint64_t val2 = (I ? SIMM13.sdw : Rs2.sdw); - xc->regs.MiscRegs.wstate = Rs1 ^ val2; - }}); - } - - 0x34: Trap::fpop1({{Throw fp_disabled;}}); //FPOP1 - 0x35: Trap::fpop2({{Throw fp_disabled;}}); //FPOP2 - - - 0x38: Branch::jmpl({{//Stuff}}); //JMPL - 0x39: Branch::return({{//Other Stuff}}); //RETURN - 0x3A: Trap::tcc({{ - switch((CC14 << 1) | (CC04 << 0)) - { - case 1: case 3: - throw illegal_instruction; - case 0: - if(passesCondition(xc->regs.MiscRegs.ccrFields.icc, machInst<25:28>)) - throw trap_instruction; - break; - case 2: - if(passesCondition(xc->regs.MiscRegs.ccrFields.xcc, machInst<25:28>)) - throw trap_instruction; - break; - } - }}); //Tcc - 0x3B: BasicOperate::flush({{//Lala}}); //FLUSH - 0x3C: BasicOperate::save({{//leprechauns); //SAVE - 0x3D: BasicOperate::restore({{//Eat my short int}}); //RESTORE - 0x3E: decode FCN { - 0x1: BasicOperate::done({{//Done thing}}); //DONE - 0x2: BasicOperate::retry({{//Retry thing}}); //RETRY - } - } - } - 0x3: decode OP3 { - format Mem { - 0x00: lduw({{Rd.uw = Mem.uw;}}); //LDUW - 0x01: ldub({{Rd.ub = Mem.ub;}}); //LDUB - 0x02: lduh({{Rd.uhw = Mem.uhw;}}); //LDUH - 0x03: ldd({{ - uint64_t val = Mem.udw; - setIntReg(RD & (~1), val<31:0>); - setIntReg(RD | 1, val<63:32>); - }});//LDD - 0x04: stw({{Mem.sw = Rd.sw;}}); //STW - 0x05: stb({{Mem.sb = Rd.sb;}}); //STB - 0x06: sth({{Mem.shw = Rd.shw;}}); //STH - 0x07: std({{ - Mem.udw = readIntReg(RD & (~1))<31:0> | (readIntReg(RD | 1)<31:0> << 32); - }});//STD - 0x08: ldsw({{Rd.sw = Mem.sw;}}); //LDSW - 0x09: ldsb({{Rd.sb = Mem.sb;}}); //LDSB - 0x0A: ldsh({{Rd.shw = Mem.shw;}}); //LDSH - 0x0B: ldx({{Rd.udw = Mem.udw;}}); //LDX - - 0x0D: ldstub({{ - Rd.ub = Mem.ub; - Mem.ub = 0xFF; - }}); //LDSTUB - 0x0E: stx({{Rd.udw = Mem.udw;}}); //STX - 0x0F: swap({{ - uint32_t temp = Rd.uw; - Rd.uw = Mem.uw; - Mem.uw = temp; - }}); //SWAP - 0x10: lduwa({{Rd.uw = Mem.uw;}}); //LDUWA - 0x11: lduba({{Rd.ub = Mem.ub;}}); //LDUBA - 0x12: lduha({{Rd.uhw = Mem.uhw;}}); //LDUHA - 0x13: ldda({{ - uint64_t val = Mem.udw; - setIntReg(RD & (~1), val<31:0>); - setIntReg(RD | 1, val<63:32>); - }}); //LDDA - 0x14: stwa({{Mem.uw = Rd.uw;}}); //STWA - 0x15: stba({{Mem.ub = Rd.ub;}}); //STBA - 0x16: stha({{Mem.uhw = Rd.uhw;}}); //STHA - 0x17: stda({{ - Mem.udw = readIntReg(RD & (~1))<31:0> | (readIntReg(RD | 1)<31:0> << 32); - }}); //STDA - 0x18: ldswa({{Rd.sw = Mem.sw;}}); //LDSWA - 0x19: ldsba({{Rd.sb = Mem.sb;}}); //LDSBA - 0x1A: ldsha({{Rd.shw = Mem.shw;}}); //LDSHA - 0x1B: ldxa({{Rd.sdw = Mem.sdw;}}); //LDXA - - 0x1D: ldstuba({{ - Rd.ub = Mem.ub; - Mem.ub = 0xFF; - }}); //LDSTUBA - 0x1E: stxa({{Mem.sdw = Rd.sdw}}); //STXA - 0x1F: swapa({{ - uint32_t temp = Rd.uw; - Rd.uw = Mem.uw; - Mem.uw = temp; - }}); //SWAPA - 0x20: Trap::ldf({{throw fp_disabled;}}); //LDF - 0x21: decode X { - 0x0: Trap::ldfsr({{throw fp_disabled;}}); //LDFSR - 0x1: Trap::ldxfsr({{throw fp_disabled;}}); //LDXFSR - } - 0x22: Trap::ldqf({{throw fp_disabled;}}); //LDQF - 0x23: Trap::lddf({{throw fp_disabled;}}); //LDDF - 0x24: Trap::stf({{throw fp_disabled;}}); //STF - 0x25: decode X { - 0x0: Trap::stfsr({{throw fp_disabled;}}); //STFSR - 0x1: Trap::stxfsr({{throw fp_disabled;}}); //STXFSR - } - 0x26: Trap::stqf({{throw fp_disabled;}}); //STQF - 0x27: Trap::stdf({{throw fp_disabled;}}); //STDF - - - - - - 0x2D: Noop::prefetch({{ }}); //PREFETCH - - - 0x30: Trap::ldfa({{throw fp_disabled;}}); //LDFA - - 0x32: Trap::ldqfa({{throw fp_disabled;}}); //LDQFA - 0x33: Trap::lddfa({{throw fp_disabled;}}); //LDDFA - 0x34: Trap::stfa({{throw fp_disabled;}}); //STFA - 0x35: Trap::stqfa({{throw fp_disabled;}}); //STQFA - 0x36: Trap::stdfa({{throw fp_disabled;}}); //STDFA - - - - - - 0x3C: Cas::casa( - {{uint64_t val = Mem.uw; - if(Rs2.uw == val) - Mem.uw = Rd.uw; - Rd.uw = val; - }}); //CASA - 0x3D: Noop::prefetcha({{ }}); //PREFETCHA - 0x3E: Cas::casxa( - {{uint64_t val = Mem.udw; - if(Rs2 == val) - Mem.udw = Rd; - Rd = val; - }}); //CASXA - } - } -} diff --git a/arch/sparc/isa/formats.isa b/arch/sparc/isa/formats.isa deleted file mode 100644 index 547f8be48..000000000 --- a/arch/sparc/isa/formats.isa +++ /dev/null @@ -1,19 +0,0 @@ -//Include the basic format -//Templates from this format are used later -##include "m5/arch/sparc/isa/formats/basic.isa" - -//Include the integerOp and integerOpCc format -##include "m5/arch/sparc/isa/formats/integerop.isa" - -//Include the mem format -##include "m5/arch/sparc/isa/formats/mem.isa" - -//Include the trap format -##include "m5/arch/sparc/isa/formats/trap.isa" - -//Include the branch format -##include "m5/arch/sparc/isa/formats/branch.isa" - -//Include the noop format -##include "m5/arch/sparc/isa/formats/noop.isa" - diff --git a/arch/sparc/isa/formats/basic.isa b/arch/sparc/isa/formats/basic.isa deleted file mode 100644 index 73df7617d..000000000 --- a/arch/sparc/isa/formats/basic.isa +++ /dev/null @@ -1,68 +0,0 @@ - -// Declarations for execute() methods. -def template BasicExecDeclare {{ - Fault execute(%(CPU_exec_context)s *, Trace::InstRecord *) const; -}}; - -// Basic instruction class declaration template. -def template BasicDeclare {{ - /** - * Static instruction class for "%(mnemonic)s". - */ - class %(class_name)s : public %(base_class)s - { - public: - // Constructor. - %(class_name)s(MachInst machInst); - %(BasicExecDeclare)s - }; -}}; - -// Basic instruction class constructor template. -def template BasicConstructor {{ - inline %(class_name)s::%(class_name)s(MachInst machInst) - : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s) - { - %(constructor)s; - } -}}; - -// Basic instruction class execute method template. -def template BasicExecute {{ - Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Fault fault = NoFault; - - %(fp_enable_check)s; - %(op_decl)s; - %(op_rd)s; - %(code)s; - - if(fault == NoFault) - { - %(op_wb)s; - } - return fault; - } -}}; - -// Basic decode template. -def template BasicDecode {{ - return new %(class_name)s(machInst); -}}; - -// Basic decode template, passing mnemonic in as string arg to constructor. -def template BasicDecodeWithMnemonic {{ - return new %(class_name)s("%(mnemonic)s", machInst); -}}; - -// The most basic instruction format... used only for a few misc. insts -def format BasicOperate(code, *flags) {{ - iop = InstObjParams(name, Name, 'SparcStaticInst', - CodeBlock(code), flags) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecode.subst(iop) - exec_output = BasicExecute.subst(iop) -}}; diff --git a/arch/sparc/isa/formats/branch.isa b/arch/sparc/isa/formats/branch.isa deleted file mode 100644 index 80101de1b..000000000 --- a/arch/sparc/isa/formats/branch.isa +++ /dev/null @@ -1,62 +0,0 @@ -//////////////////////////////////////////////////////////////////// -// -// Branch instructions -// - -output header {{ - /** - * Base class for integer operations. - */ - class Branch : public SparcStaticInst - { - protected: - // Constructor - Branch(const char *mnem, MachInst _machInst, OpClass __opClass) : - SparcStaticInst(mnem, _machInst, __opClass) - { - } - - std::string generateDisassembly(Addr pc, - const SymbolTable *symtab) const; - }; -}}; - -output decoder {{ - std::string Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - return "Branch instruction\n"; - } -}}; - -def template BranchExecute {{ - Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - //Attempt to execute the instruction - Fault fault = NoFault; - checkPriv; - - %(op_decl)s; - %(op_rd)s; - %(code)s; - - if(fault == NoFault) - { - //Write the resulting state to the execution context - %(op_wb)s; - } - - return fault; - } -}}; - -// Primary format for integer operate instructions: -def format Branch(code, *opt_flags) {{ - orig_code = code - cblk = CodeBlock(code) - iop = InstObjParams(name, Name, 'SparcStaticInst', cblk, opt_flags) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecodeWithMnemonic.subst(iop) - exec_output = BranchExecute.subst(iop) -}}; diff --git a/arch/sparc/isa/formats/integerop.isa b/arch/sparc/isa/formats/integerop.isa deleted file mode 100644 index 5a9e09896..000000000 --- a/arch/sparc/isa/formats/integerop.isa +++ /dev/null @@ -1,112 +0,0 @@ -//////////////////////////////////////////////////////////////////// -// -// Integer operate instructions -// - -output header {{ - /** - * Base class for integer operations. - */ - class IntegerOp : public SparcStaticInst - { - protected: - // Constructor - IntegerOp(const char *mnem, MachInst _machInst, OpClass __opClass) : - SparcStaticInst(mnem, _machInst, __opClass) - { - } - - std::string generateDisassembly(Addr pc, - const SymbolTable *symtab) const; - }; -}}; - -output decoder {{ - std::string IntegerOp::generateDisassembly(Addr pc, - const SymbolTable *symtab) const - { - return "Integer instruction\n"; - } -}}; - -def template IntegerExecute {{ - Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const - { - //These are set to constants when the execute method - //is generated - bool useCc = ; - bool checkPriv = ; - - //Attempt to execute the instruction - try - { - checkPriv; - - %(op_decl)s; - %(op_rd)s; - %(code)s; - } - //If we have an exception for some reason, - //deal with it - catch(SparcException except) - { - //Deal with exception - return No_Fault; - } - - //Write the resulting state to the execution context - %(op_wb)s; - if(useCc) - { - xc->regs.miscRegFile.ccrFields.iccFields.n = Rd & (1 << 63); - xc->regs.miscRegFile.ccrFields.iccFields.z = (Rd == 0); - xc->regs.miscRegFile.ccrFields.iccFields.v = ivValue; - xc->regs.miscRegFile.ccrFields.iccFields.c = icValue; - xc->regs.miscRegFile.ccrFields.xccFields.n = Rd & (1 << 31); - xc->regs.miscRegFile.ccrFields.xccFields.z = ((Rd & 0xFFFFFFFF) == 0); - xc->regs.miscRegFile.ccrFields.xccFields.v = xvValue; - xc->regs.miscRegFile.ccrFields.xccFields.c = xcValue; - } - return No_Fault; - } -}}; - -// Primary format for integer operate instructions: -def format IntegerOp(code, *opt_flags) {{ - orig_code = code - cblk = CodeBlock(code) - checkPriv = (code.find('checkPriv') != -1) - code.replace('checkPriv', '') - if checkPriv: - code.replace('checkPriv;', 'if(!xc->regs.miscRegFile.pstateFields.priv) throw privileged_opcode;') - else: - code.replace('checkPriv;', '') - for (marker, value) in (('ivValue', '0'), ('icValue', '0'), - ('xvValue', '0'), ('xcValue', '0')): - code.replace(marker, value) - iop = InstObjParams(name, Name, 'SparcStaticInst', cblk, opt_flags) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecodeWithMnemonic.subst(iop) - exec_output = IntegerExecute.subst(iop) -}}; - -// Primary format for integer operate instructions: -def format IntegerOpCc(code, icValue, ivValue, xcValue, xvValue, *opt_flags) {{ - orig_code = code - cblk = CodeBlock(code) - checkPriv = (code.find('checkPriv') != -1) - code.replace('checkPriv', '') - if checkPriv: - code.replace('checkPriv;', 'if(!xc->regs.miscRegFile.pstateFields.priv) throw privileged_opcode;') - else: - code.replace('checkPriv;', '') - for (marker, value) in (('ivValue', ivValue), ('icValue', icValue), - ('xvValue', xvValue), ('xcValue', xcValue)): - code.replace(marker, value) - iop = InstObjParams(name, Name, 'SparcStaticInst', cblk, opt_flags) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecodeWithMnemonic.subst(iop) - exec_output = IntegerExecute.subst(iop) -}}; diff --git a/arch/sparc/isa/formats/mem.isa b/arch/sparc/isa/formats/mem.isa deleted file mode 100644 index d72de47d0..000000000 --- a/arch/sparc/isa/formats/mem.isa +++ /dev/null @@ -1,73 +0,0 @@ -//////////////////////////////////////////////////////////////////// -// -// Mem instructions -// - -output header {{ - /** - * Base class for integer operations. - */ - class Mem : public SparcStaticInst - { - protected: - - // Constructor - Mem(const char *mnem, MachInst _machInst, OpClass __opClass) : - SparcStaticInst(mnem, _machInst, __opClass) - { - } - - std::string generateDisassembly(Addr pc, - const SymbolTable *symtab) const; - }; -}}; - -output decoder {{ - std::string Mem::generateDisassembly(Addr pc, const SymbolTable *symtab) const - { - return "Memory instruction\n"; - } -}}; - -def template MemExecute {{ - Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - Fault fault = NoFault; - %(op_decl)s; - %(op_rd)s; - ea_code - %(code)s; - - if(fault == NoFault) - { - //Write the resulting state to the execution context - %(op_wb)s; - } - - return fault; - } -}}; - -// Primary format for integer operate instructions: -def format Mem(code, *opt_flags) {{ - orig_code = code - cblk = CodeBlock(code) - iop = InstObjParams(name, Name, 'SparcStaticInst', cblk, opt_flags) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecodeWithMnemonic.subst(iop) - exec_output = MemExecute.subst(iop) - exec_output.replace('ea_code', 'EA = I ? (R1 + SIMM13) : R1 + R2;'); -}}; - -def format Cas(code, *opt_flags) {{ - orig_code = code - cblk = CodeBlock(code) - iop = InstObjParams(name, Name, 'SparcStaticInst', cblk, opt_flags) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecodeWithMnemonic.subst(iop) - exec_output = MemExecute.subst(iop) - exec_output.replace('ea_code', 'EA = R1;'); -}}; diff --git a/arch/sparc/isa/formats/noop.isa b/arch/sparc/isa/formats/noop.isa deleted file mode 100644 index fa4047f06..000000000 --- a/arch/sparc/isa/formats/noop.isa +++ /dev/null @@ -1,50 +0,0 @@ -//////////////////////////////////////////////////////////////////// -// -// Noop instruction -// - -output header {{ - /** - * Noop class. - */ - class Noop : public SparcStaticInst - { - protected: - // Constructor - Noop(const char *mnem, MachInst _machInst, OpClass __opClass) : - SparcStaticInst(mnem, _machInst, __opClass) - { - } - - std::string generateDisassembly(Addr pc, - const SymbolTable *symtab) const; - }; -}}; - -output decoder {{ - std::string Noop::generateDisassembly(Addr pc, - const SymbolTable *symtab) const - { - return "Noop\n"; - } -}}; - -def template NoopExecute {{ - Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - //Nothing to see here, move along - return NoFault; - } -}}; - -// Primary format for integer operate instructions: -def format Noop(code, *opt_flags) {{ - orig_code = code - cblk = CodeBlock(code) - iop = InstObjParams(name, Name, 'SparcStaticInst', cblk, opt_flags) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecodeWithMnemonic.subst(iop) - exec_output = NoopExecute.subst(iop) -}}; diff --git a/arch/sparc/isa/formats/trap.isa b/arch/sparc/isa/formats/trap.isa deleted file mode 100644 index ff3aadf72..000000000 --- a/arch/sparc/isa/formats/trap.isa +++ /dev/null @@ -1,51 +0,0 @@ -//////////////////////////////////////////////////////////////////// -// -// Trap instructions -// - -output header {{ - /** - * Base class for integer operations. - */ - class Trap : public SparcStaticInst - { - protected: - - // Constructor - Trap(const char *mnem, MachInst _machInst, OpClass __opClass) : - SparcStaticInst(mnem, _machInst, __opClass) - { - } - - std::string generateDisassembly(Addr pc, - const SymbolTable *symtab) const; - }; -}}; - -output decoder {{ - std::string Trap::generateDisassembly(Addr pc, - const SymbolTable *symtab) const - { - return "Trap instruction\n"; - } -}}; - -def template TrapExecute {{ - Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - //TODO: set up a software fault and return it. - return NoFault; - } -}}; - -// Primary format for integer operate instructions: -def format Trap(code, *opt_flags) {{ - orig_code = code - cblk = CodeBlock(code) - iop = InstObjParams(name, Name, 'SparcStaticInst', cblk, opt_flags) - header_output = BasicDeclare.subst(iop) - decoder_output = BasicConstructor.subst(iop) - decode_block = BasicDecodeWithMnemonic.subst(iop) - exec_output = TrapExecute.subst(iop) -}}; diff --git a/arch/sparc/isa/includes.isa b/arch/sparc/isa/includes.isa deleted file mode 100644 index a99018b49..000000000 --- a/arch/sparc/isa/includes.isa +++ /dev/null @@ -1,43 +0,0 @@ -//////////////////////////////////////////////////////////////////// -// -// Output include file directives. -// - -output header {{ -#include <sstream> -#include <iostream> -#include <iomanip> - -#include "cpu/static_inst.hh" -#include "arch/sparc/faults.hh" -#include "mem/mem_req.hh" // some constructors use MemReq flags -#include "arch/sparc/isa_traits.hh" -}}; - -output decoder {{ -#include "base/cprintf.hh" -#include "base/loader/symtab.hh" -#include "cpu/exec_context.hh" // for Jump::branchTarget() - -#include <math.h> -#if defined(linux) -#include <fenv.h> -#endif - -using namespace SparcISA; -}}; - -output exec {{ -#include <math.h> -#if defined(linux) -#include <fenv.h> -#endif - -#ifdef FULL_SYSTEM -//#include "arch/alpha/pseudo_inst.hh" -#endif -#include "cpu/base.hh" -#include "cpu/exetrace.hh" -#include "sim/sim_exit.hh" -}}; - diff --git a/arch/sparc/isa/main.isa b/arch/sparc/isa/main.isa deleted file mode 100644 index ab0290d58..000000000 --- a/arch/sparc/isa/main.isa +++ /dev/null @@ -1,52 +0,0 @@ -// -*- mode:c++ -*- - -// Copyright (c) 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. - -##include "m5/arch/sparc/isa/includes.isa" - -//////////////////////////////////////////////////////////////////// -// -// Namespace statement. Everything below this line will be in the -// SparcISAInst namespace. -// - -namespace SparcISA; - -//Include the bitfield definitions -##include "m5/arch/sparc/isa/bitfields.isa" - -//Include the operand_types and operand definitions -##include "m5/arch/sparc/isa/operands.isa" - -//Include the base class for sparc instructions, and some support code -##include "m5/arch/sparc/isa/base.isa" - -//Include the definitions for the instruction formats -##include "m5/arch/sparc/isa/formats.isa" - -//Include the decoder definition -##include "m5/arch/sparc/isa/decoder.isa" diff --git a/arch/sparc/isa/operands.isa b/arch/sparc/isa/operands.isa deleted file mode 100644 index 64f5abd08..000000000 --- a/arch/sparc/isa/operands.isa +++ /dev/null @@ -1,31 +0,0 @@ -def operand_types {{ - 'sb' : ('signed int', 8), - 'ub' : ('unsigned int', 8), - 'shw' : ('signed int', 16), - 'uhw' : ('unsigned int', 16), - 'sw' : ('signed int', 32), - 'uw' : ('unsigned int', 32), - 'sdw' : ('signed int', 64), - 'udw' : ('unsigned int', 64), - 'sf' : ('float', 32), - 'df' : ('float', 64), - 'qf' : ('float', 128) -}}; - -def operands {{ - # Int regs default to unsigned, but code should not count on this. - # For clarity, descriptions that depend on unsigned behavior should - # explicitly specify '.uq'. - 'Rd': ('IntReg', 'udw', 'RD', 'IsInteger', 1), - 'Rs1': ('IntReg', 'udw', 'RS1', 'IsInteger', 2), - 'Rs2': ('IntReg', 'udw', 'RS2', 'IsInteger', 3), - #'Fa': ('FloatReg', 'df', 'FA', 'IsFloating', 1), - #'Fb': ('FloatReg', 'df', 'FB', 'IsFloating', 2), - #'Fc': ('FloatReg', 'df', 'FC', 'IsFloating', 3), - 'Mem': ('Mem', 'udw', None, ('IsMemRef', 'IsLoad', 'IsStore'), 4), - #'NPC': ('NPC', 'uq', None, ( None, None, 'IsControl' ), 4), - #'Runiq': ('ControlReg', 'uq', 'Uniq', None, 1), - #'FPCR': ('ControlReg', 'uq', 'Fpcr', None, 1), - 'R0': ('IntReg', 'udw', '0', None, 1), - 'R16': ('IntReg', 'udw', '16', None, 1) -}}; diff --git a/arch/sparc/isa_traits.hh b/arch/sparc/isa_traits.hh deleted file mode 100644 index bd3c35beb..000000000 --- a/arch/sparc/isa_traits.hh +++ /dev/null @@ -1,527 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __ARCH_SPARC_ISA_TRAITS_HH__ -#define __ARCH_SPARC_ISA_TRAITS_HH__ - -#include "arch/sparc/faults.hh" -#include "base/misc.hh" -#include "config/full_system.hh" -#include "sim/host.hh" - -//This makes sure the big endian versions of certain functions are used. -namespace BigEndianGuest {} -using namespace BigEndianGuest; - -class ExecContext; -class FastCPU; -//class FullCPU; -class Checkpoint; - -#define TARGET_SPARC - -class StaticInst; -class StaticInstPtr; - -//namespace EV5 -//{ -// int DTB_ASN_ASN(uint64_t reg); -// int ITB_ASN_ASN(uint64_t reg); -//} - -namespace SparcISA -{ - typedef uint32_t MachInst; - typedef uint64_t ExtMachInst; - typedef uint8_t RegIndex; - - const int NumFloatRegs = 32; - const int NumMiscRegs = 32; - - const int // Maximum trap level - const int MaxTL = 4; - const int - const int // semantically meaningful register indices - const int ZeroReg = 0; // architecturally meaningful - const int // the rest of these depend on the ABI - const int StackPointerReg = 14; - const int ReturnAddressReg = 31; // post call, precall is 15 - const int ReturnValueReg = 8; // Post return, 24 is pre-return. - const int FramePointerReg = 30; - const int ArgumentReg0 = 8; - const int ArgumentReg1 = 9; - const int ArgumentReg2 = 10; - const int ArgumentReg3 = 11; - const int ArgumentReg4 = 12; - const int ArgumentReg5 = 13; - // Some OS syscall sue a second register (o1) to return a second value - const int SyscallPseudoReturnReg = ArgumentReg1; - - - //8K. This value is implmentation specific; and should probably - //be somewhere else. - const int LogVMPageSize = 13; - const int VMPageSize = (1 << LogVMPageSize); - - - - - - - - - - - - - - - - - - - - - - - - typedef uint64_t IntReg; - - class IntRegFile - { - private: - //For right now, let's pretend the register file is static - IntReg regs[32]; - public: - IntReg & operator [] (RegIndex index) - { - //Don't allow indexes outside of the 32 registers - index &= 0x1F; - return regs[index]; - } - }; - - void serialize(std::ostream & os); - - void unserialize(Checkpoint *cp, const std::string §ion); - - typedef float float32_t; - typedef double float64_t; - //FIXME This actually usually refers to a 10 byte float, rather than a - //16 byte float as required. This data type may have to be emulated. - typedef long double float128_t; - - class FloatRegFile - { - private: - //By using the largest data type, we ensure everything - //is aligned correctly in memory - union - { - float128_t rawRegs[16]; - uint64_t regDump[32]; - }; - class QuadRegs - { - private: - FloatRegFile * parent; - public: - QuadRegs(FloatRegFile * p) : parent(p) {;} - float128_t & operator [] (RegIndex index) - { - //Quad floats are index by the single - //precision register the start on, - //and only 16 should be accessed - index = (index >> 2) & 0xF; - return parent->rawRegs[index]; - } - }; - class DoubleRegs - { - private: - FloatRegFile * parent; - public: - DoubleRegs(FloatRegFile * p) : parent(p) {;} - float64_t & operator [] (RegIndex index) - { - //Double floats are index by the single - //precision register the start on, - //and only 32 should be accessed - index = (index >> 1) & 0x1F; - return ((float64_t *)parent->rawRegs)[index]; - } - }; - class SingleRegs - { - private: - FloatRegFile * parent; - public: - SingleRegs(FloatRegFile * p) : parent(p) {;} - float32_t & operator [] (RegIndex index) - { - //Only 32 single floats should be accessed - index &= 0x1F; - return ((float32_t *)parent->rawRegs)[index]; - } - }; - public: - void serialize(std::ostream & os); - - void unserialize(Checkpoint * cp, std::string & section); - - QuadRegs quadRegs; - DoubleRegs doubleRegs; - SingleRegs singleRegs; - FloatRegFile() : quadRegs(this), doubleRegs(this), singleRegs(this) - {;} - }; - - // control register file contents - typedef uint64_t MiscReg; - // The control registers, broken out into fields - class MiscRegFile - { - private: - union - { - uint16_t pstate; // Process State Register - struct - { - uint16_t ag:1; // Alternate Globals - uint16_t ie:1; // Interrupt enable - uint16_t priv:1; // Privelege mode - uint16_t am:1; // Address mask - uint16_t pef:1; // PSTATE enable floating-point - uint16_t red:1; // RED (reset, error, debug) state - uint16_t mm:2; // Memory Model - uint16_t tle:1; // Trap little-endian - uint16_t cle:1; // Current little-endian - } pstateFields; - }; - uint64_t tba; // Trap Base Address - union - { - uint64_t y; // Y (used in obsolete multiplication) - struct - { - uint64_t value:32; // The actual value stored in y - uint64_t :32; // reserved bits - } yFields; - }; - uint8_t pil; // Process Interrupt Register - uint8_t cwp; // Current Window Pointer - uint16_t tt[MaxTL]; // Trap Type (Type of trap which occured - // on the previous level) - union - { - uint8_t ccr; // Condition Code Register - struct - { - union - { - uint8_t icc:4; // 32-bit condition codes - struct - { - uint8_t c:1; // Carry - uint8_t v:1; // Overflow - uint8_t z:1; // Zero - uint8_t n:1; // Negative - } iccFields; - }; - union - { - uint8_t xcc:4; // 64-bit condition codes - struct - { - uint8_t c:1; // Carry - uint8_t v:1; // Overflow - uint8_t z:1; // Zero - uint8_t n:1; // Negative - } xccFields; - }; - } ccrFields; - }; - uint8_t asi; // Address Space Identifier - uint8_t tl; // Trap Level - uint64_t tpc[MaxTL]; // Trap Program Counter (value from - // previous trap level) - uint64_t tnpc[MaxTL]; // Trap Next Program Counter (value from - // previous trap level) - union - { - uint64_t tstate[MaxTL]; // Trap State - struct - { - //Values are from previous trap level - uint64_t cwp:5; // Current Window Pointer - uint64_t :2; // Reserved bits - uint64_t pstate:10; // Process State - uint64_t :6; // Reserved bits - uint64_t asi:8; // Address Space Identifier - uint64_t ccr:8; // Condition Code Register - } tstateFields[MaxTL]; - }; - union - { - uint64_t tick; // Hardware clock-tick counter - struct - { - uint64_t counter:63; // Clock-tick count - uint64_t npt:1; // Non-priveleged trap - } tickFields; - }; - uint8_t cansave; // Savable windows - uint8_t canrestore; // Restorable windows - uint8_t otherwin; // Other windows - uint8_t cleanwin; // Clean windows - union - { - uint8_t wstate; // Window State - struct - { - uint8_t normal:3; // Bits TT<4:2> are set to on a normal - // register window trap - uint8_t other:3; // Bits TT<4:2> are set to on an "otherwin" - // register window trap - } wstateFields; - }; - union - { - uint64_t ver; // Version - struct - { - uint64_t maxwin:5; // Max CWP value - uint64_t :2; // Reserved bits - uint64_t maxtl:8; // Maximum trap level - uint64_t :8; // Reserved bits - uint64_t mask:8; // Processor mask set revision number - uint64_t impl:16; // Implementation identification number - uint64_t manuf:16; // Manufacturer code - } verFields; - }; - union - { - uint64_t fsr; // Floating-Point State Register - struct - { - union - { - uint64_t cexc:5; // Current excpetion - struct - { - uint64_t nxc:1; // Inexact - uint64_t dzc:1; // Divide by zero - uint64_t ufc:1; // Underflow - uint64_t ofc:1; // Overflow - uint64_t nvc:1; // Invalid operand - } cexecFields; - }; - union - { - uint64_t aexc:5; // Accrued exception - struct - { - uint64_t nxc:1; // Inexact - uint64_t dzc:1; // Divide by zero - uint64_t ufc:1; // Underflow - uint64_t ofc:1; // Overflow - uint64_t nvc:1; // Invalid operand - } aexecFields; - }; - uint64_t fcc0:2; // Floating-Point condtion codes - uint64_t :1; // Reserved bits - uint64_t qne:1; // Deferred trap queue not empty - // with no queue, it should read 0 - uint64_t ftt:3; // Floating-Point trap type - uint64_t ver:3; // Version (of the FPU) - uint64_t :2; // Reserved bits - uint64_t ns:1; // Nonstandard floating point - union - { - uint64_t tem:5; // Trap Enable Mask - struct - { - uint64_t nxm:1; // Inexact - uint64_t dzm:1; // Divide by zero - uint64_t ufm:1; // Underflow - uint64_t ofm:1; // Overflow - uint64_t nvm:1; // Invalid operand - } temFields; - }; - uint64_t :2; // Reserved bits - uint64_t rd:2; // Rounding direction - uint64_t fcc1:2; // Floating-Point condition codes - uint64_t fcc2:2; // Floating-Point condition codes - uint64_t fcc3:2; // Floating-Point condition codes - uint64_t :26; // Reserved bits - } fsrFields; - }; - union - { - uint8_t fprs; // Floating-Point Register State - struct - { - uint8_t dl:1; // Dirty lower - uint8_t du:1; // Dirty upper - uint8_t fef:1; // FPRS enable floating-Point - } fprsFields; - }; - - public: - MiscReg readReg(int misc_reg); - - MiscReg readRegWithEffect(int misc_reg, Fault &fault, ExecContext *xc); - - Fault setReg(int misc_reg, const MiscReg &val); - - Fault setRegWithEffect(int misc_reg, const MiscReg &val, - ExecContext *xc); - - void serialize(std::ostream & os); - - void unserialize(Checkpoint * cp, std::string & section); - }; - - typedef union - { - float32_t singReg; - float64_t doubReg; - float128_t quadReg; - } FloatReg; - - typedef union - { - IntReg intreg; - FloatReg fpreg; - MiscReg ctrlreg; - } AnyReg; - - struct RegFile - { - IntRegFile intRegFile; // (signed) integer register file - FloatRegFile floatRegFile; // floating point register file - MiscRegFile miscRegFile; // control register file - - Addr pc; // Program Counter - Addr npc; // Next Program Counter - Addr nnpc; - - void serialize(std::ostream &os); - void unserialize(Checkpoint *cp, const std::string §ion); - }; - - StaticInstPtr decodeInst(MachInst); - - // return a no-op instruction... used for instruction fetch faults - extern const MachInst NoopMachInst; - - // Instruction address compression hooks - inline Addr realPCToFetchPC(const Addr &addr) - { - return addr; - } - - inline Addr fetchPCToRealPC(const Addr &addr) - { - return addr; - } - - // the size of "fetched" instructions (not necessarily the size - // of real instructions for PISA) - inline size_t fetchInstSize() - { - return sizeof(MachInst); - } - - /** - * Function to insure ISA semantics about 0 registers. - * @param xc The execution context. - */ - template <class XC> - - static inline setSyscallReturn(SyscallReturn return_value, RegFile *regs) - { - // check for error condition. SPARC syscall convention is to - // indicate success/failure in reg the carry bit of the ccr - // and put the return value itself in the standard return value reg (). - if (return_value.successful()) { - // no error - regs->miscRegFile.ccrFields.iccFields.c = 0; - regs->intRegFile[ReturnValueReg] = return_value.value(); - } else { - // got an error, return details - regs->miscRegFile.ccrFields.iccFields.c = 1; - regs->intRegFile[ReturnValueReg] = -return_value.value(); - } - } -}; - -#if !FULL_SYSTEM -class SyscallReturn -{ - public: - template <class T> - SyscallReturn(T v, bool s) - { - retval = (uint64_t)v; - success = s; - } - - template <class T> - SyscallReturn(T v) - { - success = (v >= 0); - retval = (uint64_t)v; - } - - ~SyscallReturn() {} - - SyscallReturn& operator=(const SyscallReturn& s) - { - retval = s.retval; - success = s.success; - return *this; - } - - bool successful() { return success; } - uint64_t value() { return retval; } - - private: - uint64_t retval; - bool success; -}; - -#endif - - -#if FULL_SYSTEM - -#include "arch/alpha/ev5.hh" -#endif - -#endif // __ARCH_SPARC_ISA_TRAITS_HH__ diff --git a/arch/sparc/linux/process.cc b/arch/sparc/linux/process.cc deleted file mode 100644 index fa2a7b9f5..000000000 --- a/arch/sparc/linux/process.cc +++ /dev/null @@ -1,374 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include "arch/sparc/common_syscall_emul.hh" -#include "arch/sparc/linux/process.hh" -#include "arch/sparc/isa_traits.hh" - -#include "base/trace.hh" -#include "cpu/exec_context.hh" -#include "kern/linux/linux.hh" -#include "mem/functional/functional.hh" - -#include "sim/process.hh" -#include "sim/syscall_emul.hh" - -using namespace std; -using namespace SparcISA; - - -/// Target uname() handler. -static SyscallReturn -unameFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - TypedBufferArg<Linux::utsname> name(xc->getSyscallArg(0)); - - strcpy(name->sysname, "Linux"); - strcpy(name->nodename, "m5.eecs.umich.edu"); - strcpy(name->release, "2.4.20"); - strcpy(name->version, "#1 Mon Aug 18 11:32:15 EDT 2003"); - strcpy(name->machine, "sparc"); - - name.copyOut(xc->mem); - return 0; -} - -SyscallDesc SparcLinuxProcess::syscallDescs[] = { - /* 0 */ SyscallDesc("restart_syscall", unimplementedFunc); - /* 1 */ SyscallDesc("exit", exitFunc); - /* 2 */ SyscallDesc("fork", unimplementedFunc); - /* 3 */ SyscallDesc("read", readFunc); - /* 4 */ SyscallDesc("write", writeFunc); - /* 5 */ SyscallDesc("open", openFunc<Linux>); - /* 6 */ SyscallDesc("close", closeFinc); - /* 7 */ SyscallDesc("wait4", unimplementedFunc); - /* 8 */ SyscallDesc("creat", unimplementedFunc); - /* 9 */ SyscallDesc("link", unimplementedFunc); - /* 10 */ SyscallDesc("unlink", unlinkFunc); - /* 11 */ SyscallDesc("execv", unimplementedFunc); - /* 12 */ SyscallDesc("chdir", unimplementedFunc); - /* 13 */ SyscallDesc("chown", chownFunc); - /* 14 */ SyscallDesc("mknod", unimplementedFunc); - /* 15 */ SyscallDesc("chmod", chmodFunc<Linux>); - /* 16 */ SyscallDesc("lchown", unimplementedFunc); - /* 17 */ SyscallDesc("brk", obreakFunc); - /* 18 */ SyscallDesc("perfctr", unimplementedFunc); - /* 19 */ SyscallDesc("lseek", lseekFunc); - /* 20 */ SyscallDesc("getpid", getpidFunc); - /* 21 */ SyscallDesc("capget", unimplementedFunc); - /* 22 */ SyscallDesc("capset", unimplementedFunc); - /* 23 */ SyscallDesc("setuid", setuidFunc); - /* 24 */ SyscallDesc("getuid", getuidFunc); - /* 25 */ SyscallDesc("time", unimplementedFunc); - /* 26 */ SyscallDesc("ptrace", unimplementedFunc); - /* 27 */ SyscallDesc("alarm", unimplementedFunc); - /* 28 */ SyscallDesc("sigaltstack", unimplementedFunc); - /* 29 */ SyscallDesc("pause", unimplementedFunc); - /* 30 */ SyscallDesc("utime", unimplementedFunc); - /* 31 */ SyscallDesc("lchown32", unimplementedFunc); - /* 32 */ SyscallDesc("fchown32", unimplementedFunc); - /* 33 */ SyscallDesc("access", unimplementedFunc); - /* 34 */ SyscallDesc("nice", unimplementedFunc); - /* 35 */ SyscallDesc("chown32", unimplementedFunc); - /* 36 */ SyscallDesc("sync", unimplementedFunc); - /* 37 */ SyscallDesc("kill", unimplementedFunc); - /* 38 */ SyscallDesc("stat", unimplementedFunc); - /* 39 */ SyscallDesc("sendfile", unimplementedFunc); - /* 40 */ SyscallDesc("lstat", unimplementedFunc); - /* 41 */ SyscallDesc("dup", unimplementedFunc); - /* 42 */ SyscallDesc("pipe", pipePseudoFunc); - /* 43 */ SyscallDesc("times", unimplementedFunc); - /* 44 */ SyscallDesc("getuid32", unimplementedFunc); - /* 45 */ SyscallDesc("umount2", unimplementedFunc); - /* 46 */ SyscallDesc("setgid", unimplementedFunc); - /* 47 */ SyscallDesc("getgid", getgidFunc); - /* 48 */ SyscallDesc("signal", unimplementedFunc); - /* 49 */ SyscallDesc("geteuid", geteuidFunc); - /* 50 */ SyscallDesc("getegid", getegidFunc); - /* 51 */ SyscallDesc("acct", unimplementedFunc); - /* 52 */ SyscallDesc("memory_ordering", unimplementedFunc); - /* 53 */ SyscallDesc("getgid32", unimplementedFunc); - /* 54 */ SyscallDesc("ioctl", unimplementedFunc); - /* 55 */ SyscallDesc("reboot", unimplementedFunc); - /* 56 */ SyscallDesc("mmap2", unimplementedFunc); - /* 57 */ SyscallDesc("symlink", unimplementedFunc); - /* 58 */ SyscallDesc("readlink", unimplementedFunc); - /* 59 */ SyscallDesc("execve", unimplementedFunc); - /* 60 */ SyscallDesc("umask", unimplementedFunc); - /* 61 */ SyscallDesc("chroot", unimplementedFunc); - /* 62 */ SyscallDesc("fstat", unimplementedFunc); - /* 63 */ SyscallDesc("fstat64", unimplementedFunc); - /* 64 */ SyscallDesc("getpagesize", unimplementedFunc); - /* 65 */ SyscallDesc("msync", unimplementedFunc); - /* 66 */ SyscallDesc("vfork", unimplementedFunc); - /* 67 */ SyscallDesc("pread64", unimplementedFunc); - /* 68 */ SyscallDesc("pwrite64", unimplementedFunc); - /* 69 */ SyscallDesc("geteuid32", unimplementedFunc); - /* 70 */ SyscallDesc("getdgid32", unimplementedFunc); - /* 71 */ SyscallDesc("mmap", unimplementedFunc); - /* 72 */ SyscallDesc("setreuid32", unimplementedFunc); - /* 73 */ SyscallDesc("munmap", unimplementedFunc); - /* 74 */ SyscallDesc("mprotect", unimplementedFunc); - /* 75 */ SyscallDesc("madvise", unimplementedFunc); - /* 76 */ SyscallDesc("vhangup", unimplementedFunc); - /* 77 */ SyscallDesc("truncate64", unimplementedFunc); - /* 78 */ SyscallDesc("mincore", unimplementedFunc); - /* 79 */ SyscallDesc("getgroups", unimplementedFunc); - /* 80 */ SyscallDesc("setgroups", unimplementedFunc); - /* 81 */ SyscallDesc("getpgrp", unimplementedFunc); - /* 82 */ SyscallDesc("setgroups32", unimplementedFunc); - /* 83 */ SyscallDesc("setitimer", unimplementedFunc); - /* 84 */ SyscallDesc("ftruncate64", unimplementedFunc); - /* 85 */ SyscallDesc("swapon", unimplementedFunc); - /* 86 */ SyscallDesc("getitimer", unimplementedFunc); - /* 87 */ SyscallDesc("setuid32", unimplementedFunc); - /* 88 */ SyscallDesc("sethostname", unimplementedFunc); - /* 89 */ SyscallDesc("setgid32", unimplementedFunc); - /* 90 */ SyscallDesc("dup2", unimplementedFunc); - /* 91 */ SyscallDesc("setfsuid32", unimplementedFunc); - /* 92 */ SyscallDesc("fcntl", unimplementedFunc); - /* 93 */ SyscallDesc("select", unimplementedFunc); - /* 94 */ SyscallDesc("setfsgid32", unimplementedFunc); - /* 95 */ SyscallDesc("fsync", unimplementedFunc); - /* 96 */ SyscallDesc("setpriority", unimplementedFunc); - /* 97 */ SyscallDesc("socket", unimplementedFunc); - /* 98 */ SyscallDesc("connect", unimplementedFunc); - /* 99 */ SyscallDesc("accept", unimplementedFunc); - /* 100 */ SyscallDesc("getpriority", unimplementedFunc); - /* 101 */ SyscallDesc("rt_sigreturn", unimplementedFunc); - /* 102 */ SyscallDesc("rt_sigaction", unimplementedFunc); - /* 103 */ SyscallDesc("rt_sigprocmask", unimplementedFunc); - /* 104 */ SyscallDesc("rt_sigpending", unimplementedFunc); - /* 105 */ SyscallDesc("rt_sigtimedwait", unimplementedFunc); - /* 106 */ SyscallDesc("rt_sigqueueinfo", unimplementedFunc); - /* 107 */ SyscallDesc("rt_sigsuspend", unimplementedFunc); - /* 108 */ SyscallDesc("setresuid", unimplementedFunc); - /* 109 */ SyscallDesc("getresuid", unimplementedFunc); - /* 110 */ SyscallDesc("setresgid", unimplementedFunc); - /* 111 */ SyscallDesc("getresgid", unimplementedFunc); - /* 112 */ SyscallDesc("setregid32", unimplementedFunc); - /* 113 */ SyscallDesc("recvmsg", unimplementedFunc); - /* 114 */ SyscallDesc("sendmsg", unimplementedFunc); - /* 115 */ SyscallDesc("getgroups32", unimplementedFunc); - /* 116 */ SyscallDesc("gettimeofday", unimplementedFunc); - /* 117 */ SyscallDesc("getrusage", unimplementedFunc); - /* 118 */ SyscallDesc("getsockopt", unimplementedFunc); - /* 119 */ SyscallDesc("getcwd", unimplementedFunc); - /* 120 */ SyscallDesc("readv", unimplementedFunc); - /* 121 */ SyscallDesc("writev", unimplementedFunc); - /* 122 */ SyscallDesc("settimeofday", unimplementedFunc); - /* 123 */ SyscallDesc("fchown", unimplementedFunc); - /* 124 */ SyscallDesc("fchmod", unimplementedFunc); - /* 125 */ SyscallDesc("recvfrom", unimplementedFunc); - /* 126 */ SyscallDesc("setreuid", unimplementedFunc); - /* 127 */ SyscallDesc("setregid", unimplementedFunc); - /* 128 */ SyscallDesc("rename", unimplementedFunc); - /* 129 */ SyscallDesc("truncate", unimplementedFunc); - /* 130 */ SyscallDesc("ftruncate", unimplementedFunc); - /* 131 */ SyscallDesc("flock", unimplementedFunc); - /* 132 */ SyscallDesc("lstat64", unimplementedFunc); - /* 133 */ SyscallDesc("sendto", unimplementedFunc); - /* 134 */ SyscallDesc("shutdown", unimplementedFunc); - /* 135 */ SyscallDesc("socketpair", unimplementedFunc); - /* 136 */ SyscallDesc("mkdir", unimplementedFunc); - /* 137 */ SyscallDesc("rmdir", unimplementedFunc); - /* 138 */ SyscallDesc("utimes", unimplementedFunc); - /* 139 */ SyscallDesc("stat64", unimplementedFunc); - /* 140 */ SyscallDesc("sendfile64", unimplementedFunc); - /* 141 */ SyscallDesc("getpeername", unimplementedFunc); - /* 142 */ SyscallDesc("futex", unimplementedFunc); - /* 143 */ SyscallDesc("gettid", unimplementedFunc); - /* 144 */ SyscallDesc("getrlimit", unimplementedFunc); - /* 145 */ SyscallDesc("setrlimit", unimplementedFunc); - /* 146 */ SyscallDesc("pivot_root", unimplementedFunc); - /* 147 */ SyscallDesc("prctl", unimplementedFunc); - /* 148 */ SyscallDesc("pciconfig_read", unimplementedFunc); - /* 149 */ SyscallDesc("pciconfig_write", unimplementedFunc); - /* 150 */ SyscallDesc("getsockname", unimplementedFunc); - /* 151 */ SyscallDesc("inotify_init", unimplementedFunc); - /* 152 */ SyscallDesc("inotify_add_watch", unimplementedFunc); - /* 153 */ SyscallDesc("poll", unimplementedFunc); - /* 154 */ SyscallDesc("getdents64", unimplementedFunc); - /* 155 */ SyscallDesc("fcntl64", unimplementedFunc); - /* 156 */ SyscallDesc("inotify_rm_watch", unimplementedFunc); - /* 157 */ SyscallDesc("statfs", unimplementedFunc); - /* 158 */ SyscallDesc("fstatfs", unimplementedFunc); - /* 159 */ SyscallDesc("umount", unimplementedFunc); - /* 160 */ SyscallDesc("sched_set_affinity", unimplementedFunc); - /* 161 */ SyscallDesc("sched_get_affinity", unimplementedFunc); - /* 162 */ SyscallDesc("getdomainname", unimplementedFunc); - /* 163 */ SyscallDesc("setdomainname", unimplementedFunc); - /* 164 */ SyscallDesc("utrap_install", unimplementedFunc); - /* 165 */ SyscallDesc("quotactl", unimplementedFunc); - /* 166 */ SyscallDesc("set_tid_address", unimplementedFunc); - /* 167 */ SyscallDesc("mount", unimplementedFunc); - /* 168 */ SyscallDesc("ustat", unimplementedFunc); - /* 169 */ SyscallDesc("setxattr", unimplementedFunc); - /* 170 */ SyscallDesc("lsetxattr", unimplementedFunc); - /* 171 */ SyscallDesc("fsetxattr", unimplementedFunc); - /* 172 */ SyscallDesc("getxattr", unimplementedFunc); - /* 173 */ SyscallDesc("lgetxattr", unimplementedFunc); - /* 174 */ SyscallDesc("getdents", unimplementedFunc); - /* 175 */ SyscallDesc("setsid", unimplementedFunc); - /* 176 */ SyscallDesc("fchdir", unimplementedFunc); - /* 177 */ SyscallDesc("fgetxattr", unimplementedFunc); - /* 178 */ SyscallDesc("listxattr", unimplementedFunc); - /* 179 */ SyscallDesc("llistxattr", unimplementedFunc); - /* 180 */ SyscallDesc("flistxattr", unimplementedFunc); - /* 181 */ SyscallDesc("removexattr", unimplementedFunc); - /* 182 */ SyscallDesc("lremovexattr", unimplementedFunc); - /* 183 */ SyscallDesc("sigpending", unimplementedFunc); - /* 184 */ SyscallDesc("query_module", unimplementedFunc); - /* 185 */ SyscallDesc("setpgid", unimplementedFunc); - /* 186 */ SyscallDesc("fremovexattr", unimplementedFunc); - /* 187 */ SyscallDesc("tkill", unimplementedFunc); - /* 188 */ SyscallDesc("exit_group", unimplementedFunc); - /* 189 */ SyscallDesc("uname", unameFunc); - /* 190 */ SyscallDesc("init_module", unimplementedFunc); - /* 191 */ SyscallDesc("personality", unimplementedFunc); - /* 192 */ SyscallDesc("remap_file_pages", unimplementedFunc); - /* 193 */ SyscallDesc("epoll_create", unimplementedFunc); - /* 194 */ SyscallDesc("epoll_ctl", unimplementedFunc); - /* 195 */ SyscallDesc("epoll_wait", unimplementedFunc); - /* 196 */ SyscallDesc("ioprio_set", unimplementedFunc); - /* 197 */ SyscallDesc("getppid", getppidFunc); - /* 198 */ SyscallDesc("sigaction", unimplementedFunc); - /* 199 */ SyscallDesc("sgetmask", unimplementedFunc); - /* 200 */ SyscallDesc("ssetmask", unimplementedFunc); - /* 201 */ SyscallDesc("sigsuspend", unimplementedFunc); - /* 202 */ SyscallDesc("oldlstat", unimplementedFunc); - /* 203 */ SyscallDesc("uselib", unimplementedFunc); - /* 204 */ SyscallDesc("readdir", unimplementedFunc); - /* 205 */ SyscallDesc("readahead", unimplementedFunc); - /* 206 */ SyscallDesc("socketcall", unimplementedFunc); - /* 207 */ SyscallDesc("syslog", unimplementedFunc); - /* 208 */ SyscallDesc("lookup_dcookie", unimplementedFunc); - /* 209 */ SyscallDesc("fadvise64", unimplementedFunc); - /* 210 */ SyscallDesc("fadvise64_64", unimplementedFunc); - /* 211 */ SyscallDesc("tgkill", unimplementedFunc); - /* 212 */ SyscallDesc("waitpid", unimplementedFunc); - /* 213 */ SyscallDesc("swapoff", unimplementedFunc); - /* 214 */ SyscallDesc("sysinfo", unimplementedFunc); - /* 215 */ SyscallDesc("ipc", unimplementedFunc); - /* 216 */ SyscallDesc("sigreturn", unimplementedFunc); - /* 217 */ SyscallDesc("clone", unimplementedFunc); - /* 218 */ SyscallDesc("ioprio_get", unimplementedFunc); - /* 219 */ SyscallDesc("adjtimex", unimplementedFunc); - /* 220 */ SyscallDesc("sigprocmask", unimplementedFunc); - /* 221 */ SyscallDesc("create_module", unimplementedFunc); - /* 222 */ SyscallDesc("delete_module", unimplementedFunc); - /* 223 */ SyscallDesc("get_kernel_syms", unimplementedFunc); - /* 224 */ SyscallDesc("getpgid", unimplementedFunc); - /* 225 */ SyscallDesc("bdflush", unimplementedFunc); - /* 226 */ SyscallDesc("sysfs", unimplementedFunc); - /* 227 */ SyscallDesc("afs_syscall", unimplementedFunc); - /* 228 */ SyscallDesc("setfsuid", unimplementedFunc); - /* 229 */ SyscallDesc("setfsgid", unimplementedFunc); - /* 230 */ SyscallDesc("_newselect", unimplementedFunc); - /* 231 */ SyscallDesc("time", unimplementedFunc); - /* 232 */ SyscallDesc("oldstat", unimplementedFunc); - /* 233 */ SyscallDesc("stime", unimplementedFunc); - /* 234 */ SyscallDesc("statfs64", unimplementedFunc); - /* 235 */ SyscallDesc("fstatfs64", unimplementedFunc); - /* 236 */ SyscallDesc("_llseek", unimplementedFunc); - /* 237 */ SyscallDesc("mlock", unimplementedFunc); - /* 238 */ SyscallDesc("munlock", unimplementedFunc); - /* 239 */ SyscallDesc("mlockall", unimplementedFunc); - /* 240 */ SyscallDesc("munlockall", unimplementedFunc); - /* 241 */ SyscallDesc("sched_setparam", unimplementedFunc); - /* 242 */ SyscallDesc("sched_getparam", unimplementedFunc); - /* 243 */ SyscallDesc("sched_setscheduler", unimplementedFunc); - /* 244 */ SyscallDesc("sched_getscheduler", unimplementedFunc); - /* 245 */ SyscallDesc("sched_yield", unimplementedFunc); - /* 246 */ SyscallDesc("sched_get_priority_max", unimplimented); - /* 247 */ SyscallDesc("sched_get_priority_min", unimplimented); - /* 248 */ SyscallDesc("sched_rr_get_interval", unimplimented); - /* 249 */ SyscallDesc("nanosleep", unimplementedFunc); - /* 250 */ SyscallDesc("mremap", unimplementedFunc); - /* 251 */ SyscallDesc("_sysctl", unimplementedFunc); - /* 252 */ SyscallDesc("getsid", unimplementedFunc); - /* 253 */ SyscallDesc("fdatasync", unimplementedFunc); - /* 254 */ SyscallDesc("nfsservctl", unimplementedFunc); - /* 255 */ SyscallDesc("aplib", unimplementedFunc); - /* 256 */ SyscallDesc("clock_settime", unimplementedFunc); - /* 257 */ SyscallDesc("clock_gettime", unimplementedFunc); - /* 258 */ SyscallDesc("clock_getres", unimplementedFunc); - /* 259 */ SyscallDesc("clock_nanosleep", unimplementedFunc); - /* 260 */ SyscallDesc("sched_getaffinity", unimplementedFunc); - /* 261 */ SyscallDesc("sched_setaffinity", unimplementedFunc); - /* 262 */ SyscallDesc("timer_settime", unimplementedFunc); - /* 263 */ SyscallDesc("timer_gettime", unimplementedFunc); - /* 264 */ SyscallDesc("timer_getoverrun", unimplementedFunc); - /* 265 */ SyscallDesc("timer_delete", unimplementedFunc); - /* 266 */ SyscallDesc("timer_create", unimplementedFunc); - /* 267 */ SyscallDesc("vserver", unimplementedFunc); - /* 268 */ SyscallDesc("io_setup", unimplementedFunc); - /* 269 */ SyscallDesc("io_destroy", unimplementedFunc); - /* 270 */ SyscallDesc("io_submit", unimplementedFunc); - /* 271 */ SyscallDesc("io_cancel", unimplementedFunc); - /* 272 */ SyscallDesc("io_getevents", unimplementedFunc); - /* 273 */ SyscallDesc("mq_open", unimplementedFunc); - /* 274 */ SyscallDesc("mq_unlink", unimplementedFunc); - /* 275 */ SyscallDesc("mq_timedsend", unimplementedFunc); - /* 276 */ SyscallDesc("mq_timedreceive", unimplementedFunc); - /* 277 */ SyscallDesc("mq_notify", unimplementedFunc); - /* 278 */ SyscallDesc("mq_getsetattr", unimplementedFunc); - /* 279 */ SyscallDesc("waitid", unimplementedFunc); - /* 280 */ SyscallDesc("sys_setaltroot", unimplementedFunc); - /* 281 */ SyscallDesc("add_key", unimplementedFunc); - /* 282 */ SyscallDesc("request_key", unimplementedFunc); - /* 283 */ SyscallDesc("keyctl", unimplementedFunc); -}; - -SparcLinuxProcess::SparcLinuxProcess(const std::string &name, - ObjectFile *objFile, - int stdin_fd, - int stdout_fd, - int stderr_fd, - std::vector<std::string> &argv, - std::vector<std::string> &envp) - : LiveProcess(name, objFile, stdin_fd, stdout_fd, stderr_fd, argv, envp), - Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc)) -{ - // The sparc syscall table must be <= 283 entries because that is all there - // is space for. - assert(Num_Syscall_Descs <= 283); - - init_regs->intRegFile[0] = 0; -} - - - -SyscallDesc* -AlphaLinuxProcess::getDesc(int callnum) -{ - if (callnum < 0 || callnum > Num_Syscall_Descs) - return NULL; - return &syscallDescs[callnum]; -} diff --git a/arch/sparc/linux/process.hh b/arch/sparc/linux/process.hh deleted file mode 100644 index c41406b4b..000000000 --- a/arch/sparc/linux/process.hh +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2003-2004 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. - */ - -#ifndef __SPARC_LINUX_PROCESS_HH__ -#define __SPARC_LINUX_PROCESS_HH__ - -#include "sim/process.hh" - - -/// A process with emulated SPARC/Linux syscalls. -class SparcLinuxProcess : public LiveProcess -{ - public: - /// Constructor. - SparcLinuxProcess(const std::string &name, - ObjectFile *objFile, - int stdin_fd, int stdout_fd, int stderr_fd, - std::vector<std::string> &argv, - std::vector<std::string> &envp); - - virtual SyscallDesc* getDesc(int callnum); - - /// The target system's hostname. - static const char *hostname; - - /// Array of syscall descriptors, indexed by call number. - static SyscallDesc syscallDescs[]; - - const int Num_Syscall_Descs; -}; - - -#endif // __ALPHA_LINUX_PROCESS_HH__ diff --git a/arch/sparc/process.cc b/arch/sparc/process.cc deleted file mode 100644 index 53a215379..000000000 --- a/arch/sparc/process.cc +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2003-2004 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. - */ - -#include "arch/sparc/process.hh" - -namespace SparcISA -{ - -LiveProcess * -createProcess(const string &nm, ObjectFile * objFile, - int stdin_fd, int stdout_fd, int stderr_fd, - vector<string> &argv, vector<string> &envp) -{ - LiveProcess * process = NULL; - if (objFile->getArch() != ObjectFile::SPARC) - fatal("Object file does not match architecture."); - switch (objFile->getOpSys()) { - case ObjectFile::Linux: - process = new SparcLinuxProcess(nm, objFile, - stdin_fd, stdout_fd, stderr_fd, - argv, envp); - break; - - case ObjectFile::Solaris: - default: - fatal("Unknown/unsupported operating system."); - } - return process; -} - -} // namespace SparcISA diff --git a/arch/sparc/process.hh b/arch/sparc/process.hh deleted file mode 100644 index 48041a316..000000000 --- a/arch/sparc/process.hh +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2003-2004 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. - */ - -#ifndef __SPARC_PROCESS_HH__ -#define __SPARC_PROCESS_HH__ - -#include "arch/sparc/linux/process.hh" -#include "base/loader/object_file.hh" - -namespace SparcISA -{ - -LiveProcess * -createProcess(const string &nm, ObjectFile * objFile, - int stdin_fd, int stdout_fd, int stderr_fd, - vector<string> &argv, vector<string> &envp); - -} // namespace SparcISA - -#endif // __SPARC_PROCESS_HH__ diff --git a/arch/sparc/stacktrace.hh b/arch/sparc/stacktrace.hh deleted file mode 100644 index 1d8d97a79..000000000 --- a/arch/sparc/stacktrace.hh +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __ARCH_ALPHA_STACKTRACE_HH__ -#define __ARCH_ALPHA_STACKTRACE_HH__ - -#include "base/trace.hh" -#include "cpu/static_inst.hh" - -class ExecContext; -class StackTrace; - -class ProcessInfo -{ - private: - ExecContext *xc; - - int thread_info_size; - int task_struct_size; - int task_off; - int pid_off; - int name_off; - - public: - ProcessInfo(ExecContext *_xc); - - Addr task(Addr ksp) const; - int pid(Addr ksp) const; - std::string name(Addr ksp) const; -}; - -class StackTrace -{ - protected: - typedef TheISA::MachInst MachInst; - private: - ExecContext *xc; - std::vector<Addr> stack; - - private: - bool isEntry(Addr addr); - bool decodePrologue(Addr sp, Addr callpc, Addr func, int &size, Addr &ra); - bool decodeSave(MachInst inst, int ®, int &disp); - bool decodeStack(MachInst inst, int &disp); - - void trace(ExecContext *xc, bool is_call); - - public: - StackTrace(); - StackTrace(ExecContext *xc, StaticInstPtr inst); - ~StackTrace(); - - void clear() - { - xc = 0; - stack.clear(); - } - - bool valid() const { return xc != NULL; } - bool trace(ExecContext *xc, StaticInstPtr inst); - - public: - const std::vector<Addr> &getstack() const { return stack; } - - static const int user = 1; - static const int console = 2; - static const int unknown = 3; - -#if TRACING_ON - private: - void dump(); - - public: - void dprintf() { if (DTRACE(Stack)) dump(); } -#else - public: - void dprintf() {} -#endif -}; - -inline bool -StackTrace::trace(ExecContext *xc, StaticInstPtr inst) -{ - if (!inst->isCall() && !inst->isReturn()) - return false; - - if (valid()) - clear(); - - trace(xc, !inst->isReturn()); - return true; -} - -#endif // __ARCH_ALPHA_STACKTRACE_HH__ diff --git a/base/bitfield.hh b/base/bitfield.hh deleted file mode 100644 index c59354c7d..000000000 --- a/base/bitfield.hh +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __BASE_BITFIELD_HH__ -#define __BASE_BITFIELD_HH__ - -#include "sim/host.hh" - -/** - * Generate a 64-bit mask of 'nbits' 1s, right justified. - */ -inline uint64_t -mask(int nbits) -{ - return (nbits == 64) ? (uint64_t)-1LL : (1ULL << nbits) - 1; -} - - -/** - * Extract the bitfield from position 'first' to 'last' (inclusive) - * from 'val' and right justify it. MSB is numbered 63, LSB is 0. - */ -template <class T> -inline -T -bits(T val, int first, int last) -{ - int nbits = first - last + 1; - return (val >> last) & mask(nbits); -} - -/** - * Sign-extend an N-bit value to 64 bits. - */ -template <int N> -inline -int64_t -sext(uint64_t val) -{ - int sign_bit = bits(val, N-1, N-1); - return sign_bit ? (val | ~mask(N)) : val; -} - -#endif // __BASE_BITFIELD_HH__ diff --git a/base/callback.hh b/base/callback.hh deleted file mode 100644 index 7b3023505..000000000 --- a/base/callback.hh +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __CALLBACK_HH__ -#define __CALLBACK_HH__ - -#include <list> - -/** - * Generic callback class. This base class provides a virtual process - * function that gets called when the callback queue is processed. - */ -class Callback -{ - public: - /** - * virtualize the destructor to make sure that the correct one - * gets called. - */ - virtual ~Callback() {} - - /** - * virtual process function that is invoked when the callback - * queue is executed. - */ - virtual void process() = 0; -}; - -class CallbackQueue -{ - protected: - /** - * Simple typedef for the data structure that stores all of the - * callbacks. - */ - typedef std::list<Callback *> queue; - - /** - * List of all callbacks. To be called in fifo order. - */ - queue callbacks; - - public: - /** - * Add a callback to the end of the queue - * @param callback the callback to be added to the queue - */ - void add(Callback *callback) - { - callbacks.push_back(callback); - } - - /** - * Find out if there are any callbacks in the queue - */ - bool empty() const { return callbacks.empty(); } - - /** - * process all callbacks - */ - void process() - { - queue::iterator i = callbacks.begin(); - queue::iterator end = callbacks.end(); - - while (i != end) { - (*i)->process(); - ++i; - } - } - - /** - * clear the callback queue - */ - void clear() - { - callbacks.clear(); - } -}; - -/// Helper template class to turn a simple class member function into -/// a callback. -template <class T, void (T::* F)()> -class MakeCallback : public Callback -{ - private: - T *object; - - public: - MakeCallback(T *o) - : object(o) - { } - - void process() { (object->*F)(); } -}; - -#endif // __CALLBACK_HH__ diff --git a/base/circlebuf.cc b/base/circlebuf.cc deleted file mode 100644 index 89bbfd822..000000000 --- a/base/circlebuf.cc +++ /dev/null @@ -1,213 +0,0 @@ -/* - * 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. - */ - -#include <algorithm> -#include <string> - -#include <stdio.h> -#include <string.h> -#include <unistd.h> - -#include "base/circlebuf.hh" -#include "base/cprintf.hh" -#include "base/intmath.hh" - -using namespace std; - -CircleBuf::CircleBuf(int l) - : _rollover(false), _buflen(l), _size(0), _start(0), _stop(0) -{ - _buf = new char[_buflen]; -} - -CircleBuf::~CircleBuf() -{ - if (_buf) - delete [] _buf; -} - -void -CircleBuf::dump() -{ - cprintf("start = %10d, stop = %10d, buflen = %10d\n", - _start, _stop, _buflen); - fflush(stdout); - ::write(STDOUT_FILENO, _buf, _buflen); - ::write(STDOUT_FILENO, "<\n", 2); -} - -void -CircleBuf::flush() -{ - _start = 0; - _stop = 0; - _rollover = false; -} - -void -CircleBuf::read(char *b, int len) -{ - _size -= len; - if (_size < 0) - _size = 0; - - if (_stop > _start) { - len = min(len, _stop - _start); - memcpy(b, _buf + _start, len); - _start += len; - } - else { - int endlen = _buflen - _start; - if (endlen > len) { - memcpy(b, _buf + _start, len); - _start += len; - } - else { - memcpy(b, _buf + _start, endlen); - _start = min(len - endlen, _stop); - memcpy(b + endlen, _buf, _start); - } - } -} - -void -CircleBuf::read(int fd, int len) -{ - _size -= len; - if (_size < 0) - _size = 0; - - if (_stop > _start) { - len = min(len, _stop - _start); - ::write(fd, _buf + _start, len); - _start += len; - } - else { - int endlen = _buflen - _start; - if (endlen > len) { - ::write(fd, _buf + _start, len); - _start += len; - } - else { - ::write(fd, _buf + _start, endlen); - _start = min(len - endlen, _stop); - ::write(fd, _buf, _start); - } - } -} - -void -CircleBuf::read(int fd) -{ - _size = 0; - - if (_stop > _start) { - ::write(fd, _buf + _start, _stop - _start); - } - else { - ::write(fd, _buf + _start, _buflen - _start); - ::write(fd, _buf, _stop); - } - - _start = _stop; -} - -void -CircleBuf::read(ostream &out) -{ - _size = 0; - - if (_stop > _start) { - out.write(_buf + _start, _stop - _start); - } - else { - out.write(_buf + _start, _buflen - _start); - out.write(_buf, _stop); - } - - _start = _stop; -} - -void -CircleBuf::readall(int fd) -{ - if (_rollover) - ::write(fd, _buf + _stop, _buflen - _stop); - - ::write(fd, _buf, _stop); - _start = _stop; -} - -void -CircleBuf::write(char b) -{ - write(&b, 1); -} - -void -CircleBuf::write(const char *b) -{ - write(b, strlen(b)); -} - -void -CircleBuf::write(const char *b, int len) -{ - if (len <= 0) - return; - - _size += len; - if (_size > _buflen) - _size = _buflen; - - int old_start = _start; - int old_stop = _stop; - - if (len >= _buflen) { - _start = 0; - _stop = _buflen; - _rollover = true; - memcpy(_buf, b + (len - _buflen), _buflen); - return; - } - - if (_stop + len <= _buflen) { - memcpy(_buf + _stop, b, len); - _stop += len; - } else { - int end_len = _buflen - old_stop; - _stop = len - end_len; - memcpy(_buf + old_stop, b, end_len); - memcpy(_buf, b + end_len, _stop); - _rollover = true; - } - - if (old_start > old_stop && old_start < _stop || - old_start < old_stop && _stop < old_stop) - _start = _stop + 1; -} diff --git a/base/circlebuf.hh b/base/circlebuf.hh deleted file mode 100644 index 8a64cb5f5..000000000 --- a/base/circlebuf.hh +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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. - */ - -#ifndef __CIRCLEBUF_HH__ -#define __CIRCLEBUF_HH__ - -#include <iosfwd> - -class CircleBuf -{ - protected: - char *_buf; - bool _rollover; - int _buflen; - int _size; - int _start; - int _stop; - - public: - explicit CircleBuf(int l); - ~CircleBuf(); - - bool empty() const { return _size == 0; } - int size() const { return _size; } - void dump(); - void flush(); - void read(char *b, int len); - void read(int fd, int len); - void read(int fd); - void read(std::ostream &out); - void readall(int fd); - void write(char b); - void write(const char *b); - void write(const char *b, int len); -}; - -#endif // __CIRCLEBUF_HH__ diff --git a/base/compression/lzss_compression.cc b/base/compression/lzss_compression.cc deleted file mode 100644 index 3ffdf7e95..000000000 --- a/base/compression/lzss_compression.cc +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) 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. - */ - -/** @file - * LZSSCompression definitions. - */ - -#include <assert.h> - -#include "base/compression/lzss_compression.hh" - -#include "base/misc.hh" //for fatal - -void -LZSSCompression::findSubString(uint8_t *src, int back, int size, uint16_t &L, - uint16_t &P) -{ - int front = 0; - int max_length = size - back; - L = 0; - P = back - 1; - while (front < back) { - while (src[front] != src[back] && front < back) ++front; - if (front >= back) { - return; - } - int i = 1; - while (src[front+i] == src[back+i] && i < max_length) ++i; - if (i >= L) { - L = i; - P = front; - } - if (src[front+i] != src[back+i-1]) { - // can't find a longer substring until past this point. - front += i; - } else { - ++front; - } - } -} - -int -LZSSCompression::emitByte(uint8_t *dest, uint8_t byte) -{ - if ((byte >> 5 & 0x7) == 0 || (byte >> 5 & 0x7) == 7) { - // If the top 3 bits are the same, emit 00<6bits> - dest[0] = byte & 0x3f; - return 1; - } else { - // emit 01XXXXXX <8 bits> - dest[0] = 0x40; - dest[1] = byte; - return 2; - } -} - -void -LZSSCompression::emitString(uint8_t *dest, uint16_t P, uint16_t L) -{ - // Emit 1<7P> <5P><3L> <8L> - dest[0] = 1<<7 | (P >> 5 & 0x7f); - dest[1] = ((P & 0x1f) << 3) | (L>>8 & 0x3); - dest[2] = L & 0xFF; -} - -int -LZSSCompression::compress(uint8_t *dest, uint8_t *src, int size) -{ - if (size > 4096) { - fatal("Compression can only handle block sizes of 4096 bytes or less"); - } - - // Encode the first byte. - int dest_index = emitByte(dest, src[0]); - int i = 1; - // A 11 bit field - uint16_t L; - // A 12 bit field - uint16_t P = 0; - - while (i < size && dest_index < size) { - L = 0; - - if (dest_index+3 >= size) { - dest_index = size; - continue; - } - - if (i == size - 1) { - // Output the character - dest_index += emitByte(&dest[dest_index], src[i]); - ++i; - continue; - } - findSubString(src, i, size, L, P); - if (L > 1) { - // Output the string reference - emitString(&dest[dest_index], P, L); - dest_index += 3; - i = i+L; - } else { - // Output the character - dest_index += emitByte(&dest[dest_index], src[i]); - ++i; - } - } - - if (dest_index >= size) { - // Have expansion instead of compression, just copy. - memcpy(dest,src,size); - return size; - } - return dest_index; -} - -int -LZSSCompression::uncompress(uint8_t *dest, uint8_t *src, int size) -{ - int index = 0; - int i = 0; - while (i < size) { - if (src[i] & 1<<7 ) { - // We have a string - // Extract P - int start = (src[i] & 0x3f)<<5 | ((src[i+1] >> 3) & 0x1f); - // Extract L - int len = (src[i+1] & 0x07)<<8 | src[i+2]; - i += 3; - for (int j = start; j < start+len; ++j) { - dest[index++] = dest[j]; - } - } else { - // We have a character - if (src[i] & 1<<6) { - // Value is in the next byte - dest[index++] = src[i+1]; - i += 2; - } else { - // just extend the lower 6 bits - dest[index++] = (src[i] & 0x3f) | ((src[i] & 1<<5) ? 0xC0 : 0); - ++i; - } - } - } - return index; -} diff --git a/base/compression/lzss_compression.hh b/base/compression/lzss_compression.hh deleted file mode 100644 index c136c6d60..000000000 --- a/base/compression/lzss_compression.hh +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __LZSS_COMPRESSION_HH__ -#define __LZSS_COMPRESSION_HH__ - -/** @file - * LZSSCompression declarations. - */ - -#include "sim/host.hh" // for uint8_t - -/** - * Simple LZSS compression scheme. - */ -class LZSSCompression -{ - /** - * Finds the longest substring for the given offset. - * @param src The source block that we search for substrings. - * @param back The larger offset. - * @param size The size of the source block. - * @param L The length of the largest substring. - * @param P The starting offset of the largest substring. - */ - void findSubString(uint8_t *src, int back, int size, uint16_t &L, - uint16_t &P); - - /** - * Emit an encoded byte to the compressed data array. If the 2 high - * order bits can be signed extended, use 1 byte encoding, if not use 2 - * bytes. - * @param dest The compressed data. - * @param byte The byte to emit. - * @return The number of bytes used to encode. - */ - int emitByte(uint8_t *dest, uint8_t byte); - - /** - * Emit a string reference to the compressed data array. A string reference - * always uses 3 bytes. 1 flag bit, 12 bits for the starting position, and - * 11 bits for the length of the string. This allows compression of 4096 - * byte blocks with string lengths of up to 2048 bytes. - * @param dest The compressed data. - * @param P The starting position in the uncompressed data. - * @param L The length in bytes of the string. - */ - void emitString(uint8_t *dest, uint16_t P, uint16_t L); - - public: - /** - * Compresses the source block and stores it in the destination block. If - * the compressed block grows to larger than the source block, it aborts - * and just performs a copy. - * @param dest The destination block. - * @param src The block to be compressed. - * @param size The size of the source block. - * @return The size of the compressed block. - * - * @pre Destination has enough storage to hold the compressed block. - */ - int compress(uint8_t *dest, uint8_t *src, int size); - - /** - * Unompresses the source block and stores it in the destination block. - * @param dest The destination block. - * @param src The block to be uncompressed. - * @param size The size of the source block. - * @return The size of the uncompressed block. - * - * @pre Destination has enough storage to hold the uncompressed block. - */ - int uncompress(uint8_t *dest, uint8_t *src, int size); -}; - -#endif //__LZSS_COMPRESSION_HH__ diff --git a/base/compression/null_compression.hh b/base/compression/null_compression.hh deleted file mode 100644 index 5fbcf562b..000000000 --- a/base/compression/null_compression.hh +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __BASE_COMPRESSION_NULL_COMPRESSION_HH__ -#define __BASE_COMPRESSION_NULL_COMPRESSION_HH__ - -/** - * @file - * This file defines a doNothing compression algorithm. - */ - -#include "base/misc.hh" // for fatal() -#include "sim/host.hh" - - -/** - * A dummy compression class to use when no data compression is desired. - */ -class NullCompression -{ - public: - /** - * Uncompress the data, causes a fatal since no data should be compressed. - * @param dest The output buffer. - * @param src The compressed data. - * @param size The number of bytes in src. - * - * @retval The size of the uncompressed data. - */ - static int uncompress(uint8_t * dest, uint8_t *src, int size) - { - fatal("Can't uncompress data"); - } - - /** - * Compress the data, just returns the source data. - * @param dest The output buffer. - * @param src The data to be compressed. - * @param size The number of bytes in src. - * - * @retval The size of the compressed data. - */ - - static int compress(uint8_t *dest, uint8_t *src, int size) - { - memcpy(dest,src,size); - return size; - } -}; - -#endif //__BASE_COMPRESSION_NULL_COMPRESSION_HH__ diff --git a/base/cprintf.cc b/base/cprintf.cc deleted file mode 100644 index cf332ebf2..000000000 --- a/base/cprintf.cc +++ /dev/null @@ -1,268 +0,0 @@ -/* - * 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. - */ - -#include <cassert> -#include <iomanip> -#include <iostream> -#include <sstream> - -#include "base/cprintf.hh" - -using namespace std; - -namespace cp { - -ArgList::~ArgList() -{ - while (!objects.empty()) { - delete objects.front(); - objects.pop_front(); - } -} - -void -ArgList::dump(const string &format) -{ - list_t::iterator iter = objects.begin(); - list_t::iterator end = objects.end(); - - const char *p = format.c_str(); - - stream->fill(' '); - stream->flags((ios::fmtflags)0); - - while (*p) { - switch (*p) { - case '%': { - if (p[1] == '%') { - *stream << '%'; - p += 2; - continue; - } - - Format fmt; - bool done = false; - bool end_number = false; - bool have_precision = false; - int number = 0; - - while (!done) { - ++p; - if (*p >= '0' && *p <= '9') { - if (end_number) - continue; - } else if (number > 0) - end_number = true; - - switch (*p) { - case 's': - fmt.format = Format::string; - done = true; - break; - - case 'c': - fmt.format = Format::character; - done = true; - break; - - case 'l': - continue; - - case 'p': - fmt.format = Format::integer; - fmt.base = Format::hex; - fmt.alternate_form = true; - done = true; - break; - - case 'X': - fmt.uppercase = true; - case 'x': - fmt.base = Format::hex; - fmt.format = Format::integer; - done = true; - break; - - case 'o': - fmt.base = Format::oct; - fmt.format = Format::integer; - done = true; - break; - - case 'd': - case 'i': - case 'u': - fmt.format = Format::integer; - done = true; - break; - - case 'G': - fmt.uppercase = true; - case 'g': - fmt.format = Format::floating; - fmt.float_format = Format::best; - done = true; - break; - - case 'E': - fmt.uppercase = true; - case 'e': - fmt.format = Format::floating; - fmt.float_format = Format::scientific; - done = true; - break; - - case 'f': - fmt.format = Format::floating; - fmt.float_format = Format::fixed; - done = true; - break; - - case 'n': - *stream << "we don't do %n!!!\n"; - done = true; - break; - - case '#': - fmt.alternate_form = true; - break; - - case '-': - fmt.flush_left = true; - break; - - case '+': - fmt.print_sign = true; - break; - - case ' ': - fmt.blank_space = true; - break; - - case '.': - fmt.width = number; - fmt.precision = 0; - have_precision = true; - number = 0; - end_number = false; - break; - - case '0': - if (number == 0) { - fmt.fill_zero = true; - break; - } - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - number = number * 10 + (*p - '0'); - break; - - case '%': - assert("we shouldn't get here"); - break; - - default: - done = true; - break; - } - - if (end_number) { - if (have_precision) - fmt.precision = number; - else - fmt.width = number; - - end_number = false; - number = 0; - } - } - - if (iter != end) - { - ios::fmtflags saved_flags = stream->flags(); - char old_fill = stream->fill(); - int old_precision = stream->precision(); - - (*iter)->process(*stream, fmt); - - stream->flags(saved_flags); - stream->fill(old_fill); - stream->precision(old_precision); - - ++iter; - } else { - *stream << "<missing arg for format>"; - } - - ++p; - } - break; - - case '\n': - *stream << endl; - ++p; - break; - case '\r': - ++p; - if (*p != '\n') - *stream << endl; - break; - - default: { - size_t len = strcspn(p, "%\n\r\0"); - stream->write(p, len); - p += len; - } - break; - } - } - - while (iter != end) { - *stream << "<extra arg>"; - ++iter; - } -} - -string -ArgList::dumpToString(const string &format) -{ - stringstream ss; - - dump(ss, format); - - return ss.str(); -} - -} diff --git a/base/cprintf.hh b/base/cprintf.hh deleted file mode 100644 index dcb292434..000000000 --- a/base/cprintf.hh +++ /dev/null @@ -1,198 +0,0 @@ -/* - * 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. - */ - -#ifndef __CPRINTF_HH__ -#define __CPRINTF_HH__ - -#include <iostream> -#include <list> -#include <sstream> -#include <string> - -namespace cp { - -#include "base/cprintf_formats.hh" - -class ArgList -{ - private: - class Base - { - public: - virtual ~Base() {} - virtual void process(std::ostream &out, Format &fmt) = 0; - }; - - template <typename T> - class Node : public Base - { - public: - const T &data; - - public: - Node(const T &d) : data(d) {} - virtual void process(std::ostream &out, Format &fmt) { - switch (fmt.format) { - case Format::character: - format_char(out, data, fmt); - break; - - case Format::integer: - format_integer(out, data, fmt); - break; - - case Format::floating: - format_float(out, data, fmt); - break; - - case Format::string: - format_string(out, data, fmt); - break; - - default: - out << "<bad format>"; - break; - } - } - }; - - typedef std::list<Base *> list_t; - - protected: - list_t objects; - std::ostream *stream; - - public: - ArgList() : stream(&std::cout) {} - ~ArgList(); - - template<class T> - void append(const T &data) { - Base *obj = new ArgList::Node<T>(data); - objects.push_back(obj); - } - - template<class T> - void prepend(const T &data) { - Base *obj = new ArgList::Node<T>(data); - objects.push_front(obj); - } - - void dump(const std::string &format); - void dump(std::ostream &strm, const std::string &fmt) - { stream = &strm; dump(fmt); } - - std::string dumpToString(const std::string &format); - - friend ArgList &operator<<(std::ostream &str, ArgList &list); -}; - -template<class T> -inline ArgList & -operator,(ArgList &alist, const T &data) -{ - alist.append(data); - return alist; -} - -class ArgListNull { -}; - -inline ArgList & -operator,(ArgList &alist, ArgListNull) -{ return alist; } - -// -// cprintf(format, args, ...) prints to cout -// (analogous to printf()) -// -inline void -__cprintf(const std::string &format, ArgList &args) -{ args.dump(format); delete &args; } -#define __cprintf__(format, args...) \ - cp::__cprintf(format, (*(new cp::ArgList), args)) -#define cprintf(args...) \ - __cprintf__(args, cp::ArgListNull()) - -// -// ccprintf(stream, format, args, ...) prints to the specified stream -// (analogous to fprintf()) -// -inline void -__ccprintf(std::ostream &stream, const std::string &format, ArgList &args) -{ args.dump(stream, format); delete &args; } -#define __ccprintf__(stream, format, args...) \ - cp::__ccprintf(stream, format, (*(new cp::ArgList), args)) -#define ccprintf(stream, args...) \ - __ccprintf__(stream, args, cp::ArgListNull()) - -// -// csprintf(format, args, ...) returns a string -// (roughly analogous to sprintf()) -// -inline std::string -__csprintf(const std::string &format, ArgList &args) -{ std::string s = args.dumpToString(format); delete &args; return s; } -#define __csprintf__(format, args...) \ - cp::__csprintf(format, (*(new cp::ArgList), args)) -#define csprintf(args...) \ - __csprintf__(args, cp::ArgListNull()) - -template<class T> -inline ArgList & -operator<<(ArgList &list, const T &data) -{ - list.append(data); - return list; -} - -inline ArgList & -operator<<(std::ostream &str, ArgList &list) -{ - list.stream = &str; - return list; -} - -class ArgListTemp -{ - private: - std::string format; - ArgList *args; - - public: - ArgListTemp(const std::string &f) : format(f) { args = new ArgList; } - ~ArgListTemp() { args->dump(format); delete args; } - - operator ArgList *() { return args; } -}; - -#define cformat(format) \ - (*((cp::ArgList *)cp::ArgListTemp(format))) -} - -#endif // __CPRINTF_HH__ diff --git a/base/cprintf_formats.hh b/base/cprintf_formats.hh deleted file mode 100644 index 11b0238ed..000000000 --- a/base/cprintf_formats.hh +++ /dev/null @@ -1,346 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __CPRINTF_FORMATS_HH__ -#define __CPRINTF_FORMATS_HH__ - -struct Format -{ - bool alternate_form; - bool flush_left; - bool print_sign; - bool blank_space; - bool fill_zero; - bool uppercase; - enum { dec, hex, oct } base; - enum { none, string, integer, character, floating } format; - enum { best, fixed, scientific } float_format; - int precision; - int width; - - Format() { clear(); } - - void clear() - { - alternate_form = false; - flush_left = false; - print_sign = false; - blank_space = false; - fill_zero = false; - uppercase = false; - base = dec; - format = none; - precision = -1; - width = 0; - } -}; - -template <typename T> -inline void -_format_char(std::ostream &out, const T &data, Format &fmt) -{ - using namespace std; - - out << data; -} - -template <typename T> -inline void -_format_integer(std::ostream &out, const T &data, Format &fmt) -{ - using namespace std; - - switch (fmt.base) { - case Format::hex: - out.setf(ios::hex, ios::basefield); - break; - - case Format::oct: - out.setf(ios::oct, ios::basefield); - break; - - case Format::dec: - out.setf(ios::dec, ios::basefield); - break; - } - - if (fmt.alternate_form) { - if (!fmt.fill_zero) - out.setf(ios::showbase); - else { - switch (fmt.base) { - case Format::hex: - out << "0x"; - fmt.width -= 2; - break; - case Format::oct: - out << "0"; - fmt.width -= 1; - break; - case Format::dec: - break; - } - } - } - - if (fmt.fill_zero) - out.fill('0'); - - if (fmt.width > 0) - out.width(fmt.width); - - if (fmt.flush_left && !fmt.fill_zero) - out.setf(ios::left); - - if (fmt.print_sign) - out.setf(ios::showpos); - - if (fmt.uppercase) - out.setf(ios::uppercase); - - out << data; -} - -template <typename T> -inline void -_format_float(std::ostream &out, const T &data, Format &fmt) -{ - using namespace std; - - switch (fmt.float_format) { - case Format::scientific: - if (fmt.precision != -1) { - if (fmt.width > 0) - out.width(fmt.width); - - if (fmt.precision == 0) - fmt.precision = 1; - else - out.setf(ios::scientific); - - out.precision(fmt.precision); - } else - if (fmt.width > 0) - out.width(fmt.width); - - if (fmt.uppercase) - out.setf(ios::uppercase); - break; - - case Format::fixed: - if (fmt.precision != -1) { - if (fmt.width > 0) - out.width(fmt.width); - - out.setf(ios::fixed); - out.precision(fmt.precision); - } else - if (fmt.width > 0) - out.width(fmt.width); - - break; - - default: - if (fmt.precision != -1) - out.precision(fmt.precision); - - if (fmt.width > 0) - out.width(fmt.width); - - break; - } - - out << data; -} - -template <typename T> -inline void -_format_string(std::ostream &out, const T &data, Format &fmt) -{ - using namespace std; - -#if defined(__GNUC__) && (__GNUC__ < 3) || 1 - if (fmt.width > 0) { - std::stringstream foo; - foo << data; - int flen = foo.str().size(); - - if (fmt.width > flen) { - char *spaces = new char[fmt.width - flen + 1]; - memset(spaces, ' ', fmt.width - flen); - spaces[fmt.width - flen] = 0; - - if (fmt.flush_left) - out << foo.str() << spaces; - else - out << spaces << foo.str(); - - delete [] spaces; - } else - out << data; - } else - out << data; -#else - if (fmt.width > 0) - out.width(fmt.width); - if (fmt.flush_left) - out.setf(ios::left); - - out << data; -#endif -} - -///////////////////////////////////////////////////////////////////////////// -// -// The code below controls the actual usage of formats for various types -// - -// -// character formats -// -template <typename T> -inline void -format_char(std::ostream &out, const T &data, Format &fmt) -{ out << "<bad arg type for char format>"; } - -inline void -format_char(std::ostream &out, char data, Format &fmt) -{ _format_char(out, data, fmt); } - -inline void -format_char(std::ostream &out, unsigned char data, Format &fmt) -{ _format_char(out, data, fmt); } - -inline void -format_char(std::ostream &out, signed char data, Format &fmt) -{ _format_char(out, data, fmt); } - -inline void -format_char(std::ostream &out, short data, Format &fmt) -{ _format_char(out, (char)data, fmt); } - -inline void -format_char(std::ostream &out, unsigned short data, Format &fmt) -{ _format_char(out, (char)data, fmt); } - -inline void -format_char(std::ostream &out, int data, Format &fmt) -{ _format_char(out, (char)data, fmt); } - -inline void -format_char(std::ostream &out, unsigned int data, Format &fmt) -{ _format_char(out, (char)data, fmt); } - -inline void -format_char(std::ostream &out, long data, Format &fmt) -{ _format_char(out, (char)data, fmt); } - -inline void -format_char(std::ostream &out, unsigned long data, Format &fmt) -{ _format_char(out, (char)data, fmt); } - -inline void -format_char(std::ostream &out, long long data, Format &fmt) -{ _format_char(out, (char)data, fmt); } - -inline void -format_char(std::ostream &out, unsigned long long data, Format &fmt) -{ _format_char(out, (char)data, fmt); } - -// -// integer formats -// -template <typename T> -inline void -format_integer(std::ostream &out, const T &data, Format &fmt) -{ _format_integer(out, data, fmt); } -inline void -format_integer(std::ostream &out, char data, Format &fmt) -{ _format_integer(out, data, fmt); } -inline void -format_integer(std::ostream &out, unsigned char data, Format &fmt) -{ _format_integer(out, data, fmt); } -inline void -format_integer(std::ostream &out, signed char data, Format &fmt) -{ _format_integer(out, data, fmt); } -#if 0 -inline void -format_integer(std::ostream &out, short data, Format &fmt) -{ _format_integer(out, data, fmt); } -inline void -format_integer(std::ostream &out, unsigned short data, Format &fmt) -{ _format_integer(out, data, fmt); } -inline void -format_integer(std::ostream &out, int data, Format &fmt) -{ _format_integer(out, data, fmt); } -inline void -format_integer(std::ostream &out, unsigned int data, Format &fmt) -{ _format_integer(out, data, fmt); } -inline void -format_integer(std::ostream &out, long data, Format &fmt) -{ _format_integer(out, data, fmt); } -inline void -format_integer(std::ostream &out, unsigned long data, Format &fmt) -{ _format_integer(out, data, fmt); } -inline void -format_integer(std::ostream &out, long long data, Format &fmt) -{ _format_integer(out, data, fmt); } -inline void -format_integer(std::ostream &out, unsigned long long data, Format &fmt) -{ _format_integer(out, data, fmt); } -#endif - -// -// floating point formats -// -template <typename T> -inline void -format_float(std::ostream &out, const T &data, Format &fmt) -{ out << "<bad arg type for float format>"; } - -inline void -format_float(std::ostream &out, float data, Format &fmt) -{ _format_float(out, data, fmt); } - -inline void -format_float(std::ostream &out, double data, Format &fmt) -{ _format_float(out, data, fmt); } - -// -// string formats -// -template <typename T> -inline void -format_string(std::ostream &out, const T &data, Format &fmt) -{ _format_string(out, data, fmt); } - -inline void -format_string(std::ostream &out, const std::stringstream &data, Format &fmt) -{ _format_string(out, data.str(), fmt); } - -#endif // __CPRINTF_FORMATS_HH__ diff --git a/base/crc.cc b/base/crc.cc deleted file mode 100644 index 87963ef14..000000000 --- a/base/crc.cc +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 1988, 1992, 1993 - * The 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: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sstream> -#include <string> - -#include "sim/host.hh" -#include "base/crc.hh" - -#define ETHER_CRC_POLY_LE 0xedb88320 -#define ETHER_CRC_POLY_BE 0x04c11db6 - -#if 0 -/* - * This is for reference. We have a table-driven version - * of the little-endian crc32 generator, which is faster - * than the double-loop. - */ -uint32_t -crc32le(const uint8_t *buf, size_t len) -{ - uint32_t c, crc, carry; - size_t i, j; - - crc = 0xffffffffU; /* initial value */ - - for (i = 0; i < len; i++) { - c = buf[i]; - for (j = 0; j < 8; j++) { - carry = ((crc & 0x01) ? 1 : 0) ^ (c & 0x01); - crc >>= 1; - c >>= 1; - if (carry) - crc = (crc ^ ETHER_CRC_POLY_LE); - } - } - - return (crc); -} -#else -uint32_t -crc32le(const uint8_t *buf, size_t len) -{ - static const uint32_t crctab[] = { - 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, - 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, - 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, - 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c - }; - uint32_t crc; - int i; - - crc = 0xffffffffU; /* initial value */ - - for (i = 0; i < len; i++) { - crc ^= buf[i]; - crc = (crc >> 4) ^ crctab[crc & 0xf]; - crc = (crc >> 4) ^ crctab[crc & 0xf]; - } - - return (crc); -} -#endif - -uint32_t -crc32be(const uint8_t *buf, size_t len) -{ - uint32_t c, crc, carry; - size_t i, j; - - crc = 0xffffffffU; /* initial value */ - - for (i = 0; i < len; i++) { - c = buf[i]; - for (j = 0; j < 8; j++) { - carry = ((crc & 0x80000000U) ? 1 : 0) ^ (c & 0x01); - crc <<= 1; - c >>= 1; - if (carry) - crc = (crc ^ ETHER_CRC_POLY_BE) | carry; - } - } - - return (crc); -} diff --git a/base/crc.hh b/base/crc.hh deleted file mode 100644 index 6ede07748..000000000 --- a/base/crc.hh +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __BASE_CRC_HH__ -#define __BASE_CRC_HH__ - -#include "sim/host.hh" - -uint32_t crc32be(const uint8_t *buf, size_t len); -uint32_t crc32le(const uint8_t *buf, size_t len); - -#endif // __BASE_CRC_HH__ diff --git a/base/date.cc b/base/date.cc deleted file mode 100644 index ba7698c29..000000000 --- a/base/date.cc +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 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. - */ - -const char *compileDate = __DATE__ " " __TIME__; diff --git a/base/dbl_list.hh b/base/dbl_list.hh deleted file mode 100644 index 1d06ff576..000000000 --- a/base/dbl_list.hh +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (c) 2000-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. - */ - -#ifndef __DBL_LIST_HH__ -#define __DBL_LIST_HH__ - -class DblListEl { - DblListEl *next; - DblListEl *prev; - - // remove this from list - void remove() { - prev->next = next; - next->prev = prev; - } - - // insert this before old_el - void insertBefore(DblListEl *old_el) { - prev = old_el->prev; - next = old_el; - prev->next = this; - next->prev = this; - } - - // insert this after old_el - void insertAfter(DblListEl *old_el) { - next = old_el->next; - prev = old_el; - next->prev = this; - prev->next = this; - } - - friend class DblListBase; -}; - - -// -// doubly-linked list of DblListEl objects -// -class DblListBase { - // dummy list head element: dummy.next is head, dummy.prev is tail - DblListEl dummy; - - // length counter - unsigned length; - - DblListEl *valid_or_null(DblListEl *el) { - // make sure users never see the dummy element - return (el == &dummy) ? NULL : el; - } - - public: - - DblListEl *head() { - return valid_or_null(dummy.next); - } - - DblListEl *tail() { - return valid_or_null(dummy.prev); - } - - DblListEl *next(DblListEl *el) { - return valid_or_null(el->next); - } - - DblListEl *prev(DblListEl *el) { - return valid_or_null(el->prev); - } - - bool is_empty() { - return (dummy.next == &dummy); - } - - void remove(DblListEl *el) { - el->remove(); - --length; - } - - void insertBefore(DblListEl *new_el, DblListEl *old_el) { - new_el->insertBefore(old_el); - ++length; - } - - void insertAfter(DblListEl *new_el, DblListEl *old_el) { - new_el->insertAfter(old_el); - ++length; - } - - // append to end of list, i.e. as dummy.prev - void append(DblListEl *el) { - insertBefore(el, &dummy); - } - - // prepend to front of list (push), i.e. as dummy.next - void prepend(DblListEl *el) { - insertAfter(el, &dummy); - } - - DblListEl *pop() { - DblListEl *hd = head(); - if (hd != NULL) - remove(hd); - return hd; - } - - // constructor - DblListBase() { - dummy.next = dummy.prev = &dummy; - length = 0; - } -}; - - -// -// Template class serves solely to cast args & return values -// to appropriate type (T *) -// -template<class T> class DblList : private DblListBase { - - public: - - T *head() { return (T *)DblListBase::head(); } - T *tail() { return (T *)DblListBase::tail(); } - - T *next(T *el) { return (T *)DblListBase::next(el); } - T *prev(T *el) { return (T *)DblListBase::prev(el); } - - bool is_empty() { return DblListBase::is_empty(); } - - void remove(T *el) { DblListBase::remove(el); } - - void append(T *el) { DblListBase::append(el); } - void prepend(T *el) { DblListBase::prepend(el); } - - T *pop() { return (T *)DblListBase::pop(); } - - DblList<T>() { } -}; - -#endif // __DBL_LIST_HH__ diff --git a/base/endian.hh b/base/endian.hh deleted file mode 100644 index 499eb50c5..000000000 --- a/base/endian.hh +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __ENDIAN_HH__ -#define __ENDIAN_HH__ - -#include <arpa/inet.h> - -inline bool -HostBigEndian() -{ - int x = 0x11223344; - return x == htonl(x); -} - -#endif // __ENDIAN_HH__ diff --git a/base/fast_alloc.cc b/base/fast_alloc.cc deleted file mode 100644 index 6504e07c2..000000000 --- a/base/fast_alloc.cc +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (c) 2000-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. - */ - -/* - * This code was originally written by Steve Reinhardt as part of - * the Wisconsin Wind Tunnel simulator. Relicensed as part of M5 - * by permission. - */ - -#ifndef NO_FAST_ALLOC - -#ifdef __GNUC__ -#pragma implementation -#endif - -#include <assert.h> -#include "base/fast_alloc.hh" - -void *FastAlloc::freeLists[Num_Buckets]; - -#ifdef FAST_ALLOC_STATS -unsigned FastAlloc::newCount[Num_Buckets]; -unsigned FastAlloc::deleteCount[Num_Buckets]; -unsigned FastAlloc::allocCount[Num_Buckets]; -#endif - -void *FastAlloc::moreStructs(int bucket) -{ - assert(bucket > 0 && bucket < Num_Buckets); - - int sz = bucket * Alloc_Quantum; - const int nstructs = Num_Structs_Per_New; // how many to allocate? - char *p = ::new char[nstructs * sz]; - -#ifdef FAST_ALLOC_STATS - ++allocCount[bucket]; -#endif - - freeLists[bucket] = p; - for (int i = 0; i < (nstructs-2); ++i, p += sz) - *(void **)p = p + sz; - *(void **)p = 0; - - return (p + sz); -} - - -#ifdef FAST_ALLOC_DEBUG - -#include <typeinfo> -#include <iostream> -#include <iomanip> -#include <map> -#include <string> - -using namespace std; - -// count of in-use FastAlloc objects -int FastAlloc::numInUse; - -// dummy head & tail object for doubly linked list of in-use FastAlloc -// objects -FastAlloc FastAlloc::inUseHead(&FastAlloc::inUseHead, &FastAlloc::inUseHead); - -// special constructor for dummy head: make inUsePrev & inUseNext -// point to self -FastAlloc::FastAlloc(FastAlloc *prev, FastAlloc *next) -{ - inUsePrev = prev; - inUseNext = next; -} - - -// constructor: marks as in use, add to in-use list -FastAlloc::FastAlloc() -{ - // mark this object in use - inUse = true; - - // update count - ++numInUse; - - // add to tail of list of in-use objects ("before" dummy head) - FastAlloc *myNext = &inUseHead; - FastAlloc *myPrev = inUseHead.inUsePrev; - - inUsePrev = myPrev; - inUseNext = myNext; - myPrev->inUseNext = this; - myNext->inUsePrev = this; -} - -// destructor: mark not in use, remove from in-use list -FastAlloc::~FastAlloc() -{ - assert(inUse); - inUse = false; - - --numInUse; - assert(numInUse >= 0); - - // remove me from in-use list - inUsePrev->inUseNext = inUseNext; - inUseNext->inUsePrev = inUsePrev; -} - - -// summarize in-use list -void -FastAlloc::dump_summary() -{ - map<string, int> typemap; - - for (FastAlloc *p = inUseHead.inUseNext; p != &inUseHead; p = p->inUseNext) - { - ++typemap[typeid(*p).name()]; - } - - map<string, int>::const_iterator mapiter; - - cout << " count type\n" - << " ----- ----\n"; - for (mapiter = typemap.begin(); mapiter != typemap.end(); ++mapiter) - { - cout << setw(6) << mapiter->second << " " << mapiter->first << endl; - } -} - - -// show oldest n items on in-use list -void -FastAlloc::dump_oldest(int n) -{ - // sanity check: don't want to crash the debugger if you forget to - // pass in a parameter - if (n < 0 || n > numInUse) - { - cout << "FastAlloc::dump_oldest: bad arg " << n - << " (" << numInUse << " objects in use" << endl; - return; - } - - for (FastAlloc *p = inUseHead.inUsePrev; - p != &inUseHead && n > 0; - p = p->inUsePrev, --n) - { - cout << p << " " << typeid(*p).name() << endl; - } -} - - -// -// C interfaces to FastAlloc::dump_summary() and FastAlloc::dump_oldest(). -// gdb seems to have trouble with calling C++ functions directly. -// -extern "C" void -fast_alloc_summary() -{ - FastAlloc::dump_summary(); -} - -extern "C" void -fast_alloc_oldest(int n) -{ - FastAlloc::dump_oldest(n); -} - -#endif - -#endif // NO_FAST_ALLOC diff --git a/base/fast_alloc.hh b/base/fast_alloc.hh deleted file mode 100644 index 54e35f8e0..000000000 --- a/base/fast_alloc.hh +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (c) 2000-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. - */ - -/* - * This code was originally written by Steve Reinhardt as part of - * the Wisconsin Wind Tunnel simulator. Relicensed as part of M5 - * by permission. - */ - -#ifndef __FAST_ALLOC_H__ -#define __FAST_ALLOC_H__ - -#include <stddef.h> - -// Fast structure allocator. Designed for small objects that are -// frequently allocated and deallocated. This code is derived from the -// 'alloc_struct' package used in WWT and Blizzard. C++ provides a -// much nicer framework for the same optimization. The package is -// implemented as a class, FastAlloc. Allocation and deletion are -// performed using FastAlloc's new and delete operators. Any object -// that derives from the FastAlloc class will transparently use this -// allocation package. - -// The static allocate() and deallocate() methods can also be called -// directly if desired. - -// In order for derived classes to call delete with the correct -// structure size even when they are deallocated via a base-type -// pointer, they must have a virtual destructor. It is sufficient for -// FastAlloc to declare a virtual destructor (as it does); it is not -// required for derived classes to declare their own destructor. The -// compiler will automatically generate a virtual destructor for each -// derived class. However, it is more efficient if each derived class -// defines an inline destructor, so that the compiler can statically -// collapse the destructor call chain back up the inheritance -// hierarchy. - -// Uncomment this #define to track in-use objects -// (for debugging memory leaks). -//#define FAST_ALLOC_DEBUG - -// Uncomment this #define to count news, deletes, and chunk allocations -// (by bucket). -// #define FAST_ALLOC_STATS - -#include "config/no_fast_alloc.hh" - -#if NO_FAST_ALLOC - -class FastAlloc { -}; - -#else - -class FastAlloc { - public: - - static void *allocate(size_t); - static void deallocate(void *, size_t); - - void *operator new(size_t); - void operator delete(void *, size_t); - -#ifdef FAST_ALLOC_DEBUG - FastAlloc(); - FastAlloc(FastAlloc*,FastAlloc*); // for inUseHead, see below - virtual ~FastAlloc(); -#else - virtual ~FastAlloc() {} -#endif - - private: - - // Max_Alloc_Size is the largest object that can be allocated with - // this class. There's no fundamental limit, but this limits the - // size of the freeLists array. Let's not make this really huge - // like in Blizzard. - static const int Max_Alloc_Size = 512; - - // Alloc_Quantum is the difference in size between adjacent - // buckets in the free list array. - static const int Log2_Alloc_Quantum = 3; - static const int Alloc_Quantum = (1 << Log2_Alloc_Quantum); - - // Num_Buckets = bucketFor(Max_Alloc_Size) + 1 - static const int Num_Buckets = - ((Max_Alloc_Size + Alloc_Quantum - 1) >> Log2_Alloc_Quantum) + 1; - - // when we call new() for more structures, how many should we get? - static const int Num_Structs_Per_New = 20; - - static int bucketFor(size_t); - static void *moreStructs(int bucket); - - static void *freeLists[Num_Buckets]; - -#ifdef FAST_ALLOC_STATS - static unsigned newCount[Num_Buckets]; - static unsigned deleteCount[Num_Buckets]; - static unsigned allocCount[Num_Buckets]; -#endif - -#ifdef FAST_ALLOC_DEBUG - // per-object debugging fields - bool inUse; // in-use flag - FastAlloc *inUsePrev; // ptrs to build list of in-use objects - FastAlloc *inUseNext; - - // static (global) debugging vars - static int numInUse; // count in-use objects - static FastAlloc inUseHead; // dummy head for list of in-use objects - - public: - // functions to dump debugging info (see fast_alloc.cc for C - // versions that might be more agreeable to call from gdb) - static void dump_summary(); - static void dump_oldest(int n); -#endif -}; - - -inline -int FastAlloc::bucketFor(size_t sz) -{ - return (sz + Alloc_Quantum - 1) >> Log2_Alloc_Quantum; -} - - -inline -void *FastAlloc::allocate(size_t sz) -{ - int b; - void *p; - - if (sz > Max_Alloc_Size) - return (void *)::new char[sz]; - - b = bucketFor(sz); - p = freeLists[b]; - - if (p) - freeLists[b] = *(void **)p; - else - p = moreStructs(b); - -#ifdef FAST_ALLOC_STATS - ++newCount[b]; -#endif - - return p; -} - - -inline -void FastAlloc::deallocate(void *p, size_t sz) -{ - int b; - - if (sz > Max_Alloc_Size) - { - ::delete [] (char *)p; - return; - } - - b = bucketFor(sz); - *(void **)p = freeLists[b]; - freeLists[b] = p; -#ifdef FAST_ALLOC_STATS - ++deleteCount[b]; -#endif -} - - -inline -void *FastAlloc::operator new(size_t sz) -{ - return allocate(sz); -} - - -inline -void FastAlloc::operator delete(void *p, size_t sz) -{ - deallocate(p, sz); -} - -#endif // NO_FAST_ALLOC - -#endif // __FAST_ALLOC_H__ diff --git a/base/fenv.hh b/base/fenv.hh deleted file mode 100644 index 3234f5dd3..000000000 --- a/base/fenv.hh +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __BASE_FENV_HH__ -#define __BASE_FENV_HH__ - -#include "config/use_fenv.hh" - -#if USE_FENV - -#include <fenv.h> - -#else - -// Dummy definitions to allow code to compile w/o a real <fenv.h>. - -#define FE_TONEAREST 0 -#define FE_DOWNWARD 0 -#define FE_UPWARD 0 -#define FE_TOWARDZERO 0 - -inline int fesetround(int rounding_mode) { return 0; } - -#endif // USE_FENV - - -#endif // __BASE_FENV_HH__ diff --git a/base/fifo_buffer.cc b/base/fifo_buffer.cc deleted file mode 100644 index 85b306c25..000000000 --- a/base/fifo_buffer.cc +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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. - */ - -#include "base/fifo_buffer.hh" - -template<class T> -void -FifoBuffer<T>::dump() -{ - if (buffer->count() > 0) - for (iterator i=buffer->tail(); i.notnull(); i=i.prev()) - i->dump(); -} - - diff --git a/base/fifo_buffer.hh b/base/fifo_buffer.hh deleted file mode 100644 index 03ce057c7..000000000 --- a/base/fifo_buffer.hh +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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. - */ - -#ifndef __FIFO_BUFFER_HH__ -#define __FIFO_BUFFER_HH__ - -#include "base/res_list.hh" - - -// -// The FifoBuffer requires only that the objects to be used have a default -// constructor and a dump() method -// -template<class T> -class FifoBuffer -{ - public: - typedef typename res_list<T>::iterator iterator; - - private: - res_list<T> *buffer; - - unsigned size; - - public: - FifoBuffer(unsigned sz) - { - buffer = new res_list<T>(sz, true, 0); - size = sz; - } - - void add(T &item) - { - assert(buffer->num_free() > 0); - buffer->add_head(item); - } - - iterator head() { return buffer->head(); } - iterator tail() { return buffer->tail(); } - - unsigned count() {return buffer->count();} - unsigned free_slots() {return buffer->num_free();} - - T *peek() { return (count() > 0) ? tail().data_ptr() : 0; } - - T remove() - { - assert(buffer->count() > 0); - T rval = *buffer->tail(); - buffer->remove_tail(); - return rval; - } - - void dump(); - - ~FifoBuffer() { delete buffer; } -}; - - -#endif - diff --git a/base/hashmap.hh b/base/hashmap.hh deleted file mode 100644 index 712366829..000000000 --- a/base/hashmap.hh +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __HASHMAP_HH__ -#define __HASHMAP_HH__ - -#if defined(__GNUC__) && __GNUC__ >= 3 -#include <ext/hash_map> -#else -#include <hash_map> -#endif - -#include <string> - -#include "sim/host.hh" - -#if defined(__GNUC__) && __GNUC__ >= 3 - #define __hash_namespace __gnu_cxx -#else - #define __hash_namespace std -#endif - -namespace m5 { - using ::__hash_namespace::hash_multimap; - using ::__hash_namespace::hash_map; - using ::__hash_namespace::hash; -} - - -/////////////////////////////////// -// Some default Hashing Functions -// - -namespace __hash_namespace { -#if !defined(__LP64__) && !defined(__alpha__) - template<> - struct hash<uint64_t> { - size_t operator()(uint64_t r) const { - return r; - } - }; - - template<> - struct hash<int64_t> { - size_t operator()(int64_t r) const { - return r; - }; - }; -#endif - - template<> - struct hash<std::string> { - size_t operator()(const std::string &s) const { - return(__stl_hash_string(s.c_str())); - } - }; -} - - -#endif // __HASHMAP_HH__ diff --git a/base/hostinfo.cc b/base/hostinfo.cc deleted file mode 100644 index d15e3ddc1..000000000 --- a/base/hostinfo.cc +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include <ctype.h> -#include <errno.h> -#include <math.h> -#include <unistd.h> - -#include <cstdio> -#include <cstdlib> -#include <cstring> -#include <string> - -#include "base/misc.hh" -#include "sim/host.hh" - -using namespace std; - -string -__get_hostname() -{ - char host[256]; - if (gethostname(host, sizeof host) == -1) - warn("could not get host name!"); - return host; -} - -string & -hostname() -{ - static string hostname = __get_hostname(); - return hostname; -} - -uint64_t -procInfo(char *filename, char *target) -{ - int done = 0; - char line[80]; - char format[80]; - long usage; - - FILE *fp = fopen(filename, "r"); - - while (fp && !feof(fp) && !done) { - if (fgets(line, 80, fp)) { - if (strncmp(line, target, strlen(target)) == 0) { - snprintf(format, sizeof(format), "%s %%ld", target); - sscanf(line, format, &usage); - - fclose(fp); - return usage ; - } - } - } - - if (fp) - fclose(fp); - - return 0; -} diff --git a/base/hostinfo.hh b/base/hostinfo.hh deleted file mode 100644 index 21a6e5475..000000000 --- a/base/hostinfo.hh +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __HOSTINFO_HH__ -#define __HOSTINFO_HH__ - -#include <string> - -#include "sim/host.hh" - -std::string &hostname(); - -uint64_t procInfo(char *filename, char *target); - -inline uint64_t memUsage() -{ return procInfo("/proc/self/status", "VmSize:"); } - -#endif // __HOSTINFO_HH__ diff --git a/base/hybrid_pred.cc b/base/hybrid_pred.cc deleted file mode 100644 index 21cbdb0fd..000000000 --- a/base/hybrid_pred.cc +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include <string> -#include <sstream> - -#include "base/hybrid_pred.hh" -#include "base/statistics.hh" -#include "sim/stats.hh" - -using namespace std; - -HybridPredictor::HybridPredictor(const char *_p_name, const char *_z_name, - const char *_o_name, - unsigned _index_bits, unsigned _counter_bits, - unsigned _zero_change, unsigned _one_change, - unsigned _thresh, - unsigned _global_bits, - unsigned _global_thresh, - bool _reg_individual_stats) -{ - stringstream local_name, global_name; - - pred_name = _p_name; - one_name = _o_name; - zero_name = _z_name; - reg_individual_stats = _reg_individual_stats; - - local_name << pred_name.c_str() << ":L"; - local = new SaturatingCounterPred(local_name.str(), zero_name, one_name, - _index_bits, _counter_bits, - _zero_change, _one_change, _thresh); - - global_name << pred_name.c_str() << ":G"; - global = new SaturatingCounterPred(global_name.str(), zero_name, one_name, - 0, _global_bits, 1, 1, _global_thresh); -} - -void HybridPredictor::regStats() -{ - using namespace Stats; - - string p_name; - stringstream description; - - if (reg_individual_stats) - p_name = pred_name + ":A"; - else - p_name = pred_name; - - - // - // Number of predictions - // - stringstream num_zero_preds; - num_zero_preds << p_name << ":" << zero_name << ":preds"; - description << "number of predictions of " << zero_name; - pred_zero - .name(num_zero_preds.str()) - .desc(description.str()); - description.str(""); - - stringstream num_one_preds; - num_one_preds << p_name << ":" << one_name << ":preds"; - description << "number of predictions of " << one_name; - pred_one - .name(num_one_preds.str()) - .desc(description.str()) - ; - description.str(""); - - // - // Count the number of correct predictions - // - stringstream num_zero_correct; - num_zero_correct << p_name << ":" << zero_name << ":corr_preds"; - description << "number of correct " << zero_name << " preds" ; - correct_pred_zero - .name(num_zero_correct.str()) - .desc(description.str()) - ; - description.str(""); - - stringstream num_one_correct; - num_one_correct << p_name << ":" << one_name << ":corr_preds"; - description << "number of correct " << one_name << " preds" ; - correct_pred_one - .name(num_one_correct.str()) - .desc(description.str()) - ; - description.str(""); - - - // - // Number of predictor updates - // - stringstream num_zero_updates; - num_zero_updates << p_name << ":" << zero_name << ":updates" ; - description << "number of actual " << zero_name << "s" ; - record_zero - .name(num_zero_updates.str()) - .desc(description.str()) - ; - description.str(""); - - stringstream num_one_updates; - num_one_updates << p_name << ":" << one_name << ":updates" ; - description << "number of actual " << one_name << "s" ; - record_one - .name(num_one_updates.str()) - .desc(description.str()) - ; - description.str(""); - - // - // Local & Global predictor stats - // - if (reg_individual_stats) { - local->regStats(); - global->regStats(); - } -} - -void HybridPredictor::regFormulas() -{ - using namespace Stats; - - string p_name; - stringstream description; - stringstream name; - - if (reg_individual_stats) - p_name = pred_name + ":A"; - else - p_name = pred_name; - - // - // Number of predictions - // - name << p_name << ":predictions" ; - total_preds - .name(name.str()) - .desc("total number of predictions made") - ; - total_preds = pred_one + pred_zero; - name.str(""); - - // - // Fraction of all predictions that are one or zero - // - name << p_name << ":" << zero_name << ":pred_frac"; - description << "fraction of all preds that were " << zero_name ; - frac_preds_zero - .name(name.str()) - .desc(description.str()) - ; - frac_preds_zero = 100 * record_zero / total_preds; - description.str(""); - name.str(""); - - name << p_name << ":" << one_name << ":pred_frac"; - description << "fraction of all preds that were " << one_name ; - frac_preds_one - .name(name.str()) - .desc(description.str()) - ; - frac_preds_one = 100 * record_one / total_preds; - description.str(""); - name.str(""); - - // - // Count the number of correct predictions - // - name << p_name << ":correct_preds" ; - total_correct - .name(name.str()) - .desc("total number of correct predictions made") - ; - total_correct = correct_pred_one + correct_pred_zero; - name.str(""); - - - // - // Prediction accuracy rates - // - name << p_name << ":pred_rate"; - total_accuracy - .name(name.str()) - .desc("fraction of all preds that were correct") - ; - total_accuracy = 100 * total_correct / total_preds; - name.str(""); - - name << p_name << ":" << zero_name << ":pred_rate" ; - description << "fraction of "<< zero_name <<" preds that were correct"; - zero_accuracy - .name(name.str()) - .desc(description.str()) - ; - zero_accuracy = 100 * correct_pred_zero / pred_zero; - description.str(""); - name.str(""); - - name << p_name << ":" << one_name << ":pred_rate" ; - description << "fraction of "<< one_name <<" preds that were correct"; - one_accuracy - .name(name.str()) - .desc(description.str()) - ; - one_accuracy = 100 * correct_pred_one / pred_one; - description.str(""); - name.str(""); - - // - // Coverage - // - name << p_name << ":" << zero_name << ":coverage"; - description << "fraction of " << zero_name - << "s that were predicted correctly"; - zero_coverage - .name(name.str()) - .desc(description.str()) - ; - zero_coverage = 100 * correct_pred_zero / record_zero; - description.str(""); - name.str(""); - - name << p_name << ":" << one_name << ":coverage"; - description << "fraction of " << one_name - << "s that were predicted correctly"; - one_coverage - .name(name.str()) - .desc(description.str()) - ; - one_coverage = 100 * correct_pred_one / record_one; - description.str(""); - name.str(""); - - // - // Local & Global predictor stats - // - if (reg_individual_stats) { - local->regFormulas(); - global->regFormulas(); - } - -} - diff --git a/base/hybrid_pred.hh b/base/hybrid_pred.hh deleted file mode 100644 index ea4a9d04c..000000000 --- a/base/hybrid_pred.hh +++ /dev/null @@ -1,201 +0,0 @@ -/* - * 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. - */ - -//========================================================================== -// -// This predictor takes the AND of a "local" and a "global" predictor -// in order to determine its prediction. -// -// -// -// - -#ifndef __HYBRID_PRED_HH__ -#define __HYBRID_PRED_HH__ - -#include <string> - -#include "base/sat_counter.hh" -#include "base/statistics.hh" - -class HybridPredictor : public GenericPredictor -{ - private: - std::string pred_name; - std::string one_name; - std::string zero_name; - bool reg_individual_stats; - - SaturatingCounterPred *local; - SaturatingCounterPred *global; - - unsigned long max_index; - - // - // Stats - // - Stats::Scalar<> pred_one; //num_one_preds - Stats::Scalar<> pred_zero; //num_zero_preds - Stats::Scalar<> correct_pred_one; //num_one_correct - Stats::Scalar<> correct_pred_zero; //num_zero_correct - Stats::Scalar<> record_one; //num_one_updates - Stats::Scalar<> record_zero; //num_zero_updates - - Stats::Formula total_preds; - Stats::Formula frac_preds_zero; - Stats::Formula frac_preds_one; - Stats::Formula total_correct; - Stats::Formula total_accuracy; - Stats::Formula zero_accuracy; - Stats::Formula one_accuracy; - Stats::Formula zero_coverage; - Stats::Formula one_coverage; - - public: - HybridPredictor(const char *_p_name, const char *_z_name, - const char *_o_name, - unsigned _index_bits, unsigned _counter_bits, - unsigned _zero_change, unsigned _one_change, - unsigned _thresh, - unsigned _global_bits, unsigned _global_thresh, - bool _reg_individual_stats = false); - - void clear() { - global->clear(); - local->clear(); - } - - unsigned peek(unsigned long _index) { - unsigned l = local->peek(_index); - unsigned g = global->peek(_index); - - if (l && g) - return 1; - - return 0; - } - - unsigned value(unsigned long _index) { - unsigned l = local->peek(_index); - unsigned g = global->peek(_index); - - l = l & 0xFFFF; - g = g & 0xFFFF; - - return (l << 16) | g; - - } - - unsigned predict(unsigned long _index) { - unsigned l = local->predict(_index); - unsigned g = global->predict(_index); - - if (l && g) { - ++pred_one; - return 1; - } - - ++pred_zero; - return 0; - } - - - // - // This version need only be used if local/global statistics - // will be maintained - // - unsigned predict(unsigned long _index, unsigned &_pdata) { - unsigned l = local->predict(_index); - unsigned g = global->predict(_index); - - // - // bit 0 => local predictor result - // bit 1 => global predictor result - // - _pdata = 0; - if (l) - _pdata |= 1; - if (g) - _pdata |= 2; - if (l && g) { - ++pred_one; - return 1; - } - - ++pred_zero; - return 0; - } - - void record(unsigned long _index, unsigned _val, unsigned _predicted) { - - if (_val) { - local->record(_index, _val, 0); - global->record(_index, _val, 0); - ++record_one; - - if (_val == _predicted) { - ++correct_pred_one; - } - } else { - local->record(_index, _val, 0); - global->record(_index, _val, 0); - ++record_zero; - - if (_val == _predicted) - ++correct_pred_zero; - } - } - - void record(unsigned long _index, unsigned _val, unsigned _predicted, - unsigned _pdata) - { - - local->record(_index, _val, (_pdata & 1)); - global->record(_index, _val, ((_pdata & 2) ? 1 : 0)); - - - if (_val) { - ++record_one; - - if (_val == _predicted) - ++correct_pred_one; - } else { - ++record_zero; - - if (_val == _predicted) - ++correct_pred_zero; - } - } - - void regStats(); - void regFormulas(); -}; - - -#endif // _HYBRID_PRED_HH__ - diff --git a/base/inet.cc b/base/inet.cc deleted file mode 100644 index 2e1c4c84b..000000000 --- a/base/inet.cc +++ /dev/null @@ -1,208 +0,0 @@ -/* - * 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. - */ - -#include <cstdio> -#include <sstream> -#include <string> - -#include "base/cprintf.hh" -#include "sim/host.hh" -#include "base/inet.hh" - -using namespace std; -namespace Net { - -EthAddr::EthAddr() -{ - memset(data, 0, ETH_ADDR_LEN); -} - -EthAddr::EthAddr(const uint8_t ea[ETH_ADDR_LEN]) -{ - *data = *ea; -} - -EthAddr::EthAddr(const eth_addr &ea) -{ - *data = *ea.data; -} - -EthAddr::EthAddr(const std::string &addr) -{ - parse(addr); -} - -const EthAddr & -EthAddr::operator=(const eth_addr &ea) -{ - *data = *ea.data; - return *this; -} - -const EthAddr & -EthAddr::operator=(const std::string &addr) -{ - parse(addr); - return *this; -} - -void -EthAddr::parse(const std::string &addr) -{ - // the hack below is to make sure that ETH_ADDR_LEN is 6 otherwise - // the sscanf function won't work. - int bytes[ETH_ADDR_LEN == 6 ? ETH_ADDR_LEN : -1]; - if (sscanf(addr.c_str(), "%x:%x:%x:%x:%x:%x", &bytes[0], &bytes[1], - &bytes[2], &bytes[3], &bytes[4], &bytes[5]) != ETH_ADDR_LEN) { - memset(data, 0xff, ETH_ADDR_LEN); - return; - } - - for (int i = 0; i < ETH_ADDR_LEN; ++i) { - if (bytes[i] & ~0xff) { - memset(data, 0xff, ETH_ADDR_LEN); - return; - } - - data[i] = bytes[i]; - } -} - -string -EthAddr::string() const -{ - stringstream stream; - stream << *this; - return stream.str(); -} - -bool -operator==(const EthAddr &left, const EthAddr &right) -{ - return memcmp(left.bytes(), right.bytes(), ETH_ADDR_LEN); -} - -ostream & -operator<<(ostream &stream, const EthAddr &ea) -{ - const uint8_t *a = ea.addr(); - ccprintf(stream, "%x:%x:%x:%x:%x:%x", a[0], a[1], a[2], a[3], a[4], a[5]); - return stream; -} - -uint16_t -cksum(const IpPtr &ptr) -{ - int sum = ip_cksum_add(ptr->bytes(), ptr->hlen(), 0); - return ip_cksum_carry(sum); -} - -uint16_t -__tu_cksum(const IpPtr &ip) -{ - int tcplen = ip->len() - ip->hlen(); - int sum = ip_cksum_add(ip->payload(), tcplen, 0); - sum = ip_cksum_add(&ip->ip_src, 8, sum); // source and destination - sum += htons(ip->ip_p + tcplen); - return ip_cksum_carry(sum); -} - -uint16_t -cksum(const TcpPtr &tcp) -{ return __tu_cksum(IpPtr(tcp.packet())); } - -uint16_t -cksum(const UdpPtr &udp) -{ return __tu_cksum(IpPtr(udp.packet())); } - -bool -IpHdr::options(vector<const IpOpt *> &vec) const -{ - vec.clear(); - - const uint8_t *data = bytes() + sizeof(struct ip_hdr); - int all = hlen() - sizeof(struct ip_hdr); - while (all > 0) { - const IpOpt *opt = (const IpOpt *)data; - int len = opt->len(); - if (all < len) - return false; - - vec.push_back(opt); - all -= len; - data += len; - } - - return true; -} - -bool -TcpHdr::options(vector<const TcpOpt *> &vec) const -{ - vec.clear(); - - const uint8_t *data = bytes() + sizeof(struct tcp_hdr); - int all = off() - sizeof(struct tcp_hdr); - while (all > 0) { - const TcpOpt *opt = (const TcpOpt *)data; - int len = opt->len(); - if (all < len) - return false; - - vec.push_back(opt); - all -= len; - data += len; - } - - return true; -} - -bool -TcpOpt::sack(vector<SackRange> &vec) const -{ - vec.clear(); - - const uint8_t *data = bytes() + sizeof(struct tcp_hdr); - int all = len() - offsetof(tcp_opt, opt_data.sack); - while (all > 0) { - const uint16_t *sack = (const uint16_t *)data; - int len = sizeof(uint16_t) * 2; - if (all < len) { - vec.clear(); - return false; - } - - vec.push_back(RangeIn(ntohs(sack[0]), ntohs(sack[1]))); - all -= len; - data += len; - } - - return false; -} - -/* namespace Net */ } diff --git a/base/inet.hh b/base/inet.hh deleted file mode 100644 index e07e01935..000000000 --- a/base/inet.hh +++ /dev/null @@ -1,407 +0,0 @@ -/* - * 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. - */ - -#ifndef __BASE_INET_HH__ -#define __BASE_INET_HH__ - -#include <iosfwd> -#include <string> -#include <utility> -#include <vector> - -#include "base/range.hh" -#include "dev/etherpkt.hh" -#include "sim/host.hh" - -#include "dnet/os.h" -#include "dnet/eth.h" -#include "dnet/ip.h" -#include "dnet/ip6.h" -#include "dnet/addr.h" -#include "dnet/arp.h" -#include "dnet/icmp.h" -#include "dnet/tcp.h" -#include "dnet/udp.h" -#include "dnet/intf.h" -#include "dnet/route.h" -#include "dnet/fw.h" -#include "dnet/blob.h" -#include "dnet/rand.h" - -namespace Net { - -/* - * Ethernet Stuff - */ -struct EthAddr : protected eth_addr -{ - protected: - void parse(const std::string &addr); - - public: - EthAddr(); - EthAddr(const uint8_t ea[ETH_ADDR_LEN]); - EthAddr(const eth_addr &ea); - EthAddr(const std::string &addr); - const EthAddr &operator=(const eth_addr &ea); - const EthAddr &operator=(const std::string &addr); - - int size() const { return sizeof(eth_addr); } - - const uint8_t *bytes() const { return &data[0]; } - uint8_t *bytes() { return &data[0]; } - - const uint8_t *addr() const { return &data[0]; } - bool unicast() const { return data[0] == 0x00; } - bool multicast() const { return data[0] == 0x01; } - bool broadcast() const { return data[0] == 0xff; } - std::string string() const; - - operator uint64_t() const - { - uint64_t reg = 0; - reg |= ((uint64_t)data[0]) << 40; - reg |= ((uint64_t)data[1]) << 32; - reg |= ((uint64_t)data[2]) << 24; - reg |= ((uint64_t)data[3]) << 16; - reg |= ((uint64_t)data[4]) << 8; - reg |= ((uint64_t)data[5]) << 0; - return reg; - } - -}; - -std::ostream &operator<<(std::ostream &stream, const EthAddr &ea); -bool operator==(const EthAddr &left, const EthAddr &right); - -struct EthHdr : public eth_hdr -{ - uint16_t type() const { return ntohs(eth_type); } - const EthAddr &src() const { return *(EthAddr *)ð_src; } - const EthAddr &dst() const { return *(EthAddr *)ð_dst; } - - int size() const { return sizeof(eth_hdr); } - - const uint8_t *bytes() const { return (const uint8_t *)this; } - const uint8_t *payload() const { return bytes() + size(); } - uint8_t *bytes() { return (uint8_t *)this; } - uint8_t *payload() { return bytes() + size(); } -}; - -class EthPtr -{ - protected: - friend class IpPtr; - PacketPtr p; - - public: - EthPtr() {} - EthPtr(const PacketPtr &ptr) : p(ptr) { } - - EthHdr *operator->() { return (EthHdr *)p->data; } - EthHdr &operator*() { return *(EthHdr *)p->data; } - operator EthHdr *() { return (EthHdr *)p->data; } - - const EthHdr *operator->() const { return (const EthHdr *)p->data; } - const EthHdr &operator*() const { return *(const EthHdr *)p->data; } - operator const EthHdr *() const { return (const EthHdr *)p->data; } - - const EthPtr &operator=(const PacketPtr &ptr) { p = ptr; return *this; } - - const PacketPtr packet() const { return p; } - PacketPtr packet() { return p; } - bool operator!() const { return !p; } - operator bool() const { return p; } -}; - -/* - * IP Stuff - */ -struct IpOpt; -struct IpHdr : public ip_hdr -{ - uint8_t version() const { return ip_v; } - uint8_t hlen() const { return ip_hl * 4; } - uint8_t tos() const { return ip_tos; } - uint16_t len() const { return ntohs(ip_len); } - uint16_t id() const { return ntohs(ip_id); } - uint16_t frag_flags() const { return ntohs(ip_off) >> 13; } - uint16_t frag_off() const { return ntohs(ip_off) & 0x1fff; } - uint8_t ttl() const { return ip_ttl; } - uint8_t proto() const { return ip_p; } - uint16_t sum() const { return ip_sum; } - uint32_t src() const { return ntohl(ip_src); } - uint32_t dst() const { return ntohl(ip_dst); } - - void sum(uint16_t sum) { ip_sum = sum; } - - bool options(std::vector<const IpOpt *> &vec) const; - - int size() const { return hlen(); } - const uint8_t *bytes() const { return (const uint8_t *)this; } - const uint8_t *payload() const { return bytes() + size(); } - uint8_t *bytes() { return (uint8_t *)this; } - uint8_t *payload() { return bytes() + size(); } -}; - -class IpPtr -{ - protected: - friend class TcpPtr; - friend class UdpPtr; - PacketPtr p; - - const IpHdr *h() const - { return (const IpHdr *)(p->data + sizeof(eth_hdr)); } - IpHdr *h() { return (IpHdr *)(p->data + sizeof(eth_hdr)); } - - void set(const PacketPtr &ptr) - { - EthHdr *eth = (EthHdr *)ptr->data; - if (eth->type() == ETH_TYPE_IP) - p = ptr; - else - p = 0; - } - - public: - IpPtr() {} - IpPtr(const PacketPtr &ptr) { set(ptr); } - IpPtr(const EthPtr &ptr) { set(ptr.p); } - IpPtr(const IpPtr &ptr) : p(ptr.p) { } - - IpHdr *operator->() { return h(); } - IpHdr &operator*() { return *h(); } - operator IpHdr *() { return h(); } - - const IpHdr *operator->() const { return h(); } - const IpHdr &operator*() const { return *h(); } - operator const IpHdr *() const { return h(); } - - const IpPtr &operator=(const PacketPtr &ptr) { set(ptr); return *this; } - const IpPtr &operator=(const EthPtr &ptr) { set(ptr.p); return *this; } - const IpPtr &operator=(const IpPtr &ptr) { p = ptr.p; return *this; } - - const PacketPtr packet() const { return p; } - PacketPtr packet() { return p; } - bool operator!() const { return !p; } - operator bool() const { return p; } - operator bool() { return p; } -}; - -uint16_t cksum(const IpPtr &ptr); - -struct IpOpt : public ip_opt -{ - uint8_t type() const { return opt_type; } - uint8_t typeNumber() const { return IP_OPT_NUMBER(opt_type); } - uint8_t typeClass() const { return IP_OPT_CLASS(opt_type); } - uint8_t typeCopied() const { return IP_OPT_COPIED(opt_type); } - uint8_t len() const { return IP_OPT_TYPEONLY(type()) ? 1 : opt_len; } - - bool isNumber(int num) const { return typeNumber() == IP_OPT_NUMBER(num); } - bool isClass(int cls) const { return typeClass() == IP_OPT_CLASS(cls); } - bool isCopied(int cpy) const { return typeCopied() == IP_OPT_COPIED(cpy); } - - const uint8_t *data() const { return opt_data.data8; } - void sec(ip_opt_data_sec &sec) const; - void lsrr(ip_opt_data_rr &rr) const; - void ssrr(ip_opt_data_rr &rr) const; - void ts(ip_opt_data_ts &ts) const; - uint16_t satid() const { return ntohs(opt_data.satid); } - uint16_t mtup() const { return ntohs(opt_data.mtu); } - uint16_t mtur() const { return ntohs(opt_data.mtu); } - void tr(ip_opt_data_tr &tr) const; - const uint32_t *addext() const { return &opt_data.addext[0]; } - uint16_t rtralt() const { return ntohs(opt_data.rtralt); } - void sdb(std::vector<uint32_t> &vec) const; -}; - -/* - * TCP Stuff - */ -struct TcpOpt; -struct TcpHdr : public tcp_hdr -{ - uint16_t sport() const { return ntohs(th_sport); } - uint16_t dport() const { return ntohs(th_dport); } - uint32_t seq() const { return ntohl(th_seq); } - uint32_t ack() const { return ntohl(th_ack); } - uint8_t off() const { return th_off; } - uint8_t flags() const { return th_flags & 0x3f; } - uint16_t win() const { return ntohs(th_win); } - uint16_t sum() const { return th_sum; } - uint16_t urp() const { return ntohs(th_urp); } - - void sum(uint16_t sum) { th_sum = sum; } - - bool options(std::vector<const TcpOpt *> &vec) const; - - int size() const { return off(); } - const uint8_t *bytes() const { return (const uint8_t *)this; } - const uint8_t *payload() const { return bytes() + size(); } - uint8_t *bytes() { return (uint8_t *)this; } - uint8_t *payload() { return bytes() + size(); } -}; - -class TcpPtr -{ - protected: - PacketPtr p; - int off; - - const TcpHdr *h() const { return (const TcpHdr *)(p->data + off); } - TcpHdr *h() { return (TcpHdr *)(p->data + off); } - - void set(const PacketPtr &ptr, int offset) { p = ptr; off = offset; } - void set(const IpPtr &ptr) - { - if (ptr->proto() == IP_PROTO_TCP) - set(ptr.p, sizeof(eth_hdr) + ptr->hlen()); - else - set(0, 0); - } - - public: - TcpPtr() {} - TcpPtr(const IpPtr &ptr) { set(ptr); } - TcpPtr(const TcpPtr &ptr) : p(ptr.p), off(ptr.off) {} - - TcpHdr *operator->() { return h(); } - TcpHdr &operator*() { return *h(); } - operator TcpHdr *() { return h(); } - - const TcpHdr *operator->() const { return h(); } - const TcpHdr &operator*() const { return *h(); } - operator const TcpHdr *() const { return h(); } - - const TcpPtr &operator=(const IpPtr &i) { set(i); return *this; } - const TcpPtr &operator=(const TcpPtr &t) { set(t.p, t.off); return *this; } - - const PacketPtr packet() const { return p; } - PacketPtr packet() { return p; } - bool operator!() const { return !p; } - operator bool() const { return p; } - operator bool() { return p; } -}; - -uint16_t cksum(const TcpPtr &ptr); - -typedef Range<uint16_t> SackRange; - -struct TcpOpt : public tcp_opt -{ - uint8_t type() const { return opt_type; } - uint8_t len() const { return TCP_OPT_TYPEONLY(type()) ? 1 : opt_len; } - - bool isopt(int opt) const { return type() == opt; } - - const uint8_t *data() const { return opt_data.data8; } - - uint16_t mss() const { return ntohs(opt_data.mss); } - uint8_t wscale() const { return opt_data.wscale; } - bool sack(std::vector<SackRange> &vec) const; - uint32_t echo() const { return ntohl(opt_data.echo); } - uint32_t tsval() const { return ntohl(opt_data.timestamp[0]); } - uint32_t tsecr() const { return ntohl(opt_data.timestamp[1]); } - uint32_t cc() const { return ntohl(opt_data.cc); } - uint8_t cksum() const{ return opt_data.cksum; } - const uint8_t *md5() const { return opt_data.md5; } - - int size() const { return len(); } - const uint8_t *bytes() const { return (const uint8_t *)this; } - const uint8_t *payload() const { return bytes() + size(); } - uint8_t *bytes() { return (uint8_t *)this; } - uint8_t *payload() { return bytes() + size(); } -}; - -/* - * UDP Stuff - */ -struct UdpHdr : public udp_hdr -{ - uint16_t sport() const { return ntohs(uh_sport); } - uint16_t dport() const { return ntohs(uh_dport); } - uint16_t len() const { return ntohs(uh_ulen); } - uint16_t sum() const { return uh_sum; } - - void sum(uint16_t sum) { uh_sum = sum; } - - int size() const { return sizeof(udp_hdr); } - const uint8_t *bytes() const { return (const uint8_t *)this; } - const uint8_t *payload() const { return bytes() + size(); } - uint8_t *bytes() { return (uint8_t *)this; } - uint8_t *payload() { return bytes() + size(); } -}; - -class UdpPtr -{ - protected: - PacketPtr p; - int off; - - const UdpHdr *h() const { return (const UdpHdr *)(p->data + off); } - UdpHdr *h() { return (UdpHdr *)(p->data + off); } - - void set(const PacketPtr &ptr, int offset) { p = ptr; off = offset; } - void set(const IpPtr &ptr) - { - if (ptr->proto() == IP_PROTO_UDP) - set(ptr.p, sizeof(eth_hdr) + ptr->hlen()); - else - set(0, 0); - } - - public: - UdpPtr() {} - UdpPtr(const IpPtr &ptr) { set(ptr); } - UdpPtr(const UdpPtr &ptr) : p(ptr.p), off(ptr.off) {} - - UdpHdr *operator->() { return h(); } - UdpHdr &operator*() { return *h(); } - operator UdpHdr *() { return h(); } - - const UdpHdr *operator->() const { return h(); } - const UdpHdr &operator*() const { return *h(); } - operator const UdpHdr *() const { return h(); } - - const UdpPtr &operator=(const IpPtr &i) { set(i); return *this; } - const UdpPtr &operator=(const UdpPtr &t) { set(t.p, t.off); return *this; } - - const PacketPtr packet() const { return p; } - PacketPtr packet() { return p; } - bool operator!() const { return !p; } - operator bool() const { return p; } - operator bool() { return p; } -}; - -uint16_t cksum(const UdpPtr &ptr); - -/* namespace Net */ } - -#endif // __BASE_INET_HH__ diff --git a/base/inifile.cc b/base/inifile.cc deleted file mode 100644 index eb5a1335f..000000000 --- a/base/inifile.cc +++ /dev/null @@ -1,433 +0,0 @@ -/* - * 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. - */ - -#define USE_CPP - -#ifdef USE_CPP -#include <sys/signal.h> -#include <sys/types.h> -#include <sys/wait.h> - -#include <libgen.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#endif - -#include <fstream> -#include <iostream> - -#include <vector> -#include <string> - -#include "base/inifile.hh" -#include "base/str.hh" - -using namespace std; - -IniFile::IniFile() -{} - -IniFile::~IniFile() -{ - SectionTable::iterator i = table.begin(); - SectionTable::iterator end = table.end(); - - while (i != end) { - delete (*i).second; - ++i; - } -} - - -#ifdef USE_CPP -bool -IniFile::loadCPP(const string &file, vector<char *> &cppArgs) -{ - // Open the file just to verify that we can. Otherwise if the - // file doesn't exist or has bad permissions the user will get - // confusing errors from cpp/g++. - ifstream tmpf(file.c_str()); - - if (!tmpf.is_open()) - return false; - - tmpf.close(); - - char *cfile = strncpy(new char[file.size() + 1], file.c_str(), - file.size()); - char *dir = dirname(cfile); - char *dir_arg = NULL; - if (*dir != '.') { - string arg = "-I"; - arg += dir; - - dir_arg = new char[arg.size() + 1]; - strncpy(dir_arg, arg.c_str(), arg.size()); - } - - delete [] cfile; - - char tempfile[] = "/tmp/configXXXXXX"; - int tmp_fd = mkstemp(tempfile); - - int pid = fork(); - - if (pid == -1) - return false; - - if (pid == 0) { - char filename[FILENAME_MAX]; - string::size_type i = file.copy(filename, sizeof(filename) - 1); - filename[i] = '\0'; - - int arg_count = cppArgs.size(); - - char **args = new char *[arg_count + 20]; - - int nextArg = 0; - args[nextArg++] = "g++"; - args[nextArg++] = "-E"; - args[nextArg++] = "-P"; - args[nextArg++] = "-nostdinc"; - args[nextArg++] = "-nostdinc++"; - args[nextArg++] = "-x"; - args[nextArg++] = "c++"; - args[nextArg++] = "-undef"; - - for (int i = 0; i < arg_count; i++) - args[nextArg++] = cppArgs[i]; - - if (dir_arg) - args[nextArg++] = dir_arg; - - args[nextArg++] = filename; - args[nextArg++] = NULL; - - close(STDOUT_FILENO); - if (dup2(tmp_fd, STDOUT_FILENO) == -1) - exit(1); - - execvp("g++", args); - - exit(0); - } - - int retval; - waitpid(pid, &retval, 0); - - delete [] dir_arg; - - // check for normal completion of CPP - if (!WIFEXITED(retval) || WEXITSTATUS(retval) != 0) - return false; - - close(tmp_fd); - - bool status = false; - - status = load(tempfile); - - unlink(tempfile); - - return status; -} -#endif - -bool -IniFile::load(const string &file) -{ - ifstream f(file.c_str()); - - if (!f.is_open()) - return false; - - return load(f); -} - - -const string & -IniFile::Entry::getValue() const -{ - referenced = true; - return value; -} - - -void -IniFile::Section::addEntry(const std::string &entryName, - const std::string &value, - bool append) -{ - EntryTable::iterator ei = table.find(entryName); - - if (ei == table.end()) { - // new entry - table[entryName] = new Entry(value); - } - else if (append) { - // append new reult to old entry - ei->second->appendValue(value); - } - else { - // override old entry - ei->second->setValue(value); - } -} - - -bool -IniFile::Section::add(const std::string &assignment) -{ - string::size_type offset = assignment.find('='); - if (offset == string::npos) { - // no '=' found - cerr << "Can't parse .ini line " << assignment << endl; - return false; - } - - // if "+=" rather than just "=" then append value - bool append = (assignment[offset-1] == '+'); - - string entryName = assignment.substr(0, append ? offset-1 : offset); - string value = assignment.substr(offset + 1); - - eat_white(entryName); - eat_white(value); - - addEntry(entryName, value, append); - return true; -} - - -IniFile::Entry * -IniFile::Section::findEntry(const std::string &entryName) const -{ - referenced = true; - - EntryTable::const_iterator ei = table.find(entryName); - - return (ei == table.end()) ? NULL : ei->second; -} - - -IniFile::Section * -IniFile::addSection(const string §ionName) -{ - SectionTable::iterator i = table.find(sectionName); - - if (i != table.end()) { - return i->second; - } - else { - // new entry - Section *sec = new Section(); - table[sectionName] = sec; - return sec; - } -} - - -IniFile::Section * -IniFile::findSection(const string §ionName) const -{ - SectionTable::const_iterator i = table.find(sectionName); - - return (i == table.end()) ? NULL : i->second; -} - - -// Take string of the form "<section>:<parameter>=<value>" and add to -// database. Return true if successful, false if parse error. -bool -IniFile::add(const string &str) -{ - // find ':' - string::size_type offset = str.find(':'); - if (offset == string::npos) // no ':' found - return false; - - string sectionName = str.substr(0, offset); - string rest = str.substr(offset + 1); - - eat_white(sectionName); - Section *s = addSection(sectionName); - - return s->add(rest); -} - -bool -IniFile::load(istream &f) -{ - Section *section = NULL; - - while (!f.eof()) { - f >> ws; // Eat whitespace - if (f.eof()) { - break; - } - - string line; - getline(f, line); - if (line.size() == 0) - continue; - - eat_end_white(line); - int last = line.size() - 1; - - if (line[0] == '[' && line[last] == ']') { - string sectionName = line.substr(1, last - 1); - eat_white(sectionName); - section = addSection(sectionName); - continue; - } - - if (section == NULL) - continue; - - if (!section->add(line)) - return false; - } - - return true; -} - -bool -IniFile::find(const string §ionName, const string &entryName, - string &value) const -{ - Section *section = findSection(sectionName); - if (section == NULL) - return false; - - Entry *entry = section->findEntry(entryName); - if (entry == NULL) - return false; - - value = entry->getValue(); - - return true; -} - -bool -IniFile::sectionExists(const string §ionName) const -{ - return findSection(sectionName) != NULL; -} - - -bool -IniFile::Section::printUnreferenced(const string §ionName) -{ - bool unref = false; - bool search_unref_entries = false; - vector<string> unref_ok_entries; - - Entry *entry = findEntry("unref_entries_ok"); - if (entry != NULL) { - tokenize(unref_ok_entries, entry->getValue(), ' '); - if (unref_ok_entries.size()) { - search_unref_entries = true; - } - } - - for (EntryTable::iterator ei = table.begin(); - ei != table.end(); ++ei) { - const string &entryName = ei->first; - Entry *entry = ei->second; - - if (entryName == "unref_section_ok" || - entryName == "unref_entries_ok") - { - continue; - } - - if (!entry->isReferenced()) { - if (search_unref_entries && - (std::find(unref_ok_entries.begin(), unref_ok_entries.end(), - entryName) != unref_ok_entries.end())) - { - continue; - } - - cerr << "Parameter " << sectionName << ":" << entryName - << " not referenced." << endl; - unref = true; - } - } - - return unref; -} - - -bool -IniFile::printUnreferenced() -{ - bool unref = false; - - for (SectionTable::iterator i = table.begin(); - i != table.end(); ++i) { - const string §ionName = i->first; - Section *section = i->second; - - if (!section->isReferenced()) { - if (section->findEntry("unref_section_ok") == NULL) { - cerr << "Section " << sectionName << " not referenced." - << endl; - unref = true; - } - } - else { - if (section->printUnreferenced(sectionName)) { - unref = true; - } - } - } - - return unref; -} - - -void -IniFile::Section::dump(const string §ionName) -{ - for (EntryTable::iterator ei = table.begin(); - ei != table.end(); ++ei) { - cout << sectionName << ": " << (*ei).first << " => " - << (*ei).second->getValue() << "\n"; - } -} - -void -IniFile::dump() -{ - for (SectionTable::iterator i = table.begin(); - i != table.end(); ++i) { - i->second->dump(i->first); - } -} diff --git a/base/inifile.hh b/base/inifile.hh deleted file mode 100644 index 3c6894978..000000000 --- a/base/inifile.hh +++ /dev/null @@ -1,208 +0,0 @@ -/* - * 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. - */ - -#ifndef __INIFILE_HH__ -#define __INIFILE_HH__ - -#include <fstream> -#include <list> -#include <string> -#include <vector> - -#include "base/hashmap.hh" - -/** - * @file - * Declaration of IniFile object. - * @todo Change comments to match documentation style. - */ - -/// -/// This class represents the contents of a ".ini" file. -/// -/// It's basically a two level lookup table: a set of named sections, -/// where each section is a set of key/value pairs. Section names, -/// keys, and values are all uninterpreted strings. -/// -class IniFile -{ - protected: - - /// - /// A single key/value pair. - /// - class Entry - { - std::string value; ///< The entry value. - mutable bool referenced; ///< Has this entry been used? - - public: - /// Constructor. - Entry(const std::string &v) - : value(v), referenced(false) - { - } - - /// Has this entry been used? - bool isReferenced() { return referenced; } - - /// Fetch the value. - const std::string &getValue() const; - - /// Set the value. - void setValue(const std::string &v) { value = v; } - - /// Append the given string to the value. A space is inserted - /// between the existing value and the new value. Since this - /// operation is typically used with values that are - /// space-separated lists of tokens, this keeps the tokens - /// separate. - void appendValue(const std::string &v) { value += " "; value += v; } - }; - - /// - /// A section. - /// - class Section - { - /// EntryTable type. Map of strings to Entry object pointers. - typedef m5::hash_map<std::string, Entry *> EntryTable; - - EntryTable table; ///< Table of entries. - mutable bool referenced; ///< Has this section been used? - - public: - /// Constructor. - Section() - : table(), referenced(false) - { - } - - /// Has this section been used? - bool isReferenced() { return referenced; } - - /// Add an entry to the table. If an entry with the same name - /// already exists, the 'append' parameter is checked If true, - /// the new value will be appended to the existing entry. If - /// false, the new value will replace the existing entry. - void addEntry(const std::string &entryName, const std::string &value, - bool append); - - /// Add an entry to the table given a string assigment. - /// Assignment should be of the form "param=value" or - /// "param+=value" (for append). This funciton parses the - /// assignment statment and calls addEntry(). - /// @retval True for success, false if parse error. - bool add(const std::string &assignment); - - /// Find the entry with the given name. - /// @retval Pointer to the entry object, or NULL if none. - Entry *findEntry(const std::string &entryName) const; - - /// Print the unreferenced entries in this section to cerr. - /// Messages can be suppressed using "unref_section_ok" and - /// "unref_entries_ok". - /// @param sectionName Name of this section, for use in output message. - /// @retval True if any entries were printed. - bool printUnreferenced(const std::string §ionName); - - /// Print the contents of this section to cout (for debugging). - void dump(const std::string §ionName); - }; - - /// SectionTable type. Map of strings to Section object pointers. - typedef m5::hash_map<std::string, Section *> SectionTable; - - protected: - /// Hash of section names to Section object pointers. - SectionTable table; - - /// Look up section with the given name, creating a new section if - /// not found. - /// @retval Pointer to section object. - Section *addSection(const std::string §ionName); - - /// Look up section with the given name. - /// @retval Pointer to section object, or NULL if not found. - Section *findSection(const std::string §ionName) const; - - public: - /// Constructor. - IniFile(); - - /// Destructor. - ~IniFile(); - - /// Load parameter settings from given istream. This is a helper - /// function for load(string) and loadCPP(), which open a file - /// and then pass it here. - /// @retval True if successful, false if errors were encountered. - bool load(std::istream &f); - - /// Load the specified file, passing it through the C preprocessor. - /// Parameter settings found in the file will be merged with any - /// already defined in this object. - /// @param file The path of the file to load. - /// @param cppFlags Vector of extra flags to pass to cpp. - /// @retval True if successful, false if errors were encountered. - bool loadCPP(const std::string &file, std::vector<char *> &cppFlags); - - /// Load the specified file. - /// Parameter settings found in the file will be merged with any - /// already defined in this object. - /// @param file The path of the file to load. - /// @retval True if successful, false if errors were encountered. - bool load(const std::string &file); - - /// Take string of the form "<section>:<parameter>=<value>" or - /// "<section>:<parameter>+=<value>" and add to database. - /// @retval True if successful, false if parse error. - bool add(const std::string &s); - - /// Find value corresponding to given section and entry names. - /// Value is returned by reference in 'value' param. - /// @retval True if found, false if not. - bool find(const std::string §ion, const std::string &entry, - std::string &value) const; - - /// Determine whether the named section exists in the .ini file. - /// Note that the 'Section' class is (intentionally) not public, - /// so all clients can do is get a bool that says whether there - /// are any values in that section or not. - /// @return True if the section exists. - bool sectionExists(const std::string §ion) const; - - /// Print unreferenced entries in object. Iteratively calls - /// printUnreferend() on all the constituent sections. - bool printUnreferenced(); - - /// Dump contents to cout. For debugging. - void dump(); -}; - -#endif // __INIFILE_HH__ diff --git a/base/intmath.cc b/base/intmath.cc deleted file mode 100644 index f1c1651ba..000000000 --- a/base/intmath.cc +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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. - */ - -#include "base/intmath.hh" - -int -prevPrime(int n) -{ - int decr; - - // If the number is even, let's start with the previous odd number. - if (!(n & 1)) - --n; - - // Lets test for divisibility by 3. Then we will be able to easily - // avoid numbers that are divisible by 3 in the future. - decr = n % 3; - if (decr == 0) { - n -= 2; - decr = 2; - } - else if (decr == 1) - decr = 4; - - for (;;) { - if (isPrime(n)) - return n; - n -= decr; - // Toggle between 2 and 4 to prevent trying numbers that are known - // to be divisible by 3. - decr = 6 - decr; - } -} diff --git a/base/intmath.hh b/base/intmath.hh deleted file mode 100644 index df0687c62..000000000 --- a/base/intmath.hh +++ /dev/null @@ -1,230 +0,0 @@ -/* - * 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. - */ - -#ifndef __INTMATH_HH__ -#define __INTMATH_HH__ - -#include <assert.h> - -#include "sim/host.hh" - -// Returns the prime number one less than n. -int prevPrime(int n); - -// Determine if a number is prime -template <class T> -inline bool -isPrime(T n) -{ - T i; - - if (n == 2 || n == 3) - return true; - - // Don't try every odd number to prove if it is a prime. - // Toggle between every 2nd and 4th number. - // (This is because every 6th odd number is divisible by 3.) - for (i = 5; i*i <= n; i += 6) { - if (((n % i) == 0 ) || ((n % (i + 2)) == 0) ) { - return false; - } - } - - return true; -} - -template <class T> -inline T -leastSigBit(T n) -{ - return n & ~(n - 1); -} - -template <class T> -inline bool -isPowerOf2(T n) -{ - return n != 0 && leastSigBit(n) == n; -} - -inline int -floorLog2(unsigned x) -{ - assert(x > 0); - - int y = 0; - - if (x & 0xffff0000) { y += 16; x >>= 16; } - if (x & 0x0000ff00) { y += 8; x >>= 8; } - if (x & 0x000000f0) { y += 4; x >>= 4; } - if (x & 0x0000000c) { y += 2; x >>= 2; } - if (x & 0x00000002) { y += 1; } - - return y; -} - -inline int -floorLog2(unsigned long x) -{ - assert(x > 0); - - int y = 0; - -#if defined(__LP64__) - if (x & ULL(0xffffffff00000000)) { y += 32; x >>= 32; } -#endif - if (x & 0xffff0000) { y += 16; x >>= 16; } - if (x & 0x0000ff00) { y += 8; x >>= 8; } - if (x & 0x000000f0) { y += 4; x >>= 4; } - if (x & 0x0000000c) { y += 2; x >>= 2; } - if (x & 0x00000002) { y += 1; } - - return y; -} - -inline int -floorLog2(unsigned long long x) -{ - assert(x > 0); - - int y = 0; - - if (x & ULL(0xffffffff00000000)) { y += 32; x >>= 32; } - if (x & ULL(0x00000000ffff0000)) { y += 16; x >>= 16; } - if (x & ULL(0x000000000000ff00)) { y += 8; x >>= 8; } - if (x & ULL(0x00000000000000f0)) { y += 4; x >>= 4; } - if (x & ULL(0x000000000000000c)) { y += 2; x >>= 2; } - if (x & ULL(0x0000000000000002)) { y += 1; } - - return y; -} - -inline int -floorLog2(int x) -{ - assert(x > 0); - return floorLog2((unsigned)x); -} - -inline int -floorLog2(long x) -{ - assert(x > 0); - return floorLog2((unsigned long)x); -} - -inline int -floorLog2(long long x) -{ - assert(x > 0); - return floorLog2((unsigned long long)x); -} - -template <class T> -inline int -ceilLog2(T n) -{ - if (n == 1) - return 0; - - return floorLog2(n - (T)1) + 1; -} - -template <class T> -inline T -floorPow2(T n) -{ - return (T)1 << floorLog2(n); -} - -template <class T> -inline T -ceilPow2(T n) -{ - return (T)1 << ceilLog2(n); -} - -template <class T> -inline T -divCeil(T a, T b) -{ - return (a + b - 1) / b; -} - -template <class T> -inline T -roundUp(T val, int align) -{ - T mask = (T)align - 1; - return (val + mask) & ~mask; -} - -template <class T> -inline T -roundDown(T val, T align) -{ - T mask = align - 1; - return val & ~mask; -} - -inline bool -isHex(char c) -{ - return c >= '0' && c <= '9' || - c >= 'A' && c <= 'F' || - c >= 'a' && c <= 'f'; -} - -inline bool -isOct(char c) -{ - return c >= '0' && c <= '7'; -} - -inline bool -isDec(char c) -{ - return c >= '0' && c <= '9'; -} - -inline int -hex2Int(char c) -{ - if (c >= '0' && c <= '9') - return (c - '0'); - - if (c >= 'A' && c <= 'F') - return (c - 'A') + 10; - - if (c >= 'a' && c <= 'f') - return (c - 'a') + 10; - - return 0; -} - -#endif // __INTMATH_HH__ diff --git a/base/loader/aout_object.cc b/base/loader/aout_object.cc deleted file mode 100644 index c81f7123f..000000000 --- a/base/loader/aout_object.cc +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include <string> - -#include "base/loader/aout_object.hh" - -#include "mem/functional/functional.hh" -#include "base/loader/symtab.hh" - -#include "base/trace.hh" // for DPRINTF - -#include "base/loader/exec_aout.h" - -using namespace std; - -ObjectFile * -AoutObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data) -{ - if (!N_BADMAG(*(aout_exechdr *)data)) { - // right now this is only used for Alpha PAL code - return new AoutObject(fname, fd, len, data, - ObjectFile::Alpha, ObjectFile::UnknownOpSys); - } - else { - return NULL; - } -} - - -AoutObject::AoutObject(const string &_filename, int _fd, - size_t _len, uint8_t *_data, - Arch _arch, OpSys _opSys) - : ObjectFile(_filename, _fd, _len, _data, _arch, _opSys) -{ - execHdr = (aout_exechdr *)fileData; - - entry = execHdr->entry; - - text.baseAddr = N_TXTADDR(*execHdr); - text.size = execHdr->tsize; - - data.baseAddr = N_DATADDR(*execHdr); - data.size = execHdr->dsize; - - bss.baseAddr = N_BSSADDR(*execHdr); - bss.size = execHdr->bsize; - - DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n", - text.baseAddr, text.size, data.baseAddr, data.size, - bss.baseAddr, bss.size); -} - - -bool -AoutObject::loadSections(FunctionalMemory *mem, bool loadPhys) -{ - Addr textAddr = text.baseAddr; - Addr dataAddr = data.baseAddr; - - if (loadPhys) { - textAddr &= (ULL(1) << 40) - 1; - dataAddr &= (ULL(1) << 40) - 1; - } - - // Since we don't really have an MMU and all memory is - // zero-filled, there's no need to set up the BSS segment. - if (text.size != 0) - mem->prot_write(textAddr, fileData + N_TXTOFF(*execHdr), text.size); - if (data.size != 0) - mem->prot_write(dataAddr, fileData + N_DATOFF(*execHdr), data.size); - - return true; -} - - -bool -AoutObject::loadGlobalSymbols(SymbolTable *symtab) -{ - // a.out symbols not supported yet - return false; -} - -bool -AoutObject::loadLocalSymbols(SymbolTable *symtab) -{ - // a.out symbols not supported yet - return false; -} diff --git a/base/loader/aout_object.hh b/base/loader/aout_object.hh deleted file mode 100644 index 1868192b2..000000000 --- a/base/loader/aout_object.hh +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __AOUT_OBJECT_HH__ -#define __AOUT_OBJECT_HH__ - -#include "base/loader/object_file.hh" - -// forward decls: avoid including exec_aout.h here -struct aout_exechdr; - -class AoutObject : public ObjectFile -{ - protected: - aout_exechdr *execHdr; - - AoutObject(const std::string &_filename, int _fd, - size_t _len, uint8_t *_data, - Arch _arch, OpSys _opSys); - - public: - virtual ~AoutObject() {} - - virtual bool loadSections(FunctionalMemory *mem, - bool loadPhys = false); - virtual bool loadGlobalSymbols(SymbolTable *symtab); - virtual bool loadLocalSymbols(SymbolTable *symtab); - - static ObjectFile *tryFile(const std::string &fname, int fd, - size_t len, uint8_t *data); -}; - -#endif // __AOUT_OBJECT_HH__ diff --git a/base/loader/coff_sym.h b/base/loader/coff_sym.h deleted file mode 100644 index 734d96a98..000000000 --- a/base/loader/coff_sym.h +++ /dev/null @@ -1,489 +0,0 @@ -/* - * Taken from binutils-2.14.90.0.5 include/coff/sym.h - */ - -/* Declarations of internal format of MIPS ECOFF symbols. - Originally contributed by MIPS Computer Systems and Third Eye Software. - Changes contributed by Cygnus Support are in the public domain. - - This file is just aggregated with the files that make up the GNU - release; it is not considered part of GAS, GDB, or other GNU - programs. */ - -/* - * |-----------------------------------------------------------| - * | Copyright (c) 1992, 1991, 1990 MIPS Computer Systems, Inc.| - * | MIPS Computer Systems, Inc. grants reproduction and use | - * | rights to all parties, PROVIDED that this comment is | - * | maintained in the copy. | - * |-----------------------------------------------------------| - */ -#ifndef _SYM_H -#define _SYM_H - -/* (C) Copyright 1984 by Third Eye Software, Inc. - * - * Third Eye Software, Inc. grants reproduction and use rights to - * all parties, PROVIDED that this comment is maintained in the copy. - * - * Third Eye makes no claims about the applicability of this - * symbol table to a particular use. - */ - -/* - * This file contains the definition of the Third Eye Symbol Table. - * - * Symbols are assumed to be in 'encounter order' - i.e. the order that - * the things they represent were encountered by the compiler/assembler/loader. - * EXCEPT for globals! These are assumed to be bunched together, - * probably right after the last 'normal' symbol. Globals ARE sorted - * in ascending order. - * - * ----------------------------------------------------------------------- - * A brief word about Third Eye naming/use conventions: - * - * All arrays and index's are 0 based. - * All "ifooMax" values are the highest legal value PLUS ONE. This makes - * them good for allocating arrays, etc. All checks are "ifoo < ifooMax". - * - * "isym" Index into the SYMbol table. - * "ipd" Index into the Procedure Descriptor array. - * "ifd" Index into the File Descriptor array. - * "iss" Index into String Space. - * "cb" Count of Bytes. - * "rgPd" array whose domain is "0..ipdMax-1" and RanGe is PDR. - * "rgFd" array whose domain is "0..ifdMax-1" and RanGe is FDR. - */ - - -/* - * Symbolic Header (HDR) structure. - * As long as all the pointers are set correctly, - * we don't care WHAT order the various sections come out in! - * - * A file produced solely for the use of CDB will probably NOT have - * any instructions or data areas in it, as these are available - * in the original. - */ - -typedef struct ecoff_symhdr { - coff_short magic; /* to verify validity of the table */ - coff_short vstamp; /* version stamp */ - coff_int ilineMax; /* number of line number entries */ - coff_int idnMax; /* max index into dense number table */ - coff_int ipdMax; /* number of procedures */ - coff_int isymMax; /* number of local symbols */ - coff_int ioptMax; /* max index into optimization symbol entries */ - coff_int iauxMax; /* number of auxillary symbol entries */ - coff_int issMax; /* max index into local strings */ - coff_int issExtMax; /* max index into external strings */ - coff_int ifdMax; /* number of file descriptor entries */ - coff_int crfd; /* number of relative file descriptor entries */ - coff_int iextMax; /* max index into external symbols */ - coff_addr cbLine; /* number of bytes for line number entries */ - coff_addr cbLineOffset; /* offset to start of line number entries*/ - coff_addr cbDnOffset; /* offset to start dense number table */ - coff_addr cbPdOffset; /* offset to procedure descriptor table */ - coff_addr cbSymOffset; /* offset to start of local symbols*/ - coff_addr cbOptOffset; /* offset to optimization symbol entries */ - coff_addr cbAuxOffset; /* offset to start of auxillary symbol entries*/ - coff_addr cbSsOffset; /* offset to start of local strings */ - coff_addr cbSsExtOffset; /* offset to start of external strings */ - coff_addr cbFdOffset; /* offset to file descriptor table */ - coff_addr cbRfdOffset; /* offset to relative file descriptor table */ - coff_addr cbExtOffset; /* offset to start of external symbol entries*/ - /* If you add machine dependent fields, add them here */ -} HDRR, *pHDRR; -#define cbHDRR sizeof(HDRR) -#define hdrNil ((pHDRR)0) - -/* - * The FDR and PDR structures speed mapping of address <-> name. - * They are sorted in ascending memory order and are kept in - * memory by CDB at runtime. - */ - -/* - * File Descriptor - * - * There is one of these for EVERY FILE, whether compiled with - * full debugging symbols or not. The name of a file should be - * the path name given to the compiler. This allows the user - * to simply specify the names of the directories where the COMPILES - * were done, and we will be able to find their files. - * A field whose comment starts with "R - " indicates that it will be - * setup at runtime. - */ -typedef struct ecoff_fdr { - coff_addr adr; /* memory address of beginning of file */ - coff_addr cbLineOffset; /* byte offset from header for this file ln's */ - coff_addr cbLine; /* size of lines for this file */ - coff_addr cbSs; /* number of bytes in the ss */ - coff_int rss; /* file name (of source, if known) */ - coff_int issBase; /* file's string space */ - coff_int isymBase; /* beginning of symbols */ - coff_int csym; /* count file's of symbols */ - coff_int ilineBase; /* file's line symbols */ - coff_int cline; /* count of file's line symbols */ - coff_int ioptBase; /* file's optimization entries */ - coff_int copt; /* count of file's optimization entries */ - coff_int ipdFirst; /* start of procedures for this file */ - coff_int cpd; /* count of procedures for this file */ - coff_int iauxBase; /* file's auxiliary entries */ - coff_int caux; /* count of file's auxiliary entries */ - coff_int rfdBase; /* index into the file indirect table */ - coff_int crfd; /* count file indirect entries */ - unsigned lang: 5; /* language for this file */ - unsigned fMerge : 1; /* whether this file can be merged */ - unsigned fReadin : 1; /* true if it was read in (not just created) */ - unsigned fBigendian : 1;/* if set, was compiled on big endian machine */ - /* aux's will be in compile host's sex */ - unsigned glevel : 2; /* level this file was compiled with */ - unsigned reserved : 22; /* reserved for future use */ - coff_uint reserved2; -} FDR, *pFDR; -#define cbFDR sizeof(FDR) -#define fdNil ((pFDR)0) -#define ifdNil -1 -#define ifdTemp 0 -#define ilnNil -1 - - -/* - * Procedure Descriptor - * - * There is one of these for EVERY TEXT LABEL. - * If a procedure is in a file with full symbols, then isym - * will point to the PROC symbols, else it will point to the - * global symbol for the label. - */ - -typedef struct pdr { - coff_addr adr; /* memory address of start of procedure */ - coff_addr cbLineOffset; /* byte offset for this procedure from the fd base */ - coff_int isym; /* start of local symbol entries */ - coff_int iline; /* start of line number entries*/ - coff_uint regmask; /* save register mask */ - coff_int regoffset; /* save register offset */ - coff_int iopt; /* start of optimization symbol entries*/ - coff_uint fregmask; /* save floating point register mask */ - coff_int fregoffset; /* save floating point register offset */ - coff_int frameoffset; /* frame size */ - coff_int lnLow; /* lowest line in the procedure */ - coff_int lnHigh; /* highest line in the procedure */ - /* These fields are new for 64 bit ECOFF. */ - unsigned gp_prologue : 8; /* byte size of GP prologue */ - unsigned gp_used : 1; /* true if the procedure uses GP */ - unsigned reg_frame : 1; /* true if register frame procedure */ - unsigned prof : 1; /* true if compiled with -pg */ - unsigned reserved : 13; /* reserved: must be zero */ - unsigned localoff : 8; /* offset of local variables from vfp */ - coff_short framereg; /* frame pointer register */ - coff_short pcreg; /* offset or reg of return pc */ -} PDR, *pPDR; -#define cbPDR sizeof(PDR) -#define pdNil ((pPDR) 0) -#define ipdNil -1 - -/* - * The structure of the runtime procedure descriptor created by the loader - * for use by the static exception system. - */ -/* - * If 0'd out because exception_info chokes Visual C++ and because there - * don't seem to be any references to this structure elsewhere in gdb. - */ -#if 0 -typedef struct runtime_pdr { - coff_addr adr; /* memory address of start of procedure */ - coff_uint regmask; /* save register mask */ - coff_int regoffset; /* save register offset */ - coff_uint fregmask; /* save floating point register mask */ - coff_int fregoffset; /* save floating point register offset */ - coff_int frameoffset; /* frame size */ - coff_ushort framereg; /* frame pointer register */ - coff_ushort pcreg; /* offset or reg of return pc */ - coff_int irpss; /* index into the runtime string table */ - coff_uint reserved; - struct exception_info *exception_info;/* pointer to exception array */ -} RPDR, *pRPDR; -#define cbRPDR sizeof(RPDR) -#define rpdNil ((pRPDR) 0) -#endif - -/* - * Line Numbers - * - * Line Numbers are segregated from the normal symbols because they - * are [1] smaller , [2] are of no interest to your - * average loader, and [3] are never needed in the middle of normal - * scanning and therefore slow things down. - * - * By definition, the first LINER for any given procedure will have - * the first line of a procedure and represent the first address. - */ - -typedef coff_int LINER, *pLINER; -#define lineNil ((pLINER)0) -#define cbLINER sizeof(LINER) -#define ilineNil -1 - - - -/* - * The Symbol Structure (GFW, to those who Know!) - */ - -typedef struct ecoff_sym { - coff_long value; /* value of symbol */ - coff_int iss; /* index into String Space of name */ - unsigned st : 6; /* symbol type */ - unsigned sc : 5; /* storage class - text, data, etc */ - unsigned reserved : 1; /* reserved */ - unsigned index : 20; /* index into sym/aux table */ -} SYMR, *pSYMR; -#define symNil ((pSYMR)0) -#define cbSYMR sizeof(SYMR) -#define isymNil -1 -#define indexNil 0xfffff -#define issNil -1 -#define issNull 0 - - -/* The following converts a memory resident string to an iss. - * This hack is recognized in SbFIss, in sym.c of the debugger. - */ -#define IssFSb(sb) (0x80000000 | ((coff_ulong)(sb))) - -/* E X T E R N A L S Y M B O L R E C O R D - * - * Same as the SYMR except it contains file context to determine where - * the index is. - */ -typedef struct ecoff_extsym { - SYMR asym; /* symbol for the external */ - unsigned jmptbl:1; /* symbol is a jump table entry for shlibs */ - unsigned cobol_main:1; /* symbol is a cobol main procedure */ - unsigned weakext:1; /* symbol is weak external */ - unsigned reserved:29; /* reserved for future use */ - coff_int ifd; /* where the iss and index fields point into */ -} EXTR, *pEXTR; -#define extNil ((pEXTR)0) -#define cbEXTR sizeof(EXTR) - - -/* A U X I L L A R Y T Y P E I N F O R M A T I O N */ - -/* - * Type Information Record - */ -typedef struct { - unsigned fBitfield : 1; /* set if bit width is specified */ - unsigned continued : 1; /* indicates additional TQ info in next AUX */ - unsigned bt : 6; /* basic type */ - unsigned tq4 : 4; - unsigned tq5 : 4; - /* ---- 16 bit boundary ---- */ - unsigned tq0 : 4; - unsigned tq1 : 4; /* 6 type qualifiers - tqPtr, etc. */ - unsigned tq2 : 4; - unsigned tq3 : 4; -} TIR, *pTIR; -#define cbTIR sizeof(TIR) -#define tiNil ((pTIR)0) -#define itqMax 6 - -/* - * Relative symbol record - * - * If the rfd field is 4095, the index field indexes into the global symbol - * table. - */ - -typedef struct { - unsigned rfd : 12; /* index into the file indirect table */ - unsigned index : 20; /* index int sym/aux/iss tables */ -} RNDXR, *pRNDXR; -#define cbRNDXR sizeof(RNDXR) -#define rndxNil ((pRNDXR)0) - -/* dense numbers or sometimes called block numbers are stored in this type, - * a rfd of 0xffffffff is an index into the global table. - */ -typedef struct { - coff_uint rfd; /* index into the file table */ - coff_uint index; /* index int sym/aux/iss tables */ -} DNR, *pDNR; -#define cbDNR sizeof(DNR) -#define dnNil ((pDNR)0) - - - -/* - * Auxillary information occurs only if needed. - * It ALWAYS occurs in this order when present. - - isymMac used by stProc only - TIR type info - TIR additional TQ info (if first TIR was not enough) - rndx if (bt == btStruct,btUnion,btEnum,btSet,btRange, - btTypedef): - rsym.index == iaux for btSet or btRange - else rsym.index == isym - dimLow btRange, btSet - dimMac btRange, btSet - rndx0 As many as there are tq arrays - dimLow0 - dimHigh0 - ... - rndxMax-1 - dimLowMax-1 - dimHighMax-1 - width in bits if (bit field), width in bits. - */ -#define cAuxMax (6 + (idimMax*3)) - -/* a union of all possible info in the AUX universe */ -typedef union { - TIR ti; /* type information record */ - RNDXR rndx; /* relative index into symbol table */ - coff_int dnLow; /* low dimension */ - coff_int dnHigh; /* high dimension */ - coff_int isym; /* symbol table index (end of proc) */ - coff_int iss; /* index into string space (not used) */ - coff_int width; /* width for non-default sized struc fields */ - coff_int count; /* count of ranges for variant arm */ -} AUXU, *pAUXU; -#define cbAUXU sizeof(AUXU) -#define auxNil ((pAUXU)0) -#define iauxNil -1 - - -/* - * Optimization symbols - * - * Optimization symbols contain some overlap information with the normal - * symbol table. In particular, the proc information - * is somewhat redundant but necessary to easily find the other information - * present. - * - * All of the offsets are relative to the beginning of the last otProc - */ - -typedef struct { - unsigned ot: 8; /* optimization type */ - unsigned value: 24; /* address where we are moving it to */ - RNDXR rndx; /* points to a symbol or opt entry */ - coff_ulong offset; /* relative offset this occured */ -} OPTR, *pOPTR; -#define optNil ((pOPTR) 0) -#define cbOPTR sizeof(OPTR) -#define ioptNil -1 - -/* - * File Indirect - * - * When a symbol is referenced across files the following procedure is used: - * 1) use the file index to get the File indirect entry. - * 2) use the file indirect entry to get the File descriptor. - * 3) add the sym index to the base of that file's sym table - * - */ - -typedef coff_long RFDT, *pRFDT; -#define cbRFDT sizeof(RFDT) -#define rfdNil -1 - -/* - * The file indirect table in the mips loader is known as an array of FITs. - * This is done to keep the code in the loader readable in the area where - * these tables are merged. Note this is only a name change. - */ -typedef coff_int FIT, *pFIT; -#define cbFIT sizeof(FIT) -#define ifiNil -1 -#define fiNil ((pFIT) 0) - -#ifdef _LANGUAGE_PASCAL -#define ifdNil -1 -#define ilnNil -1 -#define ipdNil -1 -#define ilineNil -1 -#define isymNil -1 -#define indexNil 16#fffff -#define issNil -1 -#define issNull 0 -#define itqMax 6 -#define iauxNil -1 -#define ioptNil -1 -#define rfdNil -1 -#define ifiNil -1 -#endif /* _LANGUAGE_PASCAL */ - - -/* Dense numbers - * - * Rather than use file index, symbol index pairs to represent symbols - * and globals, we use dense number so that they can be easily embeded - * in intermediate code and the programs that process them can - * use direct access tabls instead of hash table (which would be - * necesary otherwise because of the sparse name space caused by - * file index, symbol index pairs. Dense number are represented - * by RNDXRs. - */ - -/* - * The following table defines the meaning of each SYM field as - * a function of the "st". (scD/B == scData OR scBss) - * - * Note: the value "isymMac" is used by symbols that have the concept - * of enclosing a block of related information. This value is the - * isym of the first symbol AFTER the end associated with the primary - * symbol. For example if a procedure was at isym==90 and had an - * isymMac==155, the associated end would be at isym==154, and the - * symbol at 155 would probably (although not necessarily) be the - * symbol for the next procedure. This allows rapid skipping over - * internal information of various sorts. "stEnd"s ALWAYS have the - * isym of the primary symbol that started the block. - * - -ST SC VALUE INDEX --------- ------ -------- ------ -stFile scText address isymMac -stLabel scText address --- -stGlobal scD/B address iaux -stStatic scD/B address iaux -stParam scAbs offset iaux -stLocal scAbs offset iaux -stProc scText address iaux (isymMac is first AUX) -stStaticProc scText address iaux (isymMac is first AUX) - -stMember scNil ordinal --- (if member of enum) - (mipsread thinks the case below has a bit, not byte, offset.) -stMember scNil byte offset iaux (if member of struct/union) -stMember scBits bit offset iaux (bit field spec) - -stBlock scText address isymMac (text block) - (the code seems to think that rather than scNil, we see scInfo for - the two cases below.) -stBlock scNil cb isymMac (struct/union member define) -stBlock scNil cMembers isymMac (enum member define) - - (New types added by SGI to simplify things:) -stStruct scInfo cb isymMac (struct type define) -stUnion scInfo cb isymMac (union type define) -stEnum scInfo cMembers isymMac (enum type define) - -stEnd scText address isymStart -stEnd scNil ------- isymStart (struct/union/enum) - -stTypedef scNil ------- iaux -stRegReloc sc??? value old register number -stForward sc??? new address isym to original symbol - -stConstant scInfo value --- (scalar) -stConstant scInfo iss --- (complex, e.g. string) - - * - */ -#endif diff --git a/base/loader/coff_symconst.h b/base/loader/coff_symconst.h deleted file mode 100644 index 87bace02d..000000000 --- a/base/loader/coff_symconst.h +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Taken from binutils-2.14.90.0.5 include/coff/symconst.h - */ - -/* Declarations of constants for internal format of MIPS ECOFF symbols. - Originally contributed by MIPS Computer Systems and Third Eye Software. - Changes contributed by Cygnus Support are in the public domain. - - This file is just aggregated with the files that make up the GNU - release; it is not considered part of GAS, GDB, or other GNU - programs. */ - -/* - * |-----------------------------------------------------------| - * | Copyright (c) 1992, 1991, 1990 MIPS Computer Systems, Inc.| - * | MIPS Computer Systems, Inc. grants reproduction and use | - * | rights to all parties, PROVIDED that this comment is | - * | maintained in the copy. | - * |-----------------------------------------------------------| - */ - -/* (C) Copyright 1984 by Third Eye Software, Inc. - * - * Third Eye Software, Inc. grants reproduction and use rights to - * all parties, PROVIDED that this comment is maintained in the copy. - * - * Third Eye makes no claims about the applicability of this - * symbol table to a particular use. - */ - -/* glevels for field in FDR */ -#define GLEVEL_0 2 -#define GLEVEL_1 1 -#define GLEVEL_2 0 /* for upward compat reasons. */ -#define GLEVEL_3 3 - -/* magic number fo symheader */ -#define magicSym 0x7009 -/* The Alpha uses this value instead, for some reason. */ -#define magicSym2 0x1992 - -/* Language codes */ -#define langC 0 -#define langPascal 1 -#define langFortran 2 -#define langAssembler 3 /* one Assembley inst might map to many mach */ -#define langMachine 4 -#define langNil 5 -#define langAda 6 -#define langPl1 7 -#define langCobol 8 -#define langStdc 9 /* FIXME: Collides with SGI langCplusplus */ -#define langCplusplus 9 /* FIXME: Collides with langStdc */ -#define langCplusplusV2 10 /* SGI addition */ -#define langMax 11 /* maximun allowed 32 -- 5 bits */ - -/* The following are value definitions for the fields in the SYMR */ - -/* - * Storage Classes - */ - -#define scNil 0 -#define scText 1 /* text symbol */ -#define scData 2 /* initialized data symbol */ -#define scBss 3 /* un-initialized data symbol */ -#define scRegister 4 /* value of symbol is register number */ -#define scAbs 5 /* value of symbol is absolute */ -#define scUndefined 6 /* who knows? */ -#define scCdbLocal 7 /* variable's value is IN se->va.?? */ -#define scBits 8 /* this is a bit field */ -#define scCdbSystem 9 /* variable's value is IN CDB's address space */ -#define scDbx 9 /* overlap dbx internal use */ -#define scRegImage 10 /* register value saved on stack */ -#define scInfo 11 /* symbol contains debugger information */ -#define scUserStruct 12 /* address in struct user for current process */ -#define scSData 13 /* load time only small data */ -#define scSBss 14 /* load time only small common */ -#define scRData 15 /* load time only read only data */ -#define scVar 16 /* Var parameter (fortran,pascal) */ -#define scCommon 17 /* common variable */ -#define scSCommon 18 /* small common */ -#define scVarRegister 19 /* Var parameter in a register */ -#define scVariant 20 /* Variant record */ -#define scSUndefined 21 /* small undefined(external) data */ -#define scInit 22 /* .init section symbol */ -#define scBasedVar 23 /* Fortran or PL/1 ptr based var */ -#define scXData 24 /* exception handling data */ -#define scPData 25 /* Procedure section */ -#define scFini 26 /* .fini section */ -#define scRConst 27 /* .rconst section */ -#define scMax 32 - - -/* - * Symbol Types - */ - -#define stNil 0 /* Nuthin' special */ -#define stGlobal 1 /* external symbol */ -#define stStatic 2 /* static */ -#define stParam 3 /* procedure argument */ -#define stLocal 4 /* local variable */ -#define stLabel 5 /* label */ -#define stProc 6 /* " " Procedure */ -#define stBlock 7 /* beginnning of block */ -#define stEnd 8 /* end (of anything) */ -#define stMember 9 /* member (of anything - struct/union/enum */ -#define stTypedef 10 /* type definition */ -#define stFile 11 /* file name */ -#define stRegReloc 12 /* register relocation */ -#define stForward 13 /* forwarding address */ -#define stStaticProc 14 /* load time only static procs */ -#define stConstant 15 /* const */ -#define stStaParam 16 /* Fortran static parameters */ - /* These new symbol types have been recently added to SGI machines. */ -#define stStruct 26 /* Beginning of block defining a struct type */ -#define stUnion 27 /* Beginning of block defining a union type */ -#define stEnum 28 /* Beginning of block defining an enum type */ -#define stIndirect 34 /* Indirect type specification */ - /* Pseudo-symbols - internal to debugger */ -#define stStr 60 /* string */ -#define stNumber 61 /* pure number (ie. 4 NOR 2+2) */ -#define stExpr 62 /* 2+2 vs. 4 */ -#define stType 63 /* post-coersion SER */ -#define stMax 64 - -/* definitions for fields in TIR */ - -/* type qualifiers for ti.tq0 -> ti.(itqMax-1) */ -#define tqNil 0 /* bt is what you see */ -#define tqPtr 1 /* pointer */ -#define tqProc 2 /* procedure */ -#define tqArray 3 /* duh */ -#define tqFar 4 /* longer addressing - 8086/8 land */ -#define tqVol 5 /* volatile */ -#define tqConst 6 /* const */ -#define tqMax 8 - -/* basic types as seen in ti.bt */ -#define btNil 0 /* undefined (also, enum members) */ -#define btAdr 1 /* address - integer same size as pointer */ -#define btChar 2 /* character */ -#define btUChar 3 /* unsigned character */ -#define btShort 4 /* short */ -#define btUShort 5 /* unsigned short */ -#define btInt 6 /* int */ -#define btUInt 7 /* unsigned int */ -#define btLong 8 /* long */ -#define btULong 9 /* unsigned long */ -#define btFloat 10 /* float (real) */ -#define btDouble 11 /* Double (real) */ -#define btStruct 12 /* Structure (Record) */ -#define btUnion 13 /* Union (variant) */ -#define btEnum 14 /* Enumerated */ -#define btTypedef 15 /* defined via a typedef, isymRef points */ -#define btRange 16 /* subrange of int */ -#define btSet 17 /* pascal sets */ -#define btComplex 18 /* fortran complex */ -#define btDComplex 19 /* fortran double complex */ -#define btIndirect 20 /* forward or unnamed typedef */ -#define btFixedDec 21 /* Fixed Decimal */ -#define btFloatDec 22 /* Float Decimal */ -#define btString 23 /* Varying Length Character String */ -#define btBit 24 /* Aligned Bit String */ -#define btPicture 25 /* Picture */ -#define btVoid 26 /* void */ -#define btLongLong 27 /* long long */ -#define btULongLong 28 /* unsigned long long */ -#define btMax 64 diff --git a/base/loader/ecoff_object.cc b/base/loader/ecoff_object.cc deleted file mode 100644 index 353a5f333..000000000 --- a/base/loader/ecoff_object.cc +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include <string> - -#include "base/loader/ecoff_object.hh" - -#include "mem/functional/functional.hh" -#include "base/loader/symtab.hh" - -#include "base/trace.hh" // for DPRINTF - -#include "base/loader/exec_ecoff.h" -#include "base/loader/coff_sym.h" -#include "base/loader/coff_symconst.h" - -using namespace std; - -ObjectFile * -EcoffObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data) -{ - if (((ecoff_filehdr *)data)->f_magic == ECOFF_MAGIC_ALPHA) { - // it's Alpha ECOFF - return new EcoffObject(fname, fd, len, data, - ObjectFile::Alpha, ObjectFile::Tru64); - } - else { - return NULL; - } -} - - -EcoffObject::EcoffObject(const string &_filename, int _fd, - size_t _len, uint8_t *_data, - Arch _arch, OpSys _opSys) - : ObjectFile(_filename, _fd, _len, _data, _arch, _opSys) -{ - execHdr = (ecoff_exechdr *)fileData; - fileHdr = &(execHdr->f); - aoutHdr = &(execHdr->a); - - entry = aoutHdr->entry; - - text.baseAddr = aoutHdr->text_start; - text.size = aoutHdr->tsize; - - data.baseAddr = aoutHdr->data_start; - data.size = aoutHdr->dsize; - - bss.baseAddr = aoutHdr->bss_start; - bss.size = aoutHdr->bsize; - - DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n", - text.baseAddr, text.size, data.baseAddr, data.size, - bss.baseAddr, bss.size); -} - - -bool -EcoffObject::loadSections(FunctionalMemory *mem, bool loadPhys) -{ - Addr textAddr = text.baseAddr; - Addr dataAddr = data.baseAddr; - - if (loadPhys) { - textAddr &= (ULL(1) << 40) - 1; - dataAddr &= (ULL(1) << 40) - 1; - } - - // Since we don't really have an MMU and all memory is - // zero-filled, there's no need to set up the BSS segment. - mem->prot_write(textAddr, fileData + ECOFF_TXTOFF(execHdr), text.size); - mem->prot_write(dataAddr, fileData + ECOFF_DATOFF(execHdr), data.size); - - return true; -} - - -bool -EcoffObject::loadGlobalSymbols(SymbolTable *symtab) -{ - if (!symtab) - return false; - - if (fileHdr->f_magic != ECOFF_MAGIC_ALPHA) { - warn("loadGlobalSymbols: wrong magic on %s\n", filename); - return false; - } - - ecoff_symhdr *syms = (ecoff_symhdr *)(fileData + fileHdr->f_symptr); - if (syms->magic != magicSym2) { - warn("loadGlobalSymbols: bad symbol header magic on %s\n", filename); - return false; - } - - ecoff_extsym *ext_syms = (ecoff_extsym *)(fileData + syms->cbExtOffset); - - char *ext_strings = (char *)(fileData + syms->cbSsExtOffset); - for (int i = 0; i < syms->iextMax; i++) { - ecoff_sym *entry = &(ext_syms[i].asym); - if (entry->iss != -1) - symtab->insert(entry->value, ext_strings + entry->iss); - } - - return true; -} - -bool -EcoffObject::loadLocalSymbols(SymbolTable *symtab) -{ - if (!symtab) - return false; - - if (fileHdr->f_magic != ECOFF_MAGIC_ALPHA) { - warn("loadGlobalSymbols: wrong magic on %s\n", filename); - return false; - } - - ecoff_symhdr *syms = (ecoff_symhdr *)(fileData + fileHdr->f_symptr); - if (syms->magic != magicSym2) { - warn("loadGlobalSymbols: bad symbol header magic on %s\n", filename); - return false; - } - - ecoff_sym *local_syms = (ecoff_sym *)(fileData + syms->cbSymOffset); - char *local_strings = (char *)(fileData + syms->cbSsOffset); - ecoff_fdr *fdesc = (ecoff_fdr *)(fileData + syms->cbFdOffset); - - for (int i = 0; i < syms->ifdMax; i++) { - ecoff_sym *entry = (ecoff_sym *)(local_syms + fdesc[i].isymBase); - char *strings = (char *)(local_strings + fdesc[i].issBase); - for (int j = 0; j < fdesc[i].csym; j++) { - if (entry[j].st == stGlobal || entry[j].st == stProc) - if (entry[j].iss != -1) - symtab->insert(entry[j].value, strings + entry[j].iss); - } - } - - for (int i = 0; i < syms->isymMax; i++) { - ecoff_sym *entry = &(local_syms[i]); - if (entry->st == stProc) - symtab->insert(entry->value, local_strings + entry->iss); - } - - return true; -} diff --git a/base/loader/ecoff_object.hh b/base/loader/ecoff_object.hh deleted file mode 100644 index 78aa7f3f7..000000000 --- a/base/loader/ecoff_object.hh +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __ECOFF_OBJECT_HH__ -#define __ECOFF_OBJECT_HH__ - -#include "base/loader/object_file.hh" - -// forward decls: avoid including exec_ecoff.h here -struct ecoff_exechdr; -struct ecoff_filehdr; -struct ecoff_aouthdr; - -class EcoffObject : public ObjectFile -{ - protected: - ecoff_exechdr *execHdr; - ecoff_filehdr *fileHdr; - ecoff_aouthdr *aoutHdr; - - EcoffObject(const std::string &_filename, int _fd, - size_t _len, uint8_t *_data, - Arch _arch, OpSys _opSys); - - public: - virtual ~EcoffObject() {} - - virtual bool loadSections(FunctionalMemory *mem, - bool loadPhys = false); - virtual bool loadGlobalSymbols(SymbolTable *symtab); - virtual bool loadLocalSymbols(SymbolTable *symtab); - - static ObjectFile *tryFile(const std::string &fname, int fd, - size_t len, uint8_t *data); -}; - -#endif // __ECOFF_OBJECT_HH__ diff --git a/base/loader/elf_object.cc b/base/loader/elf_object.cc deleted file mode 100644 index 791c6f6de..000000000 --- a/base/loader/elf_object.cc +++ /dev/null @@ -1,331 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include <string> - -// Because of the -Wundef flag we have to do this -#define __LIBELF_INTERNAL__ 0 -// counterintuitive, but the flag below causes libelf to define -// 64-bit elf types that apparently didn't exist in some older -// versions of Linux. They seem to be there in 2.4.x, so don't -// set this now (it causes things to break on 64-bit platforms). -#define __LIBELF64_LINUX 0 -#define __LIBELF_NEED_LINK_H 0 -#define __LIBELF_SYMBOL_VERSIONS 0 - -#include "libelf/libelf.h" -#include "libelf/gelf.h" - -#include "base/loader/elf_object.hh" - -#include "mem/functional/functional.hh" -#include "base/loader/symtab.hh" - -#include "base/trace.hh" // for DPRINTF - - -using namespace std; - -ObjectFile * -ElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data) -{ - Elf *elf; - GElf_Ehdr ehdr; - Arch arch = UnknownArch; - OpSys opSys = UnknownOpSys; - - // check that header matches library version - if (elf_version(EV_CURRENT) == EV_NONE) - panic("wrong elf version number!"); - - // get a pointer to elf structure - elf = elf_memory((char*)data,len); - // will only fail if fd is invalid - assert(elf != NULL); - - // Check that we actually have a elf file - if (gelf_getehdr(elf, &ehdr) ==0) { - DPRINTFR(Loader, "Not ELF\n"); - elf_end(elf); - return NULL; - } - else { - //Detect the architecture - //Versioning issues in libelf need to be resolved to get the correct - //SPARC constants. - //If MIPS supports 32 bit executables, this may need to be changed. - //Also, there are other MIPS constants which may be used, like - //EM_MIPS_RS3_LE and EM_MIPS_X - //Since we don't know how to check for alpha right now, we'll - //just assume if it wasn't something else and it's 64 bit, that's - //what it must be. - if (ehdr.e_machine == EM_SPARC64 || - ehdr.e_machine == EM_SPARC || - ehdr.e_machine == EM_SPARCV9) { - arch = ObjectFile::SPARC; - } else if (ehdr.e_machine == EM_MIPS - && ehdr.e_ident[EI_CLASS] == ELFCLASS32) { - arch = ObjectFile::MIPS; - } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) { - arch = ObjectFile::Alpha; - } else { - arch = ObjectFile::UnknownArch; - } - - //Detect the operating system - switch (ehdr.e_ident[EI_OSABI]) - { - - case ELFOSABI_LINUX: - opSys = ObjectFile::Linux; - break; - case ELFOSABI_SOLARIS: - opSys = ObjectFile::Solaris; - break; - case ELFOSABI_TRU64: - opSys = ObjectFile::Tru64; - break; - default: - opSys = ObjectFile::UnknownOpSys; - } - - //take a look at the .note.ABI section - //It can let us know what's what. - if (opSys == ObjectFile::UnknownOpSys) - { - Elf_Scn *section; - GElf_Shdr shdr; - Elf_Data *data; - uint32_t osAbi;; - int secIdx = 1; - - // Get the first section - section = elf_getscn(elf, secIdx); - - // While there are no more sections - while (section != NULL) { - gelf_getshdr(section, &shdr); - if (shdr.sh_type == SHT_NOTE && !strcmp(".note.ABI-tag", - elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) { - // we have found a ABI note section - // Check the 5th 32bit word for OS 0 == linux, 1 == hurd, - // 2 == solaris, 3 == freebsd - data = elf_rawdata(section, NULL); - assert(data->d_buf); - if(ehdr.e_ident[EI_DATA] == ELFDATA2LSB) - osAbi = htole(((uint32_t*)data->d_buf)[4]); - else - osAbi = htobe(((uint32_t*)data->d_buf)[4]); - - switch(osAbi) { - case 0: - opSys = ObjectFile::Linux; - break; - case 2: - opSys = ObjectFile::Solaris; - break; - } - } // if section found - section = elf_getscn(elf, ++secIdx); - } // while sections - } - elf_end(elf); - return new ElfObject(fname, fd, len, data, arch, opSys); - } -} - - -ElfObject::ElfObject(const string &_filename, int _fd, - size_t _len, uint8_t *_data, - Arch _arch, OpSys _opSys) - : ObjectFile(_filename, _fd, _len, _data, _arch, _opSys) - -{ - Elf *elf; - GElf_Ehdr ehdr; - - // check that header matches library version - if (elf_version(EV_CURRENT) == EV_NONE) - panic("wrong elf version number!"); - - // get a pointer to elf structure - elf = elf_memory((char*)fileData,len); - // will only fail if fd is invalid - assert(elf != NULL); - - // Check that we actually have a elf file - if (gelf_getehdr(elf, &ehdr) ==0) { - panic("Not ELF, shouldn't be here"); - } - - entry = ehdr.e_entry; - - // initialize segment sizes to 0 in case they're not present - text.size = data.size = bss.size = 0; - - for (int i = 0; i < ehdr.e_phnum; ++i) { - GElf_Phdr phdr; - if (gelf_getphdr(elf, i, &phdr) == 0) { - panic("gelf_getphdr failed for section %d", i); - } - - // for now we don't care about non-loadable segments - if (!(phdr.p_type & PT_LOAD)) - continue; - - // the headers don't explicitly distinguish text from data, - // but empirically the text segment comes first. - if (text.size == 0) { // haven't seen text segment yet - text.baseAddr = phdr.p_vaddr; - text.size = phdr.p_filesz; - // remember where the data is for loadSections() - fileTextBits = fileData + phdr.p_offset; - // if there's any padding at the end that's not in the - // file, call it the bss. This happens in the "text" - // segment if there's only one loadable segment (as for - // kernel images). - bss.size = phdr.p_memsz - phdr.p_filesz; - bss.baseAddr = phdr.p_vaddr + phdr.p_filesz; - } - else if (data.size == 0) { // have text, this must be data - data.baseAddr = phdr.p_vaddr; - data.size = phdr.p_filesz; - // remember where the data is for loadSections() - fileDataBits = fileData + phdr.p_offset; - // if there's any padding at the end that's not in the - // file, call it the bss. Warn if this happens for both - // the text & data segments (should only have one bss). - if (phdr.p_memsz - phdr.p_filesz > 0 && bss.size != 0) { - warn("Two implied bss segments in file!\n"); - } - bss.size = phdr.p_memsz - phdr.p_filesz; - bss.baseAddr = phdr.p_vaddr + phdr.p_filesz; - } - } - - // should have found at least one loadable segment - assert(text.size != 0); - - DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n", - text.baseAddr, text.size, data.baseAddr, data.size, - bss.baseAddr, bss.size); - - elf_end(elf); - - // We will actually read the sections when we need to load them -} - - -bool -ElfObject::loadSections(FunctionalMemory *mem, bool loadPhys) -{ - Addr textAddr = text.baseAddr; - Addr dataAddr = data.baseAddr; - - if (loadPhys) { - textAddr &= (ULL(1) << 40) - 1; - dataAddr &= (ULL(1) << 40) - 1; - } - - // Since we don't really have an MMU and all memory is - // zero-filled, there's no need to set up the BSS segment. - if (text.size != 0) - mem->prot_write(textAddr, fileTextBits, text.size); - if (data.size != 0) - mem->prot_write(dataAddr, fileDataBits, data.size); - - return true; -} - - -bool -ElfObject::loadSomeSymbols(SymbolTable *symtab, int binding) -{ - Elf *elf; - int sec_idx = 1; // there is a 0 but it is nothing, go figure - Elf_Scn *section; - GElf_Shdr shdr; - Elf_Data *data; - int count, ii; - bool found = false; - GElf_Sym sym; - - if (!symtab) - return false; - - // check that header matches library version - if (elf_version(EV_CURRENT) == EV_NONE) - panic("wrong elf version number!"); - - // get a pointer to elf structure - elf = elf_memory((char*)fileData,len); - - assert(elf != NULL); - - // Get the first section - section = elf_getscn(elf, sec_idx); - - // While there are no more sections - while (section != NULL) { - gelf_getshdr(section, &shdr); - - if (shdr.sh_type == SHT_SYMTAB) { - found = true; - data = elf_getdata(section, NULL); - count = shdr.sh_size / shdr.sh_entsize; - DPRINTF(Loader, "Found Symbol Table, %d symbols present\n", count); - - // loop through all the symbols, only loading global ones - for (ii = 0; ii < count; ++ii) { - gelf_getsym(data, ii, &sym); - if (GELF_ST_BIND(sym.st_info) == binding) { - symtab->insert(sym.st_value, - elf_strptr(elf, shdr.sh_link, sym.st_name)); - } - } - } - ++sec_idx; - section = elf_getscn(elf, sec_idx); - } - - elf_end(elf); - - return found; -} - -bool -ElfObject::loadGlobalSymbols(SymbolTable *symtab) -{ - return loadSomeSymbols(symtab, STB_GLOBAL); -} - -bool -ElfObject::loadLocalSymbols(SymbolTable *symtab) -{ - return loadSomeSymbols(symtab, STB_LOCAL); -} diff --git a/base/loader/elf_object.hh b/base/loader/elf_object.hh deleted file mode 100644 index 66d8b3e63..000000000 --- a/base/loader/elf_object.hh +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __ELF_OBJECT_HH__ -#define __ELF_OBJECT_HH__ - -#include "base/loader/object_file.hh" - -class ElfObject : public ObjectFile -{ - protected: - - uint8_t *fileTextBits; //!< Pointer to file's text segment image - uint8_t *fileDataBits; //!< Pointer to file's data segment image - - /// Helper functions for loadGlobalSymbols() and loadLocalSymbols(). - bool loadSomeSymbols(SymbolTable *symtab, int binding); - - ElfObject(const std::string &_filename, int _fd, - size_t _len, uint8_t *_data, - Arch _arch, OpSys _opSys); - - public: - virtual ~ElfObject() {} - - virtual bool loadSections(FunctionalMemory *mem, - bool loadPhys = false); - virtual bool loadGlobalSymbols(SymbolTable *symtab); - virtual bool loadLocalSymbols(SymbolTable *symtab); - - static ObjectFile *tryFile(const std::string &fname, int fd, - size_t len, uint8_t *data); -}; - -#endif // __ELF_OBJECT_HH__ diff --git a/base/loader/object_file.cc b/base/loader/object_file.cc deleted file mode 100644 index 1410d05b8..000000000 --- a/base/loader/object_file.cc +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2002-2004 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. - */ - -#include <list> -#include <string> - -#include <sys/types.h> -#include <sys/mman.h> -#include <fcntl.h> -#include <stdio.h> -#include <unistd.h> - -#include "base/cprintf.hh" -#include "base/loader/object_file.hh" -#include "base/loader/symtab.hh" - -#include "base/loader/ecoff_object.hh" -#include "base/loader/aout_object.hh" -#include "base/loader/elf_object.hh" - -using namespace std; - -ObjectFile::ObjectFile(const string &_filename, int _fd, - size_t _len, uint8_t *_data, - Arch _arch, OpSys _opSys) - : filename(_filename), descriptor(_fd), fileData(_data), len(_len), - arch(_arch), opSys(_opSys) -{ -} - - -ObjectFile::~ObjectFile() -{ - close(); -} - - -void -ObjectFile::close() -{ - if (descriptor >= 0) { - ::close(descriptor); - descriptor = -1; - } - - if (fileData) { - ::munmap(fileData, len); - fileData = NULL; - } -} - - -ObjectFile * -createObjectFile(const string &fname) -{ - // open the file - int fd = open(fname.c_str(), O_RDONLY); - if (fd < 0) { - return NULL; - } - - // find the length of the file by seeking to the end - size_t len = (size_t)lseek(fd, 0, SEEK_END); - - // mmap the whole shebang - uint8_t *fileData = - (uint8_t *)mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0); - if (fileData == MAP_FAILED) { - close(fd); - return NULL; - } - - ObjectFile *fileObj = NULL; - - // figure out what we have here - if ((fileObj = EcoffObject::tryFile(fname, fd, len, fileData)) != NULL) { - return fileObj; - } - - if ((fileObj = AoutObject::tryFile(fname, fd, len, fileData)) != NULL) { - return fileObj; - } - - if ((fileObj = ElfObject::tryFile(fname, fd, len, fileData)) != NULL) { - return fileObj; - } - - // don't know what it is - close(fd); - munmap(fileData, len); - return NULL; -} diff --git a/base/loader/object_file.hh b/base/loader/object_file.hh deleted file mode 100644 index 1b44ae14f..000000000 --- a/base/loader/object_file.hh +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2002-2004 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. - */ - -#ifndef __OBJECT_FILE_HH__ -#define __OBJECT_FILE_HH__ - -#include <string> - -#include "sim/host.hh" // for Addr - -class FunctionalMemory; -class SymbolTable; - -class ObjectFile -{ - public: - - enum Arch { - UnknownArch, - Alpha, - SPARC, - MIPS - }; - - enum OpSys { - UnknownOpSys, - Tru64, - Linux, - Solaris - }; - - protected: - const std::string filename; - int descriptor; - uint8_t *fileData; - size_t len; - - Arch arch; - OpSys opSys; - - ObjectFile(const std::string &_filename, int _fd, - size_t _len, uint8_t *_data, - Arch _arch, OpSys _opSys); - - public: - virtual ~ObjectFile(); - - void close(); - - virtual bool loadSections(FunctionalMemory *mem, - bool loadPhys = false) = 0; - virtual bool loadGlobalSymbols(SymbolTable *symtab) = 0; - virtual bool loadLocalSymbols(SymbolTable *symtab) = 0; - - Arch getArch() const { return arch; } - OpSys getOpSys() const { return opSys; } - - protected: - - struct Section { - Addr baseAddr; - size_t size; - }; - - Addr entry; - Addr globalPtr; - - Section text; - Section data; - Section bss; - - public: - Addr entryPoint() const { return entry; } - Addr globalPointer() const { return globalPtr; } - - Addr textBase() const { return text.baseAddr; } - Addr dataBase() const { return data.baseAddr; } - Addr bssBase() const { return bss.baseAddr; } - - size_t textSize() const { return text.size; } - size_t dataSize() const { return data.size; } - size_t bssSize() const { return bss.size; } -}; - -ObjectFile *createObjectFile(const std::string &fname); - - -#endif // __OBJECT_FILE_HH__ diff --git a/base/loader/symtab.cc b/base/loader/symtab.cc deleted file mode 100644 index 25f54f9bf..000000000 --- a/base/loader/symtab.cc +++ /dev/null @@ -1,137 +0,0 @@ -/* - * 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. - */ - -#include <iostream> -#include <fstream> -#include <string> -#include <vector> - -#include "base/loader/symtab.hh" -#include "base/misc.hh" -#include "base/str.hh" -#include "sim/host.hh" -#include "sim/serialize.hh" - -using namespace std; - -SymbolTable *debugSymbolTable = NULL; - -void -SymbolTable::clear() -{ - addrTable.clear(); - symbolTable.clear(); -} - -bool -SymbolTable::insert(Addr address, string symbol) -{ - if (symbol.empty()) - return false; - - if (!addrTable.insert(make_pair(address, symbol)).second) - return false; - - if (!symbolTable.insert(make_pair(symbol, address)).second) - return false; - - return true; -} - - -bool -SymbolTable::load(const string &filename) -{ - string buffer; - ifstream file(filename.c_str()); - - if (!file) - fatal("file error: Can't open symbol table file %s\n", filename); - - while (!file.eof()) { - getline(file, buffer); - if (buffer.empty()) - continue; - - int idx = buffer.find(','); - if (idx == string::npos) - return false; - - string address = buffer.substr(0, idx); - eat_white(address); - if (address.empty()) - return false; - - string symbol = buffer.substr(idx + 1); - eat_white(symbol); - if (symbol.empty()) - return false; - - Addr addr; - if (!to_number(address, addr)) - return false; - - if (!insert(addr, symbol)) - return false; - } - - file.close(); - - return true; -} - -void -SymbolTable::serialize(const string &base, ostream &os) -{ - paramOut(os, base + ".size", addrTable.size()); - - int i = 0; - ATable::const_iterator p, end = addrTable.end(); - for (p = addrTable.begin(); p != end; ++p) { - paramOut(os, csprintf("%s.addr_%d", base, i), p->first); - paramOut(os, csprintf("%s.symbol_%d", base, i), p->second); - ++i; - } -} - -void -SymbolTable::unserialize(const string &base, Checkpoint *cp, - const string §ion) -{ - clear(); - int size; - paramIn(cp, section, base + ".size", size); - for (int i = 0; i < size; ++i) { - Addr addr; - std::string symbol; - - paramIn(cp, section, csprintf("%s.addr_%d", base, i), addr); - paramIn(cp, section, csprintf("%s.symbol_%d", base, i), symbol); - insert(addr, symbol); - } -} diff --git a/base/loader/symtab.hh b/base/loader/symtab.hh deleted file mode 100644 index ebcda1345..000000000 --- a/base/loader/symtab.hh +++ /dev/null @@ -1,173 +0,0 @@ -/* - * 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. - */ - -#ifndef __SYMTAB_HH__ -#define __SYMTAB_HH__ - -#include <iosfwd> -#include <map> - -#include "arch/isa_traits.hh" // for Addr - -class Checkpoint; -class SymbolTable -{ - public: - typedef std::map<Addr, std::string> ATable; - typedef std::map<std::string, Addr> STable; - - private: - ATable addrTable; - STable symbolTable; - - private: - bool - upperBound(Addr addr, ATable::const_iterator &iter) const - { - // find first key *larger* than desired address - iter = addrTable.upper_bound(addr); - - // if very first key is larger, we're out of luck - if (iter == addrTable.begin()) - return false; - - return true; - } - - public: - SymbolTable() {} - SymbolTable(const std::string &file) { load(file); } - ~SymbolTable() {} - - void clear(); - bool insert(Addr address, std::string symbol); - bool load(const std::string &file); - - const ATable &getAddrTable() const { return addrTable; } - const STable &getSymbolTable() const { return symbolTable; } - - public: - void serialize(const std::string &base, std::ostream &os); - void unserialize(const std::string &base, Checkpoint *cp, - const std::string §ion); - - public: - bool - findSymbol(Addr address, std::string &symbol) const - { - ATable::const_iterator i = addrTable.find(address); - if (i == addrTable.end()) - return false; - - symbol = (*i).second; - return true; - } - - bool - findAddress(const std::string &symbol, Addr &address) const - { - STable::const_iterator i = symbolTable.find(symbol); - if (i == symbolTable.end()) - return false; - - address = (*i).second; - return true; - } - - /// Find the nearest symbol equal to or less than the supplied - /// address (e.g., the label for the enclosing function). - /// @param address The address to look up. - /// @param symbol Return reference for symbol string. - /// @param sym_address Return reference for symbol address. - /// @param next_sym_address Address of following symbol (for - /// determining valid range of symbol). - /// @retval True if a symbol was found. - bool - findNearestSymbol(Addr addr, std::string &symbol, Addr &symaddr, - Addr &nextaddr) const - { - ATable::const_iterator i; - if (!upperBound(addr, i)) - return false; - - nextaddr = i->first; - --i; - symaddr = i->first; - symbol = i->second; - return true; - } - - /// Overload for findNearestSymbol() for callers who don't care - /// about next_sym_address. - bool - findNearestSymbol(Addr addr, std::string &symbol, Addr &symaddr) const - { - ATable::const_iterator i; - if (!upperBound(addr, i)) - return false; - - --i; - symaddr = i->first; - symbol = i->second; - return true; - } - - - bool - findNearestAddr(Addr addr, Addr &symaddr, Addr &nextaddr) const - { - ATable::const_iterator i; - if (!upperBound(addr, i)) - return false; - - nextaddr = i->first; - --i; - symaddr = i->first; - return true; - } - - bool - findNearestAddr(Addr addr, Addr &symaddr) const - { - ATable::const_iterator i; - if (!upperBound(addr, i)) - return false; - - --i; - symaddr = i->first; - return true; - } -}; - -/// Global unified debugging symbol table (for target). Conceptually -/// there should be one of these per System object for full system, -/// and per Process object for non-full-system, but so far one big -/// global one has worked well enough. -extern SymbolTable *debugSymbolTable; - -#endif // __SYMTAB_HH__ diff --git a/base/match.cc b/base/match.cc deleted file mode 100644 index 4f1f49b57..000000000 --- a/base/match.cc +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "base/match.hh" -#include "base/str.hh" - -using namespace std; - -ObjectMatch::ObjectMatch() -{ -} - -ObjectMatch::ObjectMatch(const string &expr) -{ - setExpression(expr); -} - -void -ObjectMatch::setExpression(const string &expr) -{ - tokens.resize(1); - tokenize(tokens[0], expr, '.'); -} - -void -ObjectMatch::setExpression(const vector<string> &expr) -{ - if (expr.empty()) { - tokens.resize(0); - } else { - tokens.resize(expr.size()); - for (int i = 0; i < expr.size(); ++i) - tokenize(tokens[i], expr[i], '.'); - } -} - -/** - * @todo this should probably be changed to just use regular - * expression code - */ -bool -ObjectMatch::domatch(const string &name) const -{ - vector<string> name_tokens; - tokenize(name_tokens, name, '.'); - int ntsize = name_tokens.size(); - - int num_expr = tokens.size(); - for (int i = 0; i < num_expr; ++i) { - const vector<string> &token = tokens[i]; - int jstop = token.size(); - - bool match = true; - for (int j = 0; j < jstop; ++j) { - if (j >= ntsize) - break; - - const string &var = token[j]; - if (var != "*" && var != name_tokens[j]) { - match = false; - break; - } - } - - if (match == true) - return true; - } - - return false; -} - diff --git a/base/match.hh b/base/match.hh deleted file mode 100644 index 1b0a083a7..000000000 --- a/base/match.hh +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* @file - * User Console Definitions - */ - -#ifndef __BASE_MATCH_HH__ -#define __BASE_MATCH_HH__ - -#include <string> -#include <vector> - -class ObjectMatch -{ - protected: - std::vector<std::vector<std::string> > tokens; - bool domatch(const std::string &name) const; - - public: - ObjectMatch(); - ObjectMatch(const std::string &expression); - void setExpression(const std::string &expression); - void setExpression(const std::vector<std::string> &expression); - bool match(const std::string &name) const - { - return tokens.empty() ? false : domatch(name); - } -}; - -#endif // __BASE_MATCH_HH__ - diff --git a/base/misc.cc b/base/misc.cc deleted file mode 100644 index f3c86827b..000000000 --- a/base/misc.cc +++ /dev/null @@ -1,124 +0,0 @@ -/* - * 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. - */ - -#include <iostream> -#include <string> - -#include "base/cprintf.hh" -#include "base/hostinfo.hh" -#include "base/misc.hh" -#include "base/output.hh" -#include "base/trace.hh" -#include "sim/host.hh" -#include "sim/root.hh" - -using namespace std; - -void -__panic(const string &format, cp::ArgList &args, const char *func, - const char *file, int line) -{ - string fmt = "panic: " + format; - switch (fmt[fmt.size() - 1]) { - case '\n': - case '\r': - break; - default: - fmt += "\n"; - } - - fmt += " @ cycle %d\n[%s:%s, line %d]\n"; - - args.append(curTick); - args.append(func); - args.append(file); - args.append(line); - args.dump(cerr, fmt); - - delete &args; - - abort(); -} - -void -__fatal(const string &format, cp::ArgList &args, const char *func, - const char *file, int line) -{ - string fmt = "fatal: " + format; - - switch (fmt[fmt.size() - 1]) { - case '\n': - case '\r': - break; - default: - fmt += "\n"; - } - - fmt += " @ cycle %d\n[%s:%s, line %d]\n"; - fmt += "Memory Usage: %ld KBytes\n"; - - args.append(curTick); - args.append(func); - args.append(file); - args.append(line); - args.append(memUsage()); - args.dump(cerr, fmt); - - delete &args; - - exit(1); -} - -void -__warn(const string &format, cp::ArgList &args, const char *func, - const char *file, int line) -{ - string fmt = "warn: " + format; - - switch (fmt[fmt.size() - 1]) { - case '\n': - case '\r': - break; - default: - fmt += "\n"; - } - -#ifdef VERBOSE_WARN - fmt += " @ cycle %d\n[%s:%s, line %d]\n"; - args.append(curTick); - args.append(func); - args.append(file); - args.append(line); -#endif - - args.dump(cerr, fmt); - if (simout.isFile(*outputStream)) - args.dump(*outputStream, fmt); - - delete &args; -} diff --git a/base/misc.hh b/base/misc.hh deleted file mode 100644 index 9255c69c6..000000000 --- a/base/misc.hh +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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. - */ - -#ifndef __MISC_HH__ -#define __MISC_HH__ - -#include <assert.h> -#include "base/cprintf.hh" - -// -// This implements a cprintf based panic() function. panic() should -// be called when something happens that should never ever happen -// regardless of what the user does (i.e., an acutal m5 bug). panic() -// calls abort which can dump core or enter the debugger. -// -// -void __panic(const std::string&, cp::ArgList &, const char*, const char*, int) - __attribute__((noreturn)); -#define __panic__(format, args...) \ - __panic(format, (*(new cp::ArgList), args), \ - __FUNCTION__, __FILE__, __LINE__) -#define panic(args...) \ - __panic__(args, cp::ArgListNull()) - -// -// This implements a cprintf based fatal() function. fatal() should -// be called when the simulation cannot continue due to some condition -// that is the user's fault (bad configuration, invalid arguments, -// etc.) and not a simulator bug. fatal() calls exit(1), i.e., a -// "normal" exit with an error code, as opposed to abort() like -// panic() does. -// -void __fatal(const std::string&, cp::ArgList &, const char*, const char*, int) - __attribute__((noreturn)); -#define __fatal__(format, args...) \ - __fatal(format, (*(new cp::ArgList), args), \ - __FUNCTION__, __FILE__, __LINE__) -#define fatal(args...) \ - __fatal__(args, cp::ArgListNull()) - -// -// This implements a cprintf based warn -// -void __warn(const std::string&, cp::ArgList &, const char*, const char*, int); -#define __warn__(format, args...) \ - __warn(format, (*(new cp::ArgList), args), \ - __FUNCTION__, __FILE__, __LINE__) -#define warn(args...) \ - __warn__(args, cp::ArgListNull()) - -// -// assert() that prints out the current cycle -// -#define m5_assert(TEST) \ - if (!(TEST)) { \ - std::cerr << "Assertion failure, curTick = " << curTick << std::endl; \ - } \ - assert(TEST); - -#endif // __MISC_HH__ diff --git a/base/mod_num.hh b/base/mod_num.hh deleted file mode 100644 index fabbb56a9..000000000 --- a/base/mod_num.hh +++ /dev/null @@ -1,201 +0,0 @@ -/* - * 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. - */ - -template<class T, T MV> -class ModNum { - private: - T value; - - // Compiler should optimize this - void setValue(T n) { value = n % MV; } - - public: - ModNum() {} - ModNum(T n) { setValue(n); } - ModNum(const ModNum<T, MV> &n) : value(n.value) {} - - ModNum operator=(T n) { - setValue(n); - return *this; - } - - const ModNum operator=(ModNum n) { - value = n.value; - return *this; - } - - // Return the value if object used as RHS - operator T() const { return value; } - - // - // Operator "+=" - // - const ModNum<T, MV> operator+=(ModNum<T, MV> r) { - setValue(value + r.value); - return *this; - } - - const ModNum<T, MV> operator+=(T r) { - setValue(value + r); - return *this; - } - - // - // Operator "-=" - // - const ModNum<T, MV> operator-=(ModNum<T, MV> r) { - setValue(value - r.value); - return *this; - } - - const ModNum<T, MV> operator-=(T r) { - setValue(value - r); - return *this; - } - - // - // Operator "++" - // - // PREFIX (like ++a) - const ModNum<T, MV> operator++() { - *this += 1; - return *this; - } - - // POSTFIX (like a++) - const ModNum<T, MV> operator++(int) { - ModNum<T, MV> rv = *this; - - *this += 1; - - return rv; - } - - // - // Operator "--" - // - // PREFIX (like --a) - const ModNum<T, MV> operator--() { - *this -= 1; - return *this; - } - - // POSTFIX (like a--) - const ModNum<T, MV> operator--(int) { - ModNum<T, MV> rv = *this; - *this -= 1; - return rv; - } -}; - - -// -// Define operator "+" like this to avoid creating a temporary -// -template<class T, T MV> -inline ModNum<T, MV> -operator+(ModNum<T, MV> l, ModNum<T, MV> r) { - l += r; - return l; -} - -template<class T, T MV> -inline ModNum<T, MV> -operator+(ModNum<T, MV> l, T r) { - l += r; - return l; -} - -template<class T, T MV> -inline ModNum<T, MV> -operator+(T l, ModNum<T, MV> r) { - r += l; - return r; -} - - -// -// Define operator "-" like this to avoid creating a temporary -// -template<class T, T MV> -inline ModNum<T, MV> -operator-(ModNum<T, MV> l, ModNum<T, MV> r) { - l -= r; - return l; -} - -template<class T, T MV> -inline ModNum<T, MV> -operator-(ModNum<T, MV> l, T r) { - l -= r; - return l; -} - -template<class T, T MV> -inline ModNum<T, MV> -operator-(T l, ModNum<T, MV> r) { - r -= l; - return r; -} - - -// -// Comparison operators -// (all other cases are handled with conversons) -// -template<class T, T MV> -inline bool -operator<(ModNum<T, MV> l, ModNum<T, MV> r) { - return l.value < r.value; -} - -template<class T, T MV> -inline bool -operator>(ModNum<T, MV> l, ModNum<T, MV> r) { - return l.value > r.value; -} - -template<class T, T MV> -inline bool -operator==(ModNum<T, MV> l, ModNum<T, MV> r) { - return l.value == r.value; -} - -template<class T, T MV> -inline bool -operator<=(ModNum<T, MV> l, ModNum<T, MV> r) { - return l.value <= r.value; -} - -template<class T, T MV> -inline bool -operator>=(ModNum<T, MV> l, ModNum<T, MV> r) { - return l.value >= r.value; -} - - diff --git a/base/mysql.cc b/base/mysql.cc deleted file mode 100644 index c8d6e933a..000000000 --- a/base/mysql.cc +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <iostream> - -#include "base/mysql.hh" -#include "base/trace.hh" - -using namespace std; - -namespace MySQL { - -inline const char * -charstar(const string &string) -{ - return string.empty() ? NULL : string.c_str(); -} - -ostream & -operator<<(ostream &stream, const Error &error) -{ - stream << error.string(); - return stream; -} - -/* - * The connection class - */ -Connection::Connection() - : valid(false) -{ -} - -Connection::~Connection() -{ - if (valid) - close(); -} - - -bool -Connection::connect(const string &xhost, const string &xuser, - const string &xpasswd, const string &xdatabase) -{ - if (connected()) - return error.set("Already Connected"); - - _host = xhost; - _user = xuser; - _passwd = xpasswd; - _database = xdatabase; - - error.clear(); - - mysql_init(&mysql); - mysql_options(&mysql, MYSQL_OPT_COMPRESS, 0); // might want to be 1 - mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "odbc"); - if (!mysql_real_connect(&mysql, charstar(_host), charstar(_user), - charstar(_passwd), charstar(_database), - 0, NULL, 0)) - return error.set(mysql_error(&mysql)); - - valid = true; - return false; -} - -void -Connection::close() -{ - mysql_close(&mysql); -} - -bool -Connection::query(const string &sql) -{ - DPRINTF(SQL, "Sending SQL query to server:\n%s", sql); - error.clear(); - if (mysql_real_query(&mysql, sql.c_str(), sql.size())) - error.set(mysql_error(&mysql)); - - return error; -} - - -/* namespace MySQL */ } diff --git a/base/mysql.hh b/base/mysql.hh deleted file mode 100644 index ae28a9dfb..000000000 --- a/base/mysql.hh +++ /dev/null @@ -1,423 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __BASE_MYSQL_HH__ -#define __BASE_MYSQL_HH__ - -#define TO_BE_INCLUDED_LATER 0 - -#include <cassert> -#include <iosfwd> -#include <mysql_version.h> -#include <mysql.h> -#include <string> -#include <sstream> - -namespace MySQL { - -class Error -{ - protected: - const char *error; - - public: - Error() : error(NULL) {} - - Error &clear() { error = NULL; return *this; } - Error &set(const char *err) { error = err; return *this; } - - const char *string() const { return error; } - - operator bool() const { return error != NULL; } - bool operator!() const { return error == NULL; } -}; - -std::ostream &operator<<(std::ostream &stream, const Error &error); - -class Result -{ - private: - MYSQL_RES *result; - int *refcount; - - void - decref() - { - if (!refcount) - return; - - *refcount -= 1; - if (*refcount == 0) { - mysql_free_result(result); - delete refcount; - } - - refcount = NULL; - } - - public: - Result() - : result(0), refcount(NULL) - { } - - Result(MYSQL_RES *res) - : result(res) - { - if (result) - refcount = new int(1); - else - refcount = NULL; - } - - Result(const Result &result) - : result(result.result), refcount(result.refcount) - { - if (result) - *refcount += 1; - } - - ~Result() - { - decref(); - } - - const Result & - operator=(MYSQL_RES *res) - { - decref(); - result = res; - if (result) - refcount = new int(1); - - return *this; - } - - const Result & - operator=(const Result &res) - { - decref(); - result = res.result; - refcount = res.refcount; - if (result) - *refcount += 1; - - return *this; - } - - operator bool() const { return result != NULL; } - bool operator!() const { return result == NULL; } - - unsigned - num_fields() - { - assert(result); - return mysql_num_fields(result); - } - - MYSQL_ROW - fetch_row() - { - return mysql_fetch_row(result); - } - - unsigned long * - fetch_lengths() - { - return mysql_fetch_lengths(result); - } -}; - -typedef MYSQL_ROW Row; - -class Connection -{ - protected: - MYSQL mysql; - bool valid; - - protected: - std::string _host; - std::string _user; - std::string _passwd; - std::string _database; - - public: - Connection(); - virtual ~Connection(); - - bool connected() const { return valid; } - bool connect(const std::string &host, const std::string &user, - const std::string &passwd, const std::string &database); - void close(); - - public: - Error error; - operator MYSQL *() { return &mysql; } - - public: - bool query(const std::string &sql); - - bool - query(const std::stringstream &sql) - { - return query(sql.str()); - } - - bool - autocommit(bool mode) - { - return mysql_autocommit(&mysql, mode); - } - - bool - commit() - { - return mysql_commit(&mysql); - } - - bool - rollback() - { - return mysql_rollback(&mysql); - } - - unsigned - field_count() - { - return mysql_field_count(&mysql); - } - - unsigned - affected_rows() - { - return mysql_affected_rows(&mysql); - } - - unsigned - insert_id() - { - return mysql_insert_id(&mysql); - } - - - Result - store_result() - { - error.clear(); - Result result = mysql_store_result(&mysql); - if (!result) - error.set(mysql_error(&mysql)); - - return result; - } -}; - -#if 0 -class BindProxy -{ - MYSQL_BIND *bind; - BindProxy(MYSQL_BIND *b) : bind(b) {} - - void operator=(bool &buffer) - { - bind->buffer_type = MYSQL_TYPE_TINY; - bind->buffer = (char *)&buffer; - } - - void operator=(int8_t &buffer) - { - bind->buffer_type = MYSQL_TYPE_TINY; - bind->buffer = (char *)&buffer; - } - - void operator=(int16_t &buffer) - { - bind->buffer_type = MYSQL_TYPE_SHORT; - bind->buffer = (char *)&buffer; - } - - void operator=(int32_t &buffer) - { - bind->buffer_type = MYSQL_TYPE_LONG; - bind->buffer = (char *)&buffer; - } - - void operator=(int64_t &buffer) - { - bind->buffer_type = MYSQL_TYPE_LONGLONG; - bind->buffer = (char *)&buffer; - } - - void operator=(uint8_t &buffer) - { - bind->buffer_type = MYSQL_TYPE_TINY; - bind->buffer = (char *)&buffer; - } - - void operator=(uint16_t &buffer) - { - bind->buffer_type = MYSQL_TYPE_SHORT; - bind->buffer = (char *)&buffer; - } - - void operator=(uint32_t &buffer) - { - bind->buffer_type = MYSQL_TYPE_LONG; - bind->buffer = (char *)&buffer; - } - - void operator=(uint64_t &buffer) - { - bind->buffer_type = MYSQL_TYPE_LONGLONG; - bind->buffer = (char *)&buffer; - } - - void operator=(float &buffer) - { - bind->buffer_type = MYSQL_TYPE_FLOAT; - bind->buffer = (char *)&buffer; - } - - void operator=(double &buffer) - { - bind->buffer_type = MYSQL_TYPE_DOUBLE; - bind->buffer = (char *)&buffer; - } - - void operator=(Time &buffer) - { - bind->buffer_type = MYSQL_TYPE_DATE; - bind->buffer = (char *)&buffer; - } - - void operator=(const char *buffer) - { - bind->buffer_type = MYSQL_TYPE_VAR_STRING; - bind->buffer = buffer; - } - - void operator=(const std::string &buffer) - { - bind->buffer_type = MYSQL_TYPE_VAR_STRING; - bind->buffer = (char *)&buffer; - bind->length = buffer.length; - } - - bool - set_null(bool null) - { - bind->is_null = null; - } -}; - -class Statement -{ - protected: - Error &error; - MYSQL_STMT *stmt; - MYSQL_BIND *bind; - int size; - - public: - Statement(Connection &mysql) - : error(mysql.error), bind(NULL), size(0) - { - stmt = mysql_stmt_init(mysql); - assert(valid() && "mysql_stmt_init(), out of memory\n"); - } - - ~Statement() - { - assert(valid()); - error.clear(); - if (mysql_stmt_close(stmt)) - error.set(mysql_stmt_error(stmt)); - - if (bind) - delete [] bind; - } - - bool valid() - { - return stmt != NULL; - } - - void prepare(const std::string &query) - { - assert(valid()); - mysql.error.clear(); - if (mysql_stmt_prepare(mysql, query, strlen(query))) - mysql.error.set(mysql_stmt_error(stmt)); - - int size = count(); - bind = new MYSQL_BIND[size]; - } - - unsigned count() - { - assert(valid()); - return mysql_stmt_param_count(stmt); - } - - unsigned affected() - { - assert(valid()); - return mysql_stmt_affected_rows(stmt); - } - - void bind(MYSQL_BIND *bind) - { - mysql.error.clear(); - if (mysql_stmt_bind_param(stmt, bind)) - mysql.error.set(mysql_stmt_error(stmt)); - } - - BindProxy operator[](int index) - { - assert(index > 0 && index < N); - return &bind[N]; - } - - operator MYSQL_BIND *() - { - return bind; - } - - void operator()() - { - assert(valid()); - error.clear(); - if (mysql_stmt_execute(stmt)) - error.set(mysql_stmt_error(stmt)); - } -} -#endif - -/* namespace MySQL */ } - -#endif // __BASE_MYSQL_HH__ diff --git a/base/output.cc b/base/output.cc deleted file mode 100644 index 2b1733f21..000000000 --- a/base/output.cc +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include <errno.h> -#include <limits.h> -#include <stdlib.h> -#include <sys/stat.h> -#include <sys/types.h> - -#include <fstream> - -#include "base/misc.hh" -#include "base/output.hh" - -using namespace std; - -OutputDirectory simout; - -/** - * - */ -OutputDirectory::OutputDirectory() -{} - -OutputDirectory::~OutputDirectory() -{} - -void -OutputDirectory::setDirectory(const string &d) -{ - if (!dir.empty()) - panic("Output directory already set!\n"); - - dir = d; - - if (dir != ".") { - if (mkdir(dir.c_str(), 0777) < 0 && errno != EEXIST) - panic("couldn't make output dir %s: %s\n", - dir, strerror(errno)); - } - - // guarantee that directory ends with a '/' - if (dir[dir.size() - 1] != '/') - dir += "/"; -} - -const string & -OutputDirectory::directory() -{ - if (dir.empty()) - panic("Output directory not set!"); - - return dir; -} - -string -OutputDirectory::resolve(const string &name) -{ - return (name[0] != '/') ? dir + name : name; -} - -ostream * -OutputDirectory::create(const string &name) -{ - if (name == "cerr" || name == "stderr") - return &cerr; - - if (name == "cout" || name == "stdout") - return &cout; - - ofstream *file = new ofstream(resolve(name).c_str(), ios::trunc); - if (!file->is_open()) - panic("Cannot open file %s", name); - - return file; -} - -ostream * -OutputDirectory::find(const string &name) -{ - if (name == "cerr" || name == "stderr") - return &cerr; - - if (name == "cout" || name == "stdout") - return &cout; - - string filename = resolve(name); - map_t::iterator i = files.find(filename); - if (i != files.end()) - return (*i).second; - - ofstream *file = new ofstream(filename.c_str(), ios::trunc); - if (!file->is_open()) - panic("Cannot open file %s", filename); - - files[filename] = file; - return file; -} - -bool -OutputDirectory::isFile(const std::ostream *os) -{ - return os && os != &cerr && os != &cout; -} diff --git a/base/output.hh b/base/output.hh deleted file mode 100644 index 3bbe73e3b..000000000 --- a/base/output.hh +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __BASE_OUTPUT_HH__ -#define __BASE_OUTPUT_HH__ - -#include <iosfwd> -#include <map> -#include <string> - -class OutputDirectory -{ - private: - typedef std::map<std::string, std::ostream *> map_t; - - map_t files; - std::string dir; - - public: - OutputDirectory(); - ~OutputDirectory(); - - void setDirectory(const std::string &dir); - const std::string &directory(); - - std::string resolve(const std::string &name); - std::ostream *create(const std::string &name); - std::ostream *find(const std::string &name); - - static bool isFile(const std::ostream *os); - static inline bool isFile(const std::ostream &os) { return isFile(&os); } -}; - -extern OutputDirectory simout; - -#endif // __BASE_OUTPUT_HH__ diff --git a/base/pollevent.cc b/base/pollevent.cc deleted file mode 100644 index 99044fc09..000000000 --- a/base/pollevent.cc +++ /dev/null @@ -1,273 +0,0 @@ -/* - * 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. - */ - -#include <sys/ioctl.h> -#include <sys/types.h> - -#include <fcntl.h> -#include <signal.h> -#include <unistd.h> - -#include "sim/async.hh" -#include "sim/host.hh" -#include "base/misc.hh" -#include "base/pollevent.hh" -#include "sim/root.hh" -#include "sim/serialize.hh" - -using namespace std; - -PollQueue pollQueue; - -///////////////////////////////////////////////////// -// -PollEvent::PollEvent(int _fd, int _events) - : queue(NULL), enabled(true) -{ - pfd.fd = _fd; - pfd.events = _events; -} - -PollEvent::~PollEvent() -{ - if (queue) - queue->remove(this); -} - -void -PollEvent::disable() -{ - if (!enabled) return; - enabled = false; - - if (queue) - queue->copy(); -} - -void -PollEvent::enable() -{ - if (enabled) return; - enabled = true; - - if (queue) - queue->copy(); -} - -void -PollEvent::serialize(ostream &os) -{ - SERIALIZE_SCALAR(pfd.fd); - SERIALIZE_SCALAR(pfd.events); - SERIALIZE_SCALAR(enabled); -} - -void -PollEvent::unserialize(Checkpoint *cp, const std::string §ion) -{ - UNSERIALIZE_SCALAR(pfd.fd); - UNSERIALIZE_SCALAR(pfd.events); - UNSERIALIZE_SCALAR(enabled); -} - -///////////////////////////////////////////////////// -// -PollQueue::PollQueue() - : poll_fds(NULL), max_size(0), num_fds(0) -{ } - -PollQueue::~PollQueue() -{ - removeHandler(); - for (int i = 0; i < num_fds; i++) - setupAsyncIO(poll_fds[0].fd, false); - - delete [] poll_fds; -} - -void -PollQueue::copy() -{ - eventvec_t::iterator i = events.begin(); - eventvec_t::iterator end = events.end(); - - num_fds = 0; - - while (i < end) { - if ((*i)->enabled) - poll_fds[num_fds++] = (*i)->pfd; - ++i; - } -} - -void -PollQueue::remove(PollEvent *event) -{ - eventvec_t::iterator i = events.begin(); - eventvec_t::iterator end = events.end(); - - while (i < end) { - if (*i == event) { - events.erase(i); - copy(); - event->queue = NULL; - return; - } - - ++i; - } - - panic("Event does not exist. Cannot remove."); -} - -void -PollQueue::schedule(PollEvent *event) -{ - if (event->queue) - panic("Event already scheduled!"); - - event->queue = this; - events.push_back(event); - setupAsyncIO(event->pfd.fd, true); - - // if we ran out of space in the fd array, double the capacity - // if this is the first time that we've scheduled an event, create - // the array with an initial size of 16 - if (++num_fds > max_size) { - if (max_size > 0) { - delete [] poll_fds; - max_size *= 2; - } else { - max_size = 16; - setupHandler(); - } - - poll_fds = new pollfd[max_size]; - } - - copy(); -} - -void -PollQueue::service() -{ - int ret = poll(poll_fds, num_fds, 0); - - if (ret <= 0) - return; - - for (int i = 0; i < num_fds; i++) { - int revents = poll_fds[i].revents; - if (revents) { - events[i]->process(revents); - if (--ret <= 0) - break; - } - } -} - -struct sigaction PollQueue::oldio; -struct sigaction PollQueue::oldalrm; -bool PollQueue::handler = false; - -void -PollQueue::setupAsyncIO(int fd, bool set) -{ - int flags = fcntl(fd, F_GETFL); - if (flags == -1) - panic("Could not set up async IO"); - - if (set) - flags |= FASYNC; - else - flags &= ~(FASYNC); - - if (fcntl(fd, F_SETFL, flags) == -1) - panic("Could not set up async IO"); - - if (set) { - if (fcntl(fd, F_SETOWN, getpid()) == -1) - panic("Could not set up async IO"); - } -} - -void -PollQueue::setupHandler() -{ - struct sigaction act; - - act.sa_handler = handleIO; - sigemptyset(&act.sa_mask); - act.sa_flags = SA_RESTART; - - if (sigaction(SIGIO, &act, &oldio) == -1) - panic("could not do sigaction"); - - act.sa_handler = handleALRM; - sigemptyset(&act.sa_mask); - act.sa_flags = SA_RESTART; - - if (sigaction(SIGALRM, &act, &oldalrm) == -1) - panic("could not do sigaction"); - - alarm(1); - - handler = true; -} - -void -PollQueue::removeHandler() -{ - if (sigaction(SIGIO, &oldio, NULL) == -1) - panic("could not remove handler"); - - if (sigaction(SIGIO, &oldalrm, NULL) == -1) - panic("could not remove handler"); -} - -void -PollQueue::handleIO(int sig) -{ - if (sig != SIGIO) - panic("Wrong Handler"); - - async_event = true; - async_io = true; -} - -void -PollQueue::handleALRM(int sig) -{ - if (sig != SIGALRM) - panic("Wrong Handler"); - - async_event = true; - async_alarm = true; - alarm(1); -} - diff --git a/base/pollevent.hh b/base/pollevent.hh deleted file mode 100644 index d39931797..000000000 --- a/base/pollevent.hh +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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. - */ - -#ifndef __POLLEVENT_H__ -#define __POLLEVENT_H__ - -#include <vector> -#include <poll.h> -#include "sim/root.hh" - -class Checkpoint; -class PollQueue; - -class PollEvent -{ - private: - friend class PollQueue; - - protected: - pollfd pfd; - PollQueue *queue; - bool enabled; - - public: - PollEvent(int fd, int event); - virtual ~PollEvent(); - - void disable(); - void enable(); - virtual void process(int revent) = 0; - - bool queued() { return queue != 0; } - - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); -}; - -class PollQueue -{ - private: - typedef std::vector<PollEvent *> eventvec_t; - eventvec_t events; - - pollfd *poll_fds; - int max_size; - int num_fds; - - public: - PollQueue(); - ~PollQueue(); - - void copy(); - void remove(PollEvent *event); - void schedule(PollEvent *event); - void service(); - - protected: - static bool handler; - static struct sigaction oldio; - static struct sigaction oldalrm; - - public: - static void setupAsyncIO(int fd, bool set); - static void handleIO(int); - static void handleALRM(int); - static void removeHandler(); - static void setupHandler(); -}; - -extern PollQueue pollQueue; - -#endif // __POLLEVENT_H__ diff --git a/base/predictor.hh b/base/predictor.hh deleted file mode 100644 index 37aa29989..000000000 --- a/base/predictor.hh +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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. - */ - -// -// Abstract base class for a generic predictor -// -// - -#ifndef __PREDICTOR_HH__ -#define __PREDICTOR_HH__ - -class GenericPredictor { - - public: - virtual void clear() = 0; - - virtual unsigned predict(unsigned long _index) = 0; - virtual unsigned predict(unsigned long _index, unsigned &pdata) = 0; - - virtual unsigned peek(unsigned long _index) = 0; - - virtual void record(unsigned long _index, unsigned _actual_value, - unsigned _pred_value) = 0; - virtual void record(unsigned long _index, unsigned _actual_value, - unsigned _pred_value, unsigned _pdata) = 0; - - virtual unsigned value(unsigned long _index) = 0; - - virtual void regStats() = 0; - virtual void regFormulas() = 0; - - virtual ~GenericPredictor() {}; -}; - -#endif // __PREDICTOR_HH__ diff --git a/base/random.cc b/base/random.cc deleted file mode 100644 index 4aac14101..000000000 --- a/base/random.cc +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include <cstdlib> -#include <cmath> - -#include "sim/param.hh" -#include "base/random.hh" -#include "base/trace.hh" - -using namespace std; - -class RandomContext : public ParamContext -{ - public: - RandomContext(const string &_iniSection) - : ::ParamContext(_iniSection) {} - ~RandomContext() {} - - void checkParams(); -}; - -RandomContext paramContext("random"); - -Param<unsigned> -seed(¶mContext, "seed", "seed to random number generator", 1); - -void -RandomContext::checkParams() -{ - ::srand48(seed); -} - -long -getLong() -{ - return mrand48(); -} - -int64_t -getUniform(int64_t min, int64_t max) -{ - double r; - r = drand48() * (max-min) + min; - return (int64_t)round(r); -} - -uint64_t -getUniformPos(uint64_t min, uint64_t max) -{ - double r; - r = drand48() * (max-min) + min; - return (uint64_t)round(r); -} - - -// idea for generating a double from erand48 -double -getDouble() -{ - union { - uint32_t _long[2]; - uint16_t _short[4]; - }; - - _long[0] = mrand48(); - _long[1] = mrand48(); - - return ldexp((double) _short[0], -48) + - ldexp((double) _short[1], -32) + - ldexp((double) _short[2], -16); -} diff --git a/base/random.hh b/base/random.hh deleted file mode 100644 index def7a4bce..000000000 --- a/base/random.hh +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __BASE_RANDOM_HH__ -#define __BASE_RANDOM_HH__ - -#include "sim/host.hh" - -long getLong(); -double getDouble(); -uint64_t getUniformPos(uint64_t min, uint64_t max); -int64_t getUniform(int64_t min, int64_t max); - -template <typename T> -struct Random; - -template<> struct Random<int8_t> -{ - static int8_t get() - { return getLong() & (int8_t)-1; } - - static int8_t uniform(int8_t min, int8_t max) - { return getUniform(min, max); } -}; - -template<> struct Random<uint8_t> -{ - static uint8_t get() - { return getLong() & (uint8_t)-1; } - - static uint8_t uniform(uint8_t min, uint8_t max) - { return getUniformPos(min, max); } -}; - -template<> struct Random<int16_t> -{ - static int16_t get() - { return getLong() & (int16_t)-1; } - - static int16_t uniform(int16_t min, int16_t max) - { return getUniform(min, max); } -}; - -template<> struct Random<uint16_t> -{ - static uint16_t get() - { return getLong() & (uint16_t)-1; } - - static uint16_t uniform(uint16_t min, uint16_t max) - { return getUniformPos(min, max); } -}; - -template<> struct Random<int32_t> -{ - static int32_t get() - { return (int32_t)getLong(); } - - static int32_t uniform(int32_t min, int32_t max) - { return getUniform(min, max); } -}; - -template<> struct Random<uint32_t> -{ - static uint32_t get() - { return (uint32_t)getLong(); } - - static uint32_t uniform(uint32_t min, uint32_t max) - { return getUniformPos(min, max); } -}; - -template<> struct Random<int64_t> -{ - static int64_t get() - { return (int64_t)getLong() << 32 || (uint64_t)getLong(); } - - static int64_t uniform(int64_t min, int64_t max) - { return getUniform(min, max); } -}; - -template<> struct Random<uint64_t> -{ - static uint64_t get() - { return (uint64_t)getLong() << 32 || (uint64_t)getLong(); } - - static uint64_t uniform(uint64_t min, uint64_t max) - { return getUniformPos(min, max); } -}; - -template<> struct Random<float> -{ - static float get() - { return getDouble(); } -}; - -template<> struct Random<double> -{ - static double get() - { return getDouble(); } -}; - -#endif // __BASE_RANDOM_HH__ diff --git a/base/range.cc b/base/range.cc deleted file mode 100644 index a4e50fc4f..000000000 --- a/base/range.cc +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "base/intmath.hh" -#include "base/range.hh" -#include "base/str.hh" - -using namespace std; - -template <class T> -bool -__x_parse_range(const std::string &str, T &first, T &last) -{ - std::vector<std::string> values; - tokenize(values, str, ':'); - - T thefirst, thelast; - - if (values.size() != 2) - return false; - - std::string s = values[0]; - std::string e = values[1]; - - if (!to_number(s, thefirst)) - return false; - - bool increment = (e[0] == '+'); - if (increment) - e = e.substr(1); - - if (!to_number(e, thelast)) - return false; - - if (increment) - thelast += thefirst - 1; - - first = thefirst; - last = thelast; - - return true; -} - -#define RANGE_PARSE(type) \ -template<> bool \ -__parse_range(const std::string &s, type &first, type &last) \ -{ return __x_parse_range(s, first, last); } - -RANGE_PARSE(unsigned long long); -RANGE_PARSE(signed long long); -RANGE_PARSE(unsigned long); -RANGE_PARSE(signed long); -RANGE_PARSE(unsigned int); -RANGE_PARSE(signed int); -RANGE_PARSE(unsigned short); -RANGE_PARSE(signed short); -RANGE_PARSE(unsigned char); -RANGE_PARSE(signed char); diff --git a/base/range.hh b/base/range.hh deleted file mode 100644 index 4e3e0fd6e..000000000 --- a/base/range.hh +++ /dev/null @@ -1,355 +0,0 @@ -/* - * 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. - */ - -#ifndef __BASE_RANGE_HH__ -#define __BASE_RANGE_HH__ - -#include <cassert> -#include <iostream> -#include <string> - -/** - * @param s range string - * EndExclusive Ranges are in the following format: - * @verbatim - * <range> := {<start_val>}:{<end>} - * <start> := <end_val> | +<delta> - * @endverbatim - */ -template <class T> -bool __parse_range(const std::string &s, T &start, T &end); - -template <class T> -struct Range -{ - T start; - T end; - - Range() { invalidate(); } - - template <class U> - Range(const std::pair<U, U> &r) - : start(r.first), end(r.second) - {} - - template <class U> - Range(const Range<U> &r) - : start(r.start), end(r.end) - {} - - Range(const std::string &s) - { - if (!__parse_range(s, start, end)) - invalidate(); - } - - template <class U> - const Range<T> &operator=(const Range<U> &r) - { - start = r.start; - end = r.end; - return *this; - } - - template <class U> - const Range<T> &operator=(const std::pair<U, U> &r) - { - start = r.first; - end = r.second; - return *this; - } - - const Range &operator=(const std::string &s) - { - if (!__parse_range(s, start, end)) - invalidate(); - return *this; - } - - void invalidate() { start = 1; end = 0; } - T size() const { return end - start + 1; } - bool valid() const { return start < end; } -}; - -template <class T> -inline std::ostream & -operator<<(std::ostream &o, const Range<T> &r) -{ - o << '[' << r.start << "," << r.end << ']'; - return o; -} - -template <class T> -inline Range<T> -RangeEx(T start, T end) -{ return std::make_pair(start, end - 1); } - -template <class T> -inline Range<T> -RangeIn(T start, T end) -{ return std::make_pair(start, end); } - -template <class T, class U> -inline Range<T> -RangeSize(T start, U size) -{ return std::make_pair(start, start + size - 1); } - -//////////////////////////////////////////////////////////////////////// -// -// Range to Range Comparisons -// - -/** - * @param range1 is a range. - * @param range2 is a range. - * @return if range1 and range2 are identical. - */ -template <class T, class U> -inline bool -operator==(const Range<T> &range1, const Range<U> &range2) -{ - return range1.start == range2.start && range1.end == range2.end; -} - -/** - * @param range1 is a range. - * @param range2 is a range. - * @return if range1 and range2 are not identical. - */ -template <class T, class U> -inline bool -operator!=(const Range<T> &range1, const Range<U> &range2) -{ - return range1.start != range2.start || range1.end != range2.end; -} - -/** - * @param range1 is a range. - * @param range2 is a range. - * @return if range1 is less than range2 and does not overlap range1. - */ -template <class T, class U> -inline bool -operator<(const Range<T> &range1, const Range<U> &range2) -{ - return range1.start < range2.start; -} - -/** - * @param range1 is a range. - * @param range2 is a range. - * @return if range1 is less than range2. range1 may overlap range2, - * but not extend beyond the end of range2. - */ -template <class T, class U> -inline bool -operator<=(const Range<T> &range1, const Range<U> &range2) -{ - return range1.start <= range2.start; -} - -/** - * @param range1 is a range. - * @param range2 is a range. - * @return if range1 is greater than range2 and does not overlap range2. - */ -template <class T, class U> -inline bool -operator>(const Range<T> &range1, const Range<U> &range2) -{ - return range1.start > range2.start; -} - -/** - * @param range1 is a range. - * @param range2 is a range. - * @return if range1 is greater than range2. range1 may overlap range2, - * but not extend beyond the beginning of range2. - */ -template <class T, class U> -inline bool -operator>=(const Range<T> &range1, const Range<U> &range2) -{ - return range1.start >= range2.start; -} - -//////////////////////////////////////////////////////////////////////// -// -// Position to Range Comparisons -// - -/** - * @param pos position compared to the range. - * @param range range compared against. - * @return indicates that position pos is within the range. - */ -template <class T, class U> -inline bool -operator==(const T &pos, const Range<U> &range) -{ - return pos >= range.start && pos <= range.end; -} - -/** - * @param pos position compared to the range. - * @param range range compared against. - * @return indicates that position pos is not within the range. - */ -template <class T, class U> -inline bool -operator!=(const T &pos, const Range<U> &range) -{ - return pos < range.start || pos > range.end; -} - -/** - * @param pos position compared to the range. - * @param range range compared against. - * @return indicates that position pos is below the range. - */ -template <class T, class U> -inline bool -operator<(const T &pos, const Range<U> &range) -{ - return pos < range.start; -} - -/** - * @param pos position compared to the range. - * @param range range compared against. - * @return indicates that position pos is below or in the range. - */ -template <class T, class U> -inline bool -operator<=(const T &pos, const Range<U> &range) -{ - return pos <= range.end; -} - -/** - * @param pos position compared to the range. - * @param range range compared against. - * @return indicates that position pos is above the range. - */ -template <class T, class U> -inline bool -operator>(const T &pos, const Range<U> &range) -{ - return pos > range.end; -} - -/** - * @param pos position compared to the range. - * @param range range compared against. - * @return indicates that position pos is above or in the range. - */ -template <class T, class U> -inline bool -operator>=(const T &pos, const Range<U> &range) -{ - return pos >= range.start; -} - -//////////////////////////////////////////////////////////////////////// -// -// Range to Position Comparisons (for symmetry) -// - -/** - * @param range range compared against. - * @param pos position compared to the range. - * @return indicates that position pos is within the range. - */ -template <class T, class U> -inline bool -operator==(const Range<T> &range, const U &pos) -{ - return pos >= range.start && pos <= range.end; -} - -/** - * @param range range compared against. - * @param pos position compared to the range. - * @return indicates that position pos is not within the range. - */ -template <class T, class U> -inline bool -operator!=(const Range<T> &range, const U &pos) -{ - return pos < range.start || pos > range.end; -} - -/** - * @param range range compared against. - * @param pos position compared to the range. - * @return indicates that position pos is above the range. - */ -template <class T, class U> -inline bool -operator<(const Range<T> &range, const U &pos) -{ - return range.end < pos; -} - -/** - * @param range range compared against. - * @param pos position compared to the range. - * @return indicates that position pos is above or in the range. - */ -template <class T, class U> -inline bool -operator<=(const Range<T> &range, const U &pos) -{ - return range.start <= pos; -} - -/** - * @param range range compared against. - * @param pos position compared to the range. - * 'range > pos' indicates that position pos is below the range. - */ -template <class T, class U> -inline bool -operator>(const Range<T> &range, const U &pos) -{ - return range.start > pos; -} - -/** - * @param range range compared against. - * @param pos position compared to the range. - * 'range >= pos' indicates that position pos is below or in the range. - */ -template <class T, class U> -inline bool -operator>=(const Range<T> &range, const U &pos) -{ - return range.end >= pos; -} - -#endif // __BASE_RANGE_HH__ diff --git a/base/refcnt.hh b/base/refcnt.hh deleted file mode 100644 index de589f7c5..000000000 --- a/base/refcnt.hh +++ /dev/null @@ -1,123 +0,0 @@ -/* - * 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. - */ - -#ifndef __REFCNT_HH__ -#define __REFCNT_HH__ - -#include <stddef.h> //For the NULL macro definition - -class RefCounted -{ - private: - int count; - - private: - RefCounted(const RefCounted &); - - public: - RefCounted() : count(0) {} - virtual ~RefCounted() {} - - void incref() { ++count; } - void decref() { if (--count <= 0) delete this; } -}; - -template <class T> -class RefCountingPtr -{ - protected: - T *data; - - void copy(T *d) - { - data = d; - if (data) - data->incref(); - } - void del() - { - if (data) - data->decref(); - } - void set(T *d) - { - if (data == d) - return; - - del(); - copy(d); - } - - - public: - RefCountingPtr() : data(NULL) {} - RefCountingPtr(T *data) { copy(data); } - RefCountingPtr(const RefCountingPtr &r) { copy(r.data); } - ~RefCountingPtr() { del(); } - - T *operator->() { return data; } - T &operator*() { return *data; } - T *get() { return data; } - - const T *operator->() const { return data; } - const T &operator*() const { return *data; } - const T *get() const { return data; } - - RefCountingPtr &operator=(T *p) { set(p); return *this; } - RefCountingPtr &operator=(const RefCountingPtr &r) - { return operator=(r.data); } - - bool operator!() const { return data == 0; } - operator bool() const { return data != 0; } -}; - -template<class T> -bool operator==(const RefCountingPtr<T> &l, const RefCountingPtr<T> &r) -{ return l.get() == r.get(); } - -template<class T> -bool operator==(const RefCountingPtr<T> &l, const T *r) -{ return l.get() == r; } - -template<class T> -bool operator==(const T &l, const RefCountingPtr<T> &r) -{ return l == r.get(); } - -template<class T> -bool operator!=(const RefCountingPtr<T> &l, const RefCountingPtr<T> &r) -{ return l.get() != r.get(); } - -template<class T> -bool operator!=(const RefCountingPtr<T> &l, const T *r) -{ return l.get() != r; } - -template<class T> -bool operator!=(const T &l, const RefCountingPtr<T> &r) -{ return l != r.get(); } - -#endif // __REFCNT_HH__ diff --git a/base/remote_gdb.cc b/base/remote_gdb.cc deleted file mode 100644 index 84093459c..000000000 --- a/base/remote_gdb.cc +++ /dev/null @@ -1,1232 +0,0 @@ -/* - * 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. - */ - -/* - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This software was developed by the Computer Systems Engineering group - * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and - * contributed to Berkeley. - * - * All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Lawrence Berkeley Laboratories. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)kgdb_stub.c 8.4 (Berkeley) 1/12/94 - */ - -/*- - * Copyright (c) 2001 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Jason R. Thorpe. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * $NetBSD: kgdb_stub.c,v 1.8 2001/07/07 22:58:00 wdk Exp $ - * - * Taken from NetBSD - * - * "Stub" to allow remote cpu to debug over a serial line using gdb. - */ - -#include <sys/signal.h> - -#include <cstdio> -#include <string> -#include <unistd.h> - -#include "base/intmath.hh" -#include "base/kgdb.h" -#include "base/remote_gdb.hh" -#include "base/socket.hh" -#include "base/trace.hh" -#include "cpu/exec_context.hh" -#include "cpu/static_inst.hh" -#include "mem/functional/physical.hh" -#include "sim/system.hh" -#include "arch/vtophys.hh" - -using namespace std; -using namespace TheISA; - -#ifndef NDEBUG -vector<RemoteGDB *> debuggers; -int current_debugger = -1; - -void -debugger() -{ - if (current_debugger >= 0 && current_debugger < debuggers.size()) { - RemoteGDB *gdb = debuggers[current_debugger]; - if (!gdb->isattached()) - gdb->listener->accept(); - if (gdb->isattached()) - gdb->trap(ALPHA_KENTRY_IF); - } -} -#endif - -/////////////////////////////////////////////////////////// -// -// -// - -GDBListener::Event::Event(GDBListener *l, int fd, int e) - : PollEvent(fd, e), listener(l) -{} - -void -GDBListener::Event::process(int revent) -{ - listener->accept(); -} - -GDBListener::GDBListener(RemoteGDB *g, int p) - : event(NULL), gdb(g), port(p) -{ - assert(!gdb->listener); - gdb->listener = this; -} - -GDBListener::~GDBListener() -{ - if (event) - delete event; -} - -string -GDBListener::name() -{ - return gdb->name() + ".listener"; -} - -void -GDBListener::listen() -{ - while (!listener.listen(port, true)) { - DPRINTF(GDBMisc, "Can't bind port %d\n", port); - port++; - } - - event = new Event(this, listener.getfd(), POLLIN); - pollQueue.schedule(event); - -#ifndef NDEBUG - gdb->number = debuggers.size(); - debuggers.push_back(gdb); -#endif - -#ifndef NDEBUG - ccprintf(cerr, "%d: %s: listening for remote gdb #%d on port %d\n", - curTick, name(), gdb->number, port); -#else - ccprintf(cerr, "%d: %s: listening for remote gdb on port %d\n", - curTick, name(), port); -#endif -} - -void -GDBListener::accept() -{ - if (!listener.islistening()) - panic("GDBListener::accept(): cannot accept if we're not listening!"); - - int sfd = listener.accept(true); - - if (sfd != -1) { - if (gdb->isattached()) - close(sfd); - else - gdb->attach(sfd); - } -} - -/////////////////////////////////////////////////////////// -// -// -// -int digit2i(char); -char i2digit(int); -void mem2hex(void *, const void *, int); -const char *hex2mem(void *, const char *, int); -Addr hex2i(const char **); - -RemoteGDB::Event::Event(RemoteGDB *g, int fd, int e) - : PollEvent(fd, e), gdb(g) -{} - -void -RemoteGDB::Event::process(int revent) -{ - if (revent & POLLIN) - gdb->trap(ALPHA_KENTRY_IF); - else if (revent & POLLNVAL) - gdb->detach(); -} - -RemoteGDB::RemoteGDB(System *_system, ExecContext *c) - : event(NULL), listener(NULL), number(-1), fd(-1), - active(false), attached(false), - system(_system), pmem(_system->physmem), context(c) -{ - memset(gdbregs, 0, sizeof(gdbregs)); -} - -RemoteGDB::~RemoteGDB() -{ - if (event) - delete event; -} - -string -RemoteGDB::name() -{ - return system->name() + ".remote_gdb"; -} - -bool -RemoteGDB::isattached() -{ return attached; } - -void -RemoteGDB::attach(int f) -{ - fd = f; - - event = new Event(this, fd, POLLIN); - pollQueue.schedule(event); - - attached = true; - DPRINTFN("remote gdb attached\n"); -} - -void -RemoteGDB::detach() -{ - attached = false; - close(fd); - fd = -1; - - pollQueue.remove(event); - DPRINTFN("remote gdb detached\n"); -} - -const char * -gdb_command(char cmd) -{ - switch (cmd) { - case KGDB_SIGNAL: return "KGDB_SIGNAL"; - case KGDB_SET_BAUD: return "KGDB_SET_BAUD"; - case KGDB_SET_BREAK: return "KGDB_SET_BREAK"; - case KGDB_CONT: return "KGDB_CONT"; - case KGDB_ASYNC_CONT: return "KGDB_ASYNC_CONT"; - case KGDB_DEBUG: return "KGDB_DEBUG"; - case KGDB_DETACH: return "KGDB_DETACH"; - case KGDB_REG_R: return "KGDB_REG_R"; - case KGDB_REG_W: return "KGDB_REG_W"; - case KGDB_SET_THREAD: return "KGDB_SET_THREAD"; - case KGDB_CYCLE_STEP: return "KGDB_CYCLE_STEP"; - case KGDB_SIG_CYCLE_STEP: return "KGDB_SIG_CYCLE_STEP"; - case KGDB_KILL: return "KGDB_KILL"; - case KGDB_MEM_W: return "KGDB_MEM_W"; - case KGDB_MEM_R: return "KGDB_MEM_R"; - case KGDB_SET_REG: return "KGDB_SET_REG"; - case KGDB_READ_REG: return "KGDB_READ_REG"; - case KGDB_QUERY_VAR: return "KGDB_QUERY_VAR"; - case KGDB_SET_VAR: return "KGDB_SET_VAR"; - case KGDB_RESET: return "KGDB_RESET"; - case KGDB_STEP: return "KGDB_STEP"; - case KGDB_ASYNC_STEP: return "KGDB_ASYNC_STEP"; - case KGDB_THREAD_ALIVE: return "KGDB_THREAD_ALIVE"; - case KGDB_TARGET_EXIT: return "KGDB_TARGET_EXIT"; - case KGDB_BINARY_DLOAD: return "KGDB_BINARY_DLOAD"; - case KGDB_CLR_HW_BKPT: return "KGDB_CLR_HW_BKPT"; - case KGDB_SET_HW_BKPT: return "KGDB_SET_HW_BKPT"; - case KGDB_START: return "KGDB_START"; - case KGDB_END: return "KGDB_END"; - case KGDB_GOODP: return "KGDB_GOODP"; - case KGDB_BADP: return "KGDB_BADP"; - default: return "KGDB_UNKNOWN"; - } -} - -/////////////////////////////////////////////////////////// -// RemoteGDB::acc -// -// Determine if the mapping at va..(va+len) is valid. -// -bool -RemoteGDB::acc(Addr va, size_t len) -{ - Addr last_va; - - va = TheISA::TruncPage(va); - last_va = TheISA::RoundPage(va + len); - - do { - if (TheISA::IsK0Seg(va)) { - if (va < (TheISA::K0SegBase + pmem->size())) { - DPRINTF(GDBAcc, "acc: Mapping is valid K0SEG <= " - "%#x < K0SEG + size\n", va); - return true; - } else { - DPRINTF(GDBAcc, "acc: Mapping invalid %#x > K0SEG + size\n", - va); - return false; - } - } - - /** - * This code says that all accesses to palcode (instruction and data) - * are valid since there isn't a va->pa mapping because palcode is - * accessed physically. At some point this should probably be cleaned up - * but there is no easy way to do it. - */ - - if (AlphaISA::PcPAL(va) || va < 0x10000) - return true; - - Addr ptbr = context->readMiscReg(AlphaISA::IPR_PALtemp20); - TheISA::PageTableEntry pte = kernel_pte_lookup(pmem, ptbr, va); - if (!pte.valid()) { - DPRINTF(GDBAcc, "acc: %#x pte is invalid\n", va); - return false; - } - va += TheISA::PageBytes; - } while (va < last_va); - - DPRINTF(GDBAcc, "acc: %#x mapping is valid\n", va); - return true; -} - -/////////////////////////////////////////////////////////// -// RemoteGDB::signal -// -// Translate a trap number into a Unix-compatible signal number. -// (GDB only understands Unix signal numbers.) -// -int -RemoteGDB::signal(int type) -{ - switch (type) { - case ALPHA_KENTRY_INT: - return (SIGTRAP); - - case ALPHA_KENTRY_UNA: - return (SIGBUS); - - case ALPHA_KENTRY_ARITH: - return (SIGFPE); - - case ALPHA_KENTRY_IF: - return (SIGILL); - - case ALPHA_KENTRY_MM: - return (SIGSEGV); - - default: - panic("unknown signal type"); - return 0; - } -} - -/////////////////////////////////////////////////////////// -// RemoteGDB::getregs -// -// Translate the kernel debugger register format into -// the GDB register format. -void -RemoteGDB::getregs() -{ - memset(gdbregs, 0, sizeof(gdbregs)); - - gdbregs[KGDB_REG_PC] = context->readPC(); - - // @todo: Currently this is very Alpha specific. - if (AlphaISA::PcPAL(gdbregs[KGDB_REG_PC])) { - for (int i = 0; i < TheISA::NumIntArchRegs; ++i) { - gdbregs[i] = context->readIntReg(AlphaISA::reg_redir[i]); - } - } else { - for (int i = 0; i < TheISA::NumIntArchRegs; ++i) { - gdbregs[i] = context->readIntReg(i); - } - } - -#ifdef KGDB_FP_REGS - for (int i = 0; i < TheISA::NumFloatArchRegs; ++i) { - gdbregs[i + KGDB_REG_F0] = context->readFloatRegInt(i); - } -#endif -} - -/////////////////////////////////////////////////////////// -// RemoteGDB::setregs -// -// Translate the GDB register format into the kernel -// debugger register format. -// -void -RemoteGDB::setregs() -{ - // @todo: Currently this is very Alpha specific. - if (AlphaISA::PcPAL(gdbregs[KGDB_REG_PC])) { - for (int i = 0; i < TheISA::NumIntArchRegs; ++i) { - context->setIntReg(AlphaISA::reg_redir[i], gdbregs[i]); - } - } else { - for (int i = 0; i < TheISA::NumIntArchRegs; ++i) { - context->setIntReg(i, gdbregs[i]); - } - } - -#ifdef KGDB_FP_REGS - for (int i = 0; i < TheISA::NumFloatArchRegs; ++i) { - context->setFloatRegInt(i, gdbregs[i + KGDB_REG_F0]); - } -#endif - context->setPC(gdbregs[KGDB_REG_PC]); -} - -void -RemoteGDB::setTempBreakpoint(TempBreakpoint &bkpt, Addr addr) -{ - DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", addr); - - bkpt.address = addr; - insertHardBreak(addr, 4); -} - -void -RemoteGDB::clearTempBreakpoint(TempBreakpoint &bkpt) -{ - DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", - bkpt.address); - - - removeHardBreak(bkpt.address, 4); - bkpt.address = 0; -} - -void -RemoteGDB::clearSingleStep() -{ - DPRINTF(GDBMisc, "clearSingleStep bt_addr=%#x nt_addr=%#x\n", - takenBkpt.address, notTakenBkpt.address); - - if (takenBkpt.address != 0) - clearTempBreakpoint(takenBkpt); - - if (notTakenBkpt.address != 0) - clearTempBreakpoint(notTakenBkpt); -} - -void -RemoteGDB::setSingleStep() -{ - Addr pc = context->readPC(); - Addr npc, bpc; - bool set_bt = false; - - npc = pc + sizeof(MachInst); - - // User was stopped at pc, e.g. the instruction at pc was not - // executed. - MachInst inst = read<MachInst>(pc); - StaticInstPtr si(inst); - if (si->hasBranchTarget(pc, context, bpc)) { - // Don't bother setting a breakpoint on the taken branch if it - // is the same as the next pc - if (bpc != npc) - set_bt = true; - } - - DPRINTF(GDBMisc, "setSingleStep bt_addr=%#x nt_addr=%#x\n", - takenBkpt.address, notTakenBkpt.address); - - setTempBreakpoint(notTakenBkpt, npc); - - if (set_bt) - setTempBreakpoint(takenBkpt, bpc); -} - -///////////////////////// -// -// - -uint8_t -RemoteGDB::getbyte() -{ - uint8_t b; - ::read(fd, &b, 1); - return b; -} - -void -RemoteGDB::putbyte(uint8_t b) -{ - ::write(fd, &b, 1); -} - -// Send a packet to gdb -void -RemoteGDB::send(const char *bp) -{ - const char *p; - uint8_t csum, c; - - DPRINTF(GDBSend, "send: %s\n", bp); - - do { - p = bp; - putbyte(KGDB_START); - for (csum = 0; (c = *p); p++) { - putbyte(c); - csum += c; - } - putbyte(KGDB_END); - putbyte(i2digit(csum >> 4)); - putbyte(i2digit(csum)); - } while ((c = getbyte() & 0x7f) == KGDB_BADP); -} - -// Receive a packet from gdb -int -RemoteGDB::recv(char *bp, int maxlen) -{ - char *p; - int c, csum; - int len; - - do { - p = bp; - csum = len = 0; - while ((c = getbyte()) != KGDB_START) - ; - - while ((c = getbyte()) != KGDB_END && len < maxlen) { - c &= 0x7f; - csum += c; - *p++ = c; - len++; - } - csum &= 0xff; - *p = '\0'; - - if (len >= maxlen) { - putbyte(KGDB_BADP); - continue; - } - - csum -= digit2i(getbyte()) * 16; - csum -= digit2i(getbyte()); - - if (csum == 0) { - putbyte(KGDB_GOODP); - // Sequence present? - if (bp[2] == ':') { - putbyte(bp[0]); - putbyte(bp[1]); - len -= 3; - bcopy(bp + 3, bp, len); - } - break; - } - putbyte(KGDB_BADP); - } while (1); - - DPRINTF(GDBRecv, "recv: %s: %s\n", gdb_command(*bp), bp); - - return (len); -} - -// Read bytes from kernel address space for debugger. -bool -RemoteGDB::read(Addr vaddr, size_t size, char *data) -{ - static Addr lastaddr = 0; - static size_t lastsize = 0; - - uint8_t *maddr; - - if (vaddr < 10) { - DPRINTF(GDBRead, "read: reading memory location zero!\n"); - vaddr = lastaddr + lastsize; - } - - DPRINTF(GDBRead, "read: addr=%#x, size=%d", vaddr, size); -#if TRACING_ON - char *d = data; - size_t s = size; -#endif - - lastaddr = vaddr; - lastsize = size; - - size_t count = min((Addr)size, - VMPageSize - (vaddr & (VMPageSize - 1))); - - maddr = vtomem(context, vaddr, count); - memcpy(data, maddr, count); - - vaddr += count; - data += count; - size -= count; - - while (size >= VMPageSize) { - maddr = vtomem(context, vaddr, count); - memcpy(data, maddr, VMPageSize); - - vaddr += VMPageSize; - data += VMPageSize; - size -= VMPageSize; - } - - if (size > 0) { - maddr = vtomem(context, vaddr, count); - memcpy(data, maddr, size); - } - -#if TRACING_ON - if (DTRACE(GDBRead)) { - if (DTRACE(GDBExtra)) { - char buf[1024]; - mem2hex(buf, d, s); - DPRINTFNR(": %s\n", buf); - } else - DPRINTFNR("\n"); - } -#endif - - return true; -} - -// Write bytes to kernel address space for debugger. -bool -RemoteGDB::write(Addr vaddr, size_t size, const char *data) -{ - static Addr lastaddr = 0; - static size_t lastsize = 0; - - uint8_t *maddr; - - if (vaddr < 10) { - DPRINTF(GDBWrite, "write: writing memory location zero!\n"); - vaddr = lastaddr + lastsize; - } - - if (DTRACE(GDBWrite)) { - DPRINTFN("write: addr=%#x, size=%d", vaddr, size); - if (DTRACE(GDBExtra)) { - char buf[1024]; - mem2hex(buf, data, size); - DPRINTFNR(": %s\n", buf); - } else - DPRINTFNR("\n"); - } - - lastaddr = vaddr; - lastsize = size; - - size_t count = min((Addr)size, - VMPageSize - (vaddr & (VMPageSize - 1))); - - maddr = vtomem(context, vaddr, count); - memcpy(maddr, data, count); - - vaddr += count; - data += count; - size -= count; - - while (size >= VMPageSize) { - maddr = vtomem(context, vaddr, count); - memcpy(maddr, data, VMPageSize); - - vaddr += VMPageSize; - data += VMPageSize; - size -= VMPageSize; - } - - if (size > 0) { - maddr = vtomem(context, vaddr, count); - memcpy(maddr, data, size); - } - -#ifdef IMB - alpha_pal_imb(); -#endif - - return true; -} - - -PCEventQueue *RemoteGDB::getPcEventQueue() -{ - return &system->pcEventQueue; -} - - -RemoteGDB::HardBreakpoint::HardBreakpoint(RemoteGDB *_gdb, Addr pc) - : PCEvent(_gdb->getPcEventQueue(), "HardBreakpoint Event", pc), - gdb(_gdb), refcount(0) -{ - DPRINTF(GDBMisc, "creating hardware breakpoint at %#x\n", evpc); -} - -void -RemoteGDB::HardBreakpoint::process(ExecContext *xc) -{ - DPRINTF(GDBMisc, "handling hardware breakpoint at %#x\n", pc()); - - if (xc == gdb->context) - gdb->trap(ALPHA_KENTRY_INT); -} - -bool -RemoteGDB::insertSoftBreak(Addr addr, size_t len) -{ - if (len != sizeof(MachInst)) - panic("invalid length\n"); - - return insertHardBreak(addr, len); -} - -bool -RemoteGDB::removeSoftBreak(Addr addr, size_t len) -{ - if (len != sizeof(MachInst)) - panic("invalid length\n"); - - return removeHardBreak(addr, len); -} - -bool -RemoteGDB::insertHardBreak(Addr addr, size_t len) -{ - if (len != sizeof(MachInst)) - panic("invalid length\n"); - - DPRINTF(GDBMisc, "inserting hardware breakpoint at %#x\n", addr); - - HardBreakpoint *&bkpt = hardBreakMap[addr]; - if (bkpt == 0) - bkpt = new HardBreakpoint(this, addr); - - bkpt->refcount++; - - return true; -} - -bool -RemoteGDB::removeHardBreak(Addr addr, size_t len) -{ - if (len != sizeof(MachInst)) - panic("invalid length\n"); - - DPRINTF(GDBMisc, "removing hardware breakpoint at %#x\n", addr); - - break_iter_t i = hardBreakMap.find(addr); - if (i == hardBreakMap.end()) - return false; - - HardBreakpoint *hbp = (*i).second; - if (--hbp->refcount == 0) { - delete hbp; - hardBreakMap.erase(i); - } - - return true; -} - -const char * -break_type(char c) -{ - switch(c) { - case '0': return "software breakpoint"; - case '1': return "hardware breakpoint"; - case '2': return "write watchpoint"; - case '3': return "read watchpoint"; - case '4': return "access watchpoint"; - default: return "unknown breakpoint/watchpoint"; - } -} - -// This function does all command processing for interfacing to a -// remote gdb. Note that the error codes are ignored by gdb at -// present, but might eventually become meaningful. (XXX) It might -// makes sense to use POSIX errno values, because that is what the -// gdb/remote.c functions want to return. -bool -RemoteGDB::trap(int type) -{ - uint64_t val; - size_t datalen, len; - char data[KGDB_BUFLEN + 1]; - char buffer[sizeof(gdbregs) * 2 + 256]; - char temp[KGDB_BUFLEN]; - const char *p; - char command, subcmd; - string var; - bool ret; - - if (!attached) - return false; - - DPRINTF(GDBMisc, "trap: PC=%#x NPC=%#x\n", - context->readPC(), context->readNextPC()); - - clearSingleStep(); - - /* - * The first entry to this function is normally through - * a breakpoint trap in kgdb_connect(), in which case we - * must advance past the breakpoint because gdb will not. - * - * On the first entry here, we expect that gdb is not yet - * listening to us, so just enter the interaction loop. - * After the debugger is "active" (connected) it will be - * waiting for a "signaled" message from us. - */ - if (!active) - active = true; - else - // Tell remote host that an exception has occurred. - snprintf((char *)buffer, sizeof(buffer), "S%02x", signal(type)); - send(buffer); - - // Stick frame regs into our reg cache. - getregs(); - - for (;;) { - datalen = recv(data, sizeof(data)); - data[sizeof(data) - 1] = 0; // Sentinel - command = data[0]; - subcmd = 0; - p = data + 1; - switch (command) { - - case KGDB_SIGNAL: - // if this command came from a running gdb, answer it -- - // the other guy has no way of knowing if we're in or out - // of this loop when he issues a "remote-signal". - snprintf((char *)buffer, sizeof(buffer), "S%02x", signal(type)); - send(buffer); - continue; - - case KGDB_REG_R: - if (2 * sizeof(gdbregs) > sizeof(buffer)) - panic("buffer too small"); - - mem2hex(buffer, gdbregs, sizeof(gdbregs)); - send(buffer); - continue; - - case KGDB_REG_W: - p = hex2mem(gdbregs, p, sizeof(gdbregs)); - if (p == NULL || *p != '\0') - send("E01"); - else { - setregs(); - send("OK"); - } - continue; - -#if 0 - case KGDB_SET_REG: - val = hex2i(&p); - if (*p++ != '=') { - send("E01"); - continue; - } - if (val < 0 && val >= KGDB_NUMREGS) { - send("E01"); - continue; - } - - gdbregs[val] = hex2i(&p); - setregs(); - send("OK"); - - continue; -#endif - - case KGDB_MEM_R: - val = hex2i(&p); - if (*p++ != ',') { - send("E02"); - continue; - } - len = hex2i(&p); - if (*p != '\0') { - send("E03"); - continue; - } - if (len > sizeof(buffer)) { - send("E04"); - continue; - } - if (!acc(val, len)) { - send("E05"); - continue; - } - - if (read(val, (size_t)len, (char *)buffer)) { - mem2hex(temp, buffer, len); - send(temp); - } else { - send("E05"); - } - continue; - - case KGDB_MEM_W: - val = hex2i(&p); - if (*p++ != ',') { - send("E06"); - continue; - } - len = hex2i(&p); - if (*p++ != ':') { - send("E07"); - continue; - } - if (len > datalen - (p - data)) { - send("E08"); - continue; - } - p = hex2mem(buffer, p, sizeof(buffer)); - if (p == NULL) { - send("E09"); - continue; - } - if (!acc(val, len)) { - send("E0A"); - continue; - } - if (write(val, (size_t)len, (char *)buffer)) - send("OK"); - else - send("E0B"); - continue; - - case KGDB_SET_THREAD: - subcmd = *p++; - val = hex2i(&p); - if (val == 0) - send("OK"); - else - send("E01"); - continue; - - case KGDB_DETACH: - case KGDB_KILL: - active = false; - clearSingleStep(); - detach(); - goto out; - - case KGDB_ASYNC_CONT: - subcmd = hex2i(&p); - if (*p++ == ';') { - val = hex2i(&p); - context->setPC(val); - context->setNextPC(val + sizeof(MachInst)); - } - clearSingleStep(); - goto out; - - case KGDB_CONT: - if (p - data < datalen) { - val = hex2i(&p); - context->setPC(val); - context->setNextPC(val + sizeof(MachInst)); - } - clearSingleStep(); - goto out; - - case KGDB_ASYNC_STEP: - subcmd = hex2i(&p); - if (*p++ == ';') { - val = hex2i(&p); - context->setPC(val); - context->setNextPC(val + sizeof(MachInst)); - } - setSingleStep(); - goto out; - - case KGDB_STEP: - if (p - data < datalen) { - val = hex2i(&p); - context->setPC(val); - context->setNextPC(val + sizeof(MachInst)); - } - setSingleStep(); - goto out; - - case KGDB_CLR_HW_BKPT: - subcmd = *p++; - if (*p++ != ',') send("E0D"); - val = hex2i(&p); - if (*p++ != ',') send("E0D"); - len = hex2i(&p); - - DPRINTF(GDBMisc, "clear %s, addr=%#x, len=%d\n", - break_type(subcmd), val, len); - - ret = false; - - switch (subcmd) { - case '0': // software breakpoint - ret = removeSoftBreak(val, len); - break; - - case '1': // hardware breakpoint - ret = removeHardBreak(val, len); - break; - - case '2': // write watchpoint - case '3': // read watchpoint - case '4': // access watchpoint - default: // unknown - send(""); - break; - } - - send(ret ? "OK" : "E0C"); - continue; - - case KGDB_SET_HW_BKPT: - subcmd = *p++; - if (*p++ != ',') send("E0D"); - val = hex2i(&p); - if (*p++ != ',') send("E0D"); - len = hex2i(&p); - - DPRINTF(GDBMisc, "set %s, addr=%#x, len=%d\n", - break_type(subcmd), val, len); - - ret = false; - - switch (subcmd) { - case '0': // software breakpoint - ret = insertSoftBreak(val, len); - break; - - case '1': // hardware breakpoint - ret = insertHardBreak(val, len); - break; - - case '2': // write watchpoint - case '3': // read watchpoint - case '4': // access watchpoint - default: // unknown - send(""); - break; - } - - send(ret ? "OK" : "E0C"); - continue; - - case KGDB_QUERY_VAR: - var = string(p, datalen - 1); - if (var == "C") - send("QC0"); - else - send(""); - continue; - - case KGDB_SET_BAUD: - case KGDB_SET_BREAK: - case KGDB_DEBUG: - case KGDB_CYCLE_STEP: - case KGDB_SIG_CYCLE_STEP: - case KGDB_READ_REG: - case KGDB_SET_VAR: - case KGDB_RESET: - case KGDB_THREAD_ALIVE: - case KGDB_TARGET_EXIT: - case KGDB_BINARY_DLOAD: - // Unsupported command - DPRINTF(GDBMisc, "Unsupported command: %s\n", - gdb_command(command)); - DDUMP(GDBMisc, (uint8_t *)data, datalen); - send(""); - continue; - - default: - // Unknown command. - DPRINTF(GDBMisc, "Unknown command: %c(%#x)\n", - command, command); - send(""); - continue; - - - } - } - - out: - return true; -} - -// Convert a hex digit into an integer. -// This returns -1 if the argument passed is no valid hex digit. -int -digit2i(char c) -{ - if (c >= '0' && c <= '9') - return (c - '0'); - else if (c >= 'a' && c <= 'f') - return (c - 'a' + 10); - else if (c >= 'A' && c <= 'F') - - return (c - 'A' + 10); - else - return (-1); -} - -// Convert the low 4 bits of an integer into an hex digit. -char -i2digit(int n) -{ - return ("0123456789abcdef"[n & 0x0f]); -} - -// Convert a byte array into an hex string. -void -mem2hex(void *vdst, const void *vsrc, int len) -{ - char *dst = (char *)vdst; - const char *src = (const char *)vsrc; - - while (len--) { - *dst++ = i2digit(*src >> 4); - *dst++ = i2digit(*src++); - } - *dst = '\0'; -} - -// Convert an hex string into a byte array. -// This returns a pointer to the character following the last valid -// hex digit. If the string ends in the middle of a byte, NULL is -// returned. -const char * -hex2mem(void *vdst, const char *src, int maxlen) -{ - char *dst = (char *)vdst; - int msb, lsb; - - while (*src && maxlen--) { - msb = digit2i(*src++); - if (msb < 0) - return (src - 1); - lsb = digit2i(*src++); - if (lsb < 0) - return (NULL); - *dst++ = (msb << 4) | lsb; - } - return (src); -} - -// Convert an hex string into an integer. -// This returns a pointer to the character following the last valid -// hex digit. -Addr -hex2i(const char **srcp) -{ - const char *src = *srcp; - Addr r = 0; - int nibble; - - while ((nibble = digit2i(*src)) >= 0) { - r *= 16; - r += nibble; - src++; - } - *srcp = src; - return (r); -} - diff --git a/base/remote_gdb.hh b/base/remote_gdb.hh deleted file mode 100644 index b7abf5116..000000000 --- a/base/remote_gdb.hh +++ /dev/null @@ -1,209 +0,0 @@ -/* - * 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. - */ - -#ifndef __REMOTE_GDB_HH__ -#define __REMOTE_GDB_HH__ - -#include <map> - -#include "base/kgdb.h" -#include "cpu/pc_event.hh" -#include "base/pollevent.hh" -#include "base/socket.hh" - -class System; -class ExecContext; -class PhysicalMemory; - -class GDBListener; -class RemoteGDB -{ - protected: - typedef TheISA::MachInst MachInst; - private: - friend void debugger(); - friend class GDBListener; - - protected: - class Event : public PollEvent - { - protected: - RemoteGDB *gdb; - - public: - Event(RemoteGDB *g, int fd, int e); - void process(int revent); - }; - - friend class Event; - Event *event; - GDBListener *listener; - int number; - - protected: - int fd; - uint64_t gdbregs[KGDB_NUMREGS]; - - protected: -#ifdef notyet - label_t recover; -#endif - bool active; - bool attached; - - System *system; - PhysicalMemory *pmem; - ExecContext *context; - - protected: - uint8_t getbyte(); - void putbyte(uint8_t b); - - int recv(char *data, int len); - void send(const char *data); - - protected: - // Machine memory - bool read(Addr addr, size_t size, char *data); - bool write(Addr addr, size_t size, const char *data); - - template <class T> T read(Addr addr); - template <class T> void write(Addr addr, T data); - - public: - RemoteGDB(System *system, ExecContext *context); - ~RemoteGDB(); - - void replaceExecContext(ExecContext *xc) { context = xc; } - - void attach(int fd); - void detach(); - bool isattached(); - - bool acc(Addr addr, size_t len); - static int signal(int type); - bool trap(int type); - - protected: - void getregs(); - void setregs(); - - void clearSingleStep(); - void setSingleStep(); - - PCEventQueue *getPcEventQueue(); - - protected: - class HardBreakpoint : public PCEvent - { - private: - RemoteGDB *gdb; - - public: - int refcount; - - public: - HardBreakpoint(RemoteGDB *_gdb, Addr addr); - std::string name() { return gdb->name() + ".hwbkpt"; } - - virtual void process(ExecContext *xc); - }; - friend class HardBreakpoint; - - typedef std::map<Addr, HardBreakpoint *> break_map_t; - typedef break_map_t::iterator break_iter_t; - break_map_t hardBreakMap; - - bool insertSoftBreak(Addr addr, size_t len); - bool removeSoftBreak(Addr addr, size_t len); - bool insertHardBreak(Addr addr, size_t len); - bool removeHardBreak(Addr addr, size_t len); - - protected: - struct TempBreakpoint { - Addr address; // set here - MachInst bkpt_inst; // saved instruction at bkpt - int init_count; // number of times to skip bkpt - int count; // current count - }; - - TempBreakpoint notTakenBkpt; - TempBreakpoint takenBkpt; - - void clearTempBreakpoint(TempBreakpoint &bkpt); - void setTempBreakpoint(TempBreakpoint &bkpt, Addr addr); - - public: - std::string name(); -}; - -template <class T> -inline T -RemoteGDB::read(Addr addr) -{ - T temp; - read(addr, sizeof(T), (char *)&temp); - return temp; -} - -template <class T> -inline void -RemoteGDB::write(Addr addr, T data) -{ write(addr, sizeof(T), (const char *)&data); } - -class GDBListener -{ - protected: - class Event : public PollEvent - { - protected: - GDBListener *listener; - - public: - Event(GDBListener *l, int fd, int e); - void process(int revent); - }; - - friend class Event; - Event *event; - - protected: - ListenSocket listener; - RemoteGDB *gdb; - int port; - - public: - GDBListener(RemoteGDB *g, int p); - ~GDBListener(); - - void accept(); - void listen(); - std::string name(); -}; - -#endif /* __REMOTE_GDB_H__ */ diff --git a/base/res_list.hh b/base/res_list.hh deleted file mode 100644 index 960ed108e..000000000 --- a/base/res_list.hh +++ /dev/null @@ -1,755 +0,0 @@ -/* - * 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. - */ - -#ifndef __RES_LIST_HH__ -#define __RES_LIST_HH__ - -#include "base/cprintf.hh" -#include <assert.h> - -#define DEBUG_REMOVE 0 - -#define DEBUG_MEMORY 0 -//#define DEBUG_MEMORY DEBUG - -class res_list_base -{ -#if DEBUG_MEMORY - protected: - static long long allocated_elements; - static long long allocated_lists; - - public: - long long get_elements(void) { - return allocated_elements; - } - long long get_lists(void) { - return allocated_lists; - } - -#endif -}; - -#if DEBUG_MEMORY -extern void what_the(void); -#endif - -template<class T> -class res_list : public res_list_base -{ - public: - class iterator; - - class res_element - { - res_element *next; - res_element *prev; - T *data; - bool allocate_data; - - public: - // always adds to the END of the list - res_element(res_element *_prev, bool allocate); - ~res_element(); - void dump(void); - - friend class res_list<T>; - friend class res_list<T>::iterator; - }; - - class iterator - { - private: - res_element *p; - - friend class res_list<T>; - - public: - // Constructors - iterator(res_element *q) : p(q) {} - iterator(void) { p=0; }; - - void dump(void); - T* data_ptr(void); - res_element *res_el_ptr(void) { return p;} - void point_to(T &d) { p->data = &d; } - - iterator next(void) { return iterator(p->next); } - iterator prev(void) { return iterator(p->prev); } - bool operator== (iterator x) { return (x.p == this->p); } - bool operator != (iterator x) { return (x.p != this->p); } - T &operator * (void) { return *(p->data); } - T* operator -> (void) { return p->data; } - bool isnull(void) { return (p==0); } - bool notnull(void) { return (p!=0); } - }; - - private: - iterator unused_elements; - iterator head_ptr; - iterator tail_ptr; - - unsigned base_elements; - unsigned extra_elements; - unsigned active_elements; - bool allocate_storage; - unsigned build_size; - - int remove_count; - - // - // Allocate new elements, and assign them to the unused_elements - // list. - // - unsigned allocate_elements(unsigned num, bool allocate_storage); - - public: - // - // List Constructor - // - res_list(unsigned size, bool alloc_storage = false, - unsigned build_sz = 5); - - // - // List Destructor - // - ~res_list(); - - iterator head(void) {return head_ptr;}; - iterator tail(void) {return tail_ptr;}; - - unsigned num_free(void) { return size() - count(); } - unsigned size(void) { return base_elements + extra_elements; } - unsigned count(void) { return active_elements; } - bool empty(void) { return count() == 0; } - bool full(void); - - // - // Insert with data copy - // - iterator insert_after(iterator prev, T *d); - iterator insert_after(iterator prev, T &d); - iterator insert_before(iterator prev, T *d); - iterator insert_before(iterator prev, T &d); - - // - // Insert new list element (no data copy) - // - iterator insert_after(iterator prev); - iterator insert_before(iterator prev); - - iterator add_tail(T *d) { return insert_after(tail_ptr, d); } - iterator add_tail(T &d) { return insert_after(tail_ptr, d); } - iterator add_tail(void) { return insert_after(tail_ptr); } - iterator add_head(T *d) { return insert_before(head_ptr, d); } - iterator add_head(T &d) { return insert_before(head_ptr, d); } - iterator add_head(void) { return insert_before(head_ptr); } - - iterator remove(iterator q); - iterator remove_head(void) {return remove(head_ptr);} - iterator remove_tail(void) {return remove(tail_ptr);} - - bool in_list(iterator j); - void free_extras(void); - void clear(void); - void dump(void); - void raw_dump(void); -}; - -template <class T> -inline -res_list<T>::res_element::res_element(res_element *_prev, bool allocate) -{ - allocate_data = allocate; - prev = _prev; - next = 0; - - if (prev) - prev->next = this; - - if (allocate) - data = new T; - else - data = 0; - -#if DEBUG_MEMORY - ++allocated_elements; -#endif -} - -template <class T> -inline -res_list<T>::res_element::~res_element(void) -{ - if (prev) - prev->next = next; - - if (next) - next->prev = prev; - - if (allocate_data) - delete data; - -#if DEBUG_MEMORY - --allocated_elements; -#endif -} - -template <class T> -inline void -res_list<T>::res_element::dump(void) -{ - cprintf(" prev = %#x\n", prev); - cprintf(" next = %#x\n", next); - cprintf(" data = %#x\n", data); -} - -template <class T> -inline void -res_list<T>::iterator::dump(void) -{ - if (p && p->data) - p->data->dump(); - else { - if (!p) - cprintf(" Null Pointer\n"); - else - cprintf(" Null 'data' Pointer\n"); - } -} - -template <class T> -inline T * -res_list<T>::iterator::data_ptr(void) -{ - if (p) - return p->data; - else - return 0; -} - - -// -// Allocate new elements, and assign them to the unused_elements -// list. -// -template <class T> -inline unsigned -res_list<T>::allocate_elements(unsigned num, bool allocate_storage) -{ - res_element *pnew, *plast = 0, *pfirst=0; - - for (int i=0; i<num; ++i) { - pnew = new res_element(plast, allocate_storage); - if (i==0) - pfirst = pnew; - plast = pnew; - } - - if (unused_elements.notnull()) { - // Add these new elements to the front of the list - plast->next = unused_elements.res_el_ptr(); - unused_elements.res_el_ptr()->prev = plast; - } - - unused_elements = iterator(pfirst); - - return num; -} - -template <class T> -inline -res_list<T>::res_list(unsigned size, bool alloc_storage, unsigned build_sz) -{ -#if DEBUG_MEMORY - ++allocated_lists; -#endif - extra_elements = 0; - active_elements = 0; - build_size = build_sz; - allocate_storage = alloc_storage; - remove_count = 0; - - // Create the new elements - base_elements = allocate_elements(size, alloc_storage); - - // The list of active elements - head_ptr = iterator(0); - tail_ptr = iterator(0); -} - -// -// List Destructor -// -template <class T> -inline -res_list<T>::~res_list(void) -{ - iterator n; - -#if DEBUG_MEMORY - --allocated_lists; -#endif - - // put everything into the unused list - clear(); - - // rudely delete all the res_elements - for (iterator p = unused_elements; - p.notnull(); - p = n) { - - n = p.next(); - - // delete the res_element - // (it will take care of deleting the data) - delete p.res_el_ptr(); - } -} - -template <class T> -inline bool -res_list<T>::full(void) -{ - if (build_size) - return false; - else - return unused_elements.isnull(); -} - -// -// Insert with data copy -// -template <class T> -inline typename res_list<T>::iterator -res_list<T>::insert_after(iterator prev, T *d) -{ - iterator p; - - if (!allocate_storage) - this->panic("Can't copy data... not allocating storage"); - - p = insert_after(prev); - if (p.notnull()) - *p = *d; - - return p; -} - - -template <class T> -inline typename res_list<T>::iterator -res_list<T>::insert_after(iterator prev, T &d) -{ - iterator p; - - p = insert_after(prev); - if (p.notnull()) { - - if (allocate_storage) { - // if we allocate storage, then copy the contents of the - // specified object to our object - *p = d; - } - else { - // if we don't allocate storage, then we just want to - // point to the specified object - p.point_to(d); - } - } - - return p; -} - - -template <class T> -inline typename res_list<T>::iterator -res_list<T>::insert_after(iterator prev) -{ - -#if DEBUG_MEMORY - if (active_elements > 2*base_elements) { - what_the(); - } -#endif - - // If we have no unused elements, make some more - if (unused_elements.isnull()) { - - if (build_size == 0) { - return 0; // No space left, and can't allocate more.... - } - - extra_elements += allocate_elements(build_size, allocate_storage); - } - - // grab the first unused element - res_element *p = unused_elements.res_el_ptr(); - - unused_elements = unused_elements.next(); - - ++active_elements; - - // Insert the new element - if (head_ptr.isnull()) { - // - // Special case #1: Empty List - // - head_ptr = p; - tail_ptr = p; - p->prev = 0; - p->next = 0; - } - else if (prev.isnull()) { - // - // Special case #2: Insert at head - // - - // our next ptr points to old head element - p->next = head_ptr.res_el_ptr(); - - // our element becomes the new head element - head_ptr = p; - - // no previous element for the head - p->prev = 0; - - // old head element points back to this element - p->next->prev = p; - } - else if (prev.next().isnull()) { - // - // Special case #3 Insert at tail - // - - // our prev pointer points to old tail element - p->prev = tail_ptr.res_el_ptr(); - - // our element becomes the new tail - tail_ptr = p; - - // no next element for the tail - p->next = 0; - - // old tail element point to this element - p->prev->next = p; - } - else { - // - // Normal insertion (after prev) - // - p->prev = prev.res_el_ptr(); - p->next = prev.next().res_el_ptr(); - - prev.res_el_ptr()->next = p; - p->next->prev = p; - } - - return iterator(p); -} - -template <class T> -inline typename res_list<T>::iterator -res_list<T>::insert_before(iterator next, T &d) -{ - iterator p; - - p = insert_before(next); - if (p.notnull()) { - - if (allocate_storage) { - // if we allocate storage, then copy the contents of the - // specified object to our object - *p = d; - } - else { - // if we don't allocate storage, then we just want to - // point to the specified object - p.point_to(d); - } - } - - return p; -} - - -template <class T> -inline typename res_list<T>::iterator -res_list<T>::insert_before(iterator next) -{ - -#if DEBUG_MEMORY - if (active_elements > 2*base_elements) { - what_the(); - } -#endif - - // If we have no unused elements, make some more - if (unused_elements.isnull()) { - - if (build_size == 0) { - return 0; // No space left, and can't allocate more.... - } - - extra_elements += allocate_elements(build_size, allocate_storage); - } - - // grab the first unused element - res_element *p = unused_elements.res_el_ptr(); - - unused_elements = unused_elements.next(); - - ++active_elements; - - // Insert the new element - if (head_ptr.isnull()) { - // - // Special case #1: Empty List - // - head_ptr = p; - tail_ptr = p; - p->prev = 0; - p->next = 0; - } - else if (next.isnull()) { - // - // Special case #2 Insert at tail - // - - // our prev pointer points to old tail element - p->prev = tail_ptr.res_el_ptr(); - - // our element becomes the new tail - tail_ptr = p; - - // no next element for the tail - p->next = 0; - - // old tail element point to this element - p->prev->next = p; - } - else if (next.prev().isnull()) { - // - // Special case #3: Insert at head - // - - // our next ptr points to old head element - p->next = head_ptr.res_el_ptr(); - - // our element becomes the new head element - head_ptr = p; - - // no previous element for the head - p->prev = 0; - - // old head element points back to this element - p->next->prev = p; - } - else { - // - // Normal insertion (before next) - // - p->next = next.res_el_ptr(); - p->prev = next.prev().res_el_ptr(); - - next.res_el_ptr()->prev = p; - p->prev->next = p; - } - - return iterator(p); -} - - -template <class T> -inline typename res_list<T>::iterator -res_list<T>::remove(iterator q) -{ - res_element *p = q.res_el_ptr(); - iterator n = 0; - - // Handle the special cases - if (active_elements == 1) { // This is the only element - head_ptr = 0; - tail_ptr = 0; - } - else if (q == head_ptr) { // This is the head element - head_ptr = q.next(); - head_ptr.res_el_ptr()->prev = 0; - - n = head_ptr; - } - else if (q == tail_ptr) { // This is the tail element - tail_ptr = q.prev(); - tail_ptr.res_el_ptr()->next = 0; - } - else { // This is between two elements - p->prev->next = p->next; - p->next->prev = p->prev; - - // Get the "next" element for return - n = p->next; - } - - --active_elements; - - // Put this element back onto the unused list - p->next = unused_elements.res_el_ptr(); - p->prev = 0; - if (p->next) { // NULL if unused list is empty - p->next->prev = p; - } - - if (!allocate_storage) { - p->data = 0; - } - - unused_elements = q; - - // A little "garbage collection" - if (++remove_count > 10) { - // free_extras(); - remove_count = 0; - } - -#if DEBUG_REMOVE - unsigned unused_count = 0; - for (iterator i=unused_elements; - i.notnull(); - i = i.next()) { - - ++unused_count; - } - - assert((active_elements+unused_count) == (base_elements+extra_elements)); -#endif - - return iterator(n); -} - - -template <class T> -inline bool -res_list<T>::in_list(iterator j) -{ - iterator i; - - for (i=head(); i.notnull(); i=i.next()) { - if (j.res_el_ptr() == i.res_el_ptr()) { - return true; - } - } - - return false; -} - -template <class T> -inline void -res_list<T>::free_extras(void) -{ - unsigned num_unused = base_elements + extra_elements - active_elements; - unsigned to_free = extra_elements; - res_element *p; - - - if (extra_elements != 0) { - // - // Free min(extra_elements, # unused elements) - // - if (extra_elements > num_unused) { - to_free = num_unused; - } - - p = unused_elements.res_el_ptr(); - for (int i=0; i<to_free; ++i) { - res_element *q = p->next; - - delete p; - - p = q; - } - - // update the unused element pointer to point to the first - // element that wasn't deleted. - unused_elements = iterator(p); - - // Update the number of extra elements - extra_elements -= to_free; - } - - return; -} - - -template <class T> -inline void -res_list<T>::clear(void) -{ - iterator i,n; - - for (i=head_ptr; i.notnull(); i=n) { - n = i.next(); - remove(i); - } - - free_extras(); -} - -template <class T> -inline void -res_list<T>::dump(void) -{ - for (iterator i=head(); !i.isnull(); i=i.next()) - i->dump(); -} - -template <class T> -inline void -res_list<T>::raw_dump(void) -{ - int j = 0; - res_element *p; - for (iterator i=head(); !i.isnull(); i=i.next()) { - cprintf("Element %d:\n", j); - - if (i.notnull()) { - p = i.res_el_ptr(); - cprintf(" points to res_element @ %#x\n", p); - p->dump(); - cprintf(" Data Element:\n"); - i->dump(); - } - else { - cprintf(" NULL iterator!\n"); - } - - ++j; - } - -} - -#endif // __RES_LIST_HH__ diff --git a/base/sat_counter.cc b/base/sat_counter.cc deleted file mode 100644 index 7920f6c81..000000000 --- a/base/sat_counter.cc +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include <sstream> - -#include "base/sat_counter.hh" -#include "base/statistics.hh" -#include "sim/stats.hh" - - -using namespace std; - - -SaturatingCounterPred::SaturatingCounterPred(string p_name, - string z_name, - string o_name, - unsigned _index_bits, - unsigned _counter_bits, - unsigned _zero_change, - unsigned _one_change, - unsigned _thresh, - unsigned _init_value) -{ - pred_name = p_name; - zero_name = z_name; - one_name = o_name; - - index_bits = _index_bits; - counter_bits = _counter_bits; - zero_change = _zero_change; - one_change = _one_change; - thresh = _thresh; - init_value = _init_value; - - max_index = (1 << index_bits) - 1; - max_value = (1 << counter_bits) - 1; - - table = new unsigned[max_index + 1]; - - // Initialize with the right parameters & clear the counter - for (int i = 0; i <= max_index; ++i) - table[i] = init_value; -} - -void SaturatingCounterPred::regStats() -{ - using namespace Stats; - stringstream name, description; - - // - // Number of predictions - // - name << pred_name << ":" << zero_name << ":preds"; - description << "number of predictions of " << zero_name; - predicted_zero - .name(name.str()) - .desc(description.str()) - ; - description.str(""); - name.str(""); - - name << pred_name << ":" << one_name << ":preds"; - description << "number of predictions of " << one_name; - predicted_one - .name(name.str()) - .desc(description.str()) - ; - description.str(""); - name.str(""); - - // - // Count the number of correct predictions - // - name << pred_name << ":" << zero_name << ":corr_preds"; - description << "number of correct " << zero_name << " preds"; - correct_pred_zero - .name(name.str()) - .desc(description.str()) - ; - description.str(""); - name.str(""); - - name << pred_name << ":" << one_name << ":corr_preds"; - description << "number of correct " << one_name << " preds"; - correct_pred_one - .name(name.str()) - .desc(description.str()) - ; - description.str(""); - name.str(""); - - // - // Number of predictor updates - // - name << pred_name << ":" << zero_name << ":updates"; - description << "number of actual " << zero_name << "s"; - record_zero - .name(name.str()) - .desc(description.str()) - ; - description.str(""); - name.str(""); - - name << pred_name << ":" << one_name << ":updates"; - description << "number of actual " << one_name << "s"; - record_one - .name(name.str()) - .desc(description.str()) - ; - description.str(""); - name.str(""); -} - -void SaturatingCounterPred::regFormulas() -{ - using namespace Stats; - stringstream name, description; - - // - // Number of predictions - // - name << pred_name << ":predictions"; - preds_total - .name(name.str()) - .desc("total number of predictions made") - ; - preds_total = predicted_zero + predicted_one; - name.str(""); - - // - // Fraction of all predictions that are one or zero - // - name << pred_name << ":" << zero_name << ":pred_frac"; - description << "fraction of all preds that were " << zero_name; - pred_frac_zero - .name(name.str()) - .desc(description.str()) - ; - pred_frac_zero = 100 * predicted_zero / preds_total; - description.str(""); - name.str(""); - - name << pred_name << ":" << one_name << ":pred_frac"; - description << "fraction of all preds that were " << one_name; - pred_frac_one - .name(name.str()) - .desc(description.str()) - ; - pred_frac_one = 100 * predicted_one / preds_total; - description.str(""); - name.str(""); - - - // - // Count the number of correct predictions - // - name << pred_name << ":correct_preds"; - correct_total - .name(name.str()) - .desc("total correct predictions made") - ; - correct_total = correct_pred_one + correct_pred_zero; - name.str(""); - - // - // Number of predictor updates - // - name << pred_name << ":updates"; - updates_total - .name(name.str()) - .desc("total number of updates") - ; - updates_total = record_zero + record_one; - name.str(""); - - // - // Prediction accuracy rates - // - name << pred_name << ":pred_rate"; - pred_rate - .name(name.str()) - .desc("correct fraction of all preds") - ; - pred_rate = correct_total / updates_total; - name.str(""); - - name << pred_name << ":" << zero_name << ":pred_rate"; - description << "fraction of " << zero_name << " preds that were correct"; - frac_correct_zero - .name(name.str()) - .desc(description.str()) - ; - frac_correct_zero = 100 * correct_pred_zero / - (correct_pred_zero + record_one - correct_pred_one); - description.str(""); - name.str(""); - - name << pred_name << ":" << one_name << ":pred_rate"; - description << "fraction of " << one_name << " preds that were correct"; - frac_correct_one - .name(name.str()) - .desc(description.str()) - ; - frac_correct_one = 100 * correct_pred_one / - (correct_pred_one + record_zero - correct_pred_zero); - description.str(""); - name.str(""); - - // - // Coverage - // - name << pred_name << ":" << zero_name << ":coverage"; - description << "fraction of " << zero_name - << "s that were predicted correctly"; - coverage_zero - .name(name.str()) - .desc(description.str()) - ; - coverage_zero = 100 * correct_pred_zero / record_zero; - description.str(""); - name.str(""); - - name << pred_name << ":" << one_name << ":coverage"; - description << "fraction of " << one_name - << "s that were predicted correctly"; - coverage_one - .name(name.str()) - .desc(description.str()) - ; - coverage_one = 100 * correct_pred_one / record_one; - description.str(""); - name.str(""); -} - - - - - - - - - - diff --git a/base/sat_counter.hh b/base/sat_counter.hh deleted file mode 100644 index d7be17b6f..000000000 --- a/base/sat_counter.hh +++ /dev/null @@ -1,190 +0,0 @@ -/* - * 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. - */ - -#ifndef __SAT_COUNTER_HH__ -#define __SAT_COUNTER_HH__ - -#include <string> - -#include "base/predictor.hh" - -#include "base/statistics.hh" -#include "sim/stats.hh" - -// -// -// A simple saturating counter predictor -// -// -class SaturatingCounterPred : public GenericPredictor -{ - private: - std::string pred_name; - std::string zero_name; - std::string one_name; - - unsigned index_bits; - unsigned counter_bits; - unsigned zero_change; - unsigned one_change; - unsigned thresh; - unsigned init_value; - - unsigned max_value; // maximum counter value - - unsigned long max_index; // also the index mask value - unsigned *table; - - // Statistics - Stats::Scalar<> predicted_one; // Total predictions of one, preds_one - Stats::Scalar<> predicted_zero; // Total predictions of zero, preds_zero - Stats::Scalar<> correct_pred_one; // Total correct predictions of one, correct_one - Stats::Scalar<> correct_pred_zero; // Total correct predictions of zero, correct_zero - - Stats::Scalar<> record_zero; //updates_zero - Stats::Scalar<> record_one; //updates_one - - Stats::Formula preds_total; - Stats::Formula pred_frac_zero; - Stats::Formula pred_frac_one; - Stats::Formula correct_total; - Stats::Formula updates_total; - Stats::Formula pred_rate; - Stats::Formula frac_correct_zero; - Stats::Formula frac_correct_one; - Stats::Formula coverage_zero; - Stats::Formula coverage_one; - - private: - bool pred_one(unsigned &counter) { return counter > thresh; } - bool pred_zero(unsigned &counter) { return counter <= thresh; } - - void update_one(unsigned &counter) { - - if (one_change) - counter += one_change; - else - counter = 0; - - // check for wrap - if (counter > max_value) - counter = max_value; - } - - void update_zero(unsigned &counter) { - if (zero_change) { - // check for wrap - if (counter < zero_change) - counter = 0; - else - counter -= zero_change; - } else - counter = 0; - } - - - public: - - SaturatingCounterPred(std::string p_name, - std::string z_name, std::string o_name, - unsigned _index_bits, unsigned _counter_bits = 2, - unsigned _zero_change = 1, unsigned _one_change = 1, - unsigned _thresh = 1, unsigned _init_value = 0); - - void clear() { - for (int i = 0; i <= max_index; ++i) - table[i] = init_value; - } - - // Record the ACTUAL result... and indicate whether the prediction - // corresponding to this event was correct - void record(unsigned long _index, unsigned _val, unsigned _predicted, - unsigned _pdata) - { - record(_index, _val, _predicted); - } - - void record(unsigned long _index, unsigned _val, unsigned _predicted) { - unsigned long index = _index & max_index; - - if (_val) { - update_one(table[index]); - ++record_one; - - if (_predicted) - ++correct_pred_one; - } else { - update_zero(table[index]); - ++record_zero; - - if (!_predicted) - ++correct_pred_zero; - } - } - - unsigned value(unsigned long _index) { - unsigned long index = _index & max_index; - - return table[index]; - } - - - unsigned predict(unsigned long _index, unsigned &pdata) { - return predict(_index); - } - - unsigned predict(unsigned long _index) { - unsigned long index = _index & max_index; - - if (pred_one(table[index])) { - ++predicted_one; - return 1; - } - - ++predicted_zero; - return 0; - } - - // No internal state is changed here - unsigned peek(unsigned long _index) { - unsigned long index = _index & max_index; - - if (pred_one(table[index])) - return 1; - - return 0; - } - - - //======================================================= - void regStats(); - void regFormulas(); -}; - - -#endif // __SAT_COUNTER_HH__ diff --git a/base/sched_list.hh b/base/sched_list.hh deleted file mode 100644 index f794e3514..000000000 --- a/base/sched_list.hh +++ /dev/null @@ -1,178 +0,0 @@ -/* - * 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. - */ - -#ifndef SCHED_LIST_HH -#define SCHED_LIST_HH - -#include <list> -#include "base/intmath.hh" -#include "base/misc.hh" - - -// Any types you use this class for must be covered here... -namespace { - void ClearEntry(int &i) { i = 0; }; - void ClearEntry(unsigned &i) { i = 0; }; - void ClearEntry(double &i) { i = 0; }; - template <class T> void ClearEntry(std::list<T> &l) { l.clear(); }; -}; - - -// -// this is a special list type that allows the user to insert elements at a -// specified positive offset from the "current" element, but only allow them -// be extracted from the "current" element -// - - -template <class T> -class SchedList -{ - T *data_array; - unsigned position; - unsigned size; - unsigned mask; - - public: - SchedList(unsigned size); - SchedList(void); - - void init(unsigned size); - - T &operator[](unsigned offset); - - void advance(void); - - void clear(void); -}; - - - -// -// Constructor -// -template<class T> -SchedList<T>::SchedList(unsigned _size) -{ - size = _size; - - // size must be a power of two - if (!isPowerOf2(size)) { - panic("SchedList: size must be a power of two"); - } - - if (size < 2) { - panic("SchedList: you don't want a list that small"); - } - - // calculate the bit mask for the modulo operation - mask = size - 1; - - data_array = new T[size]; - - if (!data_array) { - panic("SchedList: could not allocate memory"); - } - - clear(); -} - -template<class T> -SchedList<T>::SchedList(void) -{ - data_array = 0; - size = 0; -} - - -template<class T> void -SchedList<T>::init(unsigned _size) -{ - size = _size; - - if (!data_array) { - // size must be a power of two - if (size & (size-1)) { - panic("SchedList: size must be a power of two"); - } - - if (size < 2) { - panic("SchedList: you don't want a list that small"); - } - - // calculate the bit mask for the modulo operation - mask = size - 1; - - data_array = new T[size]; - - if (!data_array) { - panic("SchedList: could not allocate memory"); - } - - clear(); - } -} - - -template<class T> void -SchedList<T>::advance(void) -{ - ClearEntry(data_array[position]); - - // position = (++position % size); - position = ++position & mask; -} - - -template<class T> void -SchedList<T>::clear(void) -{ - for (unsigned i=0; i<size; ++i) { - ClearEntry(data_array[i]); - } - - position = 0; -} - - -template<class T> T& -SchedList<T>::operator[](unsigned offset) -{ - if (offset >= size) { - panic("SchedList: can't access element beyond current pointer"); - } - - // unsigned p = (position + offset) % size; - unsigned p = (position + offset) & mask; - - return data_array[p]; -} - - - -#endif diff --git a/base/socket.cc b/base/socket.cc deleted file mode 100644 index 45a60e7e3..000000000 --- a/base/socket.cc +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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. - */ - -#include <sys/types.h> -#include <sys/socket.h> - -#include <netinet/in.h> -#include <netinet/tcp.h> - -#include <errno.h> -#include <unistd.h> - -#include "sim/host.hh" -#include "base/misc.hh" -#include "base/socket.hh" - -using namespace std; - -//////////////////////////////////////////////////////////////////////// -// -// - -ListenSocket::ListenSocket() - : listening(false), fd(-1) -{} - -ListenSocket::~ListenSocket() -{ - if (fd != -1) - close(fd); -} - -// Create a socket and configure it for listening -bool -ListenSocket::listen(int port, bool reuse) -{ - if (listening) - panic("Socket already listening!"); - - fd = ::socket(PF_INET, SOCK_STREAM, 0); - if (fd < 0) - panic("Can't create socket:%s !", strerror(errno)); - - if (reuse) { - int i = 1; - if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&i, - sizeof(i)) < 0) - panic("ListenSocket(listen): setsockopt() SO_REUSEADDR failed!"); - } - - struct sockaddr_in sockaddr; - sockaddr.sin_family = PF_INET; - sockaddr.sin_addr.s_addr = INADDR_ANY; - - sockaddr.sin_port = htons(port); - int ret = ::bind(fd, (struct sockaddr *)&sockaddr, sizeof (sockaddr)); - if (ret != 0) { - if (ret == -1 && errno != EADDRINUSE) - panic("ListenSocket(listen): bind() failed!"); - return false; - } - - if (::listen(fd, 1) == -1) - panic("ListenSocket(listen): listen() failed!"); - - listening = true; - - return true; -} - - -// Open a connection. Accept will block, so if you don't want it to, -// make sure a connection is ready before you call accept. -int -ListenSocket::accept(bool nodelay) -{ - struct sockaddr_in sockaddr; - socklen_t slen = sizeof (sockaddr); - int sfd = ::accept(fd, (struct sockaddr *)&sockaddr, &slen); - if (sfd != -1 && nodelay) { - int i = 1; - ::setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (char *)&i, sizeof(i)); - } - - return sfd; -} diff --git a/base/socket.hh b/base/socket.hh deleted file mode 100644 index 848405c09..000000000 --- a/base/socket.hh +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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. - */ - -#ifndef __SOCKET_HH__ -#define __SOCKET_HH__ - -class ListenSocket -{ - protected: - bool listening; - int fd; - - public: - ListenSocket(); - virtual ~ListenSocket(); - - virtual int accept(bool nodelay = false); - virtual bool listen(int port, bool reuse = true); - - int getfd() const { return fd; } - bool islistening() const { return listening; } -}; - -#endif //__SOCKET_HH__ diff --git a/base/statistics.cc b/base/statistics.cc deleted file mode 100644 index c36f662df..000000000 --- a/base/statistics.cc +++ /dev/null @@ -1,291 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include <iomanip> -#include <fstream> -#include <list> -#include <map> -#include <string> -#include <sstream> - -#include "base/callback.hh" -#include "base/cprintf.hh" -#include "base/hostinfo.hh" -#include "base/misc.hh" -#include "base/statistics.hh" -#include "base/str.hh" -#include "base/time.hh" -#include "base/trace.hh" -#include "base/stats/statdb.hh" - -using namespace std; - -namespace Stats { - -StatData * -DataAccess::find() const -{ - return Database::find(const_cast<void *>((const void *)this)); -} - -const StatData * -getStatData(const void *stat) -{ - return Database::find(const_cast<void *>(stat)); -} - -void -DataAccess::map(StatData *data) -{ - Database::regStat(this, data); -} - -StatData * -DataAccess::statData() -{ - StatData *ptr = find(); - assert(ptr); - return ptr; -} - -const StatData * -DataAccess::statData() const -{ - const StatData *ptr = find(); - assert(ptr); - return ptr; -} - -void -DataAccess::setInit() -{ - statData()->flags |= init; -} - -void -DataAccess::setPrint() -{ - Database::regPrint(this); -} - -StatData::StatData() - : flags(none), precision(-1), prereq(0) -{ - static int count = 0; - id = count++; -} - -StatData::~StatData() -{ -} - -bool -StatData::less(StatData *stat1, StatData *stat2) -{ - const string &name1 = stat1->name; - const string &name2 = stat2->name; - - vector<string> v1; - vector<string> v2; - - tokenize(v1, name1, '.'); - tokenize(v2, name2, '.'); - - int last = min(v1.size(), v2.size()) - 1; - for (int i = 0; i < last; ++i) - if (v1[i] != v2[i]) - return v1[i] < v2[i]; - - // Special compare for last element. - if (v1[last] == v2[last]) - return v1.size() < v2.size(); - else - return v1[last] < v2[last]; - - return false; -} - -bool -StatData::baseCheck() const -{ - if (!(flags & init)) { -#ifdef DEBUG - cprintf("this is stat number %d\n", id); -#endif - panic("Not all stats have been initialized"); - return false; - } - - if ((flags & print) && name.empty()) { - panic("all printable stats must be named"); - return false; - } - - return true; -} - - -void -FormulaBase::result(VResult &vec) const -{ - if (root) - vec = root->result(); -} - -Result -FormulaBase::total() const -{ - return root ? root->total() : 0.0; -} - -size_t -FormulaBase::size() const -{ - if (!root) - return 0; - else - return root->size(); -} - -void -FormulaBase::reset() -{ -} - -bool -FormulaBase::zero() const -{ - VResult vec; - result(vec); - for (int i = 0; i < vec.size(); ++i) - if (vec[i] != 0.0) - return false; - return true; -} - -void -FormulaBase::update(StatData *) -{ -} - -string -FormulaBase::str() const -{ - return root ? root->str() : ""; -} - -Formula::Formula() -{ - setInit(); -} - -Formula::Formula(Temp r) -{ - root = r; - assert(size()); -} - -const Formula & -Formula::operator=(Temp r) -{ - assert(!root && "Can't change formulas"); - root = r; - assert(size()); - return *this; -} - -const Formula & -Formula::operator+=(Temp r) -{ - if (root) - root = NodePtr(new BinaryNode<std::plus<Result> >(root, r)); - else - root = r; - assert(size()); - return *this; -} - -void -check() -{ - typedef Database::stat_list_t::iterator iter_t; - - iter_t i, end = Database::stats().end(); - for (i = Database::stats().begin(); i != end; ++i) { - StatData *data = *i; - assert(data); - if (!data->check() || !data->baseCheck()) - panic("stat check failed for %s\n", data->name); - } - - int j = 0; - for (i = Database::stats().begin(); i != end; ++i) { - StatData *data = *i; - if (!(data->flags & print)) - data->name = "__Stat" + to_string(j++); - } - - Database::stats().sort(StatData::less); - - if (i == end) - return; - - iter_t last = i; - ++i; - - for (i = Database::stats().begin(); i != end; ++i) { - if ((*i)->name == (*last)->name) - panic("same name used twice! name=%s\n", (*i)->name); - - last = i; - } -} - -CallbackQueue resetQueue; - -void -reset() -{ - Database::stat_list_t::iterator i = Database::stats().begin(); - Database::stat_list_t::iterator end = Database::stats().end(); - while (i != end) { - StatData *data = *i; - data->reset(); - ++i; - } - - resetQueue.process(); -} - -void -registerResetCallback(Callback *cb) -{ - resetQueue.add(cb); -} - -/* namespace Stats */ } diff --git a/base/statistics.hh b/base/statistics.hh deleted file mode 100644 index 5dcfbb29d..000000000 --- a/base/statistics.hh +++ /dev/null @@ -1,2885 +0,0 @@ -/* - * Copyright (c) 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. - */ - -/** @file - * Declaration of Statistics objects. - */ - -/** -* @todo -* -* Generalized N-dimensinal vector -* documentation -* key stats -* interval stats -* -- these both can use the same function that prints out a -* specific set of stats -* VectorStandardDeviation totals -* Document Namespaces -*/ -#ifndef __BASE_STATISTICS_HH__ -#define __BASE_STATISTICS_HH__ - -#include <algorithm> -#include <cassert> -#include <cmath> -#include <functional> -#include <iosfwd> -#include <sstream> -#include <string> -#include <vector> - -#include "base/cprintf.hh" -#include "base/intmath.hh" -#include "base/refcnt.hh" -#include "base/str.hh" -#include "base/stats/flags.hh" -#include "base/stats/visit.hh" -#include "base/stats/types.hh" -#include "sim/host.hh" - -class Callback; - -/** The current simulated cycle. */ -extern Tick curTick; - -/* A namespace for all of the Statistics */ -namespace Stats { - -/* Contains the statistic implementation details */ -////////////////////////////////////////////////////////////////////// -// -// Statistics Framework Base classes -// -////////////////////////////////////////////////////////////////////// -struct StatData -{ - /** The name of the stat. */ - std::string name; - /** The description of the stat. */ - std::string desc; - /** The formatting flags. */ - StatFlags flags; - /** The display precision. */ - int precision; - /** A pointer to a prerequisite Stat. */ - const StatData *prereq; - /** - * A unique stat ID for each stat in the simulator. - * Can be used externally for lookups as well as for debugging. - */ - int id; - - StatData(); - virtual ~StatData(); - - /** - * Reset the corresponding stat to the default state. - */ - virtual void reset() = 0; - - /** - * @return true if this stat has a value and satisfies its - * requirement as a prereq - */ - virtual bool zero() const = 0; - - /** - * Check that this stat has been set up properly and is ready for - * use - * @return true for success - */ - virtual bool check() const = 0; - bool baseCheck() const; - - /** - * Visitor entry for outputing statistics data - */ - virtual void visit(Visit &visitor) = 0; - - /** - * Checks if the first stat's name is alphabetically less than the second. - * This function breaks names up at periods and considers each subname - * separately. - * @param stat1 The first stat. - * @param stat2 The second stat. - * @return stat1's name is alphabetically before stat2's - */ - static bool less(StatData *stat1, StatData *stat2); -}; - -class ScalarData : public StatData -{ - public: - virtual Counter value() const = 0; - virtual Result result() const = 0; - virtual Result total() const = 0; - virtual void visit(Visit &visitor) { visitor.visit(*this); } -}; - -template <class Stat> -class ScalarStatData : public ScalarData -{ - protected: - Stat &s; - - public: - ScalarStatData(Stat &stat) : s(stat) {} - - virtual bool check() const { return s.check(); } - virtual Counter value() const { return s.value(); } - virtual Result result() const { return s.result(); } - virtual Result total() const { return s.total(); } - virtual void reset() { s.reset(); } - virtual bool zero() const { return s.zero(); } -}; - -struct VectorData : public StatData -{ - /** Names and descriptions of subfields. */ - mutable std::vector<std::string> subnames; - mutable std::vector<std::string> subdescs; - - virtual size_t size() const = 0; - virtual const VCounter &value() const = 0; - virtual const VResult &result() const = 0; - virtual Result total() const = 0; - void update() - { - if (!subnames.empty()) { - int s = size(); - if (subnames.size() < s) - subnames.resize(s); - - if (subdescs.size() < s) - subdescs.resize(s); - } - } -}; - -template <class Stat> -class VectorStatData : public VectorData -{ - protected: - Stat &s; - mutable VCounter cvec; - mutable VResult rvec; - - public: - VectorStatData(Stat &stat) : s(stat) {} - - virtual bool check() const { return s.check(); } - virtual bool zero() const { return s.zero(); } - virtual void reset() { s.reset(); } - - virtual size_t size() const { return s.size(); } - virtual VCounter &value() const - { - s.value(cvec); - return cvec; - } - virtual const VResult &result() const - { - s.result(rvec); - return rvec; - } - virtual Result total() const { return s.total(); } - virtual void visit(Visit &visitor) - { - update(); - s.update(this); - visitor.visit(*this); - } -}; - -struct DistDataData -{ - Counter min_val; - Counter max_val; - Counter underflow; - Counter overflow; - VCounter cvec; - Counter sum; - Counter squares; - Counter samples; - - Counter min; - Counter max; - Counter bucket_size; - int size; - bool fancy; -}; - -struct DistData : public StatData -{ - /** Local storage for the entry values, used for printing. */ - DistDataData data; -}; - -template <class Stat> -class DistStatData : public DistData -{ - protected: - Stat &s; - - public: - DistStatData(Stat &stat) : s(stat) {} - - virtual bool check() const { return s.check(); } - virtual void reset() { s.reset(); } - virtual bool zero() const { return s.zero(); } - virtual void visit(Visit &visitor) - { - s.update(this); - visitor.visit(*this); - } -}; - -struct VectorDistData : public StatData -{ - std::vector<DistDataData> data; - - /** Names and descriptions of subfields. */ - mutable std::vector<std::string> subnames; - mutable std::vector<std::string> subdescs; - - /** Local storage for the entry values, used for printing. */ - mutable VResult rvec; - - virtual size_t size() const = 0; - void update() - { - int s = size(); - if (subnames.size() < s) - subnames.resize(s); - - if (subdescs.size() < s) - subdescs.resize(s); - } -}; - -template <class Stat> -class VectorDistStatData : public VectorDistData -{ - protected: - Stat &s; - - public: - VectorDistStatData(Stat &stat) : s(stat) {} - - virtual bool check() const { return s.check(); } - virtual void reset() { s.reset(); } - virtual size_t size() const { return s.size(); } - virtual bool zero() const { return s.zero(); } - virtual void visit(Visit &visitor) - { - update(); - s.update(this); - visitor.visit(*this); - } -}; - -struct Vector2dData : public StatData -{ - /** Names and descriptions of subfields. */ - std::vector<std::string> subnames; - std::vector<std::string> subdescs; - std::vector<std::string> y_subnames; - - /** Local storage for the entry values, used for printing. */ - mutable VCounter cvec; - mutable int x; - mutable int y; - - void update() - { - if (subnames.size() < x) - subnames.resize(x); - } -}; - -template <class Stat> -class Vector2dStatData : public Vector2dData -{ - protected: - Stat &s; - - public: - Vector2dStatData(Stat &stat) : s(stat) {} - - virtual bool check() const { return s.check(); } - virtual void reset() { s.reset(); } - virtual bool zero() const { return s.zero(); } - virtual void visit(Visit &visitor) - { - update(); - s.update(this); - visitor.visit(*this); - } -}; - -class DataAccess -{ - protected: - StatData *find() const; - void map(StatData *data); - - StatData *statData(); - const StatData *statData() const; - - void setInit(); - void setPrint(); -}; - -template <class Parent, class Child, template <class> class Data> -class Wrap : public Child -{ - protected: - Parent &self() { return *reinterpret_cast<Parent *>(this); } - - protected: - Data<Child> *statData() - { - StatData *__data = DataAccess::statData(); - Data<Child> *ptr = dynamic_cast<Data<Child> *>(__data); - assert(ptr); - return ptr; - } - - public: - const Data<Child> *statData() const - { - const StatData *__data = DataAccess::statData(); - const Data<Child> *ptr = dynamic_cast<const Data<Child> *>(__data); - assert(ptr); - return ptr; - } - - protected: - /** - * Copy constructor, copies are not allowed. - */ - Wrap(const Wrap &stat); - /** - * Can't copy stats. - */ - void operator=(const Wrap &); - - public: - Wrap() - { - map(new Data<Child>(*this)); - } - - /** - * Set the name and marks this stat to print at the end of simulation. - * @param name The new name. - * @return A reference to this stat. - */ - Parent &name(const std::string &_name) - { - Data<Child> *data = this->statData(); - data->name = _name; - this->setPrint(); - return this->self(); - } - - /** - * Set the description and marks this stat to print at the end of - * simulation. - * @param desc The new description. - * @return A reference to this stat. - */ - Parent &desc(const std::string &_desc) - { - this->statData()->desc = _desc; - return this->self(); - } - - /** - * Set the precision and marks this stat to print at the end of simulation. - * @param p The new precision - * @return A reference to this stat. - */ - Parent &precision(int _precision) - { - this->statData()->precision = _precision; - return this->self(); - } - - /** - * Set the flags and marks this stat to print at the end of simulation. - * @param f The new flags. - * @return A reference to this stat. - */ - Parent &flags(StatFlags _flags) - { - this->statData()->flags |= _flags; - return this->self(); - } - - /** - * Set the prerequisite stat and marks this stat to print at the end of - * simulation. - * @param prereq The prerequisite stat. - * @return A reference to this stat. - */ - template <class Stat> - Parent &prereq(const Stat &prereq) - { - this->statData()->prereq = prereq.statData(); - return this->self(); - } -}; - -template <class Parent, class Child, template <class Child> class Data> -class WrapVec : public Wrap<Parent, Child, Data> -{ - public: - // The following functions are specific to vectors. If you use them - // in a non vector context, you will get a nice compiler error! - - /** - * Set the subfield name for the given index, and marks this stat to print - * at the end of simulation. - * @param index The subfield index. - * @param name The new name of the subfield. - * @return A reference to this stat. - */ - Parent &subname(int index, const std::string &name) - { - std::vector<std::string> &subn = this->statData()->subnames; - if (subn.size() <= index) - subn.resize(index + 1); - subn[index] = name; - return this->self(); - } - - /** - * Set the subfield description for the given index and marks this stat to - * print at the end of simulation. - * @param index The subfield index. - * @param desc The new description of the subfield - * @return A reference to this stat. - */ - Parent &subdesc(int index, const std::string &desc) - { - std::vector<std::string> &subd = this->statData()->subdescs; - if (subd.size() <= index) - subd.resize(index + 1); - subd[index] = desc; - - return this->self(); - } - -}; - -template <class Parent, class Child, template <class Child> class Data> -class WrapVec2d : public WrapVec<Parent, Child, Data> -{ - public: - /** - * @warning This makes the assumption that if you're gonna subnames a 2d - * vector, you're subnaming across all y - */ - Parent &ysubnames(const char **names) - { - Data<Child> *data = this->statData(); - data->y_subnames.resize(this->y); - for (int i = 0; i < this->y; ++i) - data->y_subnames[i] = names[i]; - return this->self(); - } - Parent &ysubname(int index, const std::string subname) - { - Data<Child> *data = this->statData(); - assert(index < this->y); - data->y_subnames.resize(this->y); - data->y_subnames[index] = subname.c_str(); - return this->self(); - } -}; - -////////////////////////////////////////////////////////////////////// -// -// Simple Statistics -// -////////////////////////////////////////////////////////////////////// - -/** - * Templatized storage and interface for a simple scalar stat. - */ -struct StatStor -{ - public: - /** The paramaters for this storage type, none for a scalar. */ - struct Params { }; - - private: - /** The statistic value. */ - Counter data; - - public: - /** - * Builds this storage element and calls the base constructor of the - * datatype. - */ - StatStor(const Params &) : data(Counter()) {} - - /** - * The the stat to the given value. - * @param val The new value. - * @param p The paramters of this storage type. - */ - void set(Counter val, const Params &p) { data = val; } - /** - * Increment the stat by the given value. - * @param val The new value. - * @param p The paramters of this storage type. - */ - void inc(Counter val, const Params &p) { data += val; } - /** - * Decrement the stat by the given value. - * @param val The new value. - * @param p The paramters of this storage type. - */ - void dec(Counter val, const Params &p) { data -= val; } - /** - * Return the value of this stat as its base type. - * @param p The params of this storage type. - * @return The value of this stat. - */ - Counter value(const Params &p) const { return data; } - /** - * Return the value of this stat as a result type. - * @param p The parameters of this storage type. - * @return The value of this stat. - */ - Result result(const Params &p) const { return (Result)data; } - /** - * Reset stat value to default - */ - void reset() { data = Counter(); } - - /** - * @return true if zero value - */ - bool zero() const { return data == Counter(); } -}; - -/** - * Templatized storage and interface to a per-cycle average stat. This keeps - * a current count and updates a total (count * cycles) when this count - * changes. This allows the quick calculation of a per cycle count of the item - * being watched. This is good for keeping track of residencies in structures - * among other things. - */ -struct AvgStor -{ - public: - /** The paramaters for this storage type */ - struct Params { }; - - private: - /** The current count. */ - Counter current; - /** The total count for all cycles. */ - mutable Result total; - /** The cycle that current last changed. */ - mutable Tick last; - - public: - /** - * Build and initializes this stat storage. - */ - AvgStor(Params &p) : current(0), total(0), last(0) { } - - /** - * Set the current count to the one provided, update the total and last - * set values. - * @param val The new count. - * @param p The parameters for this storage. - */ - void set(Counter val, Params &p) { - total += current * (curTick - last); - last = curTick; - current = val; - } - - /** - * Increment the current count by the provided value, calls set. - * @param val The amount to increment. - * @param p The parameters for this storage. - */ - void inc(Counter val, Params &p) { set(current + val, p); } - - /** - * Deccrement the current count by the provided value, calls set. - * @param val The amount to decrement. - * @param p The parameters for this storage. - */ - void dec(Counter val, Params &p) { set(current - val, p); } - - /** - * Return the current count. - * @param p The parameters for this storage. - * @return The current count. - */ - Counter value(const Params &p) const { return current; } - - /** - * Return the current average. - * @param p The parameters for this storage. - * @return The current average. - */ - Result result(const Params &p) const - { - total += current * (curTick - last); - last = curTick; - return (Result)(total + current) / (Result)(curTick + 1); - } - - /** - * Reset stat value to default - */ - void reset() - { - total = 0; - last = curTick; - } - - /** - * @return true if zero value - */ - bool zero() const { return total == 0.0; } -}; - -/** - * Implementation of a scalar stat. The type of stat is determined by the - * Storage template. - */ -template <class Stor> -class ScalarBase : public DataAccess -{ - public: - typedef Stor Storage; - - /** Define the params of the storage class. */ - typedef typename Storage::Params Params; - - protected: - /** The storage of this stat. */ - char storage[sizeof(Storage)]; - - /** The parameters for this stat. */ - Params params; - - protected: - /** - * Retrieve the storage. - * @param index The vector index to access. - * @return The storage object at the given index. - */ - Storage * - data() - { - return reinterpret_cast<Storage *>(storage); - } - - /** - * Retrieve a const pointer to the storage. - * for the given index. - * @param index The vector index to access. - * @return A const pointer to the storage object at the given index. - */ - const Storage * - data() const - { - return reinterpret_cast<const Storage *>(storage); - } - - void - doInit() - { - new (storage) Storage(params); - setInit(); - } - - public: - /** - * Return the current value of this stat as its base type. - * @return The current value. - */ - Counter value() const { return data()->value(params); } - - public: - /** - * Create and initialize this stat, register it with the database. - */ - ScalarBase() - { } - - public: - // Common operators for stats - /** - * Increment the stat by 1. This calls the associated storage object inc - * function. - */ - void operator++() { data()->inc(1, params); } - /** - * Decrement the stat by 1. This calls the associated storage object dec - * function. - */ - void operator--() { data()->dec(1, params); } - - /** Increment the stat by 1. */ - void operator++(int) { ++*this; } - /** Decrement the stat by 1. */ - void operator--(int) { --*this; } - - /** - * Set the data value to the given value. This calls the associated storage - * object set function. - * @param v The new value. - */ - template <typename U> - void operator=(const U &v) { data()->set(v, params); } - - /** - * Increment the stat by the given value. This calls the associated - * storage object inc function. - * @param v The value to add. - */ - template <typename U> - void operator+=(const U &v) { data()->inc(v, params); } - - /** - * Decrement the stat by the given value. This calls the associated - * storage object dec function. - * @param v The value to substract. - */ - template <typename U> - void operator-=(const U &v) { data()->dec(v, params); } - - /** - * Return the number of elements, always 1 for a scalar. - * @return 1. - */ - size_t size() const { return 1; } - - bool check() const { return true; } - - /** - * Reset stat value to default - */ - void reset() { data()->reset(); } - - Counter value() { return data()->value(params); } - - Result result() { return data()->result(params); } - - Result total() { return result(); } - - bool zero() { return result() == 0.0; } - -}; - -class ProxyData : public ScalarData -{ - public: - virtual void visit(Visit &visitor) { visitor.visit(*this); } - virtual std::string str() const { return to_string(value()); } - virtual size_t size() const { return 1; } - virtual bool zero() const { return value() == 0; } - virtual bool check() const { return true; } - virtual void reset() { } -}; - -template <class T> -class ValueProxy : public ProxyData -{ - private: - T *scalar; - - public: - ValueProxy(T &val) : scalar(&val) {} - virtual Counter value() const { return *scalar; } - virtual Result result() const { return *scalar; } - virtual Result total() const { return *scalar; } -}; - -template <class T> -class FunctorProxy : public ProxyData -{ - private: - T *functor; - - public: - FunctorProxy(T &func) : functor(&func) {} - virtual Counter value() const { return (*functor)(); } - virtual Result result() const { return (*functor)(); } - virtual Result total() const { return (*functor)(); } -}; - -class ValueBase : public DataAccess -{ - private: - ProxyData *proxy; - - public: - ValueBase() : proxy(NULL) { } - ~ValueBase() { if (proxy) delete proxy; } - - template <class T> - void scalar(T &value) - { - proxy = new ValueProxy<T>(value); - setInit(); - } - - template <class T> - void functor(T &func) - { - proxy = new FunctorProxy<T>(func); - setInit(); - } - - Counter value() { return proxy->value(); } - Result result() const { return proxy->result(); } - Result total() const { return proxy->total(); }; - size_t size() const { return proxy->size(); } - - std::string str() const { return proxy->str(); } - bool zero() const { return proxy->zero(); } - bool check() const { return proxy != NULL; } - void reset() { } -}; - -////////////////////////////////////////////////////////////////////// -// -// Vector Statistics -// -////////////////////////////////////////////////////////////////////// - -/** - * A proxy class to access the stat at a given index in a VectorBase stat. - * Behaves like a ScalarBase. - */ -template <class Stat> -class ScalarProxy -{ - private: - /** Pointer to the parent Vector. */ - Stat *stat; - - /** The index to access in the parent VectorBase. */ - int index; - - public: - /** - * Return the current value of this stat as its base type. - * @return The current value. - */ - Counter value() const { return stat->data(index)->value(stat->params); } - - /** - * Return the current value of this statas a result type. - * @return The current value. - */ - Result result() const { return stat->data(index)->result(stat->params); } - - public: - /** - * Create and initialize this proxy, do not register it with the database. - * @param p The params to use. - * @param i The index to access. - */ - ScalarProxy(Stat *s, int i) - : stat(s), index(i) - { - assert(stat); - } - - /** - * Create a copy of the provided ScalarProxy. - * @param sp The proxy to copy. - */ - ScalarProxy(const ScalarProxy &sp) - : stat(sp.stat), index(sp.index) - {} - - /** - * Set this proxy equal to the provided one. - * @param sp The proxy to copy. - * @return A reference to this proxy. - */ - const ScalarProxy &operator=(const ScalarProxy &sp) { - stat = sp.stat; - index = sp.index; - return *this; - } - - public: - // Common operators for stats - /** - * Increment the stat by 1. This calls the associated storage object inc - * function. - */ - void operator++() { stat->data(index)->inc(1, stat->params); } - /** - * Decrement the stat by 1. This calls the associated storage object dec - * function. - */ - void operator--() { stat->data(index)->dec(1, stat->params); } - - /** Increment the stat by 1. */ - void operator++(int) { ++*this; } - /** Decrement the stat by 1. */ - void operator--(int) { --*this; } - - /** - * Set the data value to the given value. This calls the associated storage - * object set function. - * @param v The new value. - */ - template <typename U> - void operator=(const U &v) { stat->data(index)->set(v, stat->params); } - - /** - * Increment the stat by the given value. This calls the associated - * storage object inc function. - * @param v The value to add. - */ - template <typename U> - void operator+=(const U &v) { stat->data(index)->inc(v, stat->params); } - - /** - * Decrement the stat by the given value. This calls the associated - * storage object dec function. - * @param v The value to substract. - */ - template <typename U> - void operator-=(const U &v) { stat->data(index)->dec(v, stat->params); } - - /** - * Return the number of elements, always 1 for a scalar. - * @return 1. - */ - size_t size() const { return 1; } - - /** - * This stat has no state. Nothing to reset - */ - void reset() { } - - public: - std::string - str() const - { - return csprintf("%s[%d]", stat->str(), index); - - } -}; - -/** - * Implementation of a vector of stats. The type of stat is determined by the - * Storage class. @sa ScalarBase - */ -template <class Stor> -class VectorBase : public DataAccess -{ - public: - typedef Stor Storage; - - /** Define the params of the storage class. */ - typedef typename Storage::Params Params; - - /** Proxy type */ - typedef ScalarProxy<VectorBase<Storage> > Proxy; - - friend class ScalarProxy<VectorBase<Storage> >; - - protected: - /** The storage of this stat. */ - Storage *storage; - size_t _size; - - /** The parameters for this stat. */ - Params params; - - protected: - /** - * Retrieve the storage. - * @param index The vector index to access. - * @return The storage object at the given index. - */ - Storage *data(int index) { return &storage[index]; } - - /** - * Retrieve a const pointer to the storage. - * @param index The vector index to access. - * @return A const pointer to the storage object at the given index. - */ - const Storage *data(int index) const { return &storage[index]; } - - void - doInit(int s) - { - assert(s > 0 && "size must be positive!"); - assert(!storage && "already initialized"); - _size = s; - - char *ptr = new char[_size * sizeof(Storage)]; - storage = reinterpret_cast<Storage *>(ptr); - - for (int i = 0; i < _size; ++i) - new (&storage[i]) Storage(params); - - setInit(); - } - - public: - void value(VCounter &vec) const - { - vec.resize(size()); - for (int i = 0; i < size(); ++i) - vec[i] = data(i)->value(params); - } - - /** - * Copy the values to a local vector and return a reference to it. - * @return A reference to a vector of the stat values. - */ - void result(VResult &vec) const - { - vec.resize(size()); - for (int i = 0; i < size(); ++i) - vec[i] = data(i)->result(params); - } - - /** - * Return a total of all entries in this vector. - * @return The total of all vector entries. - */ - Result total() const { - Result total = 0.0; - for (int i = 0; i < size(); ++i) - total += data(i)->result(params); - return total; - } - - /** - * @return the number of elements in this vector. - */ - size_t size() const { return _size; } - - bool - zero() const - { - for (int i = 0; i < size(); ++i) - if (data(i)->zero()) - return false; - return true; - } - - bool - check() const - { - return storage != NULL; - } - - void - reset() - { - for (int i = 0; i < size(); ++i) - data(i)->reset(); - } - - public: - VectorBase() - : storage(NULL) - {} - - ~VectorBase() - { - if (!storage) - return; - - for (int i = 0; i < _size; ++i) - data(i)->~Storage(); - delete [] reinterpret_cast<char *>(storage); - } - - /** - * Return a reference (ScalarProxy) to the stat at the given index. - * @param index The vector index to access. - * @return A reference of the stat. - */ - Proxy - operator[](int index) - { - assert (index >= 0 && index < size()); - return Proxy(this, index); - } - - void update(StatData *data) {} -}; - -template <class Stat> -class VectorProxy -{ - private: - Stat *stat; - int offset; - int len; - - private: - mutable VResult vec; - - typename Stat::Storage * - data(int index) - { - assert(index < len); - return stat->data(offset + index); - } - - const typename Stat::Storage * - data(int index) const - { - assert(index < len); - return const_cast<Stat *>(stat)->data(offset + index); - } - - public: - const VResult & - result() const - { - vec.resize(size()); - - for (int i = 0; i < size(); ++i) - vec[i] = data(i)->result(stat->params); - - return vec; - } - - Result - total() const - { - Result total = 0; - for (int i = 0; i < size(); ++i) - total += data(i)->result(stat->params); - return total; - } - - public: - VectorProxy(Stat *s, int o, int l) - : stat(s), offset(o), len(l) - { - } - - VectorProxy(const VectorProxy &sp) - : stat(sp.stat), offset(sp.offset), len(sp.len) - { - } - - const VectorProxy & - operator=(const VectorProxy &sp) - { - stat = sp.stat; - offset = sp.offset; - len = sp.len; - return *this; - } - - ScalarProxy<Stat> operator[](int index) - { - assert (index >= 0 && index < size()); - return ScalarProxy<Stat>(stat, offset + index); - } - - size_t size() const { return len; } - - /** - * This stat has no state. Nothing to reset. - */ - void reset() { } -}; - -template <class Stor> -class Vector2dBase : public DataAccess -{ - public: - typedef Stor Storage; - typedef typename Storage::Params Params; - typedef VectorProxy<Vector2dBase<Storage> > Proxy; - friend class ScalarProxy<Vector2dBase<Storage> >; - friend class VectorProxy<Vector2dBase<Storage> >; - - protected: - size_t x; - size_t y; - size_t _size; - Storage *storage; - Params params; - - protected: - Storage *data(int index) { return &storage[index]; } - const Storage *data(int index) const { return &storage[index]; } - - void - doInit(int _x, int _y) - { - assert(_x > 0 && _y > 0 && "sizes must be positive!"); - assert(!storage && "already initialized"); - - Vector2dData *statdata = dynamic_cast<Vector2dData *>(find()); - - x = _x; - y = _y; - statdata->x = _x; - statdata->y = _y; - _size = x * y; - - char *ptr = new char[_size * sizeof(Storage)]; - storage = reinterpret_cast<Storage *>(ptr); - - for (int i = 0; i < _size; ++i) - new (&storage[i]) Storage(params); - - setInit(); - } - - public: - Vector2dBase() - : storage(NULL) - {} - - ~Vector2dBase() - { - if (!storage) - return; - - for (int i = 0; i < _size; ++i) - data(i)->~Storage(); - delete [] reinterpret_cast<char *>(storage); - } - - void - update(Vector2dData *newdata) - { - int size = this->size(); - newdata->cvec.resize(size); - for (int i = 0; i < size; ++i) - newdata->cvec[i] = data(i)->value(params); - } - - std::string ysubname(int i) const { return (*this->y_subnames)[i]; } - - Proxy - operator[](int index) - { - int offset = index * y; - assert (index >= 0 && offset + index < size()); - return Proxy(this, offset, y); - } - - - size_t - size() const - { - return _size; - } - - bool - zero() const - { - return data(0)->zero(); -#if 0 - for (int i = 0; i < size(); ++i) - if (!data(i)->zero()) - return false; - return true; -#endif - } - - /** - * Reset stat value to default - */ - void - reset() - { - for (int i = 0; i < size(); ++i) - data(i)->reset(); - } - - bool - check() - { - return storage != NULL; - } -}; - -////////////////////////////////////////////////////////////////////// -// -// Non formula statistics -// -////////////////////////////////////////////////////////////////////// - -/** - * Templatized storage and interface for a distrbution stat. - */ -struct DistStor -{ - public: - /** The parameters for a distribution stat. */ - struct Params - { - /** The minimum value to track. */ - Counter min; - /** The maximum value to track. */ - Counter max; - /** The number of entries in each bucket. */ - Counter bucket_size; - /** The number of buckets. Equal to (max-min)/bucket_size. */ - int size; - }; - enum { fancy = false }; - - private: - /** The smallest value sampled. */ - Counter min_val; - /** The largest value sampled. */ - Counter max_val; - /** The number of values sampled less than min. */ - Counter underflow; - /** The number of values sampled more than max. */ - Counter overflow; - /** The current sum. */ - Counter sum; - /** The sum of squares. */ - Counter squares; - /** The number of samples. */ - Counter samples; - /** Counter for each bucket. */ - VCounter cvec; - - public: - DistStor(const Params ¶ms) - : cvec(params.size) - { - reset(); - } - - /** - * Add a value to the distribution for the given number of times. - * @param val The value to add. - * @param number The number of times to add the value. - * @param params The paramters of the distribution. - */ - void sample(Counter val, int number, const Params ¶ms) - { - if (val < params.min) - underflow += number; - else if (val > params.max) - overflow += number; - else { - int index = (int)floor((val - params.min) / params.bucket_size); - assert(index < size(params)); - cvec[index] += number; - } - - if (val < min_val) - min_val = val; - - if (val > max_val) - max_val = val; - - Counter sample = val * number; - sum += sample; - squares += sample * sample; - samples += number; - } - - /** - * Return the number of buckets in this distribution. - * @return the number of buckets. - * @todo Is it faster to return the size from the parameters? - */ - size_t size(const Params &) const { return cvec.size(); } - - /** - * Returns true if any calls to sample have been made. - * @param params The paramters of the distribution. - * @return True if any values have been sampled. - */ - bool zero(const Params ¶ms) const - { - return samples == Counter(); - } - - void update(DistDataData *data, const Params ¶ms) - { - data->min = params.min; - data->max = params.max; - data->bucket_size = params.bucket_size; - data->size = params.size; - - data->min_val = (min_val == INT_MAX) ? 0 : min_val; - data->max_val = (max_val == INT_MIN) ? 0 : max_val; - data->underflow = underflow; - data->overflow = overflow; - data->cvec.resize(params.size); - for (int i = 0; i < params.size; ++i) - data->cvec[i] = cvec[i]; - - data->sum = sum; - data->squares = squares; - data->samples = samples; - } - - /** - * Reset stat value to default - */ - void reset() - { - min_val = INT_MAX; - max_val = INT_MIN; - underflow = 0; - overflow = 0; - - int size = cvec.size(); - for (int i = 0; i < size; ++i) - cvec[i] = Counter(); - - sum = Counter(); - squares = Counter(); - samples = Counter(); - } -}; - -/** - * Templatized storage and interface for a distribution that calculates mean - * and variance. - */ -struct FancyStor -{ - public: - /** - * No paramters for this storage. - */ - struct Params {}; - enum { fancy = true }; - - private: - /** The current sum. */ - Counter sum; - /** The sum of squares. */ - Counter squares; - /** The number of samples. */ - Counter samples; - - public: - /** - * Create and initialize this storage. - */ - FancyStor(const Params &) - : sum(Counter()), squares(Counter()), samples(Counter()) - { } - - /** - * Add a value the given number of times to this running average. - * Update the running sum and sum of squares, increment the number of - * values seen by the given number. - * @param val The value to add. - * @param number The number of times to add the value. - * @param p The parameters of this stat. - */ - void sample(Counter val, int number, const Params &p) - { - Counter value = val * number; - sum += value; - squares += value * value; - samples += number; - } - - void update(DistDataData *data, const Params ¶ms) - { - data->sum = sum; - data->squares = squares; - data->samples = samples; - } - - /** - * Return the number of entries in this stat, 1 - * @return 1. - */ - size_t size(const Params &) const { return 1; } - - /** - * Return true if no samples have been added. - * @return True if no samples have been added. - */ - bool zero(const Params &) const { return samples == Counter(); } - - /** - * Reset stat value to default - */ - void reset() - { - sum = Counter(); - squares = Counter(); - samples = Counter(); - } -}; - -/** - * Templatized storage for distribution that calculates per cycle mean and - * variance. - */ -struct AvgFancy -{ - public: - /** No parameters for this storage. */ - struct Params {}; - enum { fancy = true }; - - private: - /** Current total. */ - Counter sum; - /** Current sum of squares. */ - Counter squares; - - public: - /** - * Create and initialize this storage. - */ - AvgFancy(const Params &) : sum(Counter()), squares(Counter()) {} - - /** - * Add a value to the distribution for the given number of times. - * Update the running sum and sum of squares. - * @param val The value to add. - * @param number The number of times to add the value. - * @param p The paramters of the distribution. - */ - void sample(Counter val, int number, const Params &p) - { - Counter value = val * number; - sum += value; - squares += value * value; - } - - void update(DistDataData *data, const Params ¶ms) - { - data->sum = sum; - data->squares = squares; - data->samples = curTick; - } - - /** - * Return the number of entries, in this case 1. - * @return 1. - */ - size_t size(const Params ¶ms) const { return 1; } - /** - * Return true if no samples have been added. - * @return True if the sum is zero. - */ - bool zero(const Params ¶ms) const { return sum == Counter(); } - /** - * Reset stat value to default - */ - void reset() - { - sum = Counter(); - squares = Counter(); - } -}; - -/** - * Implementation of a distribution stat. The type of distribution is - * determined by the Storage template. @sa ScalarBase - */ -template <class Stor> -class DistBase : public DataAccess -{ - public: - typedef Stor Storage; - /** Define the params of the storage class. */ - typedef typename Storage::Params Params; - - protected: - /** The storage for this stat. */ - char storage[sizeof(Storage)]; - - /** The parameters for this stat. */ - Params params; - - protected: - /** - * Retrieve the storage. - * @return The storage object for this stat. - */ - Storage *data() - { - return reinterpret_cast<Storage *>(storage); - } - - /** - * Retrieve a const pointer to the storage. - * @return A const pointer to the storage object for this stat. - */ - const Storage * - data() const - { - return reinterpret_cast<const Storage *>(storage); - } - - void - doInit() - { - new (storage) Storage(params); - setInit(); - } - - public: - DistBase() { } - - /** - * Add a value to the distribtion n times. Calls sample on the storage - * class. - * @param v The value to add. - * @param n The number of times to add it, defaults to 1. - */ - template <typename U> - void sample(const U &v, int n = 1) { data()->sample(v, n, params); } - - /** - * Return the number of entries in this stat. - * @return The number of entries. - */ - size_t size() const { return data()->size(params); } - /** - * Return true if no samples have been added. - * @return True if there haven't been any samples. - */ - bool zero() const { return data()->zero(params); } - - void update(DistData *base) - { - base->data.fancy = Storage::fancy; - data()->update(&(base->data), params); - } - - /** - * Reset stat value to default - */ - void - reset() - { - data()->reset(); - } - - bool - check() - { - return true; - } -}; - -template <class Stat> -class DistProxy; - -template <class Stor> -class VectorDistBase : public DataAccess -{ - public: - typedef Stor Storage; - typedef typename Storage::Params Params; - typedef DistProxy<VectorDistBase<Storage> > Proxy; - friend class DistProxy<VectorDistBase<Storage> >; - - protected: - Storage *storage; - size_t _size; - Params params; - - protected: - Storage * - data(int index) - { - return &storage[index]; - } - - const Storage * - data(int index) const - { - return &storage[index]; - } - - void - doInit(int s) - { - assert(s > 0 && "size must be positive!"); - assert(!storage && "already initialized"); - _size = s; - - char *ptr = new char[_size * sizeof(Storage)]; - storage = reinterpret_cast<Storage *>(ptr); - - for (int i = 0; i < _size; ++i) - new (&storage[i]) Storage(params); - - setInit(); - } - - public: - VectorDistBase() - : storage(NULL) - {} - - ~VectorDistBase() - { - if (!storage) - return ; - - for (int i = 0; i < _size; ++i) - data(i)->~Storage(); - delete [] reinterpret_cast<char *>(storage); - } - - Proxy operator[](int index); - - size_t - size() const - { - return _size; - } - - bool - zero() const - { - return false; -#if 0 - for (int i = 0; i < size(); ++i) - if (!data(i)->zero(params)) - return false; - return true; -#endif - } - - /** - * Reset stat value to default - */ - void - reset() - { - for (int i = 0; i < size(); ++i) - data(i)->reset(); - } - - bool - check() - { - return storage != NULL; - } - - void - update(VectorDistData *base) - { - int size = this->size(); - base->data.resize(size); - for (int i = 0; i < size; ++i) { - base->data[i].fancy = Storage::fancy; - data(i)->update(&(base->data[i]), params); - } - } -}; - -template <class Stat> -class DistProxy -{ - private: - Stat *stat; - int index; - - protected: - typename Stat::Storage *data() { return stat->data(index); } - const typename Stat::Storage *data() const { return stat->data(index); } - - public: - DistProxy(Stat *s, int i) - : stat(s), index(i) - {} - - DistProxy(const DistProxy &sp) - : stat(sp.stat), index(sp.index) - {} - - const DistProxy &operator=(const DistProxy &sp) - { - stat = sp.stat; - index = sp.index; - return *this; - } - - public: - template <typename U> - void - sample(const U &v, int n = 1) - { - data()->sample(v, n, stat->params); - } - - size_t - size() const - { - return 1; - } - - bool - zero() const - { - return data()->zero(stat->params); - } - - /** - * Proxy has no state. Nothing to reset. - */ - void reset() { } -}; - -template <class Storage> -inline typename VectorDistBase<Storage>::Proxy -VectorDistBase<Storage>::operator[](int index) -{ - assert (index >= 0 && index < size()); - return typename VectorDistBase<Storage>::Proxy(this, index); -} - -#if 0 -template <class Storage> -Result -VectorDistBase<Storage>::total(int index) const -{ - int total = 0; - for (int i = 0; i < x_size(); ++i) { - total += data(i)->result(stat->params); - } -} -#endif - -////////////////////////////////////////////////////////////////////// -// -// Formula Details -// -////////////////////////////////////////////////////////////////////// - -/** - * Base class for formula statistic node. These nodes are used to build a tree - * that represents the formula. - */ -class Node : public RefCounted -{ - public: - /** - * Return the number of nodes in the subtree starting at this node. - * @return the number of nodes in this subtree. - */ - virtual size_t size() const = 0; - /** - * Return the result vector of this subtree. - * @return The result vector of this subtree. - */ - virtual const VResult &result() const = 0; - /** - * Return the total of the result vector. - * @return The total of the result vector. - */ - virtual Result total() const = 0; - - /** - * - */ - virtual std::string str() const = 0; -}; - -/** Reference counting pointer to a function Node. */ -typedef RefCountingPtr<Node> NodePtr; - -class ScalarStatNode : public Node -{ - private: - const ScalarData *data; - mutable VResult vresult; - - public: - ScalarStatNode(const ScalarData *d) : data(d), vresult(1) {} - virtual const VResult &result() const - { - vresult[0] = data->result(); - return vresult; - } - virtual Result total() const { return data->result(); }; - - virtual size_t size() const { return 1; } - - /** - * - */ - virtual std::string str() const { return data->name; } -}; - -template <class Stat> -class ScalarProxyNode : public Node -{ - private: - const ScalarProxy<Stat> proxy; - mutable VResult vresult; - - public: - ScalarProxyNode(const ScalarProxy<Stat> &p) - : proxy(p), vresult(1) - { } - - virtual const VResult & - result() const - { - vresult[0] = proxy.result(); - return vresult; - } - - virtual Result - total() const - { - return proxy.result(); - } - - virtual size_t - size() const - { - return 1; - } - - /** - * - */ - virtual std::string - str() const - { - return proxy.str(); - } -}; - -class VectorStatNode : public Node -{ - private: - const VectorData *data; - - public: - VectorStatNode(const VectorData *d) : data(d) { } - virtual const VResult &result() const { return data->result(); } - virtual Result total() const { return data->total(); }; - - virtual size_t size() const { return data->size(); } - - virtual std::string str() const { return data->name; } -}; - -template <class T> -class ConstNode : public Node -{ - private: - VResult vresult; - - public: - ConstNode(T s) : vresult(1, (Result)s) {} - const VResult &result() const { return vresult; } - virtual Result total() const { return vresult[0]; }; - virtual size_t size() const { return 1; } - virtual std::string str() const { return to_string(vresult[0]); } -}; - -template <class Op> -struct OpString; - -template<> -struct OpString<std::plus<Result> > -{ - static std::string str() { return "+"; } -}; - -template<> -struct OpString<std::minus<Result> > -{ - static std::string str() { return "-"; } -}; - -template<> -struct OpString<std::multiplies<Result> > -{ - static std::string str() { return "*"; } -}; - -template<> -struct OpString<std::divides<Result> > -{ - static std::string str() { return "/"; } -}; - -template<> -struct OpString<std::modulus<Result> > -{ - static std::string str() { return "%"; } -}; - -template<> -struct OpString<std::negate<Result> > -{ - static std::string str() { return "-"; } -}; - -template <class Op> -class UnaryNode : public Node -{ - public: - NodePtr l; - mutable VResult vresult; - - public: - UnaryNode(NodePtr &p) : l(p) {} - - const VResult &result() const - { - const VResult &lvec = l->result(); - int size = lvec.size(); - - assert(size > 0); - - vresult.resize(size); - Op op; - for (int i = 0; i < size; ++i) - vresult[i] = op(lvec[i]); - - return vresult; - } - - Result total() const { - Op op; - return op(l->total()); - } - - virtual size_t size() const { return l->size(); } - - virtual std::string str() const - { - return OpString<Op>::str() + l->str(); - } -}; - -template <class Op> -class BinaryNode : public Node -{ - public: - NodePtr l; - NodePtr r; - mutable VResult vresult; - - public: - BinaryNode(NodePtr &a, NodePtr &b) : l(a), r(b) {} - - const VResult &result() const - { - Op op; - const VResult &lvec = l->result(); - const VResult &rvec = r->result(); - - assert(lvec.size() > 0 && rvec.size() > 0); - - if (lvec.size() == 1 && rvec.size() == 1) { - vresult.resize(1); - vresult[0] = op(lvec[0], rvec[0]); - } else if (lvec.size() == 1) { - int size = rvec.size(); - vresult.resize(size); - for (int i = 0; i < size; ++i) - vresult[i] = op(lvec[0], rvec[i]); - } else if (rvec.size() == 1) { - int size = lvec.size(); - vresult.resize(size); - for (int i = 0; i < size; ++i) - vresult[i] = op(lvec[i], rvec[0]); - } else if (rvec.size() == lvec.size()) { - int size = rvec.size(); - vresult.resize(size); - for (int i = 0; i < size; ++i) - vresult[i] = op(lvec[i], rvec[i]); - } - - return vresult; - } - - Result total() const { - Op op; - return op(l->total(), r->total()); - } - - virtual size_t size() const { - int ls = l->size(); - int rs = r->size(); - if (ls == 1) - return rs; - else if (rs == 1) - return ls; - else { - assert(ls == rs && "Node vector sizes are not equal"); - return ls; - } - } - - virtual std::string str() const - { - return csprintf("(%s %s %s)", l->str(), OpString<Op>::str(), r->str()); - } -}; - -template <class Op> -class SumNode : public Node -{ - public: - NodePtr l; - mutable VResult vresult; - - public: - SumNode(NodePtr &p) : l(p), vresult(1) {} - - const VResult &result() const - { - const VResult &lvec = l->result(); - int size = lvec.size(); - assert(size > 0); - - vresult[0] = 0.0; - - Op op; - for (int i = 0; i < size; ++i) - vresult[0] = op(vresult[0], lvec[i]); - - return vresult; - } - - Result total() const - { - const VResult &lvec = l->result(); - int size = lvec.size(); - assert(size > 0); - - Result vresult = 0.0; - - Op op; - for (int i = 0; i < size; ++i) - vresult = op(vresult, lvec[i]); - - return vresult; - } - - virtual size_t size() const { return 1; } - - virtual std::string str() const - { - return csprintf("total(%s)", l->str()); - } -}; - - -////////////////////////////////////////////////////////////////////// -// -// Visible Statistics Types -// -////////////////////////////////////////////////////////////////////// -/** - * @defgroup VisibleStats "Statistic Types" - * These are the statistics that are used in the simulator. - * @{ - */ - -/** - * This is a simple scalar statistic, like a counter. - * @sa Stat, ScalarBase, StatStor - */ -template<int N = 0> -class Scalar : public Wrap<Scalar<N>, ScalarBase<StatStor>, ScalarStatData> -{ - public: - /** The base implementation. */ - typedef ScalarBase<StatStor> Base; - - Scalar() - { - this->doInit(); - } - - /** - * Sets the stat equal to the given value. Calls the base implementation - * of operator= - * @param v The new value. - */ - template <typename U> - void operator=(const U &v) { Base::operator=(v); } -}; - -class Value : public Wrap<Value, ValueBase, ScalarStatData> -{ - public: - /** The base implementation. */ - typedef ValueBase Base; - - template <class T> - Value &scalar(T &value) - { - Base::scalar(value); - return *this; - } - - template <class T> - Value &functor(T &func) - { - Base::functor(func); - return *this; - } -}; - -/** - * A stat that calculates the per cycle average of a value. - * @sa Stat, ScalarBase, AvgStor - */ -template<int N = 0> -class Average : public Wrap<Average<N>, ScalarBase<AvgStor>, ScalarStatData> -{ - public: - /** The base implementation. */ - typedef ScalarBase<AvgStor> Base; - - Average() - { - this->doInit(); - } - - /** - * Sets the stat equal to the given value. Calls the base implementation - * of operator= - * @param v The new value. - */ - template <typename U> - void operator=(const U &v) { Base::operator=(v); } -}; - -/** - * A vector of scalar stats. - * @sa Stat, VectorBase, StatStor - */ -template<int N = 0> -class Vector : public WrapVec<Vector<N>, VectorBase<StatStor>, VectorStatData> -{ - public: - /** The base implementation. */ - typedef ScalarBase<StatStor> Base; - - /** - * Set this vector to have the given size. - * @param size The new size. - * @return A reference to this stat. - */ - Vector &init(size_t size) { - this->doInit(size); - return *this; - } -}; - -/** - * A vector of Average stats. - * @sa Stat, VectorBase, AvgStor - */ -template<int N = 0> -class AverageVector - : public WrapVec<AverageVector<N>, VectorBase<AvgStor>, VectorStatData> -{ - public: - /** - * Set this vector to have the given size. - * @param size The new size. - * @return A reference to this stat. - */ - AverageVector &init(size_t size) { - this->doInit(size); - return *this; - } -}; - -/** - * A 2-Dimensional vecto of scalar stats. - * @sa Stat, Vector2dBase, StatStor - */ -template<int N = 0> -class Vector2d - : public WrapVec2d<Vector2d<N>, Vector2dBase<StatStor>, Vector2dStatData> -{ - public: - Vector2d &init(size_t x, size_t y) { - this->doInit(x, y); - return *this; - } -}; - -/** - * A simple distribution stat. - * @sa Stat, DistBase, DistStor - */ -template<int N = 0> -class Distribution - : public Wrap<Distribution<N>, DistBase<DistStor>, DistStatData> -{ - public: - /** Base implementation. */ - typedef DistBase<DistStor> Base; - /** The Parameter type. */ - typedef DistStor::Params Params; - - public: - /** - * Set the parameters of this distribution. @sa DistStor::Params - * @param min The minimum value of the distribution. - * @param max The maximum value of the distribution. - * @param bkt The number of values in each bucket. - * @return A reference to this distribution. - */ - Distribution &init(Counter min, Counter max, Counter bkt) { - this->params.min = min; - this->params.max = max; - this->params.bucket_size = bkt; - this->params.size = (int)rint((max - min) / bkt + 1.0); - this->doInit(); - return *this; - } -}; - -/** - * Calculates the mean and variance of all the samples. - * @sa Stat, DistBase, FancyStor - */ -template<int N = 0> -class StandardDeviation - : public Wrap<StandardDeviation<N>, DistBase<FancyStor>, DistStatData> -{ - public: - /** The base implementation */ - typedef DistBase<DistStor> Base; - /** The parameter type. */ - typedef DistStor::Params Params; - - public: - /** - * Construct and initialize this distribution. - */ - StandardDeviation() { - this->doInit(); - } -}; - -/** - * Calculates the per cycle mean and variance of the samples. - * @sa Stat, DistBase, AvgFancy - */ -template<int N = 0> -class AverageDeviation - : public Wrap<AverageDeviation<N>, DistBase<AvgFancy>, DistStatData> -{ - public: - /** The base implementation */ - typedef DistBase<DistStor> Base; - /** The parameter type. */ - typedef DistStor::Params Params; - - public: - /** - * Construct and initialize this distribution. - */ - AverageDeviation() - { - this->doInit(); - } -}; - -/** - * A vector of distributions. - * @sa Stat, VectorDistBase, DistStor - */ -template<int N = 0> -class VectorDistribution - : public WrapVec<VectorDistribution<N>, - VectorDistBase<DistStor>, - VectorDistStatData> -{ - public: - /** The base implementation */ - typedef VectorDistBase<DistStor> Base; - /** The parameter type. */ - typedef DistStor::Params Params; - - public: - /** - * Initialize storage and parameters for this distribution. - * @param size The size of the vector (the number of distributions). - * @param min The minimum value of the distribution. - * @param max The maximum value of the distribution. - * @param bkt The number of values in each bucket. - * @return A reference to this distribution. - */ - VectorDistribution &init(int size, Counter min, Counter max, Counter bkt) { - this->params.min = min; - this->params.max = max; - this->params.bucket_size = bkt; - this->params.size = (int)rint((max - min) / bkt + 1.0); - this->doInit(size); - return *this; - } -}; - -/** - * This is a vector of StandardDeviation stats. - * @sa Stat, VectorDistBase, FancyStor - */ -template<int N = 0> -class VectorStandardDeviation - : public WrapVec<VectorStandardDeviation<N>, - VectorDistBase<FancyStor>, - VectorDistStatData> -{ - public: - /** The base implementation */ - typedef VectorDistBase<FancyStor> Base; - /** The parameter type. */ - typedef DistStor::Params Params; - - public: - /** - * Initialize storage for this distribution. - * @param size The size of the vector. - * @return A reference to this distribution. - */ - VectorStandardDeviation &init(int size) { - this->doInit(size); - return *this; - } -}; - -/** - * This is a vector of AverageDeviation stats. - * @sa Stat, VectorDistBase, AvgFancy - */ -template<int N = 0> -class VectorAverageDeviation - : public WrapVec<VectorAverageDeviation<N>, - VectorDistBase<AvgFancy>, - VectorDistStatData> -{ - public: - /** The base implementation */ - typedef VectorDistBase<AvgFancy> Base; - /** The parameter type. */ - typedef DistStor::Params Params; - - public: - /** - * Initialize storage for this distribution. - * @param size The size of the vector. - * @return A reference to this distribution. - */ - VectorAverageDeviation &init(int size) { - this->doInit(size); - return *this; - } -}; - -/** - * A formula for statistics that is calculated when printed. A formula is - * stored as a tree of Nodes that represent the equation to calculate. - * @sa Stat, ScalarStat, VectorStat, Node, Temp - */ -class FormulaBase : public DataAccess -{ - protected: - /** The root of the tree which represents the Formula */ - NodePtr root; - friend class Temp; - - public: - /** - * Return the result of the Fomula in a vector. If there were no Vector - * components to the Formula, then the vector is size 1. If there were, - * like x/y with x being a vector of size 3, then the result returned will - * be x[0]/y, x[1]/y, x[2]/y, respectively. - * @return The result vector. - */ - void result(VResult &vec) const; - - /** - * Return the total Formula result. If there is a Vector - * component to this Formula, then this is the result of the - * Formula if the formula is applied after summing all the - * components of the Vector. For example, if Formula is x/y where - * x is size 3, then total() will return (x[1]+x[2]+x[3])/y. If - * there is no Vector component, total() returns the same value as - * the first entry in the VResult val() returns. - * @return The total of the result vector. - */ - Result total() const; - - /** - * Return the number of elements in the tree. - */ - size_t size() const; - - bool check() const { return true; } - - /** - * Formulas don't need to be reset - */ - void reset(); - - /** - * - */ - bool zero() const; - - /** - * - */ - void update(StatData *); - - std::string str() const; -}; - -class FormulaData : public VectorData -{ - public: - virtual std::string str() const = 0; - virtual bool check() const { return true; } -}; - -template <class Stat> -class FormulaStatData : public FormulaData -{ - protected: - Stat &s; - mutable VResult vec; - mutable VCounter cvec; - - public: - FormulaStatData(Stat &stat) : s(stat) {} - - virtual bool zero() const { return s.zero(); } - virtual void reset() { s.reset(); } - - virtual size_t size() const { return s.size(); } - virtual const VResult &result() const - { - s.result(vec); - return vec; - } - virtual Result total() const { return s.total(); } - virtual VCounter &value() const { return cvec; } - virtual void visit(Visit &visitor) - { - update(); - s.update(this); - visitor.visit(*this); - } - virtual std::string str() const { return s.str(); } -}; - -class Temp; -class Formula - : public WrapVec<Formula, - FormulaBase, - FormulaStatData> -{ - public: - /** - * Create and initialize thie formula, and register it with the database. - */ - Formula(); - - /** - * Create a formula with the given root node, register it with the - * database. - * @param r The root of the expression tree. - */ - Formula(Temp r); - - /** - * Set an unitialized Formula to the given root. - * @param r The root of the expression tree. - * @return a reference to this formula. - */ - const Formula &operator=(Temp r); - - /** - * Add the given tree to the existing one. - * @param r The root of the expression tree. - * @return a reference to this formula. - */ - const Formula &operator+=(Temp r); -}; - -class FormulaNode : public Node -{ - private: - const Formula &formula; - mutable VResult vec; - - public: - FormulaNode(const Formula &f) : formula(f) {} - - virtual size_t size() const { return formula.size(); } - virtual const VResult &result() const { formula.result(vec); return vec; } - virtual Result total() const { return formula.total(); } - - virtual std::string str() const { return formula.str(); } -}; - -/** - * Helper class to construct formula node trees. - */ -class Temp -{ - protected: - /** - * Pointer to a Node object. - */ - NodePtr node; - - public: - /** - * Copy the given pointer to this class. - * @param n A pointer to a Node object to copy. - */ - Temp(NodePtr n) : node(n) { } - - /** - * Return the node pointer. - * @return the node pointer. - */ - operator NodePtr&() { return node;} - - public: - /** - * Create a new ScalarStatNode. - * @param s The ScalarStat to place in a node. - */ - template <int N> - Temp(const Scalar<N> &s) - : node(new ScalarStatNode(s.statData())) { } - - /** - * Create a new ScalarStatNode. - * @param s The ScalarStat to place in a node. - */ - Temp(const Value &s) - : node(new ScalarStatNode(s.statData())) { } - - /** - * Create a new ScalarStatNode. - * @param s The ScalarStat to place in a node. - */ - template <int N> - Temp(const Average<N> &s) - : node(new ScalarStatNode(s.statData())) { } - - /** - * Create a new VectorStatNode. - * @param s The VectorStat to place in a node. - */ - template <int N> - Temp(const Vector<N> &s) - : node(new VectorStatNode(s.statData())) { } - - /** - * - */ - Temp(const Formula &f) - : node(new FormulaNode(f)) { } - - /** - * Create a new ScalarProxyNode. - * @param p The ScalarProxy to place in a node. - */ - template <class Stat> - Temp(const ScalarProxy<Stat> &p) - : node(new ScalarProxyNode<Stat>(p)) { } - - /** - * Create a ConstNode - * @param value The value of the const node. - */ - Temp(signed char value) - : node(new ConstNode<signed char>(value)) {} - - /** - * Create a ConstNode - * @param value The value of the const node. - */ - Temp(unsigned char value) - : node(new ConstNode<unsigned char>(value)) {} - - /** - * Create a ConstNode - * @param value The value of the const node. - */ - Temp(signed short value) - : node(new ConstNode<signed short>(value)) {} - - /** - * Create a ConstNode - * @param value The value of the const node. - */ - Temp(unsigned short value) - : node(new ConstNode<unsigned short>(value)) {} - - /** - * Create a ConstNode - * @param value The value of the const node. - */ - Temp(signed int value) - : node(new ConstNode<signed int>(value)) {} - - /** - * Create a ConstNode - * @param value The value of the const node. - */ - Temp(unsigned int value) - : node(new ConstNode<unsigned int>(value)) {} - - /** - * Create a ConstNode - * @param value The value of the const node. - */ - Temp(signed long value) - : node(new ConstNode<signed long>(value)) {} - - /** - * Create a ConstNode - * @param value The value of the const node. - */ - Temp(unsigned long value) - : node(new ConstNode<unsigned long>(value)) {} - - /** - * Create a ConstNode - * @param value The value of the const node. - */ - Temp(signed long long value) - : node(new ConstNode<signed long long>(value)) {} - - /** - * Create a ConstNode - * @param value The value of the const node. - */ - Temp(unsigned long long value) - : node(new ConstNode<unsigned long long>(value)) {} - - /** - * Create a ConstNode - * @param value The value of the const node. - */ - Temp(float value) - : node(new ConstNode<float>(value)) {} - - /** - * Create a ConstNode - * @param value The value of the const node. - */ - Temp(double value) - : node(new ConstNode<double>(value)) {} -}; - - -/** - * @} - */ - -void check(); -void reset(); -void registerResetCallback(Callback *cb); - -inline Temp -operator+(Temp l, Temp r) -{ - return NodePtr(new BinaryNode<std::plus<Result> >(l, r)); -} - -inline Temp -operator-(Temp l, Temp r) -{ - return NodePtr(new BinaryNode<std::minus<Result> >(l, r)); -} - -inline Temp -operator*(Temp l, Temp r) -{ - return NodePtr(new BinaryNode<std::multiplies<Result> >(l, r)); -} - -inline Temp -operator/(Temp l, Temp r) -{ - return NodePtr(new BinaryNode<std::divides<Result> >(l, r)); -} - -inline Temp -operator-(Temp l) -{ - return NodePtr(new UnaryNode<std::negate<Result> >(l)); -} - -template <typename T> -inline Temp -constant(T val) -{ - return NodePtr(new ConstNode<T>(val)); -} - -inline Temp -sum(Temp val) -{ - return NodePtr(new SumNode<std::plus<Result> >(val)); -} - -/* namespace Stats */ } - -#endif // __BASE_STATISTICS_HH__ diff --git a/base/stats/events.cc b/base/stats/events.cc deleted file mode 100644 index 3191aec13..000000000 --- a/base/stats/events.cc +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <vector> - -#include "base/stats/events.hh" - -#if USE_MYSQL -#include "base/cprintf.hh" -#include "base/misc.hh" -#include "base/mysql.hh" -#include "base/stats/mysql.hh" -#include "base/stats/mysql_run.hh" -#include "base/str.hh" -#endif - -#include "base/match.hh" -#include "sim/host.hh" -#include "sim/sim_object.hh" -#include "sim/root.hh" - -using namespace std; - -namespace Stats { - -Tick EventStart = ULL(0x7fffffffffffffff); - -ObjectMatch event_ignore; - -#if USE_MYSQL -class InsertEvent -{ - private: - char *query; - int size; - bool first; - static const int maxsize = 1024*1024; - - typedef map<string, uint32_t> event_map_t; - event_map_t events; - - MySQL::Connection &mysql; - uint16_t run; - - public: - InsertEvent() - : mysql(MySqlDB.conn()), run(MySqlDB.run()) - { - query = new char[maxsize + 1]; - size = 0; - first = true; - flush(); - } - ~InsertEvent() - { - flush(); - } - - void flush(); - void insert(const string &stat); -}; - -void -InsertEvent::insert(const string &stat) -{ - assert(mysql.connected()); - - event_map_t::iterator i = events.find(stat); - uint32_t event; - if (i == events.end()) { - mysql.query( - csprintf("SELECT en_id " - "from event_names " - "where en_name=\"%s\"", - stat)); - - MySQL::Result result = mysql.store_result(); - if (!result) - panic("could not get a run\n%s\n", mysql.error); - - assert(result.num_fields() == 1); - MySQL::Row row = result.fetch_row(); - if (row) { - if (!to_number(row[0], event)) - panic("invalid event id: %s\n", row[0]); - } else { - mysql.query( - csprintf("INSERT INTO " - "event_names(en_name)" - "values(\"%s\")", - stat)); - - if (mysql.error) - panic("could not get a run\n%s\n", mysql.error); - - event = mysql.insert_id(); - } - } else { - event = (*i).second; - } - - if (size + 1024 > maxsize) - flush(); - - if (!first) { - query[size++] = ','; - query[size] = '\0'; - } - - first = false; - - size += sprintf(query + size, "(%u,%u,%llu)", - event, run, (unsigned long long)curTick); -} - -void -InsertEvent::flush() -{ - static const char query_header[] = "INSERT INTO " - "events(ev_event, ev_run, ev_tick)" - "values"; - - if (size) { - MySQL::Connection &mysql = MySqlDB.conn(); - assert(mysql.connected()); - mysql.query(query); - } - - query[0] = '\0'; - size = sizeof(query_header); - first = true; - memcpy(query, query_header, size); -} - -void -__event(const string &stat) -{ - static InsertEvent event; - event.insert(stat); -} - -#endif - -/* namespace Stats */ } diff --git a/base/stats/events.hh b/base/stats/events.hh deleted file mode 100644 index 2a23240b4..000000000 --- a/base/stats/events.hh +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __BASE_STATS_EVENTS_HH__ -#define __BASE_STATS_EVENTS_HH__ - -#include <string> - -#include "base/trace.hh" -#include "config/use_mysql.hh" - -namespace Stats { - -extern Tick EventStart; - -#if USE_MYSQL -void __event(const std::string &stat); -bool MySqlConnected(); -#endif - -bool ignoreEvent(const std::string &name); - -inline void -recordEvent(const std::string &stat) -{ - if (EventStart > curTick) - return; - - DPRINTF(StatEvents, "Statistics Event: %s\n", stat); - -#if USE_MYSQL - if (!MySqlConnected()) - return; - - __event(stat); -#endif -} - -/* namespace Stats */ } - -#endif // __BASE_STATS_EVENTS_HH__ diff --git a/base/stats/flags.hh b/base/stats/flags.hh deleted file mode 100644 index 00db95bc1..000000000 --- a/base/stats/flags.hh +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __BASE_STATS_FLAGS_HH__ -#define __BASE_STATS_FLAGS_HH__ -namespace Stats { - -/** - * Define the storage for format flags. - * @todo Can probably shrink this. - */ -typedef u_int32_t StatFlags; - -/** Nothing extra to print. */ -const StatFlags none = 0x00000000; -/** This Stat is Initialized */ -const StatFlags init = 0x00000001; -/** Print this stat. */ -const StatFlags print = 0x00000002; -/** Print the total. */ -const StatFlags total = 0x00000010; -/** Print the percent of the total that this entry represents. */ -const StatFlags pdf = 0x00000020; -/** Print the cumulative percentage of total upto this entry. */ -const StatFlags cdf = 0x00000040; -/** Print the distribution. */ -const StatFlags dist = 0x00000080; -/** Don't print if this is zero. */ -const StatFlags nozero = 0x00000100; -/** Don't print if this is NAN */ -const StatFlags nonan = 0x00000200; -/** Used for SS compatability. */ -const StatFlags __substat = 0x80000000; - -/** Mask of flags that can't be set directly */ -const StatFlags __reserved = init | print | __substat; - -enum DisplayMode -{ - mode_m5, - mode_simplescalar -}; - -extern DisplayMode DefaultMode; - -/* namespace Stats */ } - -#endif // __BASE_STATS_FLAGS_HH__ diff --git a/base/stats/mysql.cc b/base/stats/mysql.cc deleted file mode 100644 index 7d0bb150b..000000000 --- a/base/stats/mysql.cc +++ /dev/null @@ -1,826 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <cassert> -#include <map> -#include <sstream> -#include <string> -#include <vector> - -#include "base/misc.hh" -#include "base/mysql.hh" -#include "base/statistics.hh" -#include "base/stats/flags.hh" -#include "base/stats/mysql.hh" -#include "base/stats/mysql_run.hh" -#include "base/stats/statdb.hh" -#include "base/stats/types.hh" -#include "base/str.hh" -#include "sim/host.hh" - -using namespace std; - -namespace Stats { - -MySqlRun MySqlDB; - -bool -MySqlConnected() -{ - return MySqlDB.connected(); -} - -void -MySqlRun::connect(const string &host, const string &user, const string &passwd, - const string &db, const string &name, const string &sample, - const string &project) -{ - if (connected()) - panic("can only get one database connection at this time!"); - - mysql.connect(host, user, passwd, db); - if (mysql.error) - panic("could not connect to database server\n%s\n", mysql.error); - - if (mysql.autocommit(false)) - panic("could not set autocommit\n%s\n", mysql.error); - - remove(name); - //cleanup(); - setup(name, sample, user, project); -} - -void -MySqlRun::setup(const string &name, const string &sample, const string &user, - const string &project) -{ - assert(mysql.connected()); - - stringstream insert; - ccprintf(insert, - "INSERT INTO " - "runs(rn_name,rn_sample,rn_user,rn_project,rn_date,rn_expire)" - "values(\"%s\", \"%s\", \"%s\", \"%s\", NOW()," - "DATE_ADD(CURDATE(), INTERVAL 31 DAY))", - name, sample, user, project); - - mysql.query(insert); - if (mysql.error) - panic("could not get a run\n%s\n", mysql.error); - - run_id = mysql.insert_id(); - if (mysql.commit()) - panic("could not commit transaction\n%s\n", mysql.error); -} - -void -MySqlRun::remove(const string &name) -{ - assert(mysql.connected()); - stringstream sql; - ccprintf(sql, "DELETE FROM runs WHERE rn_name=\"%s\"", name); - mysql.query(sql); - if (mysql.error) - panic("could not delete run\n%s\n", mysql.error); - if (mysql.commit()) - panic("could not commit transaction\n%s\n", mysql.error); -} - -void -MySqlRun::cleanup() -{ - assert(mysql.connected()); - - mysql.query("DELETE data " - "FROM data " - "LEFT JOIN runs ON dt_run=rn_id " - "WHERE rn_id IS NULL"); - - if (mysql.commit()) - panic("could not commit transaction\n%s\n", mysql.error); - - mysql.query("DELETE formula_ref " - "FROM formula_ref " - "LEFT JOIN runs ON fr_run=rn_id " - "WHERE rn_id IS NULL"); - - if (mysql.commit()) - panic("could not commit transaction\n%s\n", mysql.error); - - mysql.query("DELETE formulas " - "FROM formulas " - "LEFT JOIN formula_ref ON fm_stat=fr_stat " - "WHERE fr_stat IS NULL"); - - if (mysql.commit()) - panic("could not commit transaction\n%s\n", mysql.error); - - mysql.query("DELETE stats " - "FROM stats " - "LEFT JOIN data ON st_id=dt_stat " - "WHERE dt_stat IS NULL"); - - if (mysql.commit()) - panic("could not commit transaction\n%s\n", mysql.error); - - mysql.query("DELETE subdata " - "FROM subdata " - "LEFT JOIN data ON sd_stat=dt_stat " - "WHERE dt_stat IS NULL"); - - if (mysql.commit()) - panic("could not commit transaction\n%s\n", mysql.error); - - mysql.query("DELETE events" - "FROM events" - "LEFT JOIN runs ON ev_run=rn_id" - "WHERE rn_id IS NULL"); - - if (mysql.commit()) - panic("could not commit transaction\n%s\n", mysql.error); - - mysql.query("DELETE event_names" - "FROM event_names" - "LEFT JOIN events ON en_id=ev_event" - "WHERE ev_event IS NULL"); - - if (mysql.commit()) - panic("could not commit transaction\n%s\n", mysql.error); -} - -void -SetupStat::init() -{ - name = ""; - descr = ""; - type = ""; - print = false; - prereq = 0; - prec = -1; - nozero = false; - nonan = false; - total = false; - pdf = false; - cdf = false; - min = 0; - max = 0; - bktsize = 0; - size = 0; -} - -unsigned -SetupStat::setup() -{ - MySQL::Connection &mysql = MySqlDB.conn(); - - stringstream insert; - ccprintf(insert, - "INSERT INTO " - "stats(st_name, st_descr, st_type, st_print, st_prereq, " - "st_prec, st_nozero, st_nonan, st_total, st_pdf, st_cdf, " - "st_min, st_max, st_bktsize, st_size)" - "values(\"%s\",\"%s\",\"%s\"," - " %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)", - name, descr, type, print, prereq, (int)prec, nozero, nonan, - total, pdf, cdf, - min, max, bktsize, size); - - mysql.query(insert); - if (!mysql.error) { - int id = mysql.insert_id(); - if (mysql.commit()) - panic("could not commit transaction\n%s\n", mysql.error); - return id; - } - - stringstream select; - ccprintf(select, "SELECT * FROM stats WHERE st_name=\"%s\"", name); - - mysql.query(select); - MySQL::Result result = mysql.store_result(); - if (!result) - panic("could not find stat\n%s\n", mysql.error); - - assert(result.num_fields() == 16); - MySQL::Row row = result.fetch_row(); - if (!row) - panic("could not get stat row\n%s\n", mysql.error); - - bool tb; - int8_t ti8; - uint16_t tu16; - int64_t ti64; - uint64_t tu64; - - if (name != (char *)row[1]) - panic("failed stat check on %s:name. %s != %s\n", - name, name, row[1]); - - if (descr != (char *)row[2]) - panic("failed stat check on %s:descr. %s != %s\n", - name, descr, row[2]); - - if (type != (char *)row[3]) - panic("failed stat check on %s:type. %s != %s\n", - name, type, row[3]); - - if (!to_number(row[4], tb) || print != tb) - panic("failed stat check on %s:print. %d != %d\n", - name, print, tb); - - if (!to_number(row[6], ti8) || prec != ti8) - panic("failed stat check on %s:prec. %d != %d\n", - name, prec, ti8); - - if (!to_number(row[7], tb) || nozero != tb) - panic("failed stat check on %s:nozero. %d != %d\n", - name, nozero, tb); - - if (!to_number(row[8], tb) || nonan != tb) - panic("failed stat check on %s:nonan. %d != %d\n", - name, nonan, tb); - - if (!to_number(row[9], tb) || total != tb) - panic("failed stat check on %s:total. %d != %d\n", - name, total, tb); - - if (!to_number(row[10], tb) || pdf != tb) - panic("failed stat check on %s:pdf. %d != %d\n", - name, pdf, tb); - - if (!to_number(row[11], tb) || cdf != tb) - panic("failed stat check on %s:cdf. %d != %d\n", - name, cdf, tb); - - if (!to_number(row[12], ti64) || min != ti64) - panic("failed stat check on %s:min. %d != %d\n", - name, min, ti64); - - if (!to_number(row[13], ti64) || max != ti64) - panic("failed stat check on %s:max. %d != %d\n", - name, max, ti64); - - if (!to_number(row[14], tu64) || bktsize != tu64) - panic("failed stat check on %s:bktsize. %d != %d\n", - name, bktsize, tu64); - - if (!to_number(row[15], tu16) || size != tu16) - panic("failed stat check on %s:size. %d != %d\n", - name, size, tu16); - - to_number(row[5], prereq); - uint16_t statid; - to_number(row[0], statid); - return statid; -} - -InsertData::InsertData() -{ - query = new char[maxsize + 1]; - size = 0; - flush(); -} - -InsertData::~InsertData() -{ - delete [] query; -} - -void -InsertData::flush() -{ - if (size) { - MySQL::Connection &mysql = MySqlDB.conn(); - assert(mysql.connected()); - mysql.query(query); - if (mysql.error) - panic("could not insert data\n%s\n", mysql.error); - if (mysql.commit()) - panic("could not commit transaction\n%s\n", mysql.error); - } - - query[0] = '\0'; - size = 0; - first = true; - strcpy(query, "INSERT INTO " - "data(dt_stat,dt_x,dt_y,dt_run,dt_tick,dt_data) " - "values"); - size = strlen(query); -} - -void -InsertData::insert() -{ - if (size + 1024 > maxsize) - flush(); - - if (!first) { - query[size++] = ','; - query[size] = '\0'; - } - - first = false; - - size += sprintf(query + size, "(%u,%d,%d,%u,%llu,\"%f\")", - stat, x, y, MySqlDB.run(), (unsigned long long)tick, - data); -} - -struct InsertSubData -{ - uint16_t stat; - int16_t x; - int16_t y; - string name; - string descr; - - void setup(); -}; - -void -InsertSubData::setup() -{ - MySQL::Connection &mysql = MySqlDB.conn(); - assert(mysql.connected()); - stringstream insert; - ccprintf(insert, - "INSERT INTO subdata(sd_stat,sd_x,sd_y,sd_name,sd_descr) " - "values(%d,%d,%d,\"%s\",\"%s\")", - stat, x, y, name, descr); - - mysql.query(insert); -// if (mysql.error) -// panic("could not insert subdata\n%s\n", mysql.error); - - if (mysql.commit()) - panic("could not commit transaction\n%s\n", mysql.error); -} - -void -InsertFormula(uint16_t stat, const string &formula) -{ - MySQL::Connection &mysql = MySqlDB.conn(); - assert(mysql.connected()); - stringstream insert_formula; - ccprintf(insert_formula, - "INSERT INTO formulas(fm_stat,fm_formula) values(%d, \"%s\")", - stat, formula); - - mysql.query(insert_formula); -// if (mysql.error) -// panic("could not insert formula\n%s\n", mysql.error); - - stringstream insert_ref; - ccprintf(insert_ref, - "INSERT INTO formula_ref(fr_stat,fr_run) values(%d, %d)", - stat, MySqlDB.run()); - - mysql.query(insert_ref); -// if (mysql.error) -// panic("could not insert formula reference\n%s\n", mysql.error); - - if (mysql.commit()) - panic("could not commit transaction\n%s\n", mysql.error); -} - -void -UpdatePrereq(uint16_t stat, uint16_t prereq) -{ - MySQL::Connection &mysql = MySqlDB.conn(); - assert(mysql.connected()); - stringstream update; - ccprintf(update, "UPDATE stats SET st_prereq=%d WHERE st_id=%d", - prereq, stat); - mysql.query(update); - if (mysql.error) - panic("could not update prereq\n%s\n", mysql.error); - - if (mysql.commit()) - panic("could not commit transaction\n%s\n", mysql.error); -} - -void -MySql::configure() -{ - /* - * set up all stats! - */ - using namespace Database; - - MySQL::Connection &mysql = MySqlDB.conn(); - - stat_list_t::const_iterator i, end = stats().end(); - for (i = stats().begin(); i != end; ++i) { - (*i)->visit(*this); - } - - for (i = stats().begin(); i != end; ++i) { - StatData *data = *i; - if (data->prereq) { - uint16_t stat_id = find(data->id); - uint16_t prereq_id = find(data->prereq->id); - assert(stat_id && prereq_id); - - UpdatePrereq(stat_id, prereq_id); - } - } - - if (mysql.commit()) - panic("could not commit transaction\n%s\n", mysql.error); - - configured = true; -} - - -bool -MySql::configure(const StatData &data, string type) -{ - stat.init(); - stat.name = data.name; - stat.descr = data.desc; - stat.type = type; - stat.print = data.flags & print; - stat.prec = data.precision; - stat.nozero = data.flags & nozero; - stat.nonan = data.flags & nonan; - stat.total = data.flags & total; - stat.pdf = data.flags & pdf; - stat.cdf = data.flags & cdf; - - return stat.print; -} - -void -MySql::configure(const ScalarData &data) -{ - if (!configure(data, "SCALAR")) - return; - - insert(data.id, stat.setup()); -} - -void -MySql::configure(const VectorData &data) -{ - if (!configure(data, "VECTOR")) - return; - - uint16_t statid = stat.setup(); - - if (!data.subnames.empty()) { - InsertSubData subdata; - subdata.stat = statid; - subdata.y = 0; - for (int i = 0; i < data.subnames.size(); ++i) { - subdata.x = i; - subdata.name = data.subnames[i]; - subdata.descr = data.subdescs.empty() ? "" : data.subdescs[i]; - - if (!subdata.name.empty() || !subdata.descr.empty()) - subdata.setup(); - } - } - - insert(data.id, statid); -} - -void -MySql::configure(const DistData &data) -{ - if (!configure(data, "DIST")) - return; - - if (!data.data.fancy) { - stat.size = data.data.size; - stat.min = data.data.min; - stat.max = data.data.max; - stat.bktsize = data.data.bucket_size; - } - insert(data.id, stat.setup()); -} - -void -MySql::configure(const VectorDistData &data) -{ - if (!configure(data, "VECTORDIST")) - return; - - if (!data.data[0].fancy) { - stat.size = data.data[0].size; - stat.min = data.data[0].min; - stat.max = data.data[0].max; - stat.bktsize = data.data[0].bucket_size; - } - - uint16_t statid = stat.setup(); - - if (!data.subnames.empty()) { - InsertSubData subdata; - subdata.stat = statid; - subdata.y = 0; - for (int i = 0; i < data.subnames.size(); ++i) { - subdata.x = i; - subdata.name = data.subnames[i]; - subdata.descr = data.subdescs.empty() ? "" : data.subdescs[i]; - if (!subdata.name.empty() || !subdata.descr.empty()) - subdata.setup(); - } - } - - insert(data.id, statid); -} - -void -MySql::configure(const Vector2dData &data) -{ - if (!configure(data, "VECTOR2D")) - return; - - uint16_t statid = stat.setup(); - - if (!data.subnames.empty()) { - InsertSubData subdata; - subdata.stat = statid; - subdata.y = -1; - for (int i = 0; i < data.subnames.size(); ++i) { - subdata.x = i; - subdata.name = data.subnames[i]; - subdata.descr = data.subdescs.empty() ? "" : data.subdescs[i]; - if (!subdata.name.empty() || !subdata.descr.empty()) - subdata.setup(); - } - } - - if (!data.y_subnames.empty()) { - InsertSubData subdata; - subdata.stat = statid; - subdata.x = -1; - subdata.descr = ""; - for (int i = 0; i < data.y_subnames.size(); ++i) { - subdata.y = i; - subdata.name = data.y_subnames[i]; - if (!subdata.name.empty()) - subdata.setup(); - } - } - - insert(data.id, statid); -} - -void -MySql::configure(const FormulaData &data) -{ - configure(data, "FORMULA"); - insert(data.id, stat.setup()); - InsertFormula(find(data.id), data.str()); -} - -bool -MySql::valid() const -{ - return MySqlDB.connected(); -} - -void -MySql::output() -{ - using namespace Database; - assert(valid()); - - if (!configured) - configure(); - - // store sample # - newdata.tick = curTick; - - MySQL::Connection &mysql = MySqlDB.conn(); - - Database::stat_list_t::const_iterator i, end = Database::stats().end(); - for (i = Database::stats().begin(); i != end; ++i) { - StatData *stat = *i; - stat->visit(*this); - if (mysql.commit()) - panic("could not commit transaction\n%s\n", mysql.error); - } - - newdata.flush(); -} - -void -MySql::output(const ScalarData &data) -{ - if (!(data.flags & print)) - return; - - newdata.stat = find(data.id); - newdata.x = 0; - newdata.y = 0; - newdata.data = data.value(); - - newdata.insert(); -} - -void -MySql::output(const VectorData &data) -{ - if (!(data.flags & print)) - return; - - newdata.stat = find(data.id); - newdata.y = 0; - - const VCounter &cvec = data.value(); - int size = data.size(); - for (int x = 0; x < size; x++) { - newdata.x = x; - newdata.data = cvec[x]; - newdata.insert(); - } -} - -void -MySql::output(const DistDataData &data) -{ - const int db_sum = -1; - const int db_squares = -2; - const int db_samples = -3; - const int db_min_val = -4; - const int db_max_val = -5; - const int db_underflow = -6; - const int db_overflow = -7; - - newdata.x = db_sum; - newdata.data = data.sum; - newdata.insert(); - - newdata.x = db_squares; - newdata.data = data.squares; - newdata.insert(); - - newdata.x = db_samples; - newdata.data = data.samples; - newdata.insert(); - - if (data.samples && !data.fancy) { - newdata.x = db_min_val; - newdata.data = data.min_val; - newdata.insert(); - - newdata.x = db_max_val; - newdata.data = data.max_val; - newdata.insert(); - - newdata.x = db_underflow; - newdata.data = data.underflow; - newdata.insert(); - - newdata.x = db_overflow; - newdata.data = data.overflow; - newdata.insert(); - - int size = data.cvec.size(); - for (int x = 0; x < size; x++) { - newdata.x = x; - newdata.data = data.cvec[x]; - newdata.insert(); - } - } -} - - -void -MySql::output(const DistData &data) -{ - if (!(data.flags & print)) - return; - - newdata.stat = find(data.id); - newdata.y = 0; - output(data.data); -} - -void -MySql::output(const VectorDistData &data) -{ - if (!(data.flags & print)) - return; - - newdata.stat = find(data.id); - - int size = data.data.size(); - for (int y = 0; y < size; ++y) { - newdata.y = y; - output(data.data[y]); - } -} - -void -MySql::output(const Vector2dData &data) -{ - if (!(data.flags & print)) - return; - - newdata.stat = find(data.id); - - int index = 0; - for (int x = 0; x < data.x; x++) { - newdata.x = x; - for (int y = 0; y < data.y; y++) { - newdata.y = y; - newdata.data = data.cvec[index++]; - newdata.insert(); - } - } -} - -void -MySql::output(const FormulaData &data) -{ -} - -/* - * Implement the visitor - */ -void -MySql::visit(const ScalarData &data) -{ - if (!configured) - configure(data); - else - output(data); -} - -void -MySql::visit(const VectorData &data) -{ - if (!configured) - configure(data); - else - output(data); -} - -void -MySql::visit(const DistData &data) -{ - return; - if (!configured) - configure(data); - else - output(data); -} - -void -MySql::visit(const VectorDistData &data) -{ - return; - if (!configured) - configure(data); - else - output(data); -} - -void -MySql::visit(const Vector2dData &data) -{ - return; - if (!configured) - configure(data); - else - output(data); -} - -void -MySql::visit(const FormulaData &data) -{ - if (!configured) - configure(data); - else - output(data); -} - -/* namespace Stats */ } diff --git a/base/stats/mysql.hh b/base/stats/mysql.hh deleted file mode 100644 index af0e619e3..000000000 --- a/base/stats/mysql.hh +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __BASE_STATS_MYSQL_HH__ -#define __BASE_STATS_MYSQL_HH__ - -#include <map> -#include <string> - -#include "base/stats/output.hh" - -namespace MySQL { class Connection; } -namespace Stats { - -class DistDataData; -class MySqlRun; -bool MySqlConnected(); -extern MySqlRun MySqlDB; - -struct SetupStat -{ - std::string name; - std::string descr; - std::string type; - bool print; - uint16_t prereq; - int8_t prec; - bool nozero; - bool nonan; - bool total; - bool pdf; - bool cdf; - double min; - double max; - double bktsize; - uint16_t size; - - void init(); - unsigned setup(); -}; - -class InsertData -{ - private: - char *query; - int size; - bool first; - static const int maxsize = 1024*1024; - - public: - MySqlRun *run; - - public: - uint64_t tick; - double data; - uint16_t stat; - int16_t x; - int16_t y; - - public: - InsertData(); - ~InsertData(); - - void flush(); - void insert(); -}; - -class MySql : public Output -{ - protected: - SetupStat stat; - InsertData newdata; - std::list<FormulaData *> formulas; - bool configured; - - protected: - std::map<int, int> idmap; - - void insert(int sim_id, int db_id) - { - using namespace std; - idmap.insert(make_pair(sim_id, db_id)); - } - - int find(int sim_id) - { - using namespace std; - map<int,int>::const_iterator i = idmap.find(sim_id); - assert(i != idmap.end()); - return (*i).second; - } - public: - // Implement Visit - virtual void visit(const ScalarData &data); - virtual void visit(const VectorData &data); - virtual void visit(const DistData &data); - virtual void visit(const VectorDistData &data); - virtual void visit(const Vector2dData &data); - virtual void visit(const FormulaData &data); - - // Implement Output - virtual bool valid() const; - virtual void output(); - - protected: - // Output helper - void output(const DistDataData &data); - void output(const ScalarData &data); - void output(const VectorData &data); - void output(const DistData &data); - void output(const VectorDistData &data); - void output(const Vector2dData &data); - void output(const FormulaData &data); - - void configure(); - bool configure(const StatData &data, std::string type); - void configure(const ScalarData &data); - void configure(const VectorData &data); - void configure(const DistData &data); - void configure(const VectorDistData &data); - void configure(const Vector2dData &data); - void configure(const FormulaData &data); -}; - -/* namespace Stats */ } - -#endif // __BASE_STATS_MYSQL_HH__ diff --git a/base/stats/mysql_run.hh b/base/stats/mysql_run.hh deleted file mode 100644 index d8dcb7594..000000000 --- a/base/stats/mysql_run.hh +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __BASE_STATS_MYSQL_RUN_HH__ -#define __BASE_STATS_MYSQL_RUN_HH__ - -#include <string> - -#include "base/mysql.hh" -#include "sim/host.hh" - -namespace Stats { - -struct MySqlRun -{ - private: - MySQL::Connection mysql; - uint16_t run_id; - - protected: - void setup(const std::string &name, const std::string &sample, - const std::string &user, const std::string &project); - - void remove(const std::string &name); - void cleanup(); - - public: - bool connected() const { return mysql.connected(); } - void connect(const std::string &host, const std::string &user, - const std::string &passwd, const std::string &db, - const std::string &name, const std::string &sample, - const std::string &project); - - MySQL::Connection &conn() { return mysql; } - uint16_t run() const { return run_id; } -}; - -/* namespace Stats */ } - -#endif // __BASE_STATS_MYSQL_RUN_HH__ diff --git a/base/stats/output.hh b/base/stats/output.hh deleted file mode 100644 index ee6b38d63..000000000 --- a/base/stats/output.hh +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __BASE_STATS_OUTPUT_HH__ -#define __BASE_STATS_OUTPUT_HH__ - -#include <string> - -#include "base/stats/visit.hh" - -namespace Stats { - -struct Output : public Visit -{ - inline void operator()() { output(); } - virtual void output() = 0; - virtual bool valid() const = 0; -}; - -/* namespace Stats */ } - -#endif // __BASE_STATS_OUTPUT_HH__ diff --git a/base/stats/statdb.cc b/base/stats/statdb.cc deleted file mode 100644 index d7d1a9b6a..000000000 --- a/base/stats/statdb.cc +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "base/misc.hh" -#include "base/trace.hh" -#include "base/statistics.hh" -#include "base/stats/statdb.hh" - -using namespace std; - -namespace Stats { -namespace Database { - -StatData * -find(void *stat) -{ - stat_map_t::const_iterator i = map().find(stat); - - if (i == map().end()) - return NULL; - - return (*i).second; -} - -void -regStat(void *stat, StatData *data) -{ - if (map().find(stat) != map().end()) - panic("shouldn't register stat twice!"); - - stats().push_back(data); - -#ifndef NDEBUG - pair<stat_map_t::iterator, bool> result = -#endif - map().insert(make_pair(stat, data)); - assert(result.second && "this should never fail"); - assert(map().find(stat) != map().end()); -} - -void -regPrint(void *stat) -{ - StatData *data = find(stat); - assert(data); - data->flags |= print; -} - -TheDatabase &db() -{ - static TheDatabase db; - return db; -} - -/* namespace Database */ } -/* namespace Stats */ } diff --git a/base/stats/statdb.hh b/base/stats/statdb.hh deleted file mode 100644 index c7b586475..000000000 --- a/base/stats/statdb.hh +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __BASE_STATS_STATDB_HH__ -#define __BASE_STATS_STATDB_HH__ - -#include <iosfwd> -#include <list> -#include <map> -#include <string> - -class Python; - -namespace Stats { - -class StatData; - -namespace Database { - -typedef std::map<void *, StatData *> stat_map_t; -typedef std::list<StatData *> stat_list_t; - -// We wrap the database in a struct to make sure it is built in time. -struct TheDatabase -{ - stat_map_t map; - stat_list_t stats; -}; - -TheDatabase &db(); -inline stat_map_t &map() { return db().map; } -inline stat_list_t &stats() { return db().stats; } - -StatData *find(void *stat); -void regStat(void *stat, StatData *data); -void regPrint(void *stat); - -inline std::string name() { return "Statistics Database"; } - -/* namespace Database */ } -/* namespace Stats */ } - -#endif // __BASE_STATS_STATDB_HH__ diff --git a/base/stats/text.cc b/base/stats/text.cc deleted file mode 100644 index 360932de1..000000000 --- a/base/stats/text.cc +++ /dev/null @@ -1,721 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(__APPLE__) -#define _GLIBCPP_USE_C99 1 -#endif - -#include <iostream> -#include <fstream> -#include <string> - -#include "base/misc.hh" -#include "base/statistics.hh" -#include "base/stats/statdb.hh" -#include "base/stats/text.hh" -#include "base/stats/visit.hh" - -using namespace std; - -#ifndef NAN -float __nan(); -/** Define Not a number. */ -#define NAN (__nan()) -/** Need to define __nan() */ -#define __M5_NAN -#endif - -#ifdef __M5_NAN -float -__nan() -{ - union { - uint32_t ui; - float f; - } nan; - - nan.ui = 0x7fc00000; - return nan.f; -} -#endif - -namespace Stats { - -Text::Text() - : mystream(false), stream(NULL), compat(false), descriptions(false) -{ -} - -Text::Text(std::ostream &stream) - : mystream(false), stream(NULL), compat(false), descriptions(false) -{ - open(stream); -} - -Text::Text(const std::string &file) - : mystream(false), stream(NULL), compat(false), descriptions(false) -{ - open(file); -} - - -Text::~Text() -{ - if (mystream) { - assert(stream); - delete stream; - } -} - -void -Text::open(std::ostream &_stream) -{ - if (stream) - panic("stream already set!"); - - mystream = false; - stream = &_stream; - assert(valid()); -} - -void -Text::open(const std::string &file) -{ - if (stream) - panic("stream already set!"); - - mystream = true; - stream = new ofstream(file.c_str(), ios::trunc); - assert(valid()); -} - -bool -Text::valid() const -{ - return stream != NULL; -} - -void -Text::output() -{ - using namespace Database; - - ccprintf(*stream, "\n---------- Begin Simulation Statistics ----------\n"); - stat_list_t::const_iterator i, end = stats().end(); - for (i = stats().begin(); i != end; ++i) - (*i)->visit(*this); - ccprintf(*stream, "\n---------- End Simulation Statistics ----------\n"); - stream->flush(); -} - -bool -Text::noOutput(const StatData &data) -{ - if (!(data.flags & print)) - return true; - - if (data.prereq && data.prereq->zero()) - return true; - - return false; -} - -string -ValueToString(Result value, int precision, bool compat) -{ - stringstream val; - - if (!isnan(value)) { - if (precision != -1) - val.precision(precision); - else if (value == rint(value)) - val.precision(0); - - val.unsetf(ios::showpoint); - val.setf(ios::fixed); - val << value; - } else { - val << (compat ? "<err: div-0>" : "no value"); - } - - return val.str(); -} - -struct ScalarPrint -{ - Result value; - string name; - string desc; - StatFlags flags; - bool compat; - bool descriptions; - int precision; - Result pdf; - Result cdf; - - void operator()(ostream &stream) const; -}; - -void -ScalarPrint::operator()(ostream &stream) const -{ - if (flags & nozero && value == 0.0 || - flags & nonan && isnan(value)) - return; - - stringstream pdfstr, cdfstr; - - if (!isnan(pdf)) - ccprintf(pdfstr, "%.2f%%", pdf * 100.0); - - if (!isnan(cdf)) - ccprintf(cdfstr, "%.2f%%", cdf * 100.0); - - if (compat && flags & __substat) { - ccprintf(stream, "%32s %12s %10s %10s", name, - ValueToString(value, precision, compat), pdfstr, cdfstr); - } else { - ccprintf(stream, "%-40s %12s %10s %10s", name, - ValueToString(value, precision, compat), pdfstr, cdfstr); - } - - if (descriptions) { - if (!desc.empty()) - ccprintf(stream, " # %s", desc); - } - stream << endl; -} - -struct VectorPrint -{ - string name; - string desc; - vector<string> subnames; - vector<string> subdescs; - StatFlags flags; - bool compat; - bool descriptions; - int precision; - VResult vec; - Result total; - - void operator()(ostream &stream) const; -}; - -void -VectorPrint::operator()(std::ostream &stream) const -{ - int _size = vec.size(); - Result _total = 0.0; - - if (flags & (pdf | cdf)) { - for (int i = 0; i < _size; ++i) { - _total += vec[i]; - } - } - - string base = name + (compat ? "_" : "::"); - - ScalarPrint print; - print.name = name; - print.desc = desc; - print.precision = precision; - print.descriptions = descriptions; - print.flags = flags; - print.pdf = NAN; - print.cdf = NAN; - - bool havesub = !subnames.empty(); - - if (_size == 1) { - print.value = vec[0]; - print(stream); - } else if (!compat) { - for (int i = 0; i < _size; ++i) { - if (havesub && (i >= subnames.size() || subnames[i].empty())) - continue; - - print.name = base + (havesub ? subnames[i] : to_string(i)); - print.desc = subdescs.empty() ? desc : subdescs[i]; - print.value = vec[i]; - - if (_total && (flags & pdf)) { - print.pdf = vec[i] / _total; - print.cdf += print.pdf; - } - - print(stream); - } - - if (flags & ::Stats::total) { - print.name = base + "total"; - print.desc = desc; - print.value = total; - print(stream); - } - } else { - if (flags & ::Stats::total) { - print.value = total; - print(stream); - } - - Result _pdf = 0.0; - Result _cdf = 0.0; - if (flags & dist) { - ccprintf(stream, "%s.start_dist\n", name); - for (int i = 0; i < _size; ++i) { - print.name = havesub ? subnames[i] : to_string(i); - print.desc = subdescs.empty() ? desc : subdescs[i]; - print.flags |= __substat; - print.value = vec[i]; - - if (_total) { - _pdf = vec[i] / _total; - _cdf += _pdf; - } - - if (flags & pdf) - print.pdf = _pdf; - if (flags & cdf) - print.cdf = _cdf; - - print(stream); - } - ccprintf(stream, "%s.end_dist\n", name); - } else { - for (int i = 0; i < _size; ++i) { - if (havesub && subnames[i].empty()) - continue; - - print.name = base; - print.name += havesub ? subnames[i] : to_string(i); - print.desc = subdescs.empty() ? desc : subdescs[i]; - print.value = vec[i]; - - if (_total) { - _pdf = vec[i] / _total; - _cdf += _pdf; - } else { - _pdf = _cdf = NAN; - } - - if (flags & pdf) { - print.pdf = _pdf; - print.cdf = _cdf; - } - - print(stream); - } - } - } -} - -struct DistPrint -{ - string name; - string desc; - StatFlags flags; - bool compat; - bool descriptions; - int precision; - - Result min_val; - Result max_val; - Result underflow; - Result overflow; - VResult vec; - Result sum; - Result squares; - Result samples; - - Counter min; - Counter max; - Counter bucket_size; - int size; - bool fancy; - - void operator()(ostream &stream) const; -}; - -void -DistPrint::operator()(ostream &stream) const -{ - if (fancy) { - ScalarPrint print; - string base = name + (compat ? "_" : "::"); - - print.precision = precision; - print.flags = flags; - print.compat = compat; - print.descriptions = descriptions; - print.desc = desc; - print.pdf = NAN; - print.cdf = NAN; - - print.name = base + "mean"; - print.value = samples ? sum / samples : NAN; - print(stream); - - print.name = base + "stdev"; - print.value = samples ? sqrt((samples * squares - sum * sum) / - (samples * (samples - 1.0))) : NAN; - print(stream); - - print.name = "**Ignore: " + base + "TOT"; - print.value = samples; - print(stream); - return; - } - - assert(size == vec.size()); - - Result total = 0.0; - - total += underflow; - for (int i = 0; i < size; ++i) - total += vec[i]; - total += overflow; - - string base = name + (compat ? "." : "::"); - - ScalarPrint print; - print.desc = compat ? "" : desc; - print.flags = flags; - print.compat = compat; - print.descriptions = descriptions; - print.precision = precision; - print.pdf = NAN; - print.cdf = NAN; - - if (compat) { - ccprintf(stream, "%-42s", base + "start_dist"); - if (descriptions && !desc.empty()) - ccprintf(stream, " # %s", desc); - stream << endl; - } - - print.name = base + "samples"; - print.value = samples; - print(stream); - - print.name = base + "min_value"; - print.value = min_val; - print(stream); - - if (!compat || underflow > 0.0) { - print.name = base + "underflows"; - print.value = underflow; - if (!compat && total) { - print.pdf = underflow / total; - print.cdf += print.pdf; - } - print(stream); - } - - - if (!compat) { - for (int i = 0; i < size; ++i) { - stringstream namestr; - namestr << name; - - Counter low = i * bucket_size + min; - Counter high = ::min(low + bucket_size, max); - namestr << low; - if (low < high) - namestr << "-" << high; - - print.name = namestr.str(); - print.value = vec[i]; - if (total) { - print.pdf = vec[i] / total; - print.cdf += print.pdf; - } - print(stream); - } - - } else { - Counter _min; - Result _pdf; - Result _cdf = 0.0; - - print.flags = flags | __substat; - - for (int i = 0; i < size; ++i) { - if (flags & nozero && vec[i] == 0.0 || - flags & nonan && isnan(vec[i])) - continue; - - _min = i * bucket_size + min; - _pdf = vec[i] / total * 100.0; - _cdf += _pdf; - - - print.name = ValueToString(_min, 0, compat); - print.value = vec[i]; - print.pdf = (flags & pdf) ? _pdf : NAN; - print.cdf = (flags & cdf) ? _cdf : NAN; - print(stream); - } - - print.flags = flags; - } - - if (!compat || overflow > 0.0) { - print.name = base + "overflows"; - print.value = overflow; - if (!compat && total) { - print.pdf = overflow / total; - print.cdf += print.pdf; - } else { - print.pdf = NAN; - print.cdf = NAN; - } - print(stream); - } - - print.pdf = NAN; - print.cdf = NAN; - - if (!compat) { - print.name = base + "total"; - print.value = total; - print(stream); - } - - print.name = base + "max_value"; - print.value = max_val; - print(stream); - - if (!compat && samples != 0) { - print.name = base + "mean"; - print.value = sum / samples; - print(stream); - - print.name = base + "stdev"; - print.value = sqrt((samples * squares - sum * sum) / - (samples * (samples - 1.0))); - print(stream); - } - - if (compat) - ccprintf(stream, "%send_dist\n\n", base); -} - -void -Text::visit(const ScalarData &data) -{ - if (noOutput(data)) - return; - - ScalarPrint print; - print.value = data.result(); - print.name = data.name; - print.desc = data.desc; - print.flags = data.flags; - print.compat = compat; - print.descriptions = descriptions; - print.precision = data.precision; - print.pdf = NAN; - print.cdf = NAN; - - print(*stream); -} - -void -Text::visit(const VectorData &data) -{ - if (noOutput(data)) - return; - - int size = data.size(); - VectorPrint print; - - print.name = data.name; - print.desc = data.desc; - print.flags = data.flags; - print.compat = compat; - print.descriptions = descriptions; - print.precision = data.precision; - print.vec = data.result(); - print.total = data.total(); - - if (!data.subnames.empty()) { - for (int i = 0; i < size; ++i) { - if (!data.subnames[i].empty()) { - print.subnames = data.subnames; - print.subnames.resize(size); - for (int i = 0; i < size; ++i) { - if (!data.subnames[i].empty() && - !data.subdescs[i].empty()) { - print.subdescs = data.subdescs; - print.subdescs.resize(size); - break; - } - } - break; - } - } - } - - print(*stream); -} - -void -Text::visit(const Vector2dData &data) -{ - if (noOutput(data)) - return; - - bool havesub = false; - VectorPrint print; - - print.subnames = data.y_subnames; - print.flags = data.flags; - print.compat = compat; - print.descriptions = descriptions; - print.precision = data.precision; - - if (!data.subnames.empty()) { - for (int i = 0; i < data.x; ++i) - if (!data.subnames[i].empty()) - havesub = true; - } - - VResult tot_vec(data.y); - Result super_total = 0.0; - for (int i = 0; i < data.x; ++i) { - if (havesub && (i >= data.subnames.size() || data.subnames[i].empty())) - continue; - - int iy = i * data.y; - VResult yvec(data.y); - - Result total = 0.0; - for (int j = 0; j < data.y; ++j) { - yvec[j] = data.cvec[iy + j]; - tot_vec[j] += yvec[j]; - total += yvec[j]; - super_total += yvec[j]; - } - - print.name = data.name + "_" + (havesub ? data.subnames[i] : to_string(i)); - print.desc = data.desc; - print.vec = yvec; - print.total = total; - print(*stream); - } - - if ((data.flags & ::Stats::total) && (data.x > 1)) { - print.name = data.name; - print.desc = data.desc; - print.vec = tot_vec; - print.total = super_total; - print(*stream); - } -} - -void -Text::visit(const DistData &data) -{ - if (noOutput(data)) - return; - - DistPrint print; - - print.name = data.name; - print.desc = data.desc; - print.flags = data.flags; - print.compat = compat; - print.descriptions = descriptions; - print.precision = data.precision; - - print.min_val = data.data.min_val; - print.max_val = data.data.max_val; - print.underflow = data.data.underflow; - print.overflow = data.data.overflow; - print.vec.resize(data.data.cvec.size()); - for (int i = 0; i < print.vec.size(); ++i) - print.vec[i] = (Result)data.data.cvec[i]; - print.sum = data.data.sum; - print.squares = data.data.squares; - print.samples = data.data.samples; - - print.min = data.data.min; - print.max = data.data.max; - print.bucket_size = data.data.bucket_size; - print.size = data.data.size; - print.fancy = data.data.fancy; - - print(*stream); -} - -void -Text::visit(const VectorDistData &data) -{ - if (noOutput(data)) - return; - - for (int i = 0; i < data.size(); ++i) { - DistPrint print; - - print.name = data.name + - (data.subnames[i].empty() ? ("_" + to_string(i)) : data.subnames[i]); - print.desc = data.subdescs[i].empty() ? data.desc : data.subdescs[i]; - print.flags = data.flags; - print.compat = compat; - print.descriptions = descriptions; - print.precision = data.precision; - - print.min_val = data.data[i].min_val; - print.max_val = data.data[i].max_val; - print.underflow = data.data[i].underflow; - print.overflow = data.data[i].overflow; - print.vec.resize(data.data[i].cvec.size()); - for (int j = 0; j < print.vec.size(); ++j) - print.vec[j] = (Result)data.data[i].cvec[j]; - print.sum = data.data[i].sum; - print.squares = data.data[i].squares; - print.samples = data.data[i].samples; - - print.min = data.data[i].min; - print.max = data.data[i].max; - print.bucket_size = data.data[i].bucket_size; - print.size = data.data[i].size; - print.fancy = data.data[i].fancy; - - print(*stream); - } -} - -void -Text::visit(const FormulaData &data) -{ - visit((const VectorData &)data); -} - -/* namespace Stats */ } diff --git a/base/stats/text.hh b/base/stats/text.hh deleted file mode 100644 index 1d9da5531..000000000 --- a/base/stats/text.hh +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __BASE_STATS_TEXT_HH__ -#define __BASE_STATS_TEXT_HH__ - -#include <iosfwd> -#include <string> - -#include "base/stats/output.hh" - -namespace Stats { - -class Text : public Output -{ - protected: - bool mystream; - std::ostream *stream; - - protected: - bool noOutput(const StatData &data); - - public: - bool compat; - bool descriptions; - - public: - Text(); - Text(std::ostream &stream); - Text(const std::string &file); - ~Text(); - - void open(std::ostream &stream); - void open(const std::string &file); - - // Implement Visit - virtual void visit(const ScalarData &data); - virtual void visit(const VectorData &data); - virtual void visit(const DistData &data); - virtual void visit(const VectorDistData &data); - virtual void visit(const Vector2dData &data); - virtual void visit(const FormulaData &data); - - // Implement Output - virtual bool valid() const; - virtual void output(); -}; - -/* namespace Stats */ } - -#endif // __BASE_STATS_TEXT_HH__ diff --git a/base/stats/types.hh b/base/stats/types.hh deleted file mode 100644 index 57f1564a5..000000000 --- a/base/stats/types.hh +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __BASE_STATS_TYPES_HH__ -#define __BASE_STATS_TYPES_HH__ - -#include <vector> -#include "sim/host.hh" - -namespace Stats { - -/** All counters are of 64-bit values. */ -typedef double Counter; -/** vector of counters. */ -typedef std::vector<Counter> VCounter; - -/** All results are doubles. */ -typedef double Result; -/** vector of results. */ -typedef std::vector<Result> VResult; - -/* namespace Stats */ } - -#endif // __BASE_STATS_TYPES_HH__ diff --git a/base/stats/visit.cc b/base/stats/visit.cc deleted file mode 100644 index dd4d49502..000000000 --- a/base/stats/visit.cc +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "base/stats/visit.hh" - -namespace Stats { -namespace Detail { - -Visit::Visit() -{} - -Visit::~Visit() -{} - -/* namespace Detail */ } -/* namespace Stats */ } diff --git a/base/stats/visit.hh b/base/stats/visit.hh deleted file mode 100644 index c0593c670..000000000 --- a/base/stats/visit.hh +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __BASE_STATS_VISIT_HH__ -#define __BASE_STATS_VISIT_HH__ - -#include <string> - -#include "base/time.hh" -#include "sim/host.hh" - -namespace Stats { - -class StatData; -class ScalarData; -class VectorData; -class DistDataData; -class DistData; -class VectorDistData; -class Vector2dData; -class FormulaData; - -struct Visit -{ - Visit(); - virtual ~Visit(); - - virtual void visit(const ScalarData &data) = 0; - virtual void visit(const VectorData &data) = 0; - virtual void visit(const DistData &data) = 0; - virtual void visit(const VectorDistData &data) = 0; - virtual void visit(const Vector2dData &data) = 0; - virtual void visit(const FormulaData &data) = 0; -}; - -/* namespace Stats */ } - -#endif // __BASE_STATS_VISIT_HH__ diff --git a/base/str.cc b/base/str.cc deleted file mode 100644 index 5f7f50286..000000000 --- a/base/str.cc +++ /dev/null @@ -1,373 +0,0 @@ -/* - * 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. - */ - -#include <ctype.h> - -#include <cstring> -#include <iostream> -#include <string> -#include <vector> - -#include "base/intmath.hh" -#include "base/str.hh" - -using namespace std; - -bool -split_first(const string &s, string &lhs, string &rhs, char c) -{ - string::size_type offset = s.find(c); - if (offset == string::npos) { - lhs = s; - rhs = ""; - return false; - } - - lhs = s.substr(0, offset); - rhs = s.substr(offset + 1); - return true; -} - -bool -split_last(const string &s, string &lhs, string &rhs, char c) -{ - string::size_type offset = s.rfind(c); - if (offset == string::npos) { - lhs = s; - rhs = ""; - return false; - } - - lhs = s.substr(0, offset); - rhs = s.substr(offset + 1); - return true; -} - -void -tokenize(vector<string>& v, const string &s, char token, bool ignore) -{ - string::size_type first = 0; - string::size_type last = s.find_first_of(token); - - if (s.empty()) - return; - - if (ignore && last == first) { - while (last == first) - last = s.find_first_of(token, ++first); - - if (last == string::npos) { - if (first != s.size()) - v.push_back(s.substr(first)); - return; - } - } - - while (last != string::npos) { - v.push_back(s.substr(first, last - first)); - - if (ignore) { - first = s.find_first_not_of(token, last + 1); - - if (first == string::npos) - return; - } else - first = last + 1; - - last = s.find_first_of(token, first); - } - - v.push_back(s.substr(first)); -} - -/** - * @todo This function will not handle the smallest negative decimal - * value for a signed type - */ - -template <class T> -inline bool -__to_number(string value, T &retval) -{ - static const T maxnum = ((T)-1); - static const bool sign = maxnum < 0; - static const int bits = sizeof(T) * 8; - static const T hexmax = maxnum & (((T)1 << (bits - 4 - sign)) - 1); - static const T octmax = maxnum & (((T)1 << (bits - 3 - sign)) - 1); - static const T signmax = - (sign) ? maxnum & (((T)1 << (bits - 1)) - 1) : maxnum; - static const T decmax = signmax / 10; - -#if 0 - cout << "maxnum = 0x" << hex << (unsigned long long)maxnum << "\n" - << "sign = 0x" << hex << (unsigned long long)sign << "\n" - << "hexmax = 0x" << hex << (unsigned long long)hexmax << "\n" - << "octmax = 0x" << hex << (unsigned long long)octmax << "\n" - << "signmax = 0x" << hex << (unsigned long long)signmax << "\n" - << "decmax = 0x" << hex << (unsigned long long)decmax << "\n"; -#endif - - eat_white(value); - - bool negative = false; - bool hex = false; - bool oct = false; - int last = value.size() - 1; - retval = 0; - int i = 0; - - char c = value[i]; - if (!isDec(c)) { - if (c == '-' && sign) - negative = true; - else - return false; - } - else { - retval += c - '0'; - if (last == 0) return true; - } - - if (c == '0') - oct = true; - - c = value[++i]; - if (oct) { - if (sign && negative) - return false; - - if (!isOct(c)) { - if (c == 'X' || c == 'x') { - hex = true; - oct = false; - } else - return false; - } - else - retval += c - '0'; - } else if (!isDec(c)) - goto multiply; - else { - if (sign && negative && c == '0') - return false; - - retval *= 10; - retval += c - '0'; - if (last == 1) { - if (sign && negative) retval = -retval; - return true; - } - } - - if (hex) { - if (last == 1) - return false; - - for (i = 2; i <= last ; i++) { - c = value[i]; - if (!isHex(c)) - return false; - - if (retval > hexmax) return false; - retval *= 16; - retval += hex2Int(c); - } - return true; - } else if (oct) { - for (i = 2; i <= last ; i++) { - c = value[i]; - if (!isOct(c)) - return false; - - if (retval > octmax) return false; - retval *= 8; - retval += (c - '0'); - } - return true; - } - - for (i = 2; i < last ; i++) { - c = value[i]; - if (!isDec(c)) - goto multiply; - - if (retval > decmax) return false; - bool atmax = retval == decmax; - retval *= 10; - retval += c - '0'; - if (atmax && retval < decmax) return false; - if (sign && (retval & ((T)1 << (sizeof(T) * 8 - 1)))) - return false; - } - - c = value[last]; - if (isDec(c)) { - - if (retval > decmax) return false; - bool atmax = retval == decmax; - retval *= 10; - retval += c - '0'; - if (atmax && retval < decmax) return false; - if (sign && negative) { - if ((retval & ((T)1 << (sizeof(T) * 8 - 1))) && - retval >= (T)-signmax) - return false; - retval = -retval; - } - else - if (sign && (retval & ((T)1 << ((sizeof(T) * 8) - 1)))) - return false; - return true; - } - - multiply: - signed long long mult = 1; - T val; - switch (c) { - case 'k': - case 'K': - if (i != last) return false; - mult = 1024; - val = signmax / mult; - break; - case 'm': - case 'M': - if (i != last) return false; - mult = 1024 * 1024; - val = signmax / mult; - break; - case 'g': - case 'G': - if (i != last) return false; - mult = 1024 * 1024 * 1024; - val = signmax / mult; - break; - case 'e': - case 'E': - if (i >= last) return false; - - mult = 0; - for (i++; i <= last; i++) { - c = value[i]; - if (!isDec(c)) - return false; - - mult *= 10; - mult += c - '0'; - } - - for (i = 0; i < mult; i++) { - if (retval > signmax / 10) - return false; - retval *= 10; - if (sign && (retval & ((T)1 << (sizeof(T) * 8 - 1)))) - return false; - } - if (sign && negative) { - if ((retval & ((T)1 << (sizeof(T) * 8 - 1))) && - retval >= (T)-signmax) - return false; - retval = -retval; - } - else - if (sign && (retval & ((T)1 << ((sizeof(T) * 8) - 1)))) - return false; - - return true; - - default: - return false; - } - - if (sign && negative) - return false; - - if (mult > (unsigned long long)signmax) - return false; - - if (retval > val) - return false; - - retval *= mult; - - return true; -} - -#define STN(type) \ -template<> \ -bool to_number<type>(const string &value, type &retval) \ -{ return __to_number(value, retval); } - -STN(unsigned long long); -STN(signed long long); -STN(unsigned long); -STN(signed long); -STN(unsigned int); -STN(signed int); -STN(unsigned short); -STN(signed short); -STN(unsigned char); -STN(signed char); - -template<> -bool to_number<bool>(const string &value, bool &retval) -{ - string lowered = to_lower(value); - - if (value == "0") { - retval = false; - return true; - } - - if (value == "1"){ - retval = true; - return true; - } - - if (lowered == "false") { - retval = false; - return true; - } - - if (lowered == "true"){ - retval = true; - return true; - } - - if (lowered == "no") { - retval = false; - return true; - } - - if (lowered == "yes"){ - retval = true; - return true; - } - - return false; -} diff --git a/base/str.hh b/base/str.hh deleted file mode 100644 index 79e33a1be..000000000 --- a/base/str.hh +++ /dev/null @@ -1,141 +0,0 @@ -/* - * 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. - */ - -#ifndef __STR_HH__ -#define __STR_HH__ - -#include <sstream> -#include <string> -#include <vector> - -#include <ctype.h> - -template<class> class Hash; -template<> -class Hash<std::string> { -public: - unsigned operator()(const std::string &s) { - std::string::const_iterator i = s.begin(); - std::string::const_iterator end = s.end(); - unsigned hash = 5381; - - while (i < end) - hash = ((hash << 5) + hash) + *i++; - - return hash; - } -}; - -inline void -eat_lead_white(std::string &s) -{ - std::string::size_type off = s.find_first_not_of(' '); - if (off != std::string::npos) { - std::string::iterator begin = s.begin(); - s.erase(begin, begin + off); - } -} - -inline void -eat_end_white(std::string &s) -{ - std::string::size_type off = s.find_last_not_of(' '); - if (off != std::string::npos) - s.erase(s.begin() + off + 1, s.end()); -} - -inline void -eat_white(std::string &s) -{ - eat_lead_white(s); - eat_end_white(s); -} - -inline std::string -to_lower(const std::string &s) -{ - std::string lower; - int len = s.size(); - - lower.reserve(len); - - for (int i = 0; i < len; ++i) - lower.push_back(tolower(s[i])); - - return lower; -} - -// Split the string s into lhs and rhs on the first occurence of the -// character c. -bool -split_first(const std::string &s, std::string &lhs, std::string &rhs, char c); - -// Split the string s into lhs and rhs on the last occurence of the -// character c. -bool -split_last(const std::string &s, std::string &lhs, std::string &rhs, char c); - -// Tokenize the string <s> splitting on the character <token>, and -// place the result in the string vector <vector>. If <ign> is true, -// then empty result strings (due to trailing tokens, or consecutive -// tokens) are skipped. -void -tokenize(std::vector<std::string> &vector, const std::string &s, - char token, bool ign = true); - -template <class T> bool -to_number(const std::string &value, T &retval); - -template <class T> -inline std::string -to_string(const T &value) -{ - std::stringstream str; - str << value; - return str.str(); -} - -// Put quotes around string arg if it contains spaces. -inline std::string -quote(const std::string &s) -{ - std::string ret; - bool quote = s.find(' ') != std::string::npos; - - if (quote) - ret = '"'; - - ret += s; - - if (quote) - ret += '"'; - - return ret; -} - -#endif //__STR_HH__ diff --git a/base/time.cc b/base/time.cc deleted file mode 100644 index 5827c9a85..000000000 --- a/base/time.cc +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include <sys/types.h> -#include <sys/time.h> -#include <time.h> -#include <iostream> -#include <string> - -#include "base/time.hh" - -using namespace std; - -struct _timeval -{ - timeval tv; -}; - -double -convert(const timeval &tv) -{ - return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0; -} - -Time::Time(bool set_now) -{ - time = new _timeval; - if (set_now) - set(); -} - -Time::Time(const timeval &val) -{ - time = new _timeval; - set(val); -} - -Time::Time(const Time &val) -{ - time = new _timeval; - set(val.get()); -} - -Time::~Time() -{ - delete time; -} - -const timeval & -Time::get() const -{ - return time->tv; -} - -void -Time::set() -{ - ::gettimeofday(&time->tv, NULL); -} - -void -Time::set(const timeval &tv) -{ - memcpy(&time->tv, &tv, sizeof(timeval)); -} - -double -Time::operator()() const -{ - return convert(get()); -} - -string -Time::date(string format) const -{ - const timeval &tv = get(); - time_t sec = tv.tv_sec; - char buf[256]; - - if (format.empty()) { - ctime_r(&sec, buf); - buf[24] = '\0'; - return buf; - } - - struct tm *tm = localtime(&sec); - strftime(buf, sizeof(buf), format.c_str(), tm); - return buf; -} - -ostream & -operator<<(ostream &out, const Time &start) -{ - out << start.date(); - return out; -} - -Time -operator-(const Time &l, const Time &r) -{ - timeval tv; - timersub(&l.get(), &r.get(), &tv); - return tv; -} - -const Time Time::start(true); diff --git a/base/time.hh b/base/time.hh deleted file mode 100644 index 5731e3029..000000000 --- a/base/time.hh +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __SIM_TIME_HH__ -#define __SIM_TIME_HH__ - -#include <sys/time.h> - -#include <iosfwd> -#include <string> - -struct _timeval; - -class Time -{ - protected: - mutable _timeval *time; - - public: - explicit Time(bool set_now = false); - Time(const timeval &val); - Time(const Time &val); - ~Time(); - - void set(); - const timeval &get() const; - void set(const timeval &val); - - double operator()() const; - std::string date(std::string format = "") const; - - public: - static const Time start; -}; - -Time operator-(const Time &l, const Time &r); - -std::ostream &operator<<(std::ostream &out, const Time &time); - -#endif // __SIM_TIME_HH__ diff --git a/base/timebuf.hh b/base/timebuf.hh deleted file mode 100644 index f6b5b2781..000000000 --- a/base/timebuf.hh +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __BASE_TIMEBUF_HH__ -#define __BASE_TIMEBUF_HH__ - -#include <vector> - -template <class T> -class TimeBuffer -{ - protected: - int past; - int future; - int size; - - char *data; - std::vector<char *> index; - int base; - - void valid(int idx) - { - assert (idx >= -past && idx <= future); - } - - public: - friend class wire; - class wire - { - friend class TimeBuffer; - protected: - TimeBuffer<T> *buffer; - int index; - - void set(int idx) - { - buffer->valid(idx); - index = idx; - } - - wire(TimeBuffer<T> *buf, int i) - : buffer(buf), index(i) - { } - - public: - wire() - { } - - wire(const wire &i) - : buffer(i.buffer), index(i.index) - { } - - const wire &operator=(const wire &i) - { - buffer = i.buffer; - set(i.index); - return *this; - } - - const wire &operator=(int idx) - { - set(idx); - return *this; - } - - const wire &operator+=(int offset) - { - set(index + offset); - return *this; - } - - const wire &operator-=(int offset) - { - set(index - offset); - return *this; - } - - wire &operator++() - { - set(index + 1); - return *this; - } - - wire &operator++(int) - { - int i = index; - set(index + 1); - return wire(this, i); - } - - wire &operator--() - { - set(index - 1); - return *this; - } - - wire &operator--(int) - { - int i = index; - set(index - 1); - return wire(this, i); - } - T &operator*() const { return *buffer->access(index); } - T *operator->() const { return buffer->access(index); } - }; - - - public: - TimeBuffer(int p, int f) - : past(p), future(f), size(past + future + 1), - data(new char[size * sizeof(T)]), index(size), base(0) - { - assert(past >= 0 && future >= 0); - char *ptr = data; - for (int i = 0; i < size; i++) { - index[i] = ptr; - memset(ptr, 0, sizeof(T)); - new (ptr) T; - ptr += sizeof(T); - } - } - - TimeBuffer() - : data(NULL) - { - } - - ~TimeBuffer() - { - for (int i = 0; i < size; ++i) - (reinterpret_cast<T *>(index[i]))->~T(); - delete [] data; - } - - void - advance() - { - if (++base >= size) - base = 0; - - int ptr = base + future; - if (ptr >= size) - ptr -= size; - (reinterpret_cast<T *>(index[ptr]))->~T(); - memset(index[ptr], 0, sizeof(T)); - new (index[ptr]) T; - } - - T *access(int idx) - { - //Need more complex math here to calculate index. - valid(idx); - - int vector_index = idx + base; - if (vector_index >= size) { - vector_index -= size; - } else if (vector_index < 0) { - vector_index += size; - } - - return reinterpret_cast<T *>(index[vector_index]); - } - - T &operator[](int idx) - { - //Need more complex math here to calculate index. - valid(idx); - - int vector_index = idx + base; - if (vector_index >= size) { - vector_index -= size; - } else if (vector_index < 0) { - vector_index += size; - } - - return reinterpret_cast<T &>(*index[vector_index]); - } - - wire getWire(int idx) - { - valid(idx); - - return wire(this, idx); - } - - wire zero() - { - return wire(this, 0); - } -}; - -#endif // __BASE_TIMEBUF_HH__ - diff --git a/base/trace.cc b/base/trace.cc deleted file mode 100644 index 90db7f045..000000000 --- a/base/trace.cc +++ /dev/null @@ -1,350 +0,0 @@ -/* - * 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. - */ - -#include <ctype.h> -#include <fstream> -#include <iostream> -#include <list> -#include <string> -#include <vector> - -#include "base/misc.hh" -#include "base/trace.hh" -#include "base/str.hh" - -using namespace std; - -namespace Trace { -const string DefaultName("global"); -FlagVec flags(NumFlags, false); - -// -// This variable holds the output stream for debug information. Other -// than setting up/redirecting this stream, do *NOT* reference this -// directly; use DebugOut() (see below) to access this stream for -// output. -// -ostream *dprintf_stream = &cerr; - -ObjectMatch ignore; - -Log theLog; - -Log::Log() -{ - size = 0; - buffer = NULL; -} - - -void -Log::init(int _size) -{ - if (buffer != NULL) { - fatal("Trace::Log::init called twice!"); - } - - size = _size; - - buffer = new Record *[size]; - - for (int i = 0; i < size; ++i) { - buffer[i] = NULL; - } - - nextRecPtr = &buffer[0]; - wrapRecPtr = &buffer[size]; -} - - -Log::~Log() -{ - for (int i = 0; i < size; ++i) { - delete buffer[i]; - } - - delete [] buffer; -} - - -void -Log::append(Record *rec) -{ - // dump record to output stream if there's one open - if (dprintf_stream != NULL) { - rec->dump(*dprintf_stream); - } else { - rec->dump(cout); - } - - // no buffering: justget rid of it now - if (buffer == NULL) { - delete rec; - return; - } - - Record *oldRec = *nextRecPtr; - - if (oldRec != NULL) { - // log has wrapped: overwrite - delete oldRec; - } - - *nextRecPtr = rec; - - if (++nextRecPtr == wrapRecPtr) { - nextRecPtr = &buffer[0]; - } -} - - -void -Log::dump(ostream &os) -{ - if (buffer == NULL) { - return; - } - - Record **bufPtr = nextRecPtr; - - if (*bufPtr == NULL) { - // next record slot is empty: log must not be full yet. - // start dumping from beginning of buffer - bufPtr = buffer; - } - - do { - Record *rec = *bufPtr; - - rec->dump(os); - - if (++bufPtr == wrapRecPtr) { - bufPtr = &buffer[0]; - } - } while (bufPtr != nextRecPtr); -} - -PrintfRecord::~PrintfRecord() -{ - delete &args; -} - -void -PrintfRecord::dump(ostream &os) -{ - string fmt = ""; - - if (!name.empty()) { - fmt = "%s: " + fmt; - args.prepend(name); - } - - if (cycle != (Tick)-1) { - fmt = "%7d: " + fmt; - args.prepend(cycle); - } - - fmt += format; - - args.dump(os, fmt); - os.flush(); -} - -DataRecord::DataRecord(Tick _cycle, const string &_name, - const void *_data, int _len) - : Record(_cycle), name(_name), len(_len) -{ - data = new uint8_t[len]; - memcpy(data, _data, len); -} - -DataRecord::~DataRecord() -{ - delete [] data; -} - -void -DataRecord::dump(ostream &os) -{ - int c, i, j; - - for (i = 0; i < len; i += 16) { - ccprintf(os, "%d: %s: %08x ", cycle, name, i); - c = len - i; - if (c > 16) c = 16; - - for (j = 0; j < c; j++) { - ccprintf(os, "%02x ", data[i + j] & 0xff); - if ((j & 0xf) == 7 && j > 0) - ccprintf(os, " "); - } - - for (; j < 16; j++) - ccprintf(os, " "); - ccprintf(os, " "); - - for (j = 0; j < c; j++) { - int ch = data[i + j] & 0x7f; - ccprintf(os, - "%c", (char)(isprint(ch) ? ch : ' ')); - } - - ccprintf(os, "\n"); - - if (c < 16) - break; - } -} -} // namespace Trace - -// -// Returns the current output stream for debug information. As a -// wrapper around Trace::dprintf_stream, this handles cases where debug -// information is generated in the process of parsing .ini options, -// before we process the option that sets up the debug output stream -// itself. -// -std::ostream & -DebugOut() -{ - return *Trace::dprintf_stream; -} - -///////////////////////////////////////////// -// -// C-linkage functions for invoking from gdb -// -///////////////////////////////////////////// - -// -// Dump trace buffer to specified file (cout if NULL) -// -extern "C" -void -dumpTrace(const char *filename) -{ - if (filename != NULL) { - ofstream out(filename); - Trace::theLog.dump(out); - out.close(); - } - else { - Trace::theLog.dump(cout); - } -} - - -// -// Turn on/off trace output to cerr. Typically used when trace output -// is only going to circular buffer, but you want to see what's being -// sent there as you step through some code in gdb. This uses the -// same facility as the "trace to file" feature, and will print error -// messages rather than clobbering an existing ostream pointer. -// -extern "C" -void -echoTrace(bool on) -{ - if (on) { - if (Trace::dprintf_stream != NULL) { - cerr << "Already echoing trace to a file... go do a 'tail -f'" - << " on that file instead." << endl; - } else { - Trace::dprintf_stream = &cerr; - } - } else { - if (Trace::dprintf_stream != &cerr) { - cerr << "Not echoing trace to cerr." << endl; - } else { - Trace::dprintf_stream = NULL; - } - } -} - -extern "C" -void -printTraceFlags() -{ - using namespace Trace; - for (int i = 0; i < numFlagStrings; ++i) - if (flags[i]) - cprintf("%s\n", flagStrings[i]); -} - -void -tweakTraceFlag(const char *string, bool value) -{ - using namespace Trace; - std::string str(string); - - for (int i = 0; i < numFlagStrings; ++i) { - if (str != flagStrings[i]) - continue; - - int idx = i; - - if (idx < NumFlags) { - flags[idx] = value; - } else { - idx -= NumFlags; - if (idx >= NumCompoundFlags) { - ccprintf(cerr, "Invalid compound flag"); - return; - } - - const Flags *flagVec = compoundFlags[idx]; - - for (int j = 0; flagVec[j] != -1; ++j) { - if (flagVec[j] >= NumFlags) { - ccprintf(cerr, "Invalid compound flag"); - return; - } - flags[flagVec[j]] = value; - } - } - - cprintf("flag %s was %s\n", string, value ? "set" : "cleared"); - return; - } - - cprintf("could not find flag %s\n", string); -} - -extern "C" -void -setTraceFlag(const char *string) -{ - tweakTraceFlag(string, true); -} - -extern "C" -void -clearTraceFlag(const char *string) -{ - tweakTraceFlag(string, false); -} diff --git a/base/trace.hh b/base/trace.hh deleted file mode 100644 index 5e14f1bff..000000000 --- a/base/trace.hh +++ /dev/null @@ -1,231 +0,0 @@ -/* - * 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. - */ - -#ifndef __BASE_TRACE_HH__ -#define __BASE_TRACE_HH__ - -#include <vector> - -#include "base/cprintf.hh" -#include "base/match.hh" -#include "sim/host.hh" -#include "sim/root.hh" - -#ifndef TRACING_ON -#ifndef NDEBUG -#define TRACING_ON 1 -#else -#define TRACING_ON 0 -#endif -#endif - -#include "base/traceflags.hh" - -namespace Trace { - - typedef std::vector<bool> FlagVec; - - extern FlagVec flags; - -#if TRACING_ON - const bool On = true; -#else - const bool On = false; -#endif - - inline bool - IsOn(int t) - { - return flags[t]; - - } - - void dump(const uint8_t *data, int count); - - class Record - { - protected: - Tick cycle; - - Record(Tick _cycle) - : cycle(_cycle) - { - } - - public: - virtual ~Record() {} - - virtual void dump(std::ostream &) = 0; - }; - - class PrintfRecord : public Record - { - private: - const char *format; - const std::string &name; - cp::ArgList &args; - - public: - PrintfRecord(const char *_format, cp::ArgList &_args, - Tick cycle, const std::string &_name) - : Record(cycle), format(_format), name(_name), args(_args) - { - } - - virtual ~PrintfRecord(); - - virtual void dump(std::ostream &); - }; - - class DataRecord : public Record - { - private: - const std::string &name; - uint8_t *data; - int len; - - public: - DataRecord(Tick cycle, const std::string &name, - const void *_data, int _len); - virtual ~DataRecord(); - - virtual void dump(std::ostream &); - }; - - class Log - { - private: - int size; // number of records in log - Record **buffer; // array of 'size' Record ptrs (circular buf) - Record **nextRecPtr; // next slot to use in buffer - Record **wrapRecPtr; // &buffer[size], for quick wrap check - - public: - - Log(); - ~Log(); - - void init(int _size); - - void append(Record *); // append trace record to log - void dump(std::ostream &); // dump contents to stream - }; - - extern Log theLog; - - extern ObjectMatch ignore; - - inline void - dprintf(const char *format, cp::ArgList &args, Tick cycle, - const std::string &name) - { - if (name.empty() || !ignore.match(name)) - theLog.append(new Trace::PrintfRecord(format, args, cycle, name)); - } - - inline void - dataDump(Tick cycle, const std::string &name, const void *data, int len) - { - theLog.append(new Trace::DataRecord(cycle, name, data, len)); - } - - extern const std::string DefaultName; -}; - -// This silly little class allows us to wrap a string in a functor -// object so that we can give a name() that DPRINTF will like -struct StringWrap -{ - std::string str; - StringWrap(const std::string &s) : str(s) {} - const std::string &operator()() const { return str; } -}; - -inline const std::string &name() { return Trace::DefaultName; } -std::ostream &DebugOut(); - -// -// DPRINTF is a debugging trace facility that allows one to -// selectively enable tracing statements. To use DPRINTF, there must -// be a function or functor called name() that returns a const -// std::string & in the current scope. -// -// If you desire that the automatic printing not occur, use DPRINTFR -// (R for raw) -// - -#if TRACING_ON - -#define DTRACE(x) (Trace::IsOn(Trace::x)) - -#define DCOUT(x) if (Trace::IsOn(Trace::x)) DebugOut() - -#define DDUMP(x, data, count) \ -do { \ - if (Trace::IsOn(Trace::x)) \ - Trace::dataDump(curTick, name(), data, count); \ -} while (0) - -#define __dprintf(cycle, name, format, args...) \ - Trace::dprintf(format, (*(new cp::ArgList), args), cycle, name) - -#define DPRINTF(x, args...) \ -do { \ - if (Trace::IsOn(Trace::x)) \ - __dprintf(curTick, name(), args, cp::ArgListNull()); \ -} while (0) - -#define DPRINTFR(x, args...) \ -do { \ - if (Trace::IsOn(Trace::x)) \ - __dprintf((Tick)-1, std::string(), args, cp::ArgListNull()); \ -} while (0) - -#define DPRINTFN(args...) \ -do { \ - __dprintf(curTick, name(), args, cp::ArgListNull()); \ -} while (0) - -#define DPRINTFNR(args...) \ -do { \ - __dprintf((Tick)-1, string(), args, cp::ArgListNull()); \ -} while (0) - -#else // !TRACING_ON - -#define DTRACE(x) (false) -#define DCOUT(x) if (0) DebugOut() -#define DPRINTF(x, args...) do {} while (0) -#define DPRINTFR(args...) do {} while (0) -#define DPRINTFN(args...) do {} while (0) -#define DPRINTFNR(args...) do {} while (0) -#define DDUMP(x, data, count) do {} while (0) - -#endif // TRACING_ON - -#endif // __BASE_TRACE_HH__ diff --git a/base/traceflags.py b/base/traceflags.py deleted file mode 100644 index 47ed59c3a..000000000 --- a/base/traceflags.py +++ /dev/null @@ -1,325 +0,0 @@ -#!/usr/bin/env python - -# 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. - -# -# This file generates the header and source files for the flags -# that control the tracing facility. -# - -import sys - -if len(sys.argv) != 2: - print "%s: Need argument (basename of cc/hh files)" % sys.argv[0] - sys.exit(1) - -hhfilename = sys.argv[1] + '.hh' -ccfilename = sys.argv[1] + '.cc' - -# -# The list of trace flags that can be used to condition DPRINTFs etc. -# To define a new flag, simply add it to this list. -# -baseFlags = [ - 'TCPIP', - 'Bus', - 'ScsiDisk', - 'ScsiCtrl', - 'ScsiNone', - 'DMA', - 'DMAReadVerbose', - 'DMAWriteVerbose', - 'TLB', - 'SimpleDisk', - 'SimpleDiskData', - 'Clock', - 'Regs', - 'MC146818', - 'IPI', - 'Timer', - 'Mbox', - 'PCIA', - 'PCIDEV', - 'PciConfigAll', - 'ISP', - 'BADADDR', - 'Console', - 'ConsolePoll', - 'ConsoleVerbose', - 'AlphaConsole', - 'Flow', - 'Interrupt', - 'Fault', - 'Cycle', - 'Loader', - 'MMU', - 'Ethernet', - 'EthernetPIO', - 'EthernetDMA', - 'EthernetData', - 'EthernetDesc', - 'EthernetIntr', - 'EthernetSM', - 'EthernetCksum', - 'GDBMisc', - 'GDBAcc', - 'GDBRead', - 'GDBWrite', - 'GDBSend', - 'GDBRecv', - 'GDBExtra', - 'VtoPhys', - 'Printf', - 'DebugPrintf', - 'Serialize', - 'Event', - 'PCEvent', - 'Syscall', - 'SyscallVerbose', - 'DiskImage', - 'DiskImageRead', - 'DiskImageWrite', - 'InstExec', - 'BPredRAS', - 'Cache', - 'IIC', - 'IICMore', - 'MSHR', - 'Chains', - 'Pipeline', - 'Stats', - 'StatEvents', - 'Context', - 'Config', - 'Sampler', - 'WriteBarrier', - 'IdeCtrl', - 'IdeDisk', - 'Tsunami', - 'Uart', - 'Split', - 'SQL', - 'Thread', - 'Fetch', - 'Decode', - 'Rename', - 'IEW', - 'Commit', - 'IQ', - 'ROB', - 'FreeList', - 'RenameMap', - 'LSQ', - 'LSQUnit', - 'StoreSet', - 'MemDepUnit', - 'DynInst', - 'FullCPU', - 'CommitRate', - 'OzoneCPU', - 'FE', - 'IBE', - 'BE', - 'OzoneLSQ', - 'HWPrefetch', - 'Stack', - 'DependGraph', - 'Activity', - 'Scoreboard', - 'Writeback', - 'Checker' - ] - -# -# "Compound" flags correspond to a set of base flags. These exist -# solely for convenience in setting them via the command line: if a -# compound flag is specified, all of the corresponding base flags are -# set. Compound flags cannot be used directly in DPRINTFs etc. -# To define a new compound flag, add a new entry to this hash -# following the existing examples. -# -compoundFlagMap = { - 'GDBAll' : [ 'GDBMisc', 'GDBAcc', 'GDBRead', 'GDBWrite', 'GDBSend', 'GDBRecv', 'GDBExtra' ], - 'ScsiAll' : [ 'ScsiDisk', 'ScsiCtrl', 'ScsiNone' ], - 'DiskImageAll' : [ 'DiskImage', 'DiskImageRead', 'DiskImageWrite' ], - 'EthernetAll' : [ 'Ethernet', 'EthernetPIO', 'EthernetDMA', 'EthernetData' , 'EthernetDesc', 'EthernetIntr', 'EthernetSM', 'EthernetCksum' ], - 'EthernetNoData' : [ 'Ethernet', 'EthernetPIO', 'EthernetDesc', 'EthernetIntr', 'EthernetSM', 'EthernetCksum' ], - 'IdeAll' : [ 'IdeCtrl', 'IdeDisk' ], - 'FullCPUAll' : [ 'Fetch', 'Decode', 'Rename', 'IEW', 'Commit', 'IQ', 'ROB', 'FreeList', 'RenameMap', 'LSQ', 'LSQUnit', 'StoreSet', 'MemDepUnit', 'DynInst', 'FullCPU', 'Activity','Scoreboard','Writeback'], - 'OzoneCPUAll' : [ 'BE', 'FE', 'IBE', 'OzoneLSQ', 'OzoneCPU'] -} - -############################################################# -# -# Everything below this point generates the appropriate C++ -# declarations and definitions for the trace flags. If you are simply -# adding or modifying flag definitions, you should not have to change -# anything below. -# - -import sys - -# extract just the compound flag names into a list -compoundFlags = [] -compoundFlags.extend(compoundFlagMap.keys()) -compoundFlags.sort() - -# -# First generate the header file. This defines the Flag enum -# and some extern declarations for the .cc file. -# -try: - hhfile = file(hhfilename, 'w') -except IOError, e: - sys.exit("can't open %s: %s" % (hhfilename, e)) - -# file header boilerplate -print >>hhfile, ''' -/* - * DO NOT EDIT THIS FILE! - * - * Automatically generated from traceflags.py - */ - -#ifndef __BASE_TRACE_FLAGS_HH__ -#define __BASE_TRACE_FLAGS_HH__ - -namespace Trace { - -enum Flags { -''', - -# Generate the enum. Base flags come first, then compound flags. -idx = 0 -for flag in baseFlags: - print >>hhfile, ' %s = %d,' % (flag, idx) - idx += 1 - -numBaseFlags = idx -print >>hhfile, ' NumFlags = %d,' % idx - -# put a comment in here to separate base from compound flags -print >>hhfile, ''' - // The remaining enum values are *not* valid indices for Trace::flags. - // They are "compound" flags, which correspond to sets of base - // flags, and are used only by TraceParamContext::setFlags(). -''', - -for flag in compoundFlags: - print >>hhfile, ' %s = %d,' % (flag, idx) - idx += 1 - -numCompoundFlags = idx - numBaseFlags -print >>hhfile, ' NumCompoundFlags = %d' % numCompoundFlags - -# trailer boilerplate -print >>hhfile, '''\ -}; // enum Flags - -// Array of strings for SimpleEnumParam -extern const char *flagStrings[]; -extern const int numFlagStrings; - -// Array of arraay pointers: for each compound flag, gives the list of -// base flags to set. Inidividual flag arrays are terminated by -1. -extern const Flags *compoundFlags[]; - -/* namespace Trace */ } - -#endif // __BASE_TRACE_FLAGS_HH__ -''', - -hhfile.close() - -# -# -# Print out .cc file with array definitions. -# -# -try: - ccfile = file(ccfilename, 'w') -except OSError, e: - sys.exit("can't open %s: %s" % (ccfilename, e)) - -# file header -print >>ccfile, ''' -/* - * DO NOT EDIT THIS FILE! - * - * Automatically generated from traceflags.pl. - */ - -#include "base/traceflags.hh" - -using namespace Trace; - -const char *Trace::flagStrings[] = -{ -''', - -# The string array is used by SimpleEnumParam to map the strings -# provided by the user to enum values. -for flag in baseFlags: - print >>ccfile, ' "%s",' % flag - -for flag in compoundFlags: - print >>ccfile, ' "%s",' % flag - -print >>ccfile, '};\n' - -numFlagStrings = len(baseFlags) + len(compoundFlags); - -print >>ccfile, 'const int Trace::numFlagStrings = %d;' % numFlagStrings -print >>ccfile - -# -# Now define the individual compound flag arrays. There is an array -# for each compound flag listing the component base flags. -# - -for flag in compoundFlags: - flags = compoundFlagMap[flag] - flags.append('(Flags)-1') - print >>ccfile, 'static const Flags %sMap[] =' % flag - print >>ccfile, '{ %s };' % (', '.join(flags)) - print >>ccfile - -# -# Finally the compoundFlags[] array maps the compound flags -# to their individual arrays/ -# -print >>ccfile, 'const Flags *Trace::compoundFlags[] =' -print >>ccfile, '{' - -for flag in compoundFlags: - print >>ccfile, ' %sMap,' % flag - -# file trailer -print >>ccfile, '};' - -ccfile.close() - diff --git a/base/userinfo.cc b/base/userinfo.cc deleted file mode 100644 index 15bd72224..000000000 --- a/base/userinfo.cc +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/types.h> -#include <pwd.h> -#include <unistd.h> - -#include <string> - -std::string -username() -{ - struct passwd *pwd = getpwuid(getuid()); - - return pwd->pw_name; -} diff --git a/base/userinfo.hh b/base/userinfo.hh deleted file mode 100644 index d8ebd443c..000000000 --- a/base/userinfo.hh +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __BASE_USERINFO_HH__ -#define __BASE_USERINFO_HH__ - -#include <string> - -std::string username(); - -#endif // __BASE_USERINFO_HH__ diff --git a/build/SConstruct b/build/SConstruct deleted file mode 100644 index 1dd699ab4..000000000 --- a/build/SConstruct +++ /dev/null @@ -1,419 +0,0 @@ -# -*- mode:python -*- - -# 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. - -################################################### -# -# SCons top-level build description (SConstruct) file. -# -# To build M5, you need a directory with three things: -# 1. A copy of this file (named SConstruct). -# 2. A link named 'm5' to the top of the M5 simulator source tree. -# 3. A link named 'ext' to the top of the M5 external source tree. -# -# Then type 'scons' to build the default configuration (see below), or -# 'scons <CONFIG>/<binary>' to build some other configuration (e.g., -# 'ALPHA_FS/m5.opt' for the optimized full-system version). -# -################################################### - -# Python library imports -import sys -import os - -# Check for recent-enough Python and SCons versions -EnsurePythonVersion(2,3) -EnsureSConsVersion(0,96) - -# The absolute path to the current directory (where this file lives). -ROOT = Dir('.').abspath - -# Paths to the M5 and external source trees (local symlinks). -SRCDIR = os.path.join(ROOT, 'm5') -EXT_SRCDIR = os.path.join(ROOT, 'ext') - -# Check for 'm5' and 'ext' links, die if they don't exist. -if not os.path.isdir(SRCDIR): - print "Error: '%s' must be a link to the M5 source tree." % SRCDIR - Exit(1) - -if not os.path.isdir('ext'): - print "Error: '%s' must be a link to the M5 external source tree." \ - % EXT_SRCDIR - Exit(1) - -# tell python where to find m5 python code -sys.path.append(os.path.join(SRCDIR, 'python')) - -################################################### -# -# Figure out which configurations to set up. -# -# -# It's prohibitive to do all the combinations of base configurations -# and options, so we have to infer which ones the user wants. -# -# 1. If there are command-line targets, the configuration(s) are inferred -# from the directories of those targets. If scons was invoked from a -# subdirectory (using 'scons -u'), those targets have to be -# interpreted relative to that subdirectory. -# -# 2. If there are no command-line targets, and scons was invoked from a -# subdirectory (using 'scons -u'), the configuration is inferred from -# the name of the subdirectory. -# -# 3. If there are no command-line targets and scons was invoked from -# the root build directory, a default configuration is used. The -# built-in default is ALPHA_SE, but this can be overridden by setting the -# M5_DEFAULT_CONFIG shell environment veriable. -# -# In cases 2 & 3, the specific file target defaults to 'm5.debug', but -# this can be overridden by setting the M5_DEFAULT_BINARY shell -# environment veriable. -# -################################################### - -# Find default configuration & binary. -default_config = os.environ.get('M5_DEFAULT_CONFIG', 'ALPHA_SE') -default_binary = os.environ.get('M5_DEFAULT_BINARY', 'm5.debug') - -# Ask SCons which directory it was invoked from. If you invoke SCons -# from a subdirectory you must use the '-u' flag. -launch_dir = GetLaunchDir() - -# Build a list 'my_targets' of all the targets relative to ROOT. -if launch_dir == ROOT: - # invoked from root build dir - if len(COMMAND_LINE_TARGETS) != 0: - # easy: use specified targets as is - my_targets = COMMAND_LINE_TARGETS - else: - # default target (ALPHA_SE/m5.debug, unless overridden) - target = os.path.join(default_config, default_binary) - my_targets = [target] - Default(target) -else: - # invoked from subdirectory - if not launch_dir.startswith(ROOT): - print "Error: launch dir (%s) not a subdirectory of ROOT (%s)!" \ - (launch_dir, ROOT) - Exit(1) - # make launch_dir relative to ROOT (strip ROOT plus slash off front) - launch_dir = launch_dir[len(ROOT)+1:] - if len(COMMAND_LINE_TARGETS) != 0: - # make specified targets relative to ROOT - my_targets = map(lambda x: os.path.join(launch_dir, x), - COMMAND_LINE_TARGETS) - else: - # build default binary (m5.debug, unless overridden) using the - # config inferred by the invocation directory (the first - # subdirectory after ROOT) - target = os.path.join(launch_dir.split('/')[0], default_binary) - my_targets = [target] - Default(target) - -# Normalize target paths (gets rid of '..' in the middle, etc.) -my_targets = map(os.path.normpath, my_targets) - -# Generate a list of the unique configs that the collected targets reference. -build_dirs = [] -for t in my_targets: - dir = t.split('/')[0] - if dir not in build_dirs: - build_dirs.append(dir) - -################################################### -# -# Set up the default build environment. This environment is copied -# and modified according to each selected configuration. -# -################################################### - -env = Environment(ENV = os.environ, # inherit user's environment vars - ROOT = ROOT, - SRCDIR = SRCDIR, - EXT_SRCDIR = EXT_SRCDIR) - -env.SConsignFile("sconsign") - -# I waffle on this setting... it does avoid a few painful but -# unnecessary builds, but it also seems to make trivial builds take -# noticeably longer. -if False: - env.TargetSignatures('content') - -# M5_EXT is used by isa_parser.py to find the PLY package. -env.Append(ENV = { 'M5_EXT' : EXT_SRCDIR }) - -# Set up default C++ compiler flags -env.Append(CCFLAGS='-pipe') -env.Append(CCFLAGS='-fno-strict-aliasing') -env.Append(CCFLAGS=Split('-Wall -Wno-sign-compare -Werror -Wundef')) -if sys.platform == 'cygwin': - # cygwin has some header file issues... - env.Append(CCFLAGS=Split("-Wno-uninitialized")) -env.Append(CPPPATH=[os.path.join(EXT_SRCDIR + '/dnet')]) - -# Default libraries -env.Append(LIBS=['z']) - -# Platform-specific configuration -conf = Configure(env) - -# Check for <fenv.h> (C99 FP environment control) -have_fenv = conf.CheckHeader('fenv.h', '<>') -if not have_fenv: - print "Warning: Header file <fenv.h> not found." - print " This host has no IEEE FP rounding mode control." - -# Check for mysql. -mysql_config = WhereIs('mysql_config') -have_mysql = mysql_config != None - -# Check MySQL version. -if have_mysql: - mysql_version = os.popen(mysql_config + ' --version').read() - mysql_version = mysql_version.split('.') - mysql_major = int(mysql_version[0]) - mysql_minor = int(mysql_version[1]) - # This version check is probably overly conservative, but it deals - # with the versions we have installed. - if mysql_major < 4 or (mysql_major == 4 and mysql_minor < 1): - print "Warning: MySQL v4.1 or newer required." - have_mysql = False - -# Set up mysql_config commands. -if have_mysql: - mysql_config_include = mysql_config + ' --include' - if os.system(mysql_config_include + ' > /dev/null') != 0: - # older mysql_config versions don't support --include, use - # --cflags instead - mysql_config_include = mysql_config + ' --cflags | sed s/\\\'//g' - # This seems to work in all versions - mysql_config_libs = mysql_config + ' --libs' - -env = conf.Finish() - -# Define the universe of supported ISAs -env['ALL_ISA_LIST'] = ['alpha', 'sparc', 'mips'] - -# Define the universe of supported CPU models -env['ALL_CPU_LIST'] = ['SimpleCPU', 'FastCPU', 'FullCPU', 'AlphaFullCPU', - 'OzoneSimpleCPU', 'OzoneCPU', 'CheckerCPU'] - - -# Sticky options get saved in the options file so they persist from -# one invocation to the next (unless overridden, in which case the new -# value becomes sticky). -sticky_opts = Options(args=ARGUMENTS) -sticky_opts.AddOptions( - EnumOption('TARGET_ISA', 'Target ISA', 'alpha', env['ALL_ISA_LIST']), - BoolOption('FULL_SYSTEM', 'Full-system support', False), - BoolOption('ALPHA_TLASER', - 'Model Alpha TurboLaser platform (vs. Tsunami)', False), - BoolOption('NO_FAST_ALLOC', 'Disable fast object allocator', False), - BoolOption('EFENCE', 'Link with Electric Fence malloc debugger', - False), - BoolOption('SS_COMPATIBLE_FP', - 'Make floating-point results compatible with SimpleScalar', - False), - BoolOption('USE_SSE2', - 'Compile for SSE2 (-msse2) to get IEEE FP on x86 hosts', - False), - BoolOption('USE_MYSQL', 'Use MySQL for stats output', have_mysql), - BoolOption('USE_FENV', 'Use <fenv.h> IEEE mode control', have_fenv), - ('CC', 'C compiler', os.environ.get('CC', env['CC'])), - ('CXX', 'C++ compiler', os.environ.get('CXX', env['CXX'])), - BoolOption('BATCH', 'Use batch pool for build and tests', False), - ('BATCH_CMD', 'Batch pool submission command name', 'qdo') - ) - -# Non-sticky options only apply to the current build. -nonsticky_opts = Options(args=ARGUMENTS) -nonsticky_opts.AddOptions( - # This really should be a sticky option, but there's a bug in - # scons 0.96.1 that causes ListOptions not to be able to be - # restored from a saved option file. It looks like this is fixed - # in 0.96.9, but there's a different bug in that version that means we - # can't just upgrade. - ListOption('CPU_MODELS', 'CPU models', 'all', env['ALL_CPU_LIST']), - BoolOption('update_ref', 'Update test reference outputs', False) - ) - -# These options get exported to #defines in config/*.hh (see m5/SConscript). -env.ExportOptions = ['FULL_SYSTEM', 'ALPHA_TLASER', 'USE_FENV', \ - 'USE_MYSQL', 'NO_FAST_ALLOC', 'SS_COMPATIBLE_FP'] - -# Define a handy 'no-op' action -def no_action(target, source, env): - return 0 - -env.NoAction = Action(no_action, None) - -# libelf build is described in its own SConscript file. -# SConscript-global is the build in build/libelf shared among all -# configs. -env.SConscript('m5/libelf/SConscript-global', exports = 'env') - -################################################### -# -# Define a SCons builder for configuration flag headers. -# -################################################### - -# This function generates a config header file that #defines the -# option symbol to the current option setting (0 or 1). The source -# operands are the name of the option and a Value node containing the -# value of the option. -def build_config_file(target, source, env): - (option, value) = [s.get_contents() for s in source] - f = file(str(target[0]), 'w') - print >> f, '#define', option, value - f.close() - return None - -# Generate the message to be printed when building the config file. -def build_config_file_string(target, source, env): - (option, value) = [s.get_contents() for s in source] - return "Defining %s as %s in %s." % (option, value, target[0]) - -# Combine the two functions into a scons Action object. -config_action = Action(build_config_file, build_config_file_string) - -# The emitter munges the source & target node lists to reflect what -# we're really doing. -def config_emitter(target, source, env): - # extract option name from Builder arg - option = str(target[0]) - # True target is config header file - target = os.path.join('config', option.lower() + '.hh') - # Force value to 0/1 even if it's a Python bool - val = int(eval(str(env[option]))) - # Sources are option name & value (packaged in SCons Value nodes) - return ([target], [Value(option), Value(val)]) - -config_builder = Builder(emitter = config_emitter, action = config_action) - -env.Append(BUILDERS = { 'ConfigFile' : config_builder }) - -################################################### -# -# Define build environments for selected configurations. -# -################################################### - -# rename base env -base_env = env - -for build_dir in build_dirs: - # Make a copy of the default environment to use for this config. - env = base_env.Copy() - - # Record what build_dir was in the environment - env.Append(BUILD_DIR=build_dir); - - # Set env according to the build directory config. - - sticky_opts.files = [] - # Name of default options file is taken from 'default=' on command - # line if set, otherwise name of build dir. - default_options_file = os.path.join('default_options', - ARGUMENTS.get('default', build_dir)) - if os.path.isfile(default_options_file): - sticky_opts.files.append(default_options_file) - current_options_file = os.path.join('options', build_dir) - if os.path.isfile(current_options_file): - sticky_opts.files.append(current_options_file) - else: - # if file doesn't exist, make sure at least the directory is there - # so we can create it later - opt_dir = os.path.dirname(current_options_file) - if not os.path.isdir(opt_dir): - os.mkdir(opt_dir) - if not sticky_opts.files: - print "%s: No options file found in options, using defaults." \ - % build_dir - - # Apply current option settings to env - sticky_opts.Update(env) - nonsticky_opts.Update(env) - - # Process option settings. - - if not have_fenv and env['USE_FENV']: - print "Warning: <fenv.h> not available; " \ - "forcing USE_FENV to False in", build_dir + "." - env['USE_FENV'] = False - - if not env['USE_FENV']: - print "Warning: No IEEE FP rounding mode control in", build_dir + "." - print " FP results may deviate slightly from other platforms." - - if env['EFENCE']: - env.Append(LIBS=['efence']) - - if env['USE_MYSQL']: - if not have_mysql: - print "Warning: MySQL not available; " \ - "forcing USE_MYSQL to False in", build_dir + "." - env['USE_MYSQL'] = False - else: - print "Compiling in", build_dir, "with MySQL support." - env.ParseConfig(mysql_config_libs) - env.ParseConfig(mysql_config_include) - - # Save sticky option settings back to current options file - sticky_opts.Save(current_options_file, env) - - # Do this after we save setting back, or else we'll tack on an - # extra 'qdo' every time we run scons. - if env['BATCH']: - env['CC'] = env['BATCH_CMD'] + ' ' + env['CC'] - env['CXX'] = env['BATCH_CMD'] + ' ' + env['CXX'] - - if env['USE_SSE2']: - env.Append(CCFLAGS='-msse2') - - # The m5/SConscript file sets up the build rules in 'env' according - # to the configured options. It returns a list of environments, - # one for each variant build (debug, opt, etc.) - envList = SConscript('m5/SConscript', build_dir = build_dir, - exports = 'env', duplicate = False) - - # Set up the regression tests for each build. - for e in envList: - SConscript('m5-test/SConscript', - build_dir = os.path.join(build_dir, 'test', e.Label), - exports = { 'env' : e }, duplicate = False) - -################################################### -# -# Let SCons do its thing. At this point SCons will use the defined -# build environments to build the requested targets. -# -################################################### - diff --git a/build/default_options/ALPHA_FS b/build_opts/ALPHA_FS index ddd69b9b3..ddd69b9b3 100644 --- a/build/default_options/ALPHA_FS +++ b/build_opts/ALPHA_FS diff --git a/build/default_options/ALPHA_FS_TL b/build_opts/ALPHA_FS_TL index 4f3e201ec..4f3e201ec 100644 --- a/build/default_options/ALPHA_FS_TL +++ b/build_opts/ALPHA_FS_TL diff --git a/build/default_options/ALPHA_SE b/build_opts/ALPHA_SE index 3fedc22ca..3fedc22ca 100644 --- a/build/default_options/ALPHA_SE +++ b/build_opts/ALPHA_SE diff --git a/build/default_options/MIPS_SE b/build_opts/MIPS_SE index e74e2f69c..e74e2f69c 100644 --- a/build/default_options/MIPS_SE +++ b/build_opts/MIPS_SE diff --git a/build_opts/SPARC_FS b/build_opts/SPARC_FS new file mode 100644 index 000000000..59d17eee9 --- /dev/null +++ b/build_opts/SPARC_FS @@ -0,0 +1,2 @@ +TARGET_ISA = 'sparc' +FULL_SYSTEM = 1 diff --git a/build/default_options/SPARC_SE b/build_opts/SPARC_SE index 3b256fc34..3b256fc34 100644 --- a/build/default_options/SPARC_SE +++ b/build_opts/SPARC_SE diff --git a/configs/test/SysPaths.py b/configs/test/SysPaths.py new file mode 100644 index 000000000..c7c7db4e7 --- /dev/null +++ b/configs/test/SysPaths.py @@ -0,0 +1,32 @@ +from m5 import * + +import os.path +import sys + +# Edit the following list to include the possible paths to the binary +# and disk image directories. The first directory on the list that +# exists will be selected. +SYSTEMDIR_PATH = ['/n/poolfs/z/dist/m5/system'] + +SYSTEMDIR = None +for d in SYSTEMDIR_PATH: + if os.path.exists(d): + SYSTEMDIR = d + break + +if not SYSTEMDIR: + print >>sys.stderr, "Can't find a path to system files." + sys.exit(1) + +BINDIR = SYSTEMDIR + '/binaries' +DISKDIR = SYSTEMDIR + '/disks' + +def disk(file): + return os.path.join(DISKDIR, file) + +def binary(file): + return os.path.join(BINDIR, file) + +def script(file): + return os.path.join(SYSTEMDIR, 'boot', file) + diff --git a/configs/test/fs.py b/configs/test/fs.py new file mode 100644 index 000000000..55e7003a4 --- /dev/null +++ b/configs/test/fs.py @@ -0,0 +1,234 @@ +import m5 +from m5.objects import * +import os +from SysPaths import * + +parser = optparse.OptionParser(option_list=m5.standardOptions) + +parser.add_option("-t", "--timing", action="store_true") + +(options, args) = parser.parse_args() + +if args: + print "Error: script doesn't take any positional arguments" + sys.exit(1) + +# Base for tests is directory containing this file. +test_base = os.path.dirname(__file__) + +linux_image = env.get('LINUX_IMAGE', disk('linux-latest.img')) + +class IdeControllerPciData(PciConfigData): + VendorID = 0x8086 + DeviceID = 0x7111 + Command = 0x0 + Status = 0x280 + Revision = 0x0 + ClassCode = 0x01 + SubClassCode = 0x01 + ProgIF = 0x85 + BAR0 = 0x00000001 + BAR1 = 0x00000001 + BAR2 = 0x00000001 + BAR3 = 0x00000001 + BAR4 = 0x00000001 + BAR5 = 0x00000001 + InterruptLine = 0x1f + InterruptPin = 0x01 + BAR0Size = '8B' + BAR1Size = '4B' + BAR2Size = '8B' + BAR3Size = '4B' + BAR4Size = '16B' + +class SinicPciData(PciConfigData): + VendorID = 0x1291 + DeviceID = 0x1293 + Status = 0x0290 + SubClassCode = 0x00 + ClassCode = 0x02 + ProgIF = 0x00 + BAR0 = 0x00000000 + BAR1 = 0x00000000 + BAR2 = 0x00000000 + BAR3 = 0x00000000 + BAR4 = 0x00000000 + BAR5 = 0x00000000 + MaximumLatency = 0x34 + MinimumGrant = 0xb0 + InterruptLine = 0x1e + InterruptPin = 0x01 + BAR0Size = '64kB' + +class NSGigEPciData(PciConfigData): + VendorID = 0x100B + DeviceID = 0x0022 + Status = 0x0290 + SubClassCode = 0x00 + ClassCode = 0x02 + ProgIF = 0x00 + BAR0 = 0x00000001 + BAR1 = 0x00000000 + BAR2 = 0x00000000 + BAR3 = 0x00000000 + BAR4 = 0x00000000 + BAR5 = 0x00000000 + MaximumLatency = 0x34 + MinimumGrant = 0xb0 + InterruptLine = 0x1e + InterruptPin = 0x01 + BAR0Size = '256B' + BAR1Size = '4kB' + +class LinuxRootDisk(IdeDisk): + raw_image = RawDiskImage(image_file=linux_image, read_only=True) + image = CowDiskImage(child=Parent.raw_image, read_only=False) + +class LinuxSwapDisk(IdeDisk): + raw_image = RawDiskImage(image_file = disk('linux-bigswap2.img'), + read_only=True) + image = CowDiskImage(child = Parent.raw_image, read_only=False) + +class SpecwebFilesetDisk(IdeDisk): + raw_image = RawDiskImage(image_file = disk('specweb-fileset.img'), + read_only=True) + image = CowDiskImage(child = Parent.raw_image, read_only=False) + +class BaseTsunami(Tsunami): + cchip = TsunamiCChip(pio_addr=0x801a0000000) + pchip = TsunamiPChip(pio_addr=0x80180000000) + pciconfig = PciConfigAll(pio_addr=0x801fe000000) + fake_sm_chip = IsaFake(pio_addr=0x801fc000370) + + fake_uart1 = IsaFake(pio_addr=0x801fc0002f8) + fake_uart2 = IsaFake(pio_addr=0x801fc0003e8) + fake_uart3 = IsaFake(pio_addr=0x801fc0002e8) + fake_uart4 = IsaFake(pio_addr=0x801fc0003f0) + + fake_ppc = IsaFake(pio_addr=0x801fc0003bc) + + fake_OROM = IsaFake(pio_addr=0x800000a0000, pio_size=0x60000) + + fake_pnp_addr = IsaFake(pio_addr=0x801fc000279) + fake_pnp_write = IsaFake(pio_addr=0x801fc000a79) + fake_pnp_read0 = IsaFake(pio_addr=0x801fc000203) + fake_pnp_read1 = IsaFake(pio_addr=0x801fc000243) + fake_pnp_read2 = IsaFake(pio_addr=0x801fc000283) + fake_pnp_read3 = IsaFake(pio_addr=0x801fc0002c3) + fake_pnp_read4 = IsaFake(pio_addr=0x801fc000303) + fake_pnp_read5 = IsaFake(pio_addr=0x801fc000343) + fake_pnp_read6 = IsaFake(pio_addr=0x801fc000383) + fake_pnp_read7 = IsaFake(pio_addr=0x801fc0003c3) + + fake_ata0 = IsaFake(pio_addr=0x801fc0001f0) + fake_ata1 = IsaFake(pio_addr=0x801fc000170) + + fb = BadDevice(pio_addr=0x801fc0003d0, devicename='FrameBuffer') + io = TsunamiIO(pio_addr=0x801fc000000) + uart = Uart8250(pio_addr=0x801fc0003f8) + ethernet = NSGigE(configdata=NSGigEPciData(), + pci_bus=0, pci_dev=1, pci_func=0) + etherint = NSGigEInt(device=Parent.ethernet) +# ethernet = Sinic(configdata=SinicPciData(), +# pci_bus=0, pci_dev=1, pci_func=0) +# etherint = SinicInt(device=Parent.ethernet) + console = AlphaConsole(pio_addr=0x80200000000, disk=Parent.simple_disk) +# bridge = PciFake(configdata=BridgePciData(), pci_bus=0, pci_dev=2, pci_func=0) + +#class FreeBSDTsunami(BaseTsunami): +# disk0 = FreeBSDRootDisk(delay='0us', driveID='master') +# ide = IdeController(disks=[Parent.disk0], +# configdata=IdeControllerPciData(), +# pci_func=0, pci_dev=0, pci_bus=0) + +class LinuxTsunami(BaseTsunami): + disk0 = LinuxRootDisk(driveID='master') + disk1 = SpecwebFilesetDisk(driveID='slave') + disk2 = LinuxSwapDisk(driveID='master') + ide = IdeController(disks=[Parent.disk0, Parent.disk1, Parent.disk2], + configdata=IdeControllerPciData(), + pci_func=0, pci_dev=0, pci_bus=0) + +class LinuxAlphaSystem(LinuxAlphaSystem): + magicbus = Bus(bus_id=0) + magicbus2 = Bus(bus_id=1) + bridge = Bridge() + physmem = PhysicalMemory(range = AddrRange('128MB')) + c0a = Connector(side_a=Parent.magicbus, side_b=Parent.bridge, side_b_name="side_a") + c0b = Connector(side_a=Parent.magicbus2, side_b=Parent.bridge, side_b_name="side_b") + c1 = Connector(side_a=Parent.physmem, side_b=Parent.magicbus2) + tsunami = LinuxTsunami() + c2 = Connector(side_a=Parent.tsunami.cchip, side_a_name='pio', side_b=Parent.magicbus) + c3 = Connector(side_a=Parent.tsunami.pchip, side_a_name='pio', side_b=Parent.magicbus) + c4 = Connector(side_a=Parent.tsunami.pciconfig, side_a_name='pio', side_b=Parent.magicbus) + c5 = Connector(side_a=Parent.tsunami.fake_sm_chip, side_a_name='pio', side_b=Parent.magicbus) + c6 = Connector(side_a=Parent.tsunami.ethernet, side_a_name='pio', side_b=Parent.magicbus) + c6a = Connector(side_a=Parent.tsunami.ethernet, side_a_name='dma', side_b=Parent.magicbus) + c7 = Connector(side_a=Parent.tsunami.fake_uart1, side_a_name='pio', side_b=Parent.magicbus) + c8 = Connector(side_a=Parent.tsunami.fake_uart2, side_a_name='pio', side_b=Parent.magicbus) + c9 = Connector(side_a=Parent.tsunami.fake_uart3, side_a_name='pio', side_b=Parent.magicbus) + c10 = Connector(side_a=Parent.tsunami.fake_uart4, side_a_name='pio', side_b=Parent.magicbus) + c11 = Connector(side_a=Parent.tsunami.ide, side_a_name='pio', side_b=Parent.magicbus) + c13 = Connector(side_a=Parent.tsunami.ide, side_a_name='dma', side_b=Parent.magicbus) + c12 = Connector(side_a=Parent.tsunami.fake_ppc, side_a_name='pio', side_b=Parent.magicbus) + c14 = Connector(side_a=Parent.tsunami.fake_OROM, side_a_name='pio', side_b=Parent.magicbus) + c16 = Connector(side_a=Parent.tsunami.fake_pnp_addr, side_a_name='pio', side_b=Parent.magicbus) + c17 = Connector(side_a=Parent.tsunami.fake_pnp_write, side_a_name='pio', side_b=Parent.magicbus) + c18 = Connector(side_a=Parent.tsunami.fake_pnp_read0, side_a_name='pio', side_b=Parent.magicbus) + c19 = Connector(side_a=Parent.tsunami.fake_pnp_read1, side_a_name='pio', side_b=Parent.magicbus) + c20 = Connector(side_a=Parent.tsunami.fake_pnp_read2, side_a_name='pio', side_b=Parent.magicbus) + c21 = Connector(side_a=Parent.tsunami.fake_pnp_read3, side_a_name='pio', side_b=Parent.magicbus) + c22 = Connector(side_a=Parent.tsunami.fake_pnp_read4, side_a_name='pio', side_b=Parent.magicbus) + c23 = Connector(side_a=Parent.tsunami.fake_pnp_read5, side_a_name='pio', side_b=Parent.magicbus) + c24 = Connector(side_a=Parent.tsunami.fake_pnp_read6, side_a_name='pio', side_b=Parent.magicbus) + c25 = Connector(side_a=Parent.tsunami.fake_pnp_read7, side_a_name='pio', side_b=Parent.magicbus) + c27 = Connector(side_a=Parent.tsunami.fake_ata0, side_a_name='pio', side_b=Parent.magicbus) + c28 = Connector(side_a=Parent.tsunami.fake_ata1, side_a_name='pio', side_b=Parent.magicbus) + c30 = Connector(side_a=Parent.tsunami.fb, side_a_name='pio', side_b=Parent.magicbus) + c31 = Connector(side_a=Parent.tsunami.io, side_a_name='pio', side_b=Parent.magicbus) + c32 = Connector(side_a=Parent.tsunami.uart, side_a_name='pio', side_b=Parent.magicbus) + c33 = Connector(side_a=Parent.tsunami.console, side_a_name='pio', side_b=Parent.magicbus) + raw_image = RawDiskImage(image_file=disk('linux-latest.img'), + read_only=True) + simple_disk = SimpleDisk(disk=Parent.raw_image) + intrctrl = IntrControl() + if options.timing: + cpu = TimingSimpleCPU() + else: + cpu = AtomicSimpleCPU() + cpu.mem = Parent.magicbus2 + cpu.itb = AlphaITB() + cpu.dtb = AlphaDTB() + sim_console = SimConsole(listener=ConsoleListener(port=3456)) + kernel = binary('vmlinux') + pal = binary('ts_osfpal') + console = binary('console') + boot_osflags = 'root=/dev/hda1 console=ttyS0' +# readfile = os.path.join(test_base, 'halt.sh') + + + +class TsunamiRoot(System): + pass + + +def DualRoot(clientSystem, serverSystem): + self = Root() + self.client = clientSystem + self.server = serverSystem + + self.etherdump = EtherDump(file='ethertrace') + self.etherlink = EtherLink(int1 = Parent.client.tsunami.etherint[0], + int2 = Parent.server.tsunami.etherint[0], + dump = Parent.etherdump) + self.clock = '5GHz' + return self + +root = DualRoot(LinuxAlphaSystem(readfile=script('netperf-stream-nt-client.rcS')), + LinuxAlphaSystem(readfile=script('netperf-server.rcS'))) + +m5.instantiate(root) + +exit_event = m5.simulate() + +print 'Exiting @', m5.curTick(), 'because', exit_event.getCause() diff --git a/configs/test/hello b/configs/test/hello Binary files differnew file mode 100755 index 000000000..59c0d195c --- /dev/null +++ b/configs/test/hello diff --git a/configs/test/hello_mips b/configs/test/hello_mips Binary files differnew file mode 100755 index 000000000..a3db001ec --- /dev/null +++ b/configs/test/hello_mips diff --git a/configs/test/hello_sparc b/configs/test/hello_sparc Binary files differnew file mode 100755 index 000000000..e254ae33f --- /dev/null +++ b/configs/test/hello_sparc diff --git a/configs/test/test.py b/configs/test/test.py new file mode 100644 index 000000000..8bdea16ac --- /dev/null +++ b/configs/test/test.py @@ -0,0 +1,54 @@ +# Simple test script +# +# Alpha: "m5 test.py" +# MIPS: "m5 test.py -a Mips -c hello_mips" + +import os, optparse, sys +import m5 +from m5.objects import * + +# parse command-line arguments +parser = optparse.OptionParser(option_list=m5.standardOptions) + +parser.add_option("-c", "--cmd", default="hello") +parser.add_option("-a", "--arch", choices=["Alpha", "Mips"], default="Alpha") +parser.add_option("-t", "--timing", action="store_true") + +(options, args) = parser.parse_args() + +if args: + print "Error: script doesn't take any positional arguments" + sys.exit(1) + +# build configuration +this_dir = os.path.dirname(__file__) + +print "arch =", options.arch +process_class = eval(options.arch + "LiveProcess") + +process = process_class() +process.executable = os.path.join(this_dir, options.cmd) +process.cmd = options.cmd + +magicbus = Bus() +mem = PhysicalMemory() + +if options.timing: + cpu = TimingSimpleCPU() +else: + cpu = AtomicSimpleCPU() +cpu.workload = process +cpu.mem = magicbus + +system = System(physmem = mem, cpu = cpu) +system.c1 = Connector(side_a = mem, side_b = magicbus) +root = Root(system = system) + +# instantiate configuration +m5.instantiate(root) + +# simulate until program terminates +exit_event = m5.simulate() + +print 'Exiting @', m5.curTick(), 'because', exit_event.getCause() + diff --git a/cpu/SConscript b/cpu/SConscript deleted file mode 100644 index 3840b9d41..000000000 --- a/cpu/SConscript +++ /dev/null @@ -1,167 +0,0 @@ -# -*- 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. - -import os -import os.path - -# Import build environment variable from SConstruct. -Import('env') - -################################################################# -# -# 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. -# -################################################################# - -# CPU model-specific data is contained in cpu_models.py -# Convert to SCons File node to get path handling -models_db = File('cpu_models.py') -# slurp in contents of file -execfile(models_db.srcnode().abspath) - -# Template for execute() signature. -exec_sig_template = ''' -virtual Fault execute(%s *xc, Trace::InstRecord *traceData) const = 0; -''' - -mem_ini_sig_template = ''' -virtual Fault initiateAcc(%s *xc, Trace::InstRecord *traceData) const { panic("Not defined!"); }; -''' - -mem_comp_sig_template = ''' -virtual Fault completeAcc(uint8_t *data, %s *xc, Trace::InstRecord *traceData) const { panic("Not defined!"); return NoFault; }; -''' - -# 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 env['CPU_MODELS']: - xc_type = CpuModel.dict[cpu].strings['CPU_exec_context'] - print >> f, exec_sig_template % xc_type - print >> f, mem_ini_sig_template % xc_type - print >> f, mem_comp_sig_template % 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 "Generating static_inst_exec_sigs.hh: " \ - + ', '.join(env['CPU_MODELS']) - -# Add command to generate header to environment. -env.Command('static_inst_exec_sigs.hh', models_db, - Action(gen_cpu_exec_signatures, gen_sigs_string, - varlist = ['CPU_MODELS'])) - -################################################################# -# -# Include CPU-model-specific files based on set of models -# specified in CPU_MODELS build option. -# -################################################################# - -sources = [] - -if 'SimpleCPU' in env['CPU_MODELS']: - sources += Split('simple/cpu.cc') - -if 'FastCPU' in env['CPU_MODELS']: - sources += Split('fast/cpu.cc') - -if 'AlphaFullCPU' in env['CPU_MODELS']: - sources += Split(''' - o3/2bit_local_pred.cc - o3/alpha_dyn_inst.cc - o3/alpha_cpu.cc - o3/alpha_cpu_builder.cc - o3/bpred_unit.cc - o3/btb.cc - o3/commit.cc - o3/decode.cc - o3/fetch.cc - o3/free_list.cc - o3/fu_pool.cc - o3/cpu.cc - o3/iew.cc - o3/inst_queue.cc - o3/lsq_unit.cc - o3/lsq.cc - o3/mem_dep_unit.cc - o3/ras.cc - o3/rename.cc - o3/rename_map.cc - o3/rob.cc - o3/scoreboard.cc - o3/store_set.cc - o3/tournament_pred.cc - ''') - -if 'OzoneSimpleCPU' in env['CPU_MODELS']: - sources += Split(''' - ozone/cpu.cc - ozone/cpu_builder.cc - ozone/dyn_inst.cc - ozone/front_end.cc - ozone/inorder_back_end.cc - ozone/inst_queue.cc - ozone/rename_table.cc - ''') - -if 'OzoneCPU' in env['CPU_MODELS']: - sources += Split(''' - ozone/back_end.cc - ozone/lsq_unit.cc - ozone/lw_back_end.cc - ozone/lw_lsq.cc - ''') - -if 'CheckerCPU' in env['CPU_MODELS']: - sources += Split(''' - checker/cpu.cc - checker/cpu_builder.cc - checker/o3_cpu_builder.cc - ''') - -# FullCPU sources are included from m5/SConscript since they're not -# below this point in the file hierarchy. - -# Convert file names to SCons File objects. This takes care of the -# path relative to the top of the directory tree. -sources = [File(s) for s in sources] - -Return('sources') - diff --git a/cpu/activity.cc b/cpu/activity.cc deleted file mode 100644 index 6dcb6e341..000000000 --- a/cpu/activity.cc +++ /dev/null @@ -1,122 +0,0 @@ - -#include "base/timebuf.hh" -#include "cpu/activity.hh" - -ActivityRecorder::ActivityRecorder(int num_stages, int longest_latency, - int activity) - : activityBuffer(longest_latency, 0), longestLatency(longest_latency), - activityCount(activity), numStages(num_stages) -{ - stageActive = new bool[numStages]; - memset(stageActive, 0, numStages); -} - -void -ActivityRecorder::activity() -{ - if (activityBuffer[0]) { - return; - } - - activityBuffer[0] = true; - - ++activityCount; - - DPRINTF(Activity, "Activity: %i\n", activityCount); -} - -void -ActivityRecorder::advance() -{ - 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) -{ - 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) -{ - 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; - 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); -} diff --git a/cpu/activity.hh b/cpu/activity.hh deleted file mode 100644 index 2d53dc4bb..000000000 --- a/cpu/activity.hh +++ /dev/null @@ -1,67 +0,0 @@ - -#ifndef __CPU_ACTIVITY_HH__ -#define __CPU_ACTIVITY_HH__ - -#include "base/timebuf.hh" -#include "base/trace.hh" - -class ActivityRecorder { - public: - ActivityRecorder(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 descheduling the CPU 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); - - int getActivityCount() { return activityCount; } - - void setActivityCount(int count) - { activityCount = count; } - - bool active() { return activityCount; } - - void reset(); - - void dump(); - - void validate(); - - private: - /** 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; - - 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; - - int numStages; - - /** Records which stages are active/inactive. */ - bool *stageActive; -}; - -#endif // __CPU_ACTIVITY_HH__ diff --git a/cpu/base.cc b/cpu/base.cc deleted file mode 100644 index de03b9eab..000000000 --- a/cpu/base.cc +++ /dev/null @@ -1,378 +0,0 @@ -/* - * 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. - */ - -#include <iostream> -#include <string> -#include <sstream> - -#include "base/cprintf.hh" -#include "base/loader/symtab.hh" -#include "base/misc.hh" -#include "base/output.hh" -#include "cpu/base.hh" -#include "cpu/exec_context.hh" -#include "cpu/profile.hh" -#include "cpu/sampler/sampler.hh" -#include "sim/param.hh" -#include "sim/process.hh" -#include "sim/sim_events.hh" -#include "sim/system.hh" - -#include "base/trace.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; - -#if FULL_SYSTEM -BaseCPU::BaseCPU(Params *p) - : SimObject(p->name), clock(p->clock), checkInterrupts(true), - params(p), number_of_threads(p->numberOfThreads), system(p->system) -#else -BaseCPU::BaseCPU(Params *p) - : SimObject(p->name), clock(p->clock), params(p), - number_of_threads(p->numberOfThreads) -#endif -{ - DPRINTF(FullCPU, "BaseCPU: Creating object, mem address %#x.\n", this); - - // add self to global list of CPUs - cpuList.push_back(this); - - DPRINTF(FullCPU, "BaseCPU: CPU added to cpuList, mem address %#x.\n", - this); - - if (number_of_threads > maxThreadsPerCPU) - maxThreadsPerCPU = number_of_threads; - - // allocate per-thread instruction-based event queues - comInstEventQueue = new EventQueue *[number_of_threads]; - for (int i = 0; i < number_of_threads; ++i) - comInstEventQueue[i] = new EventQueue("instruction-based event queue"); - - // - // set up instruction-count-based termination events, if any - // - if (p->max_insts_any_thread != 0) - for (int i = 0; i < number_of_threads; ++i) - new SimExitEvent(comInstEventQueue[i], p->max_insts_any_thread, - "a thread reached the max instruction count"); - - if (p->max_insts_all_threads != 0) { - // allocate & initialize shared downcounter: each event will - // decrement this when triggered; simulation will terminate - // when counter reaches 0 - int *counter = new int; - *counter = number_of_threads; - for (int i = 0; i < number_of_threads; ++i) - new CountedExitEvent(comInstEventQueue[i], - "all threads reached the max instruction count", - p->max_insts_all_threads, *counter); - } - - // allocate per-thread load-based event queues - comLoadEventQueue = new EventQueue *[number_of_threads]; - for (int i = 0; i < number_of_threads; ++i) - comLoadEventQueue[i] = new EventQueue("load-based event queue"); - - // - // set up instruction-count-based termination events, if any - // - if (p->max_loads_any_thread != 0) - for (int i = 0; i < number_of_threads; ++i) - new SimExitEvent(comLoadEventQueue[i], p->max_loads_any_thread, - "a thread reached the max load count"); - - if (p->max_loads_all_threads != 0) { - // allocate & initialize shared downcounter: each event will - // decrement this when triggered; simulation will terminate - // when counter reaches 0 - int *counter = new int; - *counter = number_of_threads; - for (int i = 0; i < number_of_threads; ++i) - new CountedExitEvent(comLoadEventQueue[i], - "all threads reached the max load count", - p->max_loads_all_threads, *counter); - } - -#if FULL_SYSTEM - memset(interrupts, 0, sizeof(interrupts)); - intstatus = 0; -#endif - - functionTracingEnabled = false; - if (p->functionTrace) { - functionTraceStream = simout.find(csprintf("ftrace.%s", name())); - currentFunctionStart = currentFunctionEnd = 0; - functionEntryTick = p->functionTraceStart; - - if (p->functionTraceStart == 0) { - functionTracingEnabled = true; - } else { - Event *e = - new EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace>(this, - true); - e->schedule(p->functionTraceStart); - } - } -#if FULL_SYSTEM - profileEvent = NULL; - if (params->profile) - profileEvent = new ProfileEvent(this, params->profile); -#endif - -} - -BaseCPU::Params::Params() -{ -#if FULL_SYSTEM - profile = false; -#endif - checker = NULL; -} - -void -BaseCPU::enableFunctionTrace() -{ - functionTracingEnabled = true; -} - -BaseCPU::~BaseCPU() -{ -} - -void -BaseCPU::init() -{ - if (!params->deferRegistration) - registerExecContexts(); -} - -void -BaseCPU::startup() -{ -#if FULL_SYSTEM - if (!params->deferRegistration && profileEvent) - profileEvent->schedule(curTick); -#endif -} - - -void -BaseCPU::regStats() -{ - using namespace Stats; - - numCycles - .name(name() + ".numCycles") - .desc("number of cpu cycles simulated") - ; - - int size = execContexts.size(); - if (size > 1) { - for (int i = 0; i < size; ++i) { - stringstream namestr; - ccprintf(namestr, "%s.ctx%d", name(), i); - execContexts[i]->regStats(namestr.str()); - } - } else if (size == 1) - execContexts[0]->regStats(name()); - -#if FULL_SYSTEM -#endif -} - - -void -BaseCPU::registerExecContexts() -{ - for (int i = 0; i < execContexts.size(); ++i) { - ExecContext *xc = execContexts[i]; - - if (xc->status() == ExecContext::Suspended) { -#if FULL_SYSTEM - int id = params->cpu_id; - if (id != -1) - id += i; - - xc->setCpuId(system->registerExecContext(xc, id)); -#else - xc->setCpuId(xc->getProcessPtr()->registerExecContext(xc)); -#endif - } - } -} - - -void -BaseCPU::switchOut(Sampler *sampler) -{ - panic("This CPU doesn't support sampling!"); -} - -void -BaseCPU::takeOverFrom(BaseCPU *oldCPU) -{ - assert(execContexts.size() == oldCPU->execContexts.size()); - - for (int i = 0; i < execContexts.size(); ++i) { - ExecContext *newXC = execContexts[i]; - ExecContext *oldXC = oldCPU->execContexts[i]; - - newXC->takeOverFrom(oldXC); - assert(newXC->readCpuId() == oldXC->readCpuId()); -#if FULL_SYSTEM - system->replaceExecContext(newXC, newXC->readCpuId()); -#else - assert(newXC->getProcessPtr() == oldXC->getProcessPtr()); - newXC->getProcessPtr()->replaceExecContext(newXC, newXC->readCpuId()); -#endif - } - -#if FULL_SYSTEM - for (int i = 0; i < TheISA::NumInterruptLevels; ++i) - interrupts[i] = oldCPU->interrupts[i]; - intstatus = oldCPU->intstatus; - - for (int i = 0; i < execContexts.size(); ++i) - execContexts[i]->profileClear(); - - if (profileEvent) - profileEvent->schedule(curTick); -#endif -} - - -#if FULL_SYSTEM -BaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, int _interval) - : Event(&mainEventQueue), cpu(_cpu), interval(_interval) -{ } - -void -BaseCPU::ProfileEvent::process() -{ - for (int i = 0, size = cpu->execContexts.size(); i < size; ++i) { - ExecContext *xc = cpu->execContexts[i]; - xc->profileSample(); - } - - schedule(curTick + interval); -} - -void -BaseCPU::post_interrupt(int int_num, int index) -{ - DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index); - - if (int_num < 0 || int_num >= TheISA::NumInterruptLevels) - panic("int_num out of bounds\n"); - - if (index < 0 || index >= sizeof(uint64_t) * 8) - panic("int_num out of bounds\n"); - - checkInterrupts = true; - interrupts[int_num] |= 1 << index; - intstatus |= (ULL(1) << int_num); -} - -void -BaseCPU::clear_interrupt(int int_num, int index) -{ - DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index); - - if (int_num < 0 || int_num >= TheISA::NumInterruptLevels) - panic("int_num out of bounds\n"); - - if (index < 0 || index >= sizeof(uint64_t) * 8) - panic("int_num out of bounds\n"); - - interrupts[int_num] &= ~(1 << index); - if (interrupts[int_num] == 0) - intstatus &= ~(ULL(1) << int_num); -} - -void -BaseCPU::clear_interrupts() -{ - DPRINTF(Interrupt, "Interrupts all cleared\n"); - - memset(interrupts, 0, sizeof(interrupts)); - intstatus = 0; -} - - -void -BaseCPU::serialize(std::ostream &os) -{ - SERIALIZE_ARRAY(interrupts, TheISA::NumInterruptLevels); - SERIALIZE_SCALAR(intstatus); -} - -void -BaseCPU::unserialize(Checkpoint *cp, const std::string §ion) -{ - UNSERIALIZE_ARRAY(interrupts, TheISA::NumInterruptLevels); - UNSERIALIZE_SCALAR(intstatus); -} - -#endif // FULL_SYSTEM - -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; - } -} - - -DEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU) diff --git a/cpu/base.hh b/cpu/base.hh deleted file mode 100644 index dd776859d..000000000 --- a/cpu/base.hh +++ /dev/null @@ -1,238 +0,0 @@ -/* - * 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. - */ - -#ifndef __CPU_BASE_HH__ -#define __CPU_BASE_HH__ - -#include <vector> - -#include "base/statistics.hh" -#include "config/full_system.hh" -#include "cpu/sampler/sampler.hh" -#include "sim/eventq.hh" -#include "sim/sim_object.hh" -#include "arch/isa_traits.hh" - -class BranchPred; -class CheckerCPU; -class ExecContext; -class System; - -class BaseCPU : public SimObject -{ - protected: - // CPU's clock period in terms of the number of ticks of curTime. - Tick clock; - - public: - inline Tick frequency() const { return Clock::Frequency / clock; } - inline Tick cycles(int numCycles) const { return clock * numCycles; } - inline Tick curCycle() const { return curTick / clock; } - -#if FULL_SYSTEM - protected: - uint64_t interrupts[TheISA::NumInterruptLevels]; - uint64_t intstatus; - - public: - virtual void post_interrupt(int int_num, int index); - virtual void clear_interrupt(int int_num, int index); - virtual void clear_interrupts(); - bool checkInterrupts; - - bool check_interrupt(int int_num) const { - if (int_num > TheISA::NumInterruptLevels) - panic("int_num out of bounds\n"); - - return interrupts[int_num] != 0; - } - - bool check_interrupts() const { return intstatus != 0; } - uint64_t intr_status() const { return intstatus; } - - class ProfileEvent : public Event - { - private: - BaseCPU *cpu; - int interval; - - public: - ProfileEvent(BaseCPU *cpu, int interval); - void process(); - }; - ProfileEvent *profileEvent; -#endif - - protected: - std::vector<ExecContext *> execContexts; - - public: - - /// 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(int thread_num, int delay) {} - - /// Notify the CPU that the indicated context is now suspended. - virtual void suspendContext(int thread_num) {} - - /// Notify the CPU that the indicated context is now deallocated. - virtual void deallocateContext(int thread_num) {} - - /// Notify the CPU that the indicated context is now halted. - virtual void haltContext(int thread_num) {} - - public: - struct Params - { - std::string name; - int numberOfThreads; - bool deferRegistration; - Counter max_insts_any_thread; - Counter max_insts_all_threads; - Counter max_loads_any_thread; - Counter max_loads_all_threads; - Tick clock; - bool functionTrace; - Tick functionTraceStart; -#if FULL_SYSTEM - System *system; - int cpu_id; - Tick profile; -#endif - BaseCPU *checker; - - Params(); - }; - - const Params *params; - - BaseCPU(Params *params); - virtual ~BaseCPU(); - - virtual void init(); - virtual void startup(); - virtual void regStats(); - - virtual void activateWhenReady(int tid) {}; - - void registerExecContexts(); - - /// Prepare for another CPU to take over execution. When it is - /// is ready (drained pipe) it signals the sampler. - virtual void switchOut(Sampler *); - - /// 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. - */ - int number_of_threads; - - /** - * 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; - -#if FULL_SYSTEM - System *system; - - /** - * Serialize this object to the given output stream. - * @param os The stream to serialize to. - */ - virtual void serialize(std::ostream &os); - - /** - * Reconstruct the state of this object from a checkpoint. - * @param cp The checkpoint use. - * @param section The section name of this object - */ - virtual void unserialize(Checkpoint *cp, const std::string §ion); - -#endif - - /** - * Return pointer to CPU's branch predictor (NULL if none). - * @return Branch predictor pointer. - */ - virtual BranchPred *getBranchPred() { return NULL; }; - - virtual Counter totalInstructions() const { return 0; } - - // Function tracing - private: - bool functionTracingEnabled; - std::ostream *functionTraceStream; - Addr currentFunctionStart; - Addr currentFunctionEnd; - Tick functionEntryTick; - void enableFunctionTrace(); - void traceFunctionsInternal(Addr pc); - - protected: - void traceFunctions(Addr pc) - { - if (functionTracingEnabled) - traceFunctionsInternal(pc); - } - - private: - static std::vector<BaseCPU *> cpuList; //!< Static global cpu list - - public: - static int numSimulatedCPUs() { return cpuList.size(); } - static Counter numSimulatedInstructions() - { - Counter total = 0; - - int size = cpuList.size(); - for (int i = 0; i < size; ++i) - total += cpuList[i]->totalInstructions(); - - return total; - } - - public: - // Number of CPU cycles simulated - Stats::Scalar<> numCycles; -}; - -#endif // __CPU_BASE_HH__ diff --git a/cpu/base_dyn_inst.cc b/cpu/base_dyn_inst.cc deleted file mode 100644 index 7ab760ae3..000000000 --- a/cpu/base_dyn_inst.cc +++ /dev/null @@ -1,448 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <iostream> -#include <set> -#include <string> -#include <sstream> - -#include "base/cprintf.hh" -#include "base/trace.hh" - -#include "arch/faults.hh" -#include "cpu/exetrace.hh" -#include "mem/mem_req.hh" - -#include "cpu/base_dyn_inst.hh" -#include "cpu/o3/alpha_impl.hh" -#include "cpu/o3/alpha_cpu.hh" -#include "cpu/ozone/simple_impl.hh" -#include "cpu/ozone/ozone_impl.hh" - -using namespace std; -using namespace TheISA; - -#define NOHASH -#ifndef NOHASH - -#include "base/hashmap.hh" - -unsigned int MyHashFunc(const BaseDynInst *addr) -{ - unsigned a = (unsigned)addr; - unsigned hash = (((a >> 14) ^ ((a >> 2) & 0xffff))) & 0x7FFFFFFF; - - return hash; -} - -typedef m5::hash_map<const BaseDynInst *, const BaseDynInst *, MyHashFunc> -my_hash_t; - -my_hash_t thishash; -#endif - -template <class Impl> -BaseDynInst<Impl>::BaseDynInst(ExtMachInst machInst, Addr inst_PC, - Addr pred_PC, InstSeqNum seq_num, - FullCPU *cpu) - : staticInst(machInst), traceData(NULL), cpu(cpu)/*, xc(cpu->xcBase())*/ -{ - seqNum = seq_num; - - PC = inst_PC; - nextPC = PC + sizeof(MachInst); - predPC = pred_PC; - - initVars(); -} - -template <class Impl> -BaseDynInst<Impl>::BaseDynInst(StaticInstPtr &_staticInst) - : staticInst(_staticInst), traceData(NULL) -{ - seqNum = 0; - initVars(); -} - -template <class Impl> -void -BaseDynInst<Impl>::initVars() -{ - req = NULL; - effAddr = MemReq::inval_addr; - physEffAddr = MemReq::inval_addr; - storeSize = 0; - - readyRegs = 0; - - completed = false; - resultReady = false; - canIssue = false; - issued = false; - executed = false; - canCommit = false; - committed = false; - squashed = false; - squashedInIQ = false; - squashedInLSQ = false; - squashedInROB = false; - eaCalcDone = false; - memOpDone = false; - lqIdx = -1; - sqIdx = -1; - reachedCommit = false; - - blockingInst = false; - recoverInst = false; - - iqEntry = false; - robEntry = false; - - serializeBefore = false; - serializeAfter = false; - serializeHandled = false; - - // 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 unimplemented opcode. -// fault = new UnimplementedOpcodeFault; - fault = NoFault; - - ++instcount; - - if (instcount > 1500) { - cpu->dumpInsts(); -#ifdef DEBUG - dumpSNList(); -#endif - assert(instcount <= 1500); - } - - DPRINTF(DynInst, "DynInst: [sn:%lli] Instruction created. Instcount=%i\n", - seqNum, instcount); - -#ifdef DEBUG - cpu->snList.insert(seqNum); -#endif -} - -template <class Impl> -BaseDynInst<Impl>::~BaseDynInst() -{ - if (req) { - req = NULL; - } - - if (traceData) { - delete traceData; - } - - --instcount; - - DPRINTF(DynInst, "DynInst: [sn:%lli] Instruction destroyed. Instcount=%i\n", - seqNum, instcount); -#ifdef DEBUG - cpu->snList.erase(seqNum); -#endif -} - -#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>::prefetch(Addr addr, unsigned flags) -{ - // This is the "functional" implementation of prefetch. Not much - // happens here since prefetches don't affect the architectural - // state. - - // Generate a MemReq so we can translate the effective address. - MemReqPtr req = new MemReq(addr, thread->getXCProxy(), 1, flags); - req->asid = asid; - - // Prefetches never cause faults. - fault = NoFault; - - // note this is a local, not BaseDynInst::fault - Fault trans_fault = cpu->translateDataReadReq(req); - - if (trans_fault == NoFault && !(req->flags & UNCACHEABLE)) { - // It's a valid address to cacheable space. Record key MemReq - // parameters so we can generate another one just like it for - // the timing access without calling translate() again (which - // might mess up the TLB). - effAddr = req->vaddr; - physEffAddr = req->paddr; - memReqFlags = req->flags; - } else { - // Bogus address (invalid or uncacheable space). Mark it by - // setting the eff_addr to InvalidAddr. - effAddr = physEffAddr = MemReq::inval_addr; - } - - if (traceData) { - traceData->setAddr(addr); - } -} - -template <class Impl> -void -BaseDynInst<Impl>::writeHint(Addr addr, int size, unsigned flags) -{ - // Need to create a MemReq here so we can do a translation. This - // will casue a TLB miss trap if necessary... not sure whether - // that's the best thing to do or not. We don't really need the - // MemReq otherwise, since wh64 has no functional effect. - MemReqPtr req = new MemReq(addr, thread->getXCProxy(), size, flags); - req->asid = asid; - - fault = cpu->translateDataWriteReq(req); - - if (fault == NoFault && !(req->flags & UNCACHEABLE)) { - // Record key MemReq parameters so we can generate another one - // just like it for the timing access without calling translate() - // again (which might mess up the TLB). - effAddr = req->vaddr; - physEffAddr = req->paddr; - memReqFlags = req->flags; - } else { - // ignore faults & accesses to uncacheable space... treat as no-op - effAddr = physEffAddr = MemReq::inval_addr; - } - - storeSize = size; - storeData = 0; -} - -/** - * @todo Need to find a way to get the cache block size here. - */ -template <class Impl> -Fault -BaseDynInst<Impl>::copySrcTranslate(Addr src) -{ - MemReqPtr req = new MemReq(src, thread->getXCProxy(), 64); - req->asid = asid; - - // translate to physical address - Fault fault = cpu->translateDataReadReq(req); - - if (fault == NoFault) { - thread->copySrcAddr = src; - thread->copySrcPhysAddr = req->paddr; - } else { - thread->copySrcAddr = 0; - thread->copySrcPhysAddr = 0; - } - return fault; -} - -/** - * @todo Need to find a way to get the cache block size here. - */ -template <class Impl> -Fault -BaseDynInst<Impl>::copy(Addr dest) -{ - uint8_t data[64]; - FunctionalMemory *mem = thread->mem; - assert(thread->copySrcPhysAddr || thread->misspeculating()); - MemReqPtr req = new MemReq(dest, thread->getXCProxy(), 64); - req->asid = asid; - - // translate to physical address - Fault fault = cpu->translateDataWriteReq(req); - - if (fault == NoFault) { - Addr dest_addr = req->paddr; - // Need to read straight from memory since we have more than 8 bytes. - req->paddr = thread->copySrcPhysAddr; - mem->read(req, data); - req->paddr = dest_addr; - mem->write(req, data); - } - return fault; -} - -template <class Impl> -void -BaseDynInst<Impl>::dump() -{ - cprintf("T%d : %#08d `", threadNumber, PC); - cout << staticInst->disassemble(PC); - cprintf("'\n"); -} - -template <class Impl> -void -BaseDynInst<Impl>::dump(std::string &outstring) -{ - std::ostringstream s; - s << "T" << threadNumber << " : 0x" << PC << " " - << staticInst->disassemble(PC); - - outstring = s.str(); -} - -#if 0 -template <class Impl> -Fault -BaseDynInst<Impl>::mem_access(mem_cmd cmd, Addr addr, void *p, int nbytes) -{ - Fault fault; - - // check alignments, even speculative this test should always pass - if ((nbytes & nbytes - 1) != 0 || (addr & nbytes - 1) != 0) { - for (int i = 0; i < nbytes; i++) - ((char *) p)[i] = 0; - - // I added the following because according to the comment above, - // we should never get here. The comment lies -#if 0 - panic("unaligned access. Cycle = %n", curTick); -#endif - return NoFault; - } - - MemReqPtr req = new MemReq(addr, thread, nbytes); - switch(cmd) { - case Read: - fault = spec_mem->read(req, (uint8_t *)p); - break; - - case Write: - fault = spec_mem->write(req, (uint8_t *)p); - if (fault != NoFault) - break; - - specMemWrite = true; - storeSize = nbytes; - switch(nbytes) { - case sizeof(uint8_t): - *(uint8_t)&storeData = (uint8_t *)p; - break; - case sizeof(uint16_t): - *(uint16_t)&storeData = (uint16_t *)p; - break; - case sizeof(uint32_t): - *(uint32_t)&storeData = (uint32_t *)p; - break; - case sizeof(uint64_t): - *(uint64_t)&storeData = (uint64_t *)p; - break; - } - break; - - default: - fault = genMachineCheckFault(); - break; - } - - trace_mem(fault, cmd, addr, p, nbytes); - - return fault; -} - -#endif - -template <class Impl> -void -BaseDynInst<Impl>::markSrcRegReady() -{ - if (++readyRegs == numSrcRegs()) { - canIssue = true; - } -} - -template <class Impl> -void -BaseDynInst<Impl>::markSrcRegReady(RegIndex src_idx) -{ - ++readyRegs; - - _readySrcRegIdx[src_idx] = true; - - if (readyRegs == numSrcRegs()) { - canIssue = true; - } -} - -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; -} - -// Forward declaration -template class BaseDynInst<AlphaSimpleImpl>; - -template <> -int -BaseDynInst<AlphaSimpleImpl>::instcount = 0; - -// Forward declaration -template class BaseDynInst<SimpleImpl>; - -template <> -int -BaseDynInst<SimpleImpl>::instcount = 0; - -// Forward declaration -template class BaseDynInst<OzoneImpl>; - -template <> -int -BaseDynInst<OzoneImpl>::instcount = 0; diff --git a/cpu/base_dyn_inst.hh b/cpu/base_dyn_inst.hh deleted file mode 100644 index 388ea4a8d..000000000 --- a/cpu/base_dyn_inst.hh +++ /dev/null @@ -1,738 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_BASE_DYN_INST_HH__ -#define __CPU_BASE_DYN_INST_HH__ - -#include <list> -#include <string> - -#include "base/fast_alloc.hh" -#include "base/trace.hh" -#include "config/full_system.hh" -#include "cpu/exetrace.hh" -#include "cpu/inst_seq.hh" -#include "cpu/static_inst.hh" -#include "encumbered/cpu/full/op_class.hh" -#include "mem/functional/memory_control.hh" -#include "sim/system.hh" -/* -#include "encumbered/cpu/full/bpred_update.hh" -#include "encumbered/cpu/full/spec_memory.hh" -#include "encumbered/cpu/full/spec_state.hh" -#include "encumbered/mem/functional/main.hh" -*/ - -/** - * @file - * Defines a dynamic instruction context. - */ - -// Forward declaration. -class StaticInstPtr; - -template <class Impl> -class BaseDynInst : public FastAlloc, public RefCounted -{ - public: - // Typedef for the CPU. - typedef typename Impl::FullCPU FullCPU; - typedef typename FullCPU::ImplState ImplState; - - // Binary machine instruction type. - typedef TheISA::MachInst MachInst; - // Extended machine instruction type - typedef TheISA::ExtMachInst ExtMachInst; - // Logical register index type. - typedef TheISA::RegIndex RegIndex; - // Integer register index type. - typedef TheISA::IntReg IntReg; - - // The DynInstPtr type. - typedef typename Impl::DynInstPtr DynInstPtr; - - // The list of instructions iterator type. - typedef typename std::list<DynInstPtr>::iterator ListIt; - - enum { - MaxInstSrcRegs = TheISA::MaxInstSrcRegs, /// Max source regs - MaxInstDestRegs = TheISA::MaxInstDestRegs, /// Max dest regs - }; - - /** The StaticInst used by this BaseDynInst. */ - StaticInstPtr staticInst; - - //////////////////////////////////////////// - // - // INSTRUCTION EXECUTION - // - //////////////////////////////////////////// - /** InstRecord that tracks this instructions. */ - Trace::InstRecord *traceData; - - /** - * Does a read to a given address. - * @param addr The address to read. - * @param data The read's data is written into this parameter. - * @param flags The request's flags. - * @return Returns any fault due to the read. - */ - template <class T> - Fault read(Addr addr, T &data, unsigned flags); - - /** - * Does a write to a given address. - * @param data The data to be written. - * @param addr The address to write to. - * @param flags The request's flags. - * @param res The result of the write (for load locked/store conditionals). - * @return Returns any fault due to the write. - */ - template <class T> - Fault write(T data, Addr addr, unsigned flags, - uint64_t *res); - - void prefetch(Addr addr, unsigned flags); - void writeHint(Addr addr, int size, unsigned flags); - Fault copySrcTranslate(Addr src); - Fault copy(Addr dest); - - /** @todo: Consider making this private. */ - public: - /** The sequence number of the instruction. */ - InstSeqNum seqNum; - - /** Is the instruction in the IQ */ - bool iqEntry; - - /** Is the instruction in the ROB */ - bool robEntry; - - /** Is the instruction in the LSQ */ - bool lsqEntry; - - /** Is the instruction completed. */ - bool completed; - - /** Is the instruction's result ready. */ - bool resultReady; - - /** Can this instruction issue. */ - bool canIssue; - - /** Has this instruction issued. */ - bool issued; - - /** Has this instruction executed (or made it through execute) yet. */ - bool executed; - - /** Can this instruction commit. */ - bool canCommit; - - /** Is this instruction committed. */ - bool committed; - - /** Is this instruction squashed. */ - bool squashed; - - /** Is this instruction squashed in the instruction queue. */ - bool squashedInIQ; - - /** Is this instruction squashed in the instruction queue. */ - bool squashedInLSQ; - - /** Is this instruction squashed in the instruction queue. */ - bool squashedInROB; - - /** Is this a recover instruction. */ - bool recoverInst; - - /** Is this a thread blocking instruction. */ - bool blockingInst; /* this inst has called thread_block() */ - - /** Is this a thread syncrhonization instruction. */ - bool threadsyncWait; - - /** The thread this instruction is from. */ - short threadNumber; - - /** data address space ID, for loads & stores. */ - short asid; - - /** How many source registers are ready. */ - unsigned readyRegs; - - /** Pointer to the FullCPU object. */ - FullCPU *cpu; - - /** Pointer to the exec context. */ - ImplState *thread; - - /** The kind of fault this instruction has generated. */ - Fault fault; - - /** The memory request. */ - MemReqPtr req; - - /** The effective virtual address (lds & stores only). */ - Addr effAddr; - - /** The effective physical address. */ - Addr physEffAddr; - - /** Effective virtual address for a copy source. */ - Addr copySrcEffAddr; - - /** Effective physical address for a copy source. */ - Addr copySrcPhysEffAddr; - - /** The memory request flags (from translation). */ - unsigned memReqFlags; - - /** The size of the data to be stored. */ - int storeSize; - - /** The data to be stored. */ - IntReg storeData; - - union Result { - uint64_t integer; - float fp; - double dbl; - }; - - /** The result of the instruction; assumes for now that there's only one - * destination register. - */ - Result instResult; - - /** PC of this instruction. */ - Addr PC; - - /** Next non-speculative PC. It is not filled in at fetch, but rather - * once the target of the branch is truly known (either decode or - * execute). - */ - Addr nextPC; - - /** Predicted next PC. */ - Addr predPC; - - /** Count of total number of dynamic instructions. */ - static int instcount; - -#ifdef DEBUG - void dumpSNList(); -#endif - - /** Whether or not the source register is ready. - * @todo: Not sure this should be here vs the derived class. - */ - bool _readySrcRegIdx[MaxInstSrcRegs]; - - public: - /** BaseDynInst constructor given a binary instruction. - * @param inst The binary instruction. - * @param PC The PC of the instruction. - * @param pred_PC The predicted next PC. - * @param seq_num The sequence number of the instruction. - * @param cpu Pointer to the instruction's CPU. - */ - BaseDynInst(ExtMachInst inst, Addr PC, Addr pred_PC, InstSeqNum seq_num, - FullCPU *cpu); - - /** BaseDynInst constructor given a StaticInst pointer. - * @param _staticInst The StaticInst for this BaseDynInst. - */ - BaseDynInst(StaticInstPtr &_staticInst); - - /** BaseDynInst destructor. */ - ~BaseDynInst(); - - private: - /** Function to initialize variables in the constructors. */ - void initVars(); - - public: - /** - * @todo: Make this function work; currently it is a dummy function. - * @param fault Last fault. - * @param cmd Last command. - * @param addr Virtual address of access. - * @param p Memory accessed. - * @param nbytes Access size. - */ - void - trace_mem(Fault fault, - MemCmd cmd, - Addr addr, - void *p, - int nbytes); - - /** Dumps out contents of this BaseDynInst. */ - void dump(); - - /** Dumps out contents of this BaseDynInst into given string. */ - void dump(std::string &outstring); - - /** Returns the fault type. */ - Fault getFault() { return fault; } - - /** Checks whether or not this instruction has had its branch target - * calculated yet. For now it is not utilized and is hacked to be - * always false. - * @todo: Actually use this instruction. - */ - bool doneTargCalc() { return false; } - - /** Returns the next PC. This could be the speculative next PC if it is - * called prior to the actual branch target being calculated. - */ - Addr readNextPC() { return nextPC; } - - /** Set the predicted target of this current instruction. */ - void setPredTarg(Addr predicted_PC) { predPC = predicted_PC; } - - /** Returns the predicted target of the branch. */ - Addr readPredTarg() { return predPC; } - - /** Returns whether the instruction was predicted taken or not. */ - bool predTaken() { return predPC != (PC + sizeof(MachInst)); } - - /** Returns whether the instruction mispredicted. */ - bool mispredicted() { return predPC != nextPC; } - - // - // Instruction types. Forward checks to StaticInst object. - // - bool isNop() const { return staticInst->isNop(); } - bool isMemRef() const { return staticInst->isMemRef(); } - bool isLoad() const { return staticInst->isLoad(); } - bool isStore() const { return staticInst->isStore(); } - bool isStoreConditional() const - { return staticInst->isStoreConditional(); } - bool isInstPrefetch() const { return staticInst->isInstPrefetch(); } - bool isDataPrefetch() const { return staticInst->isDataPrefetch(); } - bool isCopy() const { return staticInst->isCopy(); } - bool isInteger() const { return staticInst->isInteger(); } - bool isFloating() const { return staticInst->isFloating(); } - bool isControl() const { return staticInst->isControl(); } - bool isCall() const { return staticInst->isCall(); } - bool isReturn() const { return staticInst->isReturn(); } - bool isDirectCtrl() const { return staticInst->isDirectCtrl(); } - bool isIndirectCtrl() const { return staticInst->isIndirectCtrl(); } - bool isCondCtrl() const { return staticInst->isCondCtrl(); } - bool isUncondCtrl() const { return staticInst->isUncondCtrl(); } - bool isThreadSync() const { return staticInst->isThreadSync(); } - bool isSerializing() const { return staticInst->isSerializing(); } - bool isSerializeBefore() const - { return staticInst->isSerializeBefore() || serializeBefore; } - bool isSerializeAfter() const - { return staticInst->isSerializeAfter() || serializeAfter; } - bool isMemBarrier() const { return staticInst->isMemBarrier(); } - bool isWriteBarrier() const { return staticInst->isWriteBarrier(); } - bool isNonSpeculative() const { return staticInst->isNonSpeculative(); } - bool isQuiesce() const { return staticInst->isQuiesce(); } - bool isIprAccess() const { return staticInst->isIprAccess(); } - bool isUnverifiable() const { return staticInst->isUnverifiable(); } - - /** Temporarily sets this instruction as a serialize before instruction. */ - void setSerializeBefore() { serializeBefore = true; } - - /** Clears the serializeBefore part of this instruction. */ - void clearSerializeBefore() { serializeBefore = false; } - - /** Checks if this serializeBefore is only temporarily set. */ - bool isTempSerializeBefore() { return serializeBefore; } - - /** Tracks if instruction has been externally set as serializeBefore. */ - bool serializeBefore; - - /** Temporarily sets this instruction as a serialize after instruction. */ - void setSerializeAfter() { serializeAfter = true; } - - /** Clears the serializeAfter part of this instruction.*/ - void clearSerializeAfter() { serializeAfter = false; } - - /** Checks if this serializeAfter is only temporarily set. */ - bool isTempSerializeAfter() { return serializeAfter; } - - /** Tracks if instruction has been externally set as serializeAfter. */ - bool serializeAfter; - - /** Checks if the serialization part of this instruction has been - * handled. This does not apply to the temporary serializing - * state; it only applies to this instruction's own permanent - * serializing state. - */ - bool isSerializeHandled() { return serializeHandled; } - - /** Sets the serialization part of this instruction as handled. */ - void setSerializeHandled() { serializeHandled = true; } - - /** Whether or not the serialization of this instruction has been handled. */ - bool serializeHandled; - - /** Returns the opclass of this instruction. */ - OpClass opClass() const { return staticInst->opClass(); } - - /** Returns the branch target address. */ - Addr branchTarget() const { return staticInst->branchTarget(PC); } - - /** Returns the number of source registers. */ - int8_t numSrcRegs() const { return staticInst->numSrcRegs(); } - - /** Returns the number of destination registers. */ - int8_t numDestRegs() const { return staticInst->numDestRegs(); } - - // the following are used to track physical register usage - // for machines with separate int & FP reg files - int8_t numFPDestRegs() const { return staticInst->numFPDestRegs(); } - int8_t numIntDestRegs() const { return staticInst->numIntDestRegs(); } - - /** Returns the logical register index of the i'th destination register. */ - RegIndex destRegIdx(int i) const { return staticInst->destRegIdx(i); } - - /** Returns the logical register index of the i'th source register. */ - RegIndex srcRegIdx(int i) const { return staticInst->srcRegIdx(i); } - - /** Returns the result of an integer instruction. */ - uint64_t readIntResult() { return instResult.integer; } - - /** Returns the result of a floating point instruction. */ - float readFloatResult() { return instResult.fp; } - - /** Returns the result of a floating point (double) instruction. */ - double readDoubleResult() { return instResult.dbl; } - - void setIntReg(const StaticInst *si, int idx, uint64_t val) - { - instResult.integer = val; - } - - void setFloatRegSingle(const StaticInst *si, int idx, float val) - { - instResult.fp = val; - } - - void setFloatRegDouble(const StaticInst *si, int idx, double val) - { - instResult.dbl = val; - } - - void setFloatRegInt(const StaticInst *si, int idx, uint64_t val) - { - instResult.integer = val; - } - - /** Records that one of the source registers is ready. */ - void markSrcRegReady(); - - /** Marks a specific register as ready. */ - void markSrcRegReady(RegIndex src_idx); - - /** Returns if a source register is ready. */ - bool isReadySrcRegIdx(int idx) const - { - return this->_readySrcRegIdx[idx]; - } - - /** Sets this instruction as completed. */ - void setCompleted() { completed = true; } - - /** Returns whether or not this instruction is completed. */ - bool isCompleted() const { return completed; } - - void setResultReady() { resultReady = true; } - - bool isResultReady() const { return resultReady; } - - /** Sets this instruction as ready to issue. */ - void setCanIssue() { canIssue = true; } - - /** Returns whether or not this instruction is ready to issue. */ - bool readyToIssue() const { return canIssue; } - - /** Sets this instruction as issued from the IQ. */ - void setIssued() { issued = true; } - - /** Returns whether or not this instruction has issued. */ - bool isIssued() const { return issued; } - - /** Sets this instruction as executed. */ - void setExecuted() { executed = true; } - - /** Returns whether or not this instruction has executed. */ - bool isExecuted() const { return executed; } - - /** Sets this instruction as ready to commit. */ - void setCanCommit() { canCommit = true; } - - /** Clears this instruction as being ready to commit. */ - void clearCanCommit() { canCommit = false; } - - /** Returns whether or not this instruction is ready to commit. */ - bool readyToCommit() const { return canCommit; } - - /** Sets this instruction as committed. */ - void setCommitted() { committed = true; } - - /** Returns whether or not this instruction is committed. */ - bool isCommitted() const { return committed; } - - /** Sets this instruction as squashed. */ - void setSquashed() { squashed = true; } - - /** Returns whether or not this instruction is squashed. */ - bool isSquashed() const { return squashed; } - - //Instruction Queue Entry - //----------------------- - /** Sets this instruction as a entry the IQ. */ - void setInIQ() { iqEntry = true; } - - /** Sets this instruction as a entry the IQ. */ - void removeInIQ() { iqEntry = false; } - - /** Sets this instruction as squashed in the IQ. */ - void setSquashedInIQ() { squashedInIQ = true; squashed = true;} - - /** Returns whether or not this instruction is squashed in the IQ. */ - bool isSquashedInIQ() const { return squashedInIQ; } - - /** Returns whether or not this instruction has issued. */ - bool isInIQ() const { return iqEntry; } - - - //Load / Store Queue Functions - //----------------------- - /** Sets this instruction as a entry the LSQ. */ - void setInLSQ() { lsqEntry = true; } - - /** Sets this instruction as a entry the LSQ. */ - void removeInLSQ() { lsqEntry = false; } - - /** Sets this instruction as squashed in the LSQ. */ - void setSquashedInLSQ() { squashedInLSQ = true;} - - /** Returns whether or not this instruction is squashed in the LSQ. */ - bool isSquashedInLSQ() const { return squashedInLSQ; } - - /** Returns whether or not this instruction is in the LSQ. */ - bool isInLSQ() const { return lsqEntry; } - - - //Reorder Buffer Functions - //----------------------- - /** Sets this instruction as a entry the ROB. */ - void setInROB() { robEntry = true; } - - /** Sets this instruction as a entry the ROB. */ - void removeInROB() { robEntry = false; } - - /** Sets this instruction as squashed in the ROB. */ - void setSquashedInROB() { squashedInROB = true; } - - /** Returns whether or not this instruction is squashed in the ROB. */ - bool isSquashedInROB() const { return squashedInROB; } - - /** Returns whether or not this instruction is in the ROB. */ - bool isInROB() const { return robEntry; } - - /** Read the PC of this instruction. */ - const Addr readPC() const { return PC; } - - /** Set the next PC of this instruction (its actual target). */ - void setNextPC(uint64_t val) - { - nextPC = val; -// instResult.integer = val; - } - - void setASID(short addr_space_id) { asid = addr_space_id; } - - void setThread(unsigned tid) { threadNumber = tid; } - - void setState(ImplState *state) { thread = state; } - - /** Returns the exec context. - * @todo: Remove this once the ExecContext is no longer used. - */ - ExecContext *xcBase() { return thread->getXCProxy(); } - - private: - /** Instruction effective address. - * @todo: Consider if this is necessary or not. - */ - Addr instEffAddr; - - /** Whether or not the effective address calculation is completed. - * @todo: Consider if this is necessary or not. - */ - bool eaCalcDone; - - public: - /** Sets the effective address. */ - void setEA(Addr &ea) { instEffAddr = ea; eaCalcDone = true; } - - /** Returns the effective address. */ - const Addr &getEA() const { return req->vaddr; } - - /** Returns whether or not the eff. addr. calculation has been completed. */ - bool doneEACalc() { return eaCalcDone; } - - /** Returns whether or not the eff. addr. source registers are ready. */ - bool eaSrcsReady(); - - /** Whether or not the memory operation is done. */ - bool memOpDone; - - public: - /** Load queue index. */ - int16_t lqIdx; - - /** Store queue index. */ - int16_t sqIdx; - - bool reachedCommit; - - /** Iterator pointing to this BaseDynInst in the list of all insts. */ - ListIt instListIt; - - /** Returns iterator to this instruction in the list of all insts. */ - ListIt &getInstListIt() { return instListIt; } - - /** Sets iterator for this instruction in the list of all insts. */ - void setInstListIt(ListIt _instListIt) { instListIt = _instListIt; } -}; - -template<class Impl> -template<class T> -inline Fault -BaseDynInst<Impl>::read(Addr addr, T &data, unsigned flags) -{ - if (executed) { - fault = cpu->read(req, data, lqIdx); - return fault; - } - - req = new MemReq(addr, thread->getXCProxy(), sizeof(T), flags); - req->asid = asid; - req->thread_num = threadNumber; - req->pc = this->PC; - - if ((req->vaddr & (TheISA::VMPageSize - 1)) + req->size > - TheISA::VMPageSize) { - return TheISA::genAlignmentFault(); - } - - fault = cpu->translateDataReadReq(req); - - effAddr = req->vaddr; - physEffAddr = req->paddr; - memReqFlags = req->flags; - - if (fault == NoFault) { -#if FULL_SYSTEM - if (cpu->system->memctrl->badaddr(physEffAddr)) { - fault = TheISA::genMachineCheckFault(); - data = (T)-1; - this->setExecuted(); - } else { - fault = cpu->read(req, data, lqIdx); - } -#else - fault = cpu->read(req, data, lqIdx); -#endif - } else { - // Return a fixed value to keep simulation deterministic even - // along misspeculated paths. - data = (T)-1; - - // Commit will have to clean up whatever happened. Set this - // instruction as executed. - this->setExecuted(); - } - - if (traceData) { - traceData->setAddr(addr); - traceData->setData(data); - } - - return fault; -} - -template<class Impl> -template<class T> -inline Fault -BaseDynInst<Impl>::write(T data, Addr addr, unsigned flags, uint64_t *res) -{ - if (traceData) { - traceData->setAddr(addr); - traceData->setData(data); - } - - req = new MemReq(addr, thread->getXCProxy(), sizeof(T), flags); - - req->asid = asid; - req->thread_num = threadNumber; - req->pc = this->PC; - - if ((req->vaddr & (TheISA::VMPageSize - 1)) + req->size > - TheISA::VMPageSize) { - return TheISA::genAlignmentFault(); - } - - fault = cpu->translateDataWriteReq(req); - - effAddr = req->vaddr; - physEffAddr = req->paddr; - memReqFlags = req->flags; - - if (fault == NoFault) { -#if FULL_SYSTEM - if (cpu->system->memctrl->badaddr(physEffAddr)) { - fault = TheISA::genMachineCheckFault(); - } else { - fault = cpu->write(req, data, sqIdx); - } -#else - fault = cpu->write(req, data, sqIdx); -#endif - } - - if (res) { - // always return some result to keep misspeculated paths - // (which will ignore faults) deterministic - *res = (fault == NoFault) ? req->result : 0; - } - - return fault; -} - -#endif // __CPU_BASE_DYN_INST_HH__ diff --git a/cpu/checker/cpu.cc b/cpu/checker/cpu.cc deleted file mode 100644 index 41ff6e769..000000000 --- a/cpu/checker/cpu.cc +++ /dev/null @@ -1,757 +0,0 @@ -/* - * Copyright (c) 2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <list> -#include <string> - -#include "base/refcnt.hh" -#include "cpu/base.hh" -#include "cpu/base_dyn_inst.hh" -#include "cpu/checker/cpu.hh" -#include "cpu/cpu_exec_context.hh" -#include "cpu/exec_context.hh" -#include "cpu/static_inst.hh" -#include "sim/byteswap.hh" -#include "sim/sim_object.hh" -#include "sim/stats.hh" - -#include "cpu/o3/alpha_dyn_inst.hh" -#include "cpu/o3/alpha_impl.hh" - -#include "cpu/ozone/dyn_inst.hh" -#include "cpu/ozone/ozone_impl.hh" -#include "cpu/ozone/simple_impl.hh" - -#if FULL_SYSTEM -#include "sim/system.hh" -#include "arch/vtophys.hh" -#endif // FULL_SYSTEM - -using namespace std; -//The CheckerCPU does alpha only -using namespace AlphaISA; - -void -CheckerCPU::init() -{ -} - -CheckerCPU::CheckerCPU(Params *p) - : BaseCPU(p), cpuXC(NULL), xcProxy(NULL) -{ - memReq = new MemReq(); - memReq->xc = xcProxy; - memReq->asid = 0; - memReq->data = new uint8_t[64]; - - numInst = 0; - startNumInst = 0; - numLoad = 0; - startNumLoad = 0; - youngestSN = 0; - - changedPC = willChangePC = changedNextPC = false; - - exitOnError = p->exitOnError; -#if FULL_SYSTEM - itb = p->itb; - dtb = p->dtb; - systemPtr = NULL; - memPtr = NULL; -#endif -} - -CheckerCPU::~CheckerCPU() -{ -} - -void -CheckerCPU::setMemory(FunctionalMemory *mem) -{ - memPtr = mem; -#if !FULL_SYSTEM - cpuXC = new CPUExecContext(this, /* thread_num */ 0, mem, - /* asid */ 0); - - cpuXC->setStatus(ExecContext::Suspended); - xcProxy = cpuXC->getProxy(); - execContexts.push_back(xcProxy); -#else - if (systemPtr) { - cpuXC = new CPUExecContext(this, 0, systemPtr, itb, dtb, memPtr, false); - - cpuXC->setStatus(ExecContext::Suspended); - xcProxy = cpuXC->getProxy(); - execContexts.push_back(xcProxy); - memReq->xc = xcProxy; - delete cpuXC->kernelStats; - cpuXC->kernelStats = NULL; - } -#endif -} - -#if FULL_SYSTEM -void -CheckerCPU::setSystem(System *system) -{ - systemPtr = system; - - if (memPtr) { - cpuXC = new CPUExecContext(this, 0, systemPtr, itb, dtb, memPtr, false); - - cpuXC->setStatus(ExecContext::Suspended); - xcProxy = cpuXC->getProxy(); - execContexts.push_back(xcProxy); - memReq->xc = xcProxy; - delete cpuXC->kernelStats; - cpuXC->kernelStats = NULL; - } -} -#endif - -void -CheckerCPU::serialize(ostream &os) -{ -/* - BaseCPU::serialize(os); - SERIALIZE_SCALAR(inst); - nameOut(os, csprintf("%s.xc", name())); - cpuXC->serialize(os); - cacheCompletionEvent.serialize(os); -*/ -} - -void -CheckerCPU::unserialize(Checkpoint *cp, const string §ion) -{ -/* - BaseCPU::unserialize(cp, section); - UNSERIALIZE_SCALAR(inst); - cpuXC->unserialize(cp, csprintf("%s.xc", section)); -*/ -} - -Fault -CheckerCPU::copySrcTranslate(Addr src) -{ - panic("Unimplemented!"); -} - -Fault -CheckerCPU::copy(Addr dest) -{ - panic("Unimplemented!"); -} - -template <class T> -Fault -CheckerCPU::read(Addr addr, T &data, unsigned flags) -{ - memReq->reset(addr, sizeof(T), flags); - - // translate to physical address - translateDataReadReq(memReq); - - memReq->cmd = Read; - memReq->completionEvent = NULL; - memReq->time = curTick; - memReq->flags &= ~INST_READ; - - if (!(memReq->flags & UNCACHEABLE)) { - // Access memory to see if we have the same data - cpuXC->read(memReq, data); - } else { - // Assume the data is correct if it's an uncached access - memcpy(&data, &unverifiedResult.integer, sizeof(T)); - } - - return NoFault; -} - -#ifndef DOXYGEN_SHOULD_SKIP_THIS - -template -Fault -CheckerCPU::read(Addr addr, uint64_t &data, unsigned flags); - -template -Fault -CheckerCPU::read(Addr addr, uint32_t &data, unsigned flags); - -template -Fault -CheckerCPU::read(Addr addr, uint16_t &data, unsigned flags); - -template -Fault -CheckerCPU::read(Addr addr, uint8_t &data, unsigned flags); - -#endif //DOXYGEN_SHOULD_SKIP_THIS - -template<> -Fault -CheckerCPU::read(Addr addr, double &data, unsigned flags) -{ - return read(addr, *(uint64_t*)&data, flags); -} - -template<> -Fault -CheckerCPU::read(Addr addr, float &data, unsigned flags) -{ - return read(addr, *(uint32_t*)&data, flags); -} - -template<> -Fault -CheckerCPU::read(Addr addr, int32_t &data, unsigned flags) -{ - return read(addr, (uint32_t&)data, flags); -} - -template <class T> -Fault -CheckerCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) -{ - memReq->reset(addr, sizeof(T), flags); - - // translate to physical address - cpuXC->translateDataWriteReq(memReq); - - // Can compare the write data and result only if it's cacheable, - // not a store conditional, or is a store conditional that - // succeeded. - // @todo: Verify that actual memory matches up with these values. - // Right now it only verifies that the instruction data is the - // same as what was in the request that got sent to memory; there - // is no verification that it is the same as what is in memory. - // This is because the LSQ would have to be snooped in the CPU to - // verify this data. - if (unverifiedReq && - !(unverifiedReq->flags & UNCACHEABLE) && - (!(unverifiedReq->flags & LOCKED) || - ((unverifiedReq->flags & LOCKED) && - unverifiedReq->result == 1))) { -#if 0 - memReq->cmd = Read; - memReq->completionEvent = NULL; - memReq->time = curTick; - memReq->flags &= ~INST_READ; - cpuXC->read(memReq, inst_data); -#endif - T inst_data; - memcpy(&inst_data, unverifiedReq->data, sizeof(T)); - - if (data != inst_data) { - warn("%lli: Store value does not match value in memory! " - "Instruction: %#x, memory: %#x", - curTick, inst_data, data); - 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 (res) - *res = unverifiedReq->result; - - return NoFault; -} - - -#ifndef DOXYGEN_SHOULD_SKIP_THIS -template -Fault -CheckerCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res); - -template -Fault -CheckerCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res); - -template -Fault -CheckerCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res); - -template -Fault -CheckerCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res); - -#endif //DOXYGEN_SHOULD_SKIP_THIS - -template<> -Fault -CheckerCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) -{ - return write(*(uint64_t*)&data, addr, flags, res); -} - -template<> -Fault -CheckerCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) -{ - return write(*(uint32_t*)&data, addr, flags, res); -} - -template<> -Fault -CheckerCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) -{ - return write((uint32_t)data, addr, flags, res); -} - - -#if FULL_SYSTEM -Addr -CheckerCPU::dbg_vtophys(Addr addr) -{ - return vtophys(xcProxy, addr); -} -#endif // FULL_SYSTEM - -bool -CheckerCPU::translateInstReq(MemReqPtr &req) -{ -#if FULL_SYSTEM - return (cpuXC->translateInstReq(req) == NoFault); -#else - cpuXC->translateInstReq(req); - return true; -#endif -} - -void -CheckerCPU::translateDataReadReq(MemReqPtr &req) -{ - cpuXC->translateDataReadReq(req); - - if (req->vaddr != unverifiedReq->vaddr) { - warn("%lli: Request virtual addresses do not match! Inst: %#x, " - "checker: %#x", - curTick, unverifiedReq->vaddr, req->vaddr); - handleError(); - } - req->paddr = unverifiedReq->paddr; - - if (checkFlags(req)) { - warn("%lli: Request flags do not match! Inst: %#x, checker: %#x", - curTick, unverifiedReq->flags, req->flags); - handleError(); - } -} - -void -CheckerCPU::translateDataWriteReq(MemReqPtr &req) -{ - cpuXC->translateDataWriteReq(req); - - if (req->vaddr != unverifiedReq->vaddr) { - warn("%lli: Request virtual addresses do not match! Inst: %#x, " - "checker: %#x", - curTick, unverifiedReq->vaddr, req->vaddr); - handleError(); - } - req->paddr = unverifiedReq->paddr; - - if (checkFlags(req)) { - warn("%lli: Request flags do not match! Inst: %#x, checker: %#x", - curTick, unverifiedReq->flags, req->flags); - handleError(); - } -} - -bool -CheckerCPU::checkFlags(MemReqPtr &req) -{ - // Remove any dynamic flags that don't have to do with the request itself. - unsigned flags = unverifiedReq->flags; - unsigned mask = LOCKED | PHYSICAL | VPTE | ALTMODE | UNCACHEABLE | NO_FAULT; - flags = flags & (mask); - if (flags == req->flags) { - return false; - } else { - return true; - } -} - -template <class DynInstPtr> -void -Checker<DynInstPtr>::tick(DynInstPtr &completed_inst) -{ - DynInstPtr inst; - - // 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:%#x to list.\n", - completed_inst->seqNum, completed_inst->readPC()); - 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:%#x to list.\n", - completed_inst->seqNum, completed_inst->readPC()); - 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; - } - } - } - - // 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:%#x.\n", - inst->seqNum, inst->readPC()); - unverifiedResult.integer = inst->readIntResult(); - unverifiedReq = inst->req; - numCycles++; - - Fault fault = NoFault; - - // maintain $r0 semantics - cpuXC->setIntReg(ZeroReg, 0); -#ifdef TARGET_ALPHA - cpuXC->setFloatRegDouble(ZeroReg, 0.0); -#endif // TARGET_ALPHA - - // 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 %#x\n", - cpuXC->readPC()); - if (willChangePC) { - if (newPC == cpuXC->readPC()) { - DPRINTF(Checker, "Changed PC matches expected PC\n"); - } else { - warn("%lli: Changed PC does not match expected PC, " - "changed: %#x, expected: %#x", - curTick, cpuXC->readPC(), newPC); - handleError(); - } - willChangePC = false; - } - changedPC = false; - } - if (changedNextPC) { - DPRINTF(Checker, "Changed NextPC recently to %#x\n", - cpuXC->readNextPC()); - changedNextPC = false; - } - - // Try to fetch the instruction - -#if FULL_SYSTEM -#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0 -#else -#define IFETCH_FLAGS(pc) 0 -#endif - - // set up memory request for instruction fetch - memReq->cmd = Read; - memReq->reset(cpuXC->readPC() & ~3, sizeof(uint32_t), - IFETCH_FLAGS(cpuXC->readPC())); - - bool succeeded = translateInstReq(memReq); - - if (!succeeded) { - if (inst->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 %#x was not found in the ITB!", - curTick, cpuXC->readPC()); - handleError(); - - // go to the next instruction - cpuXC->setPC(cpuXC->readNextPC()); - cpuXC->setNextPC(cpuXC->readNextPC() + sizeof(MachInst)); - - 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 = inst->getFault(); - } - } - - if (fault == NoFault) { - cpuXC->mem->read(memReq, machInst); - - // keep an instruction count - numInst++; - - // decode the instruction - machInst = gtoh(machInst); - // Checks that the instruction matches what we expected it to be. - // Checks both the machine instruction and the PC. - validateInst(inst); - - curStaticInst = StaticInst::decode(makeExtMI(machInst, - cpuXC->readPC())); - -#if FULL_SYSTEM - cpuXC->setInst(machInst); -#endif // FULL_SYSTEM - - fault = inst->getFault(); - } - - // 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) { - - cpuXC->func_exe_inst++; - - fault = curStaticInst->execute(this, NULL); - - // Checks to make sure instrution results are correct. - validateExecution(inst); - - if (curStaticInst->isLoad()) { - ++numLoad; - } - } - - if (fault != NoFault) { -#if FULL_SYSTEM - fault->invoke(xcProxy); - willChangePC = true; - newPC = cpuXC->readPC(); - DPRINTF(Checker, "Fault, PC is now %#x\n", newPC); -#else // !FULL_SYSTEM - fatal("fault (%d) detected @ PC 0x%08p", fault, cpuXC->readPC()); -#endif // FULL_SYSTEM - } else { -#if THE_ISA != MIPS_ISA - // go to the next instruction - cpuXC->setPC(cpuXC->readNextPC()); - cpuXC->setNextPC(cpuXC->readNextPC() + sizeof(MachInst)); -#else - // go to the next instruction - cpuXC->setPC(cpuXC->readNextPC()); - cpuXC->setNextPC(cpuXC->readNextNPC()); - cpuXC->setNextNPC(cpuXC->readNextNPC() + sizeof(MachInst)); -#endif - - } - -#if FULL_SYSTEM - // @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 = cpuXC->readPC(); - system->pcEventQueue.service(xcProxy); - count++; - } while (oldpc != cpuXC->readPC()); - if (count > 1) { - willChangePC = true; - newPC = cpuXC->readPC(); - DPRINTF(Checker, "PC Event, PC is now %#x\n", newPC); - } -#endif - - // @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()) { - inst = instList.front(); - instList.pop_front(); - } else { - break; - } - } -} - -template <class DynInstPtr> -void -Checker<DynInstPtr>::switchOut(Sampler *s) -{ - instList.clear(); -} - -template <class DynInstPtr> -void -Checker<DynInstPtr>::takeOverFrom(BaseCPU *oldCPU) -{ -} - -template <class DynInstPtr> -void -Checker<DynInstPtr>::validateInst(DynInstPtr &inst) -{ - if (inst->readPC() != cpuXC->readPC()) { - warn("%lli: PCs do not match! Inst: %#x, checker: %#x", - curTick, inst->readPC(), cpuXC->readPC()); - if (changedPC) { - warn("%lli: Changed PCs recently, may not be an error", - curTick); - } else { - handleError(); - } - } - - MachInst mi = static_cast<MachInst>(inst->staticInst->machInst); - - if (mi != machInst) { - warn("%lli: Binary instructions do not match! Inst: %#x, " - "checker: %#x", - curTick, mi, machInst); - handleError(); - } -} - -template <class DynInstPtr> -void -Checker<DynInstPtr>::validateExecution(DynInstPtr &inst) -{ - if (inst->numDestRegs()) { - // @todo: Support more destination registers. - 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. - RegIndex idx = inst->destRegIdx(0); - if (idx < TheISA::FP_Base_DepTag) { - cpuXC->setIntReg(idx, inst->readIntResult()); - } else if (idx < TheISA::Fpcr_DepTag) { - cpuXC->setFloatRegInt(idx, inst->readIntResult()); - } else { - cpuXC->setMiscReg(idx, inst->readIntResult()); - } - } else if (result.integer != inst->readIntResult()) { - warn("%lli: Instruction results do not match! (Results may not " - "actually be integers) Inst: %#x, checker: %#x", - curTick, inst->readIntResult(), result.integer); - handleError(); - } - } - - if (inst->readNextPC() != cpuXC->readNextPC()) { - warn("%lli: Instruction next PCs do not match! Inst: %#x, " - "checker: %#x", - curTick, inst->readNextPC(), cpuXC->readNextPC()); - handleError(); - } - - // 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->xcBase()->readMiscReg(misc_reg_idx) != - cpuXC->readMiscReg(misc_reg_idx)) { - warn("%lli: Misc reg idx %i (side effect) does not match! " - "Inst: %#x, checker: %#x", - curTick, misc_reg_idx, - inst->xcBase()->readMiscReg(misc_reg_idx), - cpuXC->readMiscReg(misc_reg_idx)); - handleError(); - } - } -} - -template <class DynInstPtr> -void -Checker<DynInstPtr>::validateState() -{ -} - -template <class DynInstPtr> -void -Checker<DynInstPtr>::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:%#x\n[sn:%lli]\n[tid:%i]\n" - "Completed:%i\n", - (*inst_list_it)->readPC(), - (*inst_list_it)->seqNum, - (*inst_list_it)->threadNumber, - (*inst_list_it)->isCompleted()); - - cprintf("\n"); - - inst_list_it--; - ++num; - } - -} - -template -class Checker<RefCountingPtr<OzoneDynInst<OzoneImpl> > >; - -template -class Checker<RefCountingPtr<AlphaDynInst<AlphaSimpleImpl> > >; diff --git a/cpu/checker/cpu.hh b/cpu/checker/cpu.hh deleted file mode 100644 index 37fe59d95..000000000 --- a/cpu/checker/cpu.hh +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Copyright (c) 2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_CHECKER_CPU_HH__ -#define __CPU_CHECKER_CPU_HH__ - -#include <list> -#include <queue> -#include <map> - -#include "base/statistics.hh" -#include "config/full_system.hh" -#include "cpu/base.hh" -#include "cpu/base_dyn_inst.hh" -#include "cpu/cpu_exec_context.hh" -#include "cpu/pc_event.hh" -#include "cpu/static_inst.hh" -#include "sim/eventq.hh" - -// forward declarations -#if FULL_SYSTEM -class Processor; -class AlphaITB; -class AlphaDTB; -class PhysicalMemory; - -class RemoteGDB; -class GDBListener; - -#else - -class Process; - -#endif // FULL_SYSTEM -template <class> -class BaseDynInst; -class ExecContext; -class MemInterface; -class Checkpoint; -class Sampler; - -class CheckerCPU : public BaseCPU -{ - protected: - typedef TheISA::MachInst MachInst; - typedef TheISA::MiscReg MiscReg; - public: - // main simulation loop (one cycle) - virtual void init(); - - struct Params : public BaseCPU::Params - { -#if FULL_SYSTEM - AlphaITB *itb; - AlphaDTB *dtb; - FunctionalMemory *mem; -#else - Process *process; -#endif - bool exitOnError; - }; - - public: - CheckerCPU(Params *p); - virtual ~CheckerCPU(); - - void setMemory(FunctionalMemory *mem); - - FunctionalMemory *memPtr; - -#if FULL_SYSTEM - void setSystem(System *system); - - System *systemPtr; -#endif - public: - // execution context - CPUExecContext *cpuXC; - - ExecContext *xcProxy; - - AlphaITB *itb; - AlphaDTB *dtb; - -#if FULL_SYSTEM - Addr dbg_vtophys(Addr addr); -#endif - - union Result { - uint64_t integer; - float fp; - double dbl; - }; - - Result result; - - // current instruction - MachInst machInst; - - // Refcounted pointer to the one memory request. - MemReqPtr memReq; - - StaticInstPtr curStaticInst; - - // number of simulated instructions - Counter numInst; - Counter startNumInst; - - std::queue<int> miscRegIdxs; - - virtual Counter totalInstructions() const - { - return numInst - startNumInst; - } - - // number of simulated loads - Counter numLoad; - Counter startNumLoad; - - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); - - template <class T> - Fault read(Addr addr, T &data, unsigned flags); - - template <class T> - Fault write(T data, Addr addr, unsigned flags, uint64_t *res); - - // 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"); } - - void prefetch(Addr addr, unsigned flags) - { - // need to do this... - } - - void writeHint(Addr addr, int size, unsigned flags) - { - // need to do this... - } - - Fault copySrcTranslate(Addr src); - - Fault copy(Addr dest); - - // 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 readIntReg(const StaticInst *si, int idx) - { - return cpuXC->readIntReg(si->srcRegIdx(idx)); - } - - float readFloatRegSingle(const StaticInst *si, int idx) - { - int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag; - return cpuXC->readFloatRegSingle(reg_idx); - } - - double readFloatRegDouble(const StaticInst *si, int idx) - { - int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag; - return cpuXC->readFloatRegDouble(reg_idx); - } - - uint64_t readFloatRegInt(const StaticInst *si, int idx) - { - int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag; - return cpuXC->readFloatRegInt(reg_idx); - } - - void setIntReg(const StaticInst *si, int idx, uint64_t val) - { - cpuXC->setIntReg(si->destRegIdx(idx), val); - result.integer = val; - } - - void setFloatRegSingle(const StaticInst *si, int idx, float val) - { - int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag; - cpuXC->setFloatRegSingle(reg_idx, val); - result.fp = val; - } - - void setFloatRegDouble(const StaticInst *si, int idx, double val) - { - int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag; - cpuXC->setFloatRegDouble(reg_idx, val); - result.dbl = val; - } - - void setFloatRegInt(const StaticInst *si, int idx, uint64_t val) - { - int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag; - cpuXC->setFloatRegInt(reg_idx, val); - result.integer = val; - } - - uint64_t readPC() { return cpuXC->readPC(); } - void setNextPC(uint64_t val) { - cpuXC->setNextPC(val); - } - - MiscReg readMiscReg(int misc_reg) - { - return cpuXC->readMiscReg(misc_reg); - } - - MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) - { - return cpuXC->readMiscRegWithEffect(misc_reg, fault); - } - - Fault setMiscReg(int misc_reg, const MiscReg &val) - { - result.integer = val; - miscRegIdxs.push(misc_reg); - return cpuXC->setMiscReg(misc_reg, val); - } - - Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) - { - miscRegIdxs.push(misc_reg); - return cpuXC->setMiscRegWithEffect(misc_reg, val); - } - - void recordPCChange(uint64_t val) { changedPC = true; } - void recordNextPCChange(uint64_t val) { changedNextPC = true; } - - bool translateInstReq(MemReqPtr &req); - void translateDataWriteReq(MemReqPtr &req); - void translateDataReadReq(MemReqPtr &req); - -#if FULL_SYSTEM - Fault hwrei() { return cpuXC->hwrei(); } - int readIntrFlag() { return cpuXC->readIntrFlag(); } - void setIntrFlag(int val) { cpuXC->setIntrFlag(val); } - bool inPalMode() { return cpuXC->inPalMode(); } - void ev5_trap(Fault fault) { fault->invoke(xcProxy); } - bool simPalCheck(int palFunc) { return cpuXC->simPalCheck(palFunc); } -#else - // 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() { } -#endif - - void handleError() - { - if (exitOnError) - panic("Checker found error!"); - } - bool checkFlags(MemReqPtr &req); - - ExecContext *xcBase() { return xcProxy; } - CPUExecContext *cpuXCBase() { return cpuXC; } - - Result unverifiedResult; - MemReqPtr unverifiedReq; - - bool changedPC; - bool willChangePC; - uint64_t newPC; - bool changedNextPC; - bool exitOnError; - - InstSeqNum youngestSN; -}; - -template <class DynInstPtr> -class Checker : public CheckerCPU -{ - public: - Checker(Params *p) - : CheckerCPU(p) - { } - - void switchOut(Sampler *s); - void takeOverFrom(BaseCPU *oldCPU); - - void tick(DynInstPtr &inst); - - void validateInst(DynInstPtr &inst); - void validateExecution(DynInstPtr &inst); - void validateState(); - - std::list<DynInstPtr> instList; - typedef typename std::list<DynInstPtr>::iterator InstListIt; - void dumpInsts(); -}; - -#endif // __CPU_CHECKER_CPU_HH__ diff --git a/cpu/checker/cpu_builder.cc b/cpu/checker/cpu_builder.cc deleted file mode 100644 index 397ccab14..000000000 --- a/cpu/checker/cpu_builder.cc +++ /dev/null @@ -1,126 +0,0 @@ - -#include <string> - -#include "cpu/checker/cpu.hh" -#include "cpu/inst_seq.hh" -#include "cpu/ozone/dyn_inst.hh" -#include "cpu/ozone/ozone_impl.hh" -#include "mem/base_mem.hh" -#include "sim/builder.hh" -#include "sim/process.hh" -#include "sim/sim_object.hh" - -class OzoneChecker : public Checker<RefCountingPtr<OzoneDynInst<OzoneImpl> > > -{ - public: - OzoneChecker(Params *p) - : Checker<RefCountingPtr<OzoneDynInst<OzoneImpl> > >(p) - { } -}; - -//////////////////////////////////////////////////////////////////////// -// -// CheckerCPU Simulation Object -// -BEGIN_DECLARE_SIM_OBJECT_PARAMS(OzoneChecker) - - Param<Counter> max_insts_any_thread; - Param<Counter> max_insts_all_threads; - Param<Counter> max_loads_any_thread; - Param<Counter> max_loads_all_threads; - -#if FULL_SYSTEM - SimObjectParam<AlphaITB *> itb; - SimObjectParam<AlphaDTB *> dtb; - SimObjectParam<FunctionalMemory *> mem; - SimObjectParam<System *> system; - Param<int> cpu_id; - Param<Tick> profile; -#else - SimObjectParam<Process *> workload; -#endif // FULL_SYSTEM - Param<int> clock; - SimObjectParam<BaseMem *> icache; - SimObjectParam<BaseMem *> dcache; - - Param<bool> defer_registration; - Param<bool> exitOnError; - Param<bool> function_trace; - Param<Tick> function_trace_start; - -END_DECLARE_SIM_OBJECT_PARAMS(OzoneChecker) - -BEGIN_INIT_SIM_OBJECT_PARAMS(OzoneChecker) - - INIT_PARAM(max_insts_any_thread, - "terminate when any thread reaches this inst count"), - INIT_PARAM(max_insts_all_threads, - "terminate when all threads have reached this inst count"), - INIT_PARAM(max_loads_any_thread, - "terminate when any thread reaches this load count"), - INIT_PARAM(max_loads_all_threads, - "terminate when all threads have reached this load count"), - -#if FULL_SYSTEM - INIT_PARAM(itb, "Instruction TLB"), - INIT_PARAM(dtb, "Data TLB"), - INIT_PARAM(mem, "memory"), - INIT_PARAM(system, "system object"), - INIT_PARAM(cpu_id, "processor ID"), - INIT_PARAM(profile, ""), -#else - INIT_PARAM(workload, "processes to run"), -#endif // FULL_SYSTEM - - INIT_PARAM(clock, "clock speed"), - INIT_PARAM(icache, "L1 instruction cache object"), - INIT_PARAM(dcache, "L1 data cache object"), - - INIT_PARAM(defer_registration, "defer system registration (for sampling)"), - INIT_PARAM(exitOnError, "exit on error"), - INIT_PARAM(function_trace, "Enable function trace"), - INIT_PARAM(function_trace_start, "Cycle to start function trace") - -END_INIT_SIM_OBJECT_PARAMS(OzoneChecker) - - -CREATE_SIM_OBJECT(OzoneChecker) -{ - OzoneChecker::Params *params = new OzoneChecker::Params(); - params->name = getInstanceName(); - params->numberOfThreads = 1; - 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->exitOnError = exitOnError; - params->deferRegistration = defer_registration; - params->functionTrace = function_trace; - params->functionTraceStart = function_trace_start; - 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; - BaseMem *cache = icache; - cache = dcache; - -#if FULL_SYSTEM - params->itb = itb; - params->dtb = dtb; - params->mem = mem; - params->system = system; - params->cpu_id = cpu_id; - params->profile = profile; -#else - params->process = workload; -#endif - - OzoneChecker *cpu = new OzoneChecker(params); - return cpu; -} - -REGISTER_SIM_OBJECT("OzoneChecker", OzoneChecker) diff --git a/cpu/checker/exec_context.hh b/cpu/checker/exec_context.hh deleted file mode 100644 index 38784867d..000000000 --- a/cpu/checker/exec_context.hh +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright (c) 2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_CHECKER_EXEC_CONTEXT_HH__ -#define __CPU_CHECKER_EXEC_CONTEXT_HH__ - -#include "cpu/checker/cpu.hh" -#include "cpu/cpu_exec_context.hh" -#include "cpu/exec_context.hh" - -class EndQuiesceEvent; -namespace Kernel { - class Statistics; -}; - -template <class XC> -class CheckerExecContext : public ExecContext -{ - public: - CheckerExecContext(XC *actual_xc, - CheckerCPU *checker_cpu) - : actualXC(actual_xc), checkerXC(checker_cpu->cpuXC), - checkerCPU(checker_cpu) - { } - - private: - XC *actualXC; - CPUExecContext *checkerXC; - CheckerCPU *checkerCPU; - - public: - - BaseCPU *getCpuPtr() { return actualXC->getCpuPtr(); } - - void setCpuId(int id) - { - actualXC->setCpuId(id); - checkerXC->setCpuId(id); - } - - int readCpuId() { return actualXC->readCpuId(); } - - FunctionalMemory *getMemPtr() { return actualXC->getMemPtr(); } - -#if FULL_SYSTEM - System *getSystemPtr() { return actualXC->getSystemPtr(); } - - PhysicalMemory *getPhysMemPtr() { return actualXC->getPhysMemPtr(); } - - AlphaITB *getITBPtr() { return actualXC->getITBPtr(); } - - AlphaDTB *getDTBPtr() { return actualXC->getDTBPtr(); } - - Kernel::Statistics *getKernelStats() { return actualXC->getKernelStats(); } -#else - Process *getProcessPtr() { return actualXC->getProcessPtr(); } -#endif - - Status status() const { return actualXC->status(); } - - void setStatus(Status new_status) - { - actualXC->setStatus(new_status); - checkerXC->setStatus(new_status); - } - - /// Set the status to Active. Optional delay indicates number of - /// cycles to wait before beginning execution. - void activate(int delay = 1) { actualXC->activate(delay); } - - /// Set the status to Suspended. - void suspend() { actualXC->suspend(); } - - /// Set the status to Unallocated. - void deallocate() { actualXC->deallocate(); } - - /// Set the status to Halted. - void halt() { actualXC->halt(); } - -#if FULL_SYSTEM - void dumpFuncProfile() { actualXC->dumpFuncProfile(); } -#endif - - void takeOverFrom(ExecContext *oldContext) - { - actualXC->takeOverFrom(oldContext); - checkerXC->takeOverFrom(oldContext); - } - - void regStats(const std::string &name) { actualXC->regStats(name); } - - void serialize(std::ostream &os) { actualXC->serialize(os); } - void unserialize(Checkpoint *cp, const std::string §ion) - { actualXC->unserialize(cp, section); } - -#if FULL_SYSTEM - EndQuiesceEvent *getQuiesceEvent() { return actualXC->getQuiesceEvent(); } - - Tick readLastActivate() { return actualXC->readLastActivate(); } - Tick readLastSuspend() { return actualXC->readLastSuspend(); } - - void profileClear() { return actualXC->profileClear(); } - void profileSample() { return actualXC->profileSample(); } -#endif - - int getThreadNum() { return actualXC->getThreadNum(); } - - // @todo: Do I need this? - MachInst getInst() { return actualXC->getInst(); } - - // @todo: Do I need this? - void copyArchRegs(ExecContext *xc) - { - actualXC->copyArchRegs(xc); - checkerXC->copyArchRegs(xc); - } - - void clearArchRegs() - { - actualXC->clearArchRegs(); - checkerXC->clearArchRegs(); - } - - // - // New accessors for new decoder. - // - uint64_t readIntReg(int reg_idx) - { return actualXC->readIntReg(reg_idx); } - - float readFloatRegSingle(int reg_idx) - { return actualXC->readFloatRegSingle(reg_idx); } - - double readFloatRegDouble(int reg_idx) - { return actualXC->readFloatRegDouble(reg_idx); } - - uint64_t readFloatRegInt(int reg_idx) - { return actualXC->readFloatRegInt(reg_idx); } - - void setIntReg(int reg_idx, uint64_t val) - { - actualXC->setIntReg(reg_idx, val); - checkerXC->setIntReg(reg_idx, val); - } - - void setFloatRegSingle(int reg_idx, float val) - { - actualXC->setFloatRegSingle(reg_idx, val); - checkerXC->setFloatRegSingle(reg_idx, val); - } - - void setFloatRegDouble(int reg_idx, double val) - { - actualXC->setFloatRegDouble(reg_idx, val); - checkerXC->setFloatRegSingle(reg_idx, val); - } - - void setFloatRegInt(int reg_idx, uint64_t val) - { - actualXC->setFloatRegInt(reg_idx, val); - checkerXC->setFloatRegInt(reg_idx, val); - } - - uint64_t readPC() { return actualXC->readPC(); } - - void setPC(uint64_t val) - { - actualXC->setPC(val); - checkerXC->setPC(val); - checkerCPU->recordPCChange(val); - } - - uint64_t readNextPC() { return actualXC->readNextPC(); } - - void setNextPC(uint64_t val) - { - actualXC->setNextPC(val); - checkerXC->setNextPC(val); - checkerCPU->recordNextPCChange(val); - } - - MiscReg readMiscReg(int misc_reg) - { return actualXC->readMiscReg(misc_reg); } - - MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) - { return actualXC->readMiscRegWithEffect(misc_reg, fault); } - - Fault setMiscReg(int misc_reg, const MiscReg &val) - { - checkerXC->setMiscReg(misc_reg, val); - return actualXC->setMiscReg(misc_reg, val); - } - - Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) - { - checkerXC->setMiscRegWithEffect(misc_reg, val); - return actualXC->setMiscRegWithEffect(misc_reg, val); - } - - unsigned readStCondFailures() - { return actualXC->readStCondFailures(); } - - void setStCondFailures(unsigned sc_failures) - { - checkerXC->setStCondFailures(sc_failures); - actualXC->setStCondFailures(sc_failures); - } -#if FULL_SYSTEM - bool inPalMode() { return actualXC->inPalMode(); } -#endif - - // @todo: Fix this! - bool misspeculating() { return actualXC->misspeculating(); } - -#if !FULL_SYSTEM - IntReg getSyscallArg(int i) { return actualXC->getSyscallArg(i); } - - // used to shift args for indirect syscall - void setSyscallArg(int i, IntReg val) - { - checkerXC->setSyscallArg(i, val); - actualXC->setSyscallArg(i, val); - } - - void setSyscallReturn(SyscallReturn return_value) - { - checkerXC->setSyscallReturn(return_value); - actualXC->setSyscallReturn(return_value); - } - - Counter readFuncExeInst() { return actualXC->readFuncExeInst(); } -#endif -}; - -#endif // __CPU_CHECKER_EXEC_CONTEXT_HH__ diff --git a/cpu/checker/o3_cpu_builder.cc b/cpu/checker/o3_cpu_builder.cc deleted file mode 100644 index 125bfa398..000000000 --- a/cpu/checker/o3_cpu_builder.cc +++ /dev/null @@ -1,126 +0,0 @@ - -#include <string> - -#include "cpu/checker/cpu.hh" -#include "cpu/inst_seq.hh" -#include "cpu/o3/alpha_dyn_inst.hh" -#include "cpu/o3/alpha_impl.hh" -#include "mem/base_mem.hh" -#include "sim/builder.hh" -#include "sim/process.hh" -#include "sim/sim_object.hh" - -class O3Checker : public Checker<RefCountingPtr<AlphaDynInst<AlphaSimpleImpl> > > -{ - public: - O3Checker(Params *p) - : Checker<RefCountingPtr<AlphaDynInst<AlphaSimpleImpl> > >(p) - { } -}; - -//////////////////////////////////////////////////////////////////////// -// -// CheckerCPU Simulation Object -// -BEGIN_DECLARE_SIM_OBJECT_PARAMS(O3Checker) - - Param<Counter> max_insts_any_thread; - Param<Counter> max_insts_all_threads; - Param<Counter> max_loads_any_thread; - Param<Counter> max_loads_all_threads; - -#if FULL_SYSTEM - SimObjectParam<AlphaITB *> itb; - SimObjectParam<AlphaDTB *> dtb; - SimObjectParam<FunctionalMemory *> mem; - SimObjectParam<System *> system; - Param<int> cpu_id; - Param<Tick> profile; -#else - SimObjectParam<Process *> workload; -#endif // FULL_SYSTEM - Param<int> clock; - SimObjectParam<BaseMem *> icache; - SimObjectParam<BaseMem *> dcache; - - Param<bool> defer_registration; - Param<bool> exitOnError; - Param<bool> function_trace; - Param<Tick> function_trace_start; - -END_DECLARE_SIM_OBJECT_PARAMS(O3Checker) - -BEGIN_INIT_SIM_OBJECT_PARAMS(O3Checker) - - INIT_PARAM(max_insts_any_thread, - "terminate when any thread reaches this inst count"), - INIT_PARAM(max_insts_all_threads, - "terminate when all threads have reached this inst count"), - INIT_PARAM(max_loads_any_thread, - "terminate when any thread reaches this load count"), - INIT_PARAM(max_loads_all_threads, - "terminate when all threads have reached this load count"), - -#if FULL_SYSTEM - INIT_PARAM(itb, "Instruction TLB"), - INIT_PARAM(dtb, "Data TLB"), - INIT_PARAM(mem, "memory"), - INIT_PARAM(system, "system object"), - INIT_PARAM(cpu_id, "processor ID"), - INIT_PARAM(profile, ""), -#else - INIT_PARAM(workload, "processes to run"), -#endif // FULL_SYSTEM - - INIT_PARAM(clock, "clock speed"), - INIT_PARAM(icache, "L1 instruction cache object"), - INIT_PARAM(dcache, "L1 data cache object"), - - INIT_PARAM(defer_registration, "defer system registration (for sampling)"), - INIT_PARAM(exitOnError, "exit on error"), - INIT_PARAM(function_trace, "Enable function trace"), - INIT_PARAM(function_trace_start, "Cycle to start function trace") - -END_INIT_SIM_OBJECT_PARAMS(O3Checker) - - -CREATE_SIM_OBJECT(O3Checker) -{ - O3Checker::Params *params = new O3Checker::Params(); - params->name = getInstanceName(); - params->numberOfThreads = 1; - 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->exitOnError = exitOnError; - params->deferRegistration = defer_registration; - params->functionTrace = function_trace; - params->functionTraceStart = function_trace_start; - 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; - BaseMem *cache = icache; - cache = dcache; - -#if FULL_SYSTEM - params->itb = itb; - params->dtb = dtb; - params->mem = mem; - params->system = system; - params->cpu_id = cpu_id; - params->profile = profile; -#else - params->process = workload; -#endif - - O3Checker *cpu = new O3Checker(params); - return cpu; -} - -REGISTER_SIM_OBJECT("O3Checker", O3Checker) diff --git a/cpu/cpu_exec_context.cc b/cpu/cpu_exec_context.cc deleted file mode 100644 index e30295ef8..000000000 --- a/cpu/cpu_exec_context.cc +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright (c) 2001-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. - */ - -#include <string> - -#include "cpu/base.hh" -#include "cpu/cpu_exec_context.hh" -#include "cpu/exec_context.hh" - -#if FULL_SYSTEM -#include "base/callback.hh" -#include "base/cprintf.hh" -#include "base/output.hh" -#include "base/trace.hh" -#include "cpu/profile.hh" -#include "cpu/quiesce_event.hh" -#include "kern/kernel_stats.hh" -#include "sim/serialize.hh" -#include "sim/sim_exit.hh" -#include "sim/system.hh" -#include "arch/stacktrace.hh" -#else -#include "sim/process.hh" -#endif - -using namespace std; - -// constructor -#if FULL_SYSTEM -CPUExecContext::CPUExecContext(BaseCPU *_cpu, int _thread_num, System *_sys, - AlphaITB *_itb, AlphaDTB *_dtb, - FunctionalMemory *_mem, - bool use_kernel_stats) - : _status(ExecContext::Unallocated), cpu(_cpu), thread_num(_thread_num), - cpu_id(-1), lastActivate(0), lastSuspend(0), mem(_mem), itb(_itb), - dtb(_dtb), system(_sys), memctrl(_sys->memctrl), physmem(_sys->physmem), - profile(NULL), func_exe_inst(0), storeCondFailures(0) -{ - proxy = new ProxyExecContext<CPUExecContext>(this); - - quiesceEvent = new EndQuiesceEvent(proxy); - - memset(®s, 0, sizeof(RegFile)); - - if (cpu->params->profile) { - profile = new FunctionProfile(system->kernelSymtab); - Callback *cb = - new MakeCallback<CPUExecContext, - &CPUExecContext::dumpFuncProfile>(this); - registerExitCallback(cb); - } - - // let's fill with a dummy node for now so we don't get a segfault - // on the first cycle when there's no node available. - static ProfileNode dummyNode; - profileNode = &dummyNode; - profilePC = 3; - - if (use_kernel_stats) { - kernelStats = new Kernel::Statistics(system); - } else { - kernelStats = NULL; - } -} -#else -CPUExecContext::CPUExecContext(BaseCPU *_cpu, int _thread_num, - Process *_process, int _asid) - : _status(ExecContext::Unallocated), - cpu(_cpu), thread_num(_thread_num), cpu_id(-1), lastActivate(0), - lastSuspend(0), process(_process), mem(process->getMemory()), asid(_asid), - func_exe_inst(0), storeCondFailures(0) -{ - memset(®s, 0, sizeof(RegFile)); - proxy = new ProxyExecContext<CPUExecContext>(this); -} - -CPUExecContext::CPUExecContext(BaseCPU *_cpu, int _thread_num, - FunctionalMemory *_mem, int _asid) - : cpu(_cpu), thread_num(_thread_num), process(0), mem(_mem), asid(_asid), - func_exe_inst(0), storeCondFailures(0) -{ - memset(®s, 0, sizeof(RegFile)); - proxy = new ProxyExecContext<CPUExecContext>(this); -} - -CPUExecContext::CPUExecContext(RegFile *regFile) - : cpu(NULL), thread_num(-1), process(NULL), mem(NULL), asid(-1), - func_exe_inst(0), storeCondFailures(0) -{ - regs = *regFile; - proxy = new ProxyExecContext<CPUExecContext>(this); -} - -#endif - -CPUExecContext::~CPUExecContext() -{ - delete proxy; -} - -#if FULL_SYSTEM -void -CPUExecContext::dumpFuncProfile() -{ - std::ostream *os = simout.create(csprintf("profile.%s.dat", cpu->name())); - profile->dump(proxy, *os); -} - -void -CPUExecContext::profileClear() -{ - if (profile) - profile->clear(); -} - -void -CPUExecContext::profileSample() -{ - if (profile) - profile->sample(profileNode, profilePC); -} - -#endif - -void -CPUExecContext::takeOverFrom(ExecContext *oldContext) -{ - // some things should already be set up - assert(mem == oldContext->getMemPtr()); -#if FULL_SYSTEM - assert(system == oldContext->getSystemPtr()); -#else - assert(process == oldContext->getProcessPtr()); -#endif - - // copy over functional state - _status = oldContext->status(); - copyArchRegs(oldContext); - cpu_id = oldContext->readCpuId(); -#if !FULL_SYSTEM - func_exe_inst = oldContext->readFuncExeInst(); -#else - EndQuiesceEvent *quiesce = oldContext->getQuiesceEvent(); - if (quiesce) { - // Point the quiesce event's XC at this XC so that it wakes up - // the proper CPU. - quiesce->xc = proxy; - } - if (quiesceEvent) { - quiesceEvent->xc = proxy; - } -#endif - - storeCondFailures = 0; - - oldContext->setStatus(ExecContext::Unallocated); -} - -void -CPUExecContext::serialize(ostream &os) -{ - SERIALIZE_ENUM(_status); - regs.serialize(os); - // thread_num and cpu_id are deterministic from the config - SERIALIZE_SCALAR(func_exe_inst); - SERIALIZE_SCALAR(inst); - -#if FULL_SYSTEM - Tick quiesceEndTick = 0; - if (quiesceEvent->scheduled()) - quiesceEndTick = quiesceEvent->when(); - SERIALIZE_SCALAR(quiesceEndTick); - if (kernelStats) - kernelStats->serialize(os); -#endif -} - - -void -CPUExecContext::unserialize(Checkpoint *cp, const std::string §ion) -{ - UNSERIALIZE_ENUM(_status); - regs.unserialize(cp, section); - // thread_num and cpu_id are deterministic from the config - UNSERIALIZE_SCALAR(func_exe_inst); - UNSERIALIZE_SCALAR(inst); - -#if FULL_SYSTEM - Tick quiesceEndTick; - UNSERIALIZE_SCALAR(quiesceEndTick); - if (quiesceEndTick) - quiesceEvent->schedule(quiesceEndTick); - if (kernelStats) - kernelStats->unserialize(cp, section); -#endif -} - - -void -CPUExecContext::activate(int delay) -{ - if (status() == ExecContext::Active) - return; - - lastActivate = curTick; - - if (status() == ExecContext::Unallocated) { - cpu->activateWhenReady(thread_num); - return; - } - - _status = ExecContext::Active; - - // status() == Suspended - cpu->activateContext(thread_num, delay); -} - -void -CPUExecContext::suspend() -{ - if (status() == ExecContext::Suspended) - return; - - lastActivate = curTick; - lastSuspend = curTick; -/* -#if FULL_SYSTEM - // Don't change the status from active if there are pending interrupts - if (cpu->check_interrupts()) { - assert(status() == ExecContext::Active); - return; - } -#endif -*/ - _status = ExecContext::Suspended; - cpu->suspendContext(thread_num); -} - -void -CPUExecContext::deallocate() -{ - if (status() == ExecContext::Unallocated) - return; - - _status = ExecContext::Unallocated; - cpu->deallocateContext(thread_num); -} - -void -CPUExecContext::halt() -{ - if (status() == ExecContext::Halted) - return; - - _status = ExecContext::Halted; - cpu->haltContext(thread_num); -} - - -void -CPUExecContext::regStats(const string &name) -{ -#if FULL_SYSTEM - if (kernelStats) - kernelStats->regStats(name + ".kern"); -#endif -} - -void -CPUExecContext::copyArchRegs(ExecContext *xc) -{ - // First loop through the integer registers. - for (int i = 0; i < AlphaISA::NumIntRegs; ++i) { - setIntReg(i, xc->readIntReg(i)); - } - - // Then loop through the floating point registers. - for (int i = 0; i < AlphaISA::NumFloatRegs; ++i) { - setFloatRegDouble(i, xc->readFloatRegDouble(i)); - setFloatRegInt(i, xc->readFloatRegInt(i)); - } - - // Copy misc. registers - regs.miscRegs.copyMiscRegs(xc); - - // Lastly copy PC/NPC - setPC(xc->readPC()); - setNextPC(xc->readNextPC()); -} - diff --git a/cpu/cpu_exec_context.hh b/cpu/cpu_exec_context.hh deleted file mode 100644 index 061fe450a..000000000 --- a/cpu/cpu_exec_context.hh +++ /dev/null @@ -1,524 +0,0 @@ -/* - * Copyright (c) 2001-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. - */ - -#ifndef __CPU_CPU_EXEC_CONTEXT_HH__ -#define __CPU_CPU_EXEC_CONTEXT_HH__ - -#include "arch/isa_traits.hh" -#include "config/full_system.hh" -#include "cpu/exec_context.hh" -#include "mem/functional/functional.hh" -#include "mem/mem_req.hh" -#include "sim/byteswap.hh" -#include "sim/eventq.hh" -#include "sim/host.hh" -#include "sim/serialize.hh" - -// forward declaration: see functional_memory.hh -class FunctionalMemory; -class PhysicalMemory; -class BaseCPU; - -#if FULL_SYSTEM - -#include "sim/system.hh" -#include "arch/tlb.hh" - -class FunctionProfile; -class ProfileNode; -class MemoryController; - -namespace Kernel { - class Statistics; -}; - -#else // !FULL_SYSTEM - -#include "sim/process.hh" - -#endif // FULL_SYSTEM - -// -// The CPUExecContext object represents a functional context for -// instruction execution. It incorporates everything required for -// architecture-level functional simulation of a single thread. -// - -class CPUExecContext -{ - protected: - typedef TheISA::RegFile RegFile; - typedef TheISA::MachInst MachInst; - typedef TheISA::MiscRegFile MiscRegFile; - typedef TheISA::MiscReg MiscReg; - public: - typedef ExecContext::Status Status; - - private: - Status _status; - - public: - Status status() const { return _status; } - - void setStatus(Status newStatus) { _status = newStatus; } - - /// 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(); - - /// Set the status to Unallocated. - void deallocate(); - - /// Set the status to Halted. - void halt(); - - protected: - RegFile regs; // correct-path register context - - public: - // pointer to CPU associated with this context - BaseCPU *cpu; - - ProxyExecContext<CPUExecContext> *proxy; - - // Current instruction - MachInst inst; - - // Index of hardware thread context on the CPU that this represents. - int thread_num; - - // ID of this context w.r.t. the System or Process object to which - // it belongs. For full-system mode, this is the system CPU ID. - int cpu_id; - - Tick lastActivate; - Tick lastSuspend; - -#if FULL_SYSTEM - FunctionalMemory *mem; - AlphaITB *itb; - AlphaDTB *dtb; - System *system; - - // the following two fields are redundant, since we can always - // look them up through the system pointer, but we'll leave them - // here for now for convenience - MemoryController *memctrl; - PhysicalMemory *physmem; - - FunctionProfile *profile; - ProfileNode *profileNode; - Addr profilePC; - void dumpFuncProfile(); - - EndQuiesceEvent *quiesceEvent; - - EndQuiesceEvent *getQuiesceEvent() { return quiesceEvent; } - - Tick readLastActivate() { return lastActivate; } - - Tick readLastSuspend() { return lastSuspend; } - - void profileClear(); - - void profileSample(); - - Kernel::Statistics *getKernelStats() { return kernelStats; } - - Kernel::Statistics *kernelStats; -#else - Process *process; - - FunctionalMemory *mem; // functional storage for process address space - - // Address space ID. Note that this is used for TIMING cache - // simulation only; all functional memory accesses should use - // one of the FunctionalMemory pointers above. - short asid; - -#endif - - /** - * Temporary storage to pass the source address from copy_load to - * copy_store. - * @todo Remove this temporary when we have a better way to do it. - */ - Addr copySrcAddr; - /** - * Temp storage for the physical source address of a copy. - * @todo Remove this temporary when we have a better way to do it. - */ - Addr copySrcPhysAddr; - - - /* - * number of executed instructions, for matching with syscall trace - * points in EIO files. - */ - Counter func_exe_inst; - - // - // Count failed store conditionals so we can warn of apparent - // application deadlock situations. - unsigned storeCondFailures; - - // constructor: initialize context from given process structure -#if FULL_SYSTEM - CPUExecContext(BaseCPU *_cpu, int _thread_num, System *_system, - AlphaITB *_itb, AlphaDTB *_dtb, FunctionalMemory *_mem, - bool use_kernel_stats = true); -#else - CPUExecContext(BaseCPU *_cpu, int _thread_num, Process *_process, int _asid); - CPUExecContext(BaseCPU *_cpu, int _thread_num, FunctionalMemory *_mem, - int _asid); - // Constructor to use XC to pass reg file around. Not used for anything - // else. - CPUExecContext(RegFile *regFile); -#endif - virtual ~CPUExecContext(); - - virtual void takeOverFrom(ExecContext *oldContext); - - void regStats(const std::string &name); - - void serialize(std::ostream &os); - void unserialize(Checkpoint *cp, const std::string §ion); - - BaseCPU *getCpuPtr() { return cpu; } - - ExecContext *getProxy() { return proxy; } - - int getThreadNum() { return thread_num; } - -#if FULL_SYSTEM - System *getSystemPtr() { return system; } - - PhysicalMemory *getPhysMemPtr() { return physmem; } - - AlphaITB *getITBPtr() { return itb; } - - AlphaDTB *getDTBPtr() { return dtb; } - - bool validInstAddr(Addr addr) { return true; } - bool validDataAddr(Addr addr) { return true; } - int getInstAsid() { return regs.instAsid(); } - int getDataAsid() { return regs.dataAsid(); } - - Fault translateInstReq(MemReqPtr &req) - { - return itb->translate(req); - } - - Fault translateDataReadReq(MemReqPtr &req) - { - return dtb->translate(req, false); - } - - Fault translateDataWriteReq(MemReqPtr &req) - { - return dtb->translate(req, true); - } - -#else - Process *getProcessPtr() { return process; } - - bool validInstAddr(Addr addr) - { return process->validInstAddr(addr); } - - bool validDataAddr(Addr addr) - { return process->validDataAddr(addr); } - - int getInstAsid() { return asid; } - int getDataAsid() { return asid; } - - Fault dummyTranslation(MemReqPtr &req) - { -#if 0 - assert((req->vaddr >> 48 & 0xffff) == 0); -#endif - - // put the asid in the upper 16 bits of the paddr - req->paddr = req->vaddr & ~((Addr)0xffff << sizeof(Addr) * 8 - 16); - req->paddr = req->paddr | (Addr)req->asid << sizeof(Addr) * 8 - 16; - return NoFault; - } - Fault translateInstReq(MemReqPtr &req) - { - return dummyTranslation(req); - } - Fault translateDataReadReq(MemReqPtr &req) - { - return dummyTranslation(req); - } - Fault translateDataWriteReq(MemReqPtr &req) - { - return dummyTranslation(req); - } - -#endif - - template <class T> - Fault read(MemReqPtr &req, T &data) - { -#if FULL_SYSTEM && defined(TARGET_ALPHA) - if (req->flags & LOCKED) { - req->xc->setMiscReg(TheISA::Lock_Addr_DepTag, req->paddr); - req->xc->setMiscReg(TheISA::Lock_Flag_DepTag, true); - } -#endif - - Fault error; - error = mem->read(req, data); - data = LittleEndianGuest::gtoh(data); - return error; - } - - template <class T> - Fault write(MemReqPtr &req, T &data) - { -#if FULL_SYSTEM && defined(TARGET_ALPHA) - ExecContext *xc; - - // If this is a store conditional, act appropriately - if (req->flags & LOCKED) { - xc = req->xc; - - if (req->flags & UNCACHEABLE) { - // Don't update result register (see stq_c in isa_desc) - req->result = 2; - xc->setStCondFailures(0);//Needed? [RGD] - } else { - bool lock_flag = xc->readMiscReg(TheISA::Lock_Flag_DepTag); - Addr lock_addr = xc->readMiscReg(TheISA::Lock_Addr_DepTag); - req->result = lock_flag; - if (!lock_flag || - ((lock_addr & ~0xf) != (req->paddr & ~0xf))) { - xc->setMiscReg(TheISA::Lock_Flag_DepTag, false); - xc->setStCondFailures(xc->readStCondFailures() + 1); - if (((xc->readStCondFailures()) % 100000) == 0) { - std::cerr << "Warning: " - << xc->readStCondFailures() - << " consecutive store conditional failures " - << "on cpu " << req->xc->readCpuId() - << std::endl; - } - return NoFault; - } - else xc->setStCondFailures(0); - } - } - - // Need to clear any locked flags on other proccessors for - // this address. Only do this for succsful Store Conditionals - // and all other stores (WH64?). Unsuccessful Store - // Conditionals would have returned above, and wouldn't fall - // through. - for (int i = 0; i < system->execContexts.size(); i++){ - xc = system->execContexts[i]; - if ((xc->readMiscReg(TheISA::Lock_Addr_DepTag) & ~0xf) == - (req->paddr & ~0xf)) { - xc->setMiscReg(TheISA::Lock_Flag_DepTag, false); - } - } - -#endif - return mem->write(req, (T)LittleEndianGuest::htog(data)); - } - - virtual bool misspeculating(); - - - MachInst getInst() { return inst; } - - void setInst(MachInst new_inst) - { - inst = new_inst; - } - - Fault instRead(MemReqPtr &req) - { - return mem->read(req, inst); - } - - void setCpuId(int id) { cpu_id = id; } - - int readCpuId() { return cpu_id; } - - FunctionalMemory *getMemPtr() { return mem; } - - void copyArchRegs(ExecContext *xc); - - // - // New accessors for new decoder. - // - uint64_t readIntReg(int reg_idx) - { - return regs.intRegFile[reg_idx]; - } - - float readFloatRegSingle(int reg_idx) - { - return (float)regs.floatRegFile.d[reg_idx]; - } - - double readFloatRegDouble(int reg_idx) - { - return regs.floatRegFile.d[reg_idx]; - } - - uint64_t readFloatRegInt(int reg_idx) - { - return regs.floatRegFile.q[reg_idx]; - } - - void setIntReg(int reg_idx, uint64_t val) - { - regs.intRegFile[reg_idx] = val; - } - - void setFloatRegSingle(int reg_idx, float val) - { - regs.floatRegFile.d[reg_idx] = (double)val; - } - - void setFloatRegDouble(int reg_idx, double val) - { - regs.floatRegFile.d[reg_idx] = val; - } - - void setFloatRegInt(int reg_idx, uint64_t val) - { - regs.floatRegFile.q[reg_idx] = val; - } - - uint64_t readPC() - { - return regs.pc; - } - - void setPC(uint64_t val) - { - regs.pc = val; - } - - uint64_t readNextPC() - { - return regs.npc; - } - - void setNextPC(uint64_t val) - { - regs.npc = val; - } - - uint64_t readNextNPC() - { - return regs.nnpc; - } - - void setNextNPC(uint64_t val) - { - regs.nnpc = val; - } - - - MiscReg readMiscReg(int misc_reg) - { - return regs.miscRegs.readReg(misc_reg); - } - - MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) - { - return regs.miscRegs.readRegWithEffect(misc_reg, fault, proxy); - } - - Fault setMiscReg(int misc_reg, const MiscReg &val) - { - return regs.miscRegs.setReg(misc_reg, val); - } - - Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) - { - return regs.miscRegs.setRegWithEffect(misc_reg, val, proxy); - } - - unsigned readStCondFailures() { return storeCondFailures; } - - void setStCondFailures(unsigned sc_failures) - { storeCondFailures = sc_failures; } - - void clearArchRegs() { memset(®s, 0, sizeof(regs)); } - -#if FULL_SYSTEM - int readIntrFlag() { return regs.intrflag; } - void setIntrFlag(int val) { regs.intrflag = val; } - Fault hwrei(); - bool inPalMode() { return AlphaISA::PcPAL(regs.pc); } - bool simPalCheck(int palFunc); -#endif - -#if !FULL_SYSTEM - TheISA::IntReg getSyscallArg(int i) - { - return regs.intRegFile[TheISA::ArgumentReg0 + i]; - } - - // used to shift args for indirect syscall - void setSyscallArg(int i, TheISA::IntReg val) - { - regs.intRegFile[TheISA::ArgumentReg0 + i] = val; - } - - void setSyscallReturn(SyscallReturn return_value) - { - TheISA::setSyscallReturn(return_value, ®s); - } - - void syscall() - { - process->syscall(proxy); - } - - Counter readFuncExeInst() { return func_exe_inst; } - - void setFuncExeInst(Counter new_val) { func_exe_inst = new_val; } -#endif -}; - - -// for non-speculative execution context, spec_mode is always false -inline bool -CPUExecContext::misspeculating() -{ - return false; -} - -#endif // __CPU_CPU_EXEC_CONTEXT_HH__ diff --git a/cpu/cpu_models.py b/cpu/cpu_models.py deleted file mode 100644 index 2b1ae6277..000000000 --- a/cpu/cpu_models.py +++ /dev/null @@ -1,80 +0,0 @@ -# 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. - -################ -# CpuModel class -# -# The CpuModel class encapsulates everything the ISA parser needs to -# know about a particular CPU model. - -class CpuModel: - # Dict of available CPU model objects. Accessible as CpuModel.dict. - dict = {} - - # Constructor. Automatically adds models to CpuModel.dict. - def __init__(self, name, filename, includes, strings): - self.name = name - self.filename = filename # filename for output exec code - self.includes = includes # include files needed in exec file - # The 'strings' dict holds all the per-CPU symbols we can - # substitute into templates etc. - self.strings = strings - # Add self to dict - CpuModel.dict[name] = self - - -# -# Define CPU models. -# -# Parameters are: -# - name of model -# - filename for generated ISA execution file -# - includes needed for generated ISA execution file -# - substitution strings for ISA description templates -# - -CpuModel('SimpleCPU', 'simple_cpu_exec.cc', - '#include "cpu/simple/cpu.hh"', - { 'CPU_exec_context': 'SimpleCPU' }) -CpuModel('FastCPU', 'fast_cpu_exec.cc', - '#include "cpu/fast/cpu.hh"', - { 'CPU_exec_context': 'FastCPU' }) -CpuModel('FullCPU', 'full_cpu_exec.cc', - '#include "encumbered/cpu/full/dyn_inst.hh"', - { 'CPU_exec_context': 'DynInst' }) -CpuModel('AlphaFullCPU', 'alpha_o3_exec.cc', - '#include "cpu/o3/alpha_dyn_inst.hh"', - { 'CPU_exec_context': 'AlphaDynInst<AlphaSimpleImpl>' }) -CpuModel('OzoneSimpleCPU', 'ozone_simple_exec.cc', - '#include "cpu/ozone/dyn_inst.hh"', - { 'CPU_exec_context': 'OzoneDynInst<SimpleImpl>' }) -CpuModel('OzoneCPU', 'ozone_exec.cc', - '#include "cpu/ozone/dyn_inst.hh"', - { 'CPU_exec_context': 'OzoneDynInst<OzoneImpl>' }) -CpuModel('CheckerCPU', 'checker_cpu_exec.cc', - '#include "cpu/checker/cpu.hh"', - { 'CPU_exec_context': 'CheckerCPU' }) - diff --git a/cpu/exec_context.hh b/cpu/exec_context.hh deleted file mode 100644 index e1f1016e5..000000000 --- a/cpu/exec_context.hh +++ /dev/null @@ -1,382 +0,0 @@ -/* - * Copyright (c) 2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_EXEC_CONTEXT_HH__ -#define __CPU_EXEC_CONTEXT_HH__ - -#include "config/full_system.hh" -#include "mem/mem_req.hh" -#include "sim/faults.hh" -#include "sim/host.hh" -#include "sim/serialize.hh" -#include "sim/byteswap.hh" - -// forward declaration: see functional_memory.hh -// @todo: Figure out a more architecture independent way to obtain the ITB and -// DTB pointers. -class AlphaDTB; -class AlphaITB; -class BaseCPU; -class EndQuiesceEvent; -class Event; -class FunctionalMemory; -class PhysicalMemory; -class Process; -class System; -namespace Kernel { - class Statistics; -}; - -class ExecContext -{ - protected: - typedef TheISA::RegFile RegFile; - typedef TheISA::MachInst MachInst; - typedef TheISA::IntReg IntReg; - typedef TheISA::MiscRegFile MiscRegFile; - typedef TheISA::MiscReg MiscReg; - public: - enum Status - { - /// Initialized but not running yet. All CPUs start in - /// this state, but most transition to Active on cycle 1. - /// In MP or SMT systems, non-primary contexts will stay - /// in this state until a thread is assigned to them. - Unallocated, - - /// Running. Instructions should be executed only when - /// the context is in this state. - Active, - - /// Temporarily inactive. Entered while waiting for - /// synchronization, etc. - Suspended, - - /// Permanently shut down. Entered when target executes - /// m5exit pseudo-instruction. When all contexts enter - /// this state, the simulation will terminate. - Halted - }; - - virtual ~ExecContext() { }; - - virtual BaseCPU *getCpuPtr() = 0; - - virtual void setCpuId(int id) = 0; - - virtual int readCpuId() = 0; - - virtual FunctionalMemory *getMemPtr() = 0; - -#if FULL_SYSTEM - virtual System *getSystemPtr() = 0; - - virtual PhysicalMemory *getPhysMemPtr() = 0; - - virtual AlphaITB *getITBPtr() = 0; - - virtual AlphaDTB * getDTBPtr() = 0; - - virtual Kernel::Statistics *getKernelStats() = 0; -#else - virtual Process *getProcessPtr() = 0; -#endif - - virtual Status status() const = 0; - - virtual void setStatus(Status new_status) = 0; - - /// Set the status to Active. Optional delay indicates number of - /// cycles to wait before beginning execution. - virtual void activate(int delay = 1) = 0; - - /// Set the status to Suspended. - virtual void suspend() = 0; - - /// Set the status to Unallocated. - virtual void deallocate() = 0; - - /// Set the status to Halted. - virtual void halt() = 0; - -#if FULL_SYSTEM - virtual void dumpFuncProfile() = 0; -#endif - - virtual void takeOverFrom(ExecContext *old_context) = 0; - - virtual void regStats(const std::string &name) = 0; - - virtual void serialize(std::ostream &os) = 0; - virtual void unserialize(Checkpoint *cp, const std::string §ion) = 0; - -#if FULL_SYSTEM - virtual EndQuiesceEvent *getQuiesceEvent() = 0; - - // Not necessarily the best location for these... - // Having an extra function just to read these is obnoxious - virtual Tick readLastActivate() = 0; - virtual Tick readLastSuspend() = 0; - - virtual void profileClear() = 0; - virtual void profileSample() = 0; -#endif - - virtual int getThreadNum() = 0; - - // Also somewhat obnoxious. Really only used for the TLB fault. - // However, may be quite useful in SPARC. - virtual TheISA::MachInst getInst() = 0; - - virtual void copyArchRegs(ExecContext *xc) = 0; - - virtual void clearArchRegs() = 0; - - // - // New accessors for new decoder. - // - virtual uint64_t readIntReg(int reg_idx) = 0; - - virtual float readFloatRegSingle(int reg_idx) = 0; - - virtual double readFloatRegDouble(int reg_idx) = 0; - - virtual uint64_t readFloatRegInt(int reg_idx) = 0; - - virtual void setIntReg(int reg_idx, uint64_t val) = 0; - - virtual void setFloatRegSingle(int reg_idx, float val) = 0; - - virtual void setFloatRegDouble(int reg_idx, double val) = 0; - - virtual void setFloatRegInt(int reg_idx, uint64_t val) = 0; - - virtual uint64_t readPC() = 0; - - virtual void setPC(uint64_t val) = 0; - - virtual uint64_t readNextPC() = 0; - - virtual void setNextPC(uint64_t val) = 0; - - virtual MiscReg readMiscReg(int misc_reg) = 0; - - virtual MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) = 0; - - virtual Fault setMiscReg(int misc_reg, const MiscReg &val) = 0; - - virtual Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) = 0; - - // Also not necessarily the best location for these two. Hopefully will go - // away once we decide upon where st cond failures goes. - virtual unsigned readStCondFailures() = 0; - - virtual void setStCondFailures(unsigned sc_failures) = 0; - -#if FULL_SYSTEM - virtual bool inPalMode() = 0; -#endif - - // Only really makes sense for old CPU model. Still could be useful though. - virtual bool misspeculating() = 0; - -#if !FULL_SYSTEM - virtual IntReg getSyscallArg(int i) = 0; - - // used to shift args for indirect syscall - virtual void setSyscallArg(int i, IntReg val) = 0; - - virtual void setSyscallReturn(SyscallReturn return_value) = 0; - -// virtual void syscall() = 0; - - // Same with st cond failures. - virtual Counter readFuncExeInst() = 0; -#endif -}; - -template <class XC> -class ProxyExecContext : public ExecContext -{ - public: - ProxyExecContext(XC *actual_xc) - { actualXC = actual_xc; } - - private: - XC *actualXC; - - public: - - BaseCPU *getCpuPtr() { return actualXC->getCpuPtr(); } - - void setCpuId(int id) { actualXC->setCpuId(id); } - - int readCpuId() { return actualXC->readCpuId(); } - - FunctionalMemory *getMemPtr() { return actualXC->getMemPtr(); } - -#if FULL_SYSTEM - System *getSystemPtr() { return actualXC->getSystemPtr(); } - - PhysicalMemory *getPhysMemPtr() { return actualXC->getPhysMemPtr(); } - - AlphaITB *getITBPtr() { return actualXC->getITBPtr(); } - - AlphaDTB *getDTBPtr() { return actualXC->getDTBPtr(); } - - Kernel::Statistics *getKernelStats() { return actualXC->getKernelStats(); } -#else - Process *getProcessPtr() { return actualXC->getProcessPtr(); } -#endif - - Status status() const { return actualXC->status(); } - - void setStatus(Status new_status) { actualXC->setStatus(new_status); } - - /// Set the status to Active. Optional delay indicates number of - /// cycles to wait before beginning execution. - void activate(int delay = 1) { actualXC->activate(delay); } - - /// Set the status to Suspended. - void suspend() { actualXC->suspend(); } - - /// Set the status to Unallocated. - void deallocate() { actualXC->deallocate(); } - - /// Set the status to Halted. - void halt() { actualXC->halt(); } - -#if FULL_SYSTEM - void dumpFuncProfile() { actualXC->dumpFuncProfile(); } -#endif - - void takeOverFrom(ExecContext *oldContext) - { actualXC->takeOverFrom(oldContext); } - - void regStats(const std::string &name) { actualXC->regStats(name); } - - void serialize(std::ostream &os) { actualXC->serialize(os); } - void unserialize(Checkpoint *cp, const std::string §ion) - { actualXC->unserialize(cp, section); } - -#if FULL_SYSTEM - EndQuiesceEvent *getQuiesceEvent() { return actualXC->getQuiesceEvent(); } - - Tick readLastActivate() { return actualXC->readLastActivate(); } - Tick readLastSuspend() { return actualXC->readLastSuspend(); } - - void profileClear() { return actualXC->profileClear(); } - void profileSample() { return actualXC->profileSample(); } -#endif - - int getThreadNum() { return actualXC->getThreadNum(); } - - // @todo: Do I need this? - MachInst getInst() { return actualXC->getInst(); } - - // @todo: Do I need this? - void copyArchRegs(ExecContext *xc) { actualXC->copyArchRegs(xc); } - - void clearArchRegs() { actualXC->clearArchRegs(); } - - // - // New accessors for new decoder. - // - uint64_t readIntReg(int reg_idx) - { return actualXC->readIntReg(reg_idx); } - - float readFloatRegSingle(int reg_idx) - { return actualXC->readFloatRegSingle(reg_idx); } - - double readFloatRegDouble(int reg_idx) - { return actualXC->readFloatRegDouble(reg_idx); } - - uint64_t readFloatRegInt(int reg_idx) - { return actualXC->readFloatRegInt(reg_idx); } - - void setIntReg(int reg_idx, uint64_t val) - { actualXC->setIntReg(reg_idx, val); } - - void setFloatRegSingle(int reg_idx, float val) - { actualXC->setFloatRegSingle(reg_idx, val); } - - void setFloatRegDouble(int reg_idx, double val) - { actualXC->setFloatRegDouble(reg_idx, val); } - - void setFloatRegInt(int reg_idx, uint64_t val) - { actualXC->setFloatRegInt(reg_idx, val); } - - uint64_t readPC() { return actualXC->readPC(); } - - void setPC(uint64_t val) { actualXC->setPC(val); } - - uint64_t readNextPC() { return actualXC->readNextPC(); } - - void setNextPC(uint64_t val) { actualXC->setNextPC(val); } - - MiscReg readMiscReg(int misc_reg) - { return actualXC->readMiscReg(misc_reg); } - - MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) - { return actualXC->readMiscRegWithEffect(misc_reg, fault); } - - Fault setMiscReg(int misc_reg, const MiscReg &val) - { return actualXC->setMiscReg(misc_reg, val); } - - Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) - { return actualXC->setMiscRegWithEffect(misc_reg, val); } - - unsigned readStCondFailures() - { return actualXC->readStCondFailures(); } - - void setStCondFailures(unsigned sc_failures) - { actualXC->setStCondFailures(sc_failures); } -#if FULL_SYSTEM - bool inPalMode() { return actualXC->inPalMode(); } -#endif - - // @todo: Fix this! - bool misspeculating() { return actualXC->misspeculating(); } - -#if !FULL_SYSTEM - IntReg getSyscallArg(int i) { return actualXC->getSyscallArg(i); } - - // used to shift args for indirect syscall - void setSyscallArg(int i, IntReg val) - { actualXC->setSyscallArg(i, val); } - - void setSyscallReturn(SyscallReturn return_value) - { actualXC->setSyscallReturn(return_value); } - -// void syscall() { actualXC->syscall(); } - - Counter readFuncExeInst() { return actualXC->readFuncExeInst(); } -#endif -}; - -#endif diff --git a/cpu/exetrace.cc b/cpu/exetrace.cc deleted file mode 100644 index d5eacd839..000000000 --- a/cpu/exetrace.cc +++ /dev/null @@ -1,231 +0,0 @@ -/* - * 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. - */ - -#include <fstream> -#include <iomanip> - -#include "sim/param.hh" -#include "encumbered/cpu/full/dyn_inst.hh" -#include "encumbered/cpu/full/spec_state.hh" -#include "encumbered/cpu/full/issue.hh" -#include "cpu/exetrace.hh" -#include "base/loader/symtab.hh" -#include "cpu/base.hh" -#include "cpu/static_inst.hh" - -using namespace std; - - -//////////////////////////////////////////////////////////////////////// -// -// Methods for the InstRecord object -// - - -void -Trace::InstRecord::dump(ostream &outs) -{ - if (flags[INTEL_FORMAT]) { -#if FULL_SYSTEM - bool is_trace_system = (cpu->system->name() == trace_system); -#else - bool is_trace_system = true; -#endif - if (is_trace_system) { - ccprintf(outs, "%7d ) ", cycle); - outs << "0x" << hex << PC << ":\t"; - if (staticInst->isLoad()) { - outs << "<RD 0x" << hex << addr; - outs << ">"; - } else if (staticInst->isStore()) { - outs << "<WR 0x" << hex << addr; - outs << ">"; - } - outs << endl; - } - } else { - if (flags[PRINT_CYCLE]) - ccprintf(outs, "%7d: ", cycle); - - outs << cpu->name() << " "; - - if (flags[TRACE_MISSPEC]) - outs << (misspeculating ? "-" : "+") << " "; - - if (flags[PRINT_THREAD_NUM]) - outs << "T" << thread << " : "; - - - std::string sym_str; - Addr sym_addr; - if (debugSymbolTable - && debugSymbolTable->findNearestSymbol(PC, sym_str, sym_addr) - && flags[PC_SYMBOL]) { - if (PC != sym_addr) - sym_str += csprintf("+%d", PC - sym_addr); - outs << "@" << sym_str << " : "; - } - else { - outs << "0x" << hex << PC << " : "; - } - - // - // Print decoded instruction - // - -#if defined(__GNUC__) && (__GNUC__ < 3) - // There's a bug in gcc 2.x library that prevents setw() - // from working properly on strings - string mc(staticInst->disassemble(PC, debugSymbolTable)); - while (mc.length() < 26) - mc += " "; - outs << mc; -#else - outs << setw(26) << left << staticInst->disassemble(PC, debugSymbolTable); -#endif - - outs << " : "; - - if (flags[PRINT_OP_CLASS]) { - outs << opClassStrings[staticInst->opClass()] << " : "; - } - - if (flags[PRINT_RESULT_DATA] && data_status != DataInvalid) { - outs << " D="; -#if 0 - if (data_status == DataDouble) - ccprintf(outs, "%f", data.as_double); - else - ccprintf(outs, "%#018x", data.as_int); -#else - ccprintf(outs, "%#018x", data.as_int); -#endif - } - - if (flags[PRINT_EFF_ADDR] && addr_valid) - outs << " A=0x" << hex << addr; - - if (flags[PRINT_INT_REGS] && regs_valid) { - for (int i = 0; i < 32;) - for (int j = i + 1; i <= j; i++) - ccprintf(outs, "r%02d = %#018x%s", i, iregs->regs[i], - ((i == j) ? "\n" : " ")); - outs << "\n"; - } - - if (flags[PRINT_FETCH_SEQ] && fetch_seq_valid) - outs << " FetchSeq=" << dec << fetch_seq; - - if (flags[PRINT_CP_SEQ] && cp_seq_valid) - outs << " CPSeq=" << dec << cp_seq; - - // - // End of line... - // - outs << endl; - } -} - - -vector<bool> Trace::InstRecord::flags(NUM_BITS); -string Trace::InstRecord::trace_system; - -//////////////////////////////////////////////////////////////////////// -// -// Parameter space for per-cycle execution address tracing options. -// Derive from ParamContext so we can override checkParams() function. -// -class ExecutionTraceParamContext : public ParamContext -{ - public: - ExecutionTraceParamContext(const string &_iniSection) - : ParamContext(_iniSection) - { - } - - void checkParams(); // defined at bottom of file -}; - -ExecutionTraceParamContext exeTraceParams("exetrace"); - -Param<bool> exe_trace_spec(&exeTraceParams, "speculative", - "capture speculative instructions", true); - -Param<bool> exe_trace_print_cycle(&exeTraceParams, "print_cycle", - "print cycle number", true); -Param<bool> exe_trace_print_opclass(&exeTraceParams, "print_opclass", - "print op class", true); -Param<bool> exe_trace_print_thread(&exeTraceParams, "print_thread", - "print thread number", true); -Param<bool> exe_trace_print_effaddr(&exeTraceParams, "print_effaddr", - "print effective address", true); -Param<bool> exe_trace_print_data(&exeTraceParams, "print_data", - "print result data", true); -Param<bool> exe_trace_print_iregs(&exeTraceParams, "print_iregs", - "print all integer regs", false); -Param<bool> exe_trace_print_fetchseq(&exeTraceParams, "print_fetchseq", - "print fetch sequence number", false); -Param<bool> exe_trace_print_cp_seq(&exeTraceParams, "print_cpseq", - "print correct-path sequence number", false); -Param<bool> exe_trace_pc_symbol(&exeTraceParams, "pc_symbol", - "Use symbols for the PC if available", true); -Param<bool> exe_trace_intel_format(&exeTraceParams, "intel_format", - "print trace in intel compatible format", false); -Param<string> exe_trace_system(&exeTraceParams, "trace_system", - "print trace of which system (client or server)", - "client"); - - -// -// Helper function for ExecutionTraceParamContext::checkParams() just -// to get us into the InstRecord namespace -// -void -Trace::InstRecord::setParams() -{ - flags[TRACE_MISSPEC] = exe_trace_spec; - - flags[PRINT_CYCLE] = exe_trace_print_cycle; - flags[PRINT_OP_CLASS] = exe_trace_print_opclass; - flags[PRINT_THREAD_NUM] = exe_trace_print_thread; - flags[PRINT_RESULT_DATA] = exe_trace_print_effaddr; - flags[PRINT_EFF_ADDR] = exe_trace_print_data; - flags[PRINT_INT_REGS] = exe_trace_print_iregs; - flags[PRINT_FETCH_SEQ] = exe_trace_print_fetchseq; - flags[PRINT_CP_SEQ] = exe_trace_print_cp_seq; - flags[PC_SYMBOL] = exe_trace_pc_symbol; - flags[INTEL_FORMAT] = exe_trace_intel_format; - trace_system = exe_trace_system; -} - -void -ExecutionTraceParamContext::checkParams() -{ - Trace::InstRecord::setParams(); -} - diff --git a/cpu/exetrace.hh b/cpu/exetrace.hh deleted file mode 100644 index 2f70e26e7..000000000 --- a/cpu/exetrace.hh +++ /dev/null @@ -1,189 +0,0 @@ -/* - * 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. - */ - -#ifndef __EXETRACE_HH__ -#define __EXETRACE_HH__ - -#include <fstream> -#include <vector> - -#include "sim/host.hh" -#include "cpu/inst_seq.hh" // for InstSeqNum -#include "base/trace.hh" -#include "cpu/exec_context.hh" -#include "cpu/static_inst.hh" - -class BaseCPU; - - -namespace Trace { - -class InstRecord : public Record -{ - protected: - typedef TheISA::IntRegFile IntRegFile; - - // The following fields are initialized by the constructor and - // thus guaranteed to be valid. - BaseCPU *cpu; - // need to make this ref-counted so it doesn't go away before we - // dump the record - StaticInstPtr staticInst; - Addr PC; - bool misspeculating; - unsigned thread; - - // The remaining fields are only valid for particular instruction - // types (e.g, addresses for memory ops) or when particular - // options are enabled (e.g., tracing full register contents). - // Each data field has an associated valid flag to indicate - // whether the data field is valid. - Addr addr; - bool addr_valid; - - union { - uint64_t as_int; - double as_double; - } data; - enum { - DataInvalid = 0, - DataInt8 = 1, // set to equal number of bytes - DataInt16 = 2, - DataInt32 = 4, - DataInt64 = 8, - DataDouble = 3 - } data_status; - - InstSeqNum fetch_seq; - bool fetch_seq_valid; - - InstSeqNum cp_seq; - bool cp_seq_valid; - - struct iRegFile { - IntRegFile regs; - }; - iRegFile *iregs; - bool regs_valid; - - public: - InstRecord(Tick _cycle, BaseCPU *_cpu, - const StaticInstPtr &_staticInst, - Addr _pc, bool spec, int _thread) - : Record(_cycle), cpu(_cpu), staticInst(_staticInst), PC(_pc), - misspeculating(spec), thread(_thread) - { - data_status = DataInvalid; - addr_valid = false; - regs_valid = false; - - fetch_seq_valid = false; - cp_seq_valid = false; - } - - virtual ~InstRecord() { } - - virtual void dump(std::ostream &outs); - - void setAddr(Addr a) { addr = a; addr_valid = true; } - - void setData(uint64_t d) { data.as_int = d; data_status = DataInt64; } - void setData(uint32_t d) { data.as_int = d; data_status = DataInt32; } - void setData(uint16_t d) { data.as_int = d; data_status = DataInt16; } - void setData(uint8_t d) { data.as_int = d; data_status = DataInt8; } - - void setData(int64_t d) { setData((uint64_t)d); } - void setData(int32_t d) { setData((uint32_t)d); } - void setData(int16_t d) { setData((uint16_t)d); } - void setData(int8_t d) { setData((uint8_t)d); } - - void setData(double d) { data.as_double = d; data_status = DataDouble; } - - void setFetchSeq(InstSeqNum seq) - { fetch_seq = seq; fetch_seq_valid = true; } - - void setCPSeq(InstSeqNum seq) - { cp_seq = seq; cp_seq_valid = true; } - - void setRegs(const IntRegFile ®s); - - void finalize() { theLog.append(this); } - - enum InstExecFlagBits { - TRACE_MISSPEC = 0, - PRINT_CYCLE, - PRINT_OP_CLASS, - PRINT_THREAD_NUM, - PRINT_RESULT_DATA, - PRINT_EFF_ADDR, - PRINT_INT_REGS, - PRINT_FETCH_SEQ, - PRINT_CP_SEQ, - PC_SYMBOL, - INTEL_FORMAT, - NUM_BITS - }; - - static std::vector<bool> flags; - static std::string trace_system; - - static void setParams(); - - static bool traceMisspec() { return flags[TRACE_MISSPEC]; } -}; - - -inline void -InstRecord::setRegs(const IntRegFile ®s) -{ - if (!iregs) - iregs = new iRegFile; - - memcpy(&iregs->regs, regs, sizeof(IntRegFile)); - regs_valid = true; -} - -inline -InstRecord * -getInstRecord(Tick cycle, ExecContext *xc, BaseCPU *cpu, - const StaticInstPtr staticInst, - Addr pc, int thread = 0) -{ - if (DTRACE(InstExec) && - (InstRecord::traceMisspec() || !xc->misspeculating())) { - return new InstRecord(cycle, cpu, staticInst, pc, - xc->misspeculating(), thread); - } - - return NULL; -} - - -} - -#endif // __EXETRACE_HH__ diff --git a/cpu/inst_seq.hh b/cpu/inst_seq.hh deleted file mode 100644 index 356d19df0..000000000 --- a/cpu/inst_seq.hh +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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. - */ - -#ifndef __STD_TYPES_HH__ -#define __STD_TYPES_HH__ - -#include <stdint.h> - -// 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__ diff --git a/cpu/intr_control.cc b/cpu/intr_control.cc deleted file mode 100644 index 43e7f654c..000000000 --- a/cpu/intr_control.cc +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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. - */ - -#include <string> -#include <vector> - -#include "cpu/base.hh" -#include "cpu/exec_context.hh" -#include "cpu/intr_control.hh" -#include "sim/builder.hh" -#include "sim/sim_object.hh" - -using namespace std; - -IntrControl::IntrControl(const string &name, BaseCPU *c) - : SimObject(name), cpu(c) -{} - -/* @todo - *Fix the cpu sim object parameter to be a system pointer - *instead, to avoid some extra dereferencing - */ -void -IntrControl::post(int int_num, int index) -{ - std::vector<ExecContext *> &xcvec = cpu->system->execContexts; - BaseCPU *temp = xcvec[0]->getCpuPtr(); - temp->post_interrupt(int_num, index); -} - -void -IntrControl::post(int cpu_id, int int_num, int index) -{ - std::vector<ExecContext *> &xcvec = cpu->system->execContexts; - BaseCPU *temp = xcvec[cpu_id]->getCpuPtr(); - temp->post_interrupt(int_num, index); -} - -void -IntrControl::clear(int int_num, int index) -{ - std::vector<ExecContext *> &xcvec = cpu->system->execContexts; - BaseCPU *temp = xcvec[0]->getCpuPtr(); - temp->clear_interrupt(int_num, index); -} - -void -IntrControl::clear(int cpu_id, int int_num, int index) -{ - std::vector<ExecContext *> &xcvec = cpu->system->execContexts; - BaseCPU *temp = xcvec[cpu_id]->getCpuPtr(); - temp->clear_interrupt(int_num, index); -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(IntrControl) - - SimObjectParam<BaseCPU *> cpu; - -END_DECLARE_SIM_OBJECT_PARAMS(IntrControl) - -BEGIN_INIT_SIM_OBJECT_PARAMS(IntrControl) - - INIT_PARAM(cpu, "the cpu") - -END_INIT_SIM_OBJECT_PARAMS(IntrControl) - -CREATE_SIM_OBJECT(IntrControl) -{ - return new IntrControl(getInstanceName(), cpu); -} - -REGISTER_SIM_OBJECT("IntrControl", IntrControl) diff --git a/cpu/intr_control.hh b/cpu/intr_control.hh deleted file mode 100644 index 5ec4e14cb..000000000 --- a/cpu/intr_control.hh +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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. - */ - -#ifndef __INTR_CONTROL_HH__ -#define __INTR_CONTROL_HH__ - -#include <vector> -#include "base/misc.hh" -#include "cpu/base.hh" -#include "sim/sim_object.hh" -#include "sim/system.hh" - - -class IntrControl : public SimObject -{ - public: - BaseCPU *cpu; - IntrControl(const std::string &name, BaseCPU *c); - - void clear(int int_num, int index = 0); - void post(int int_num, int index = 0); - void clear(int cpu_id, int int_num, int index); - void post(int cpu_id, int int_num, int index); -}; - -#endif // __INTR_CONTROL_HH__ - - - - - - - diff --git a/cpu/memtest/memtest.cc b/cpu/memtest/memtest.cc deleted file mode 100644 index 94b66b70b..000000000 --- a/cpu/memtest/memtest.cc +++ /dev/null @@ -1,441 +0,0 @@ -/* - * 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. - */ - -// FIX ME: make trackBlkAddr use blocksize from actual cache, not hard coded - -#include <iomanip> -#include <set> -#include <sstream> -#include <string> -#include <vector> - -#include "base/misc.hh" -#include "base/statistics.hh" -#include "cpu/cpu_exec_context.hh" -#include "cpu/memtest/memtest.hh" -#include "mem/cache/base_cache.hh" -#include "sim/builder.hh" -#include "sim/sim_events.hh" -#include "sim/stats.hh" - -using namespace std; -using namespace TheISA; - -int TESTER_ALLOCATOR=0; - -MemTest::MemTest(const string &name, - MemInterface *_cache_interface, - FunctionalMemory *main_mem, - FunctionalMemory *check_mem, - unsigned _memorySize, - unsigned _percentReads, - unsigned _percentCopies, - unsigned _percentUncacheable, - unsigned _progressInterval, - unsigned _percentSourceUnaligned, - unsigned _percentDestUnaligned, - Addr _traceAddr, - Counter _max_loads) - : SimObject(name), - tickEvent(this), - cacheInterface(_cache_interface), - mainMem(main_mem), - checkMem(check_mem), - size(_memorySize), - percentReads(_percentReads), - percentCopies(_percentCopies), - percentUncacheable(_percentUncacheable), - progressInterval(_progressInterval), - nextProgressMessage(_progressInterval), - percentSourceUnaligned(_percentSourceUnaligned), - percentDestUnaligned(percentDestUnaligned), - maxLoads(_max_loads) -{ - vector<string> cmd; - cmd.push_back("/bin/ls"); - vector<string> null_vec; - cpuXC = new CPUExecContext(NULL, 0, mainMem, 0); - - blockSize = cacheInterface->getBlockSize(); - blockAddrMask = blockSize - 1; - traceBlockAddr = blockAddr(_traceAddr); - - //setup data storage with interesting values - uint8_t *data1 = new uint8_t[size]; - uint8_t *data2 = new uint8_t[size]; - uint8_t *data3 = new uint8_t[size]; - memset(data1, 1, size); - memset(data2, 2, size); - memset(data3, 3, size); - curTick = 0; - - baseAddr1 = 0x100000; - baseAddr2 = 0x400000; - uncacheAddr = 0x800000; - - // set up intial memory contents here - mainMem->prot_write(baseAddr1, data1, size); - checkMem->prot_write(baseAddr1, data1, size); - mainMem->prot_write(baseAddr2, data2, size); - checkMem->prot_write(baseAddr2, data2, size); - mainMem->prot_write(uncacheAddr, data3, size); - checkMem->prot_write(uncacheAddr, data3, size); - - delete [] data1; - delete [] data2; - delete [] data3; - - // set up counters - noResponseCycles = 0; - numReads = 0; - tickEvent.schedule(0); - - id = TESTER_ALLOCATOR++; -} - -static void -printData(ostream &os, uint8_t *data, int nbytes) -{ - os << hex << setfill('0'); - // assume little-endian: print bytes from highest address to lowest - for (uint8_t *dp = data + nbytes - 1; dp >= data; --dp) { - os << setw(2) << (unsigned)*dp; - } - os << dec; -} - -void -MemTest::completeRequest(MemReqPtr &req, uint8_t *data) -{ - //Remove the address from the list of outstanding - std::set<unsigned>::iterator removeAddr = outstandingAddrs.find(req->paddr); - assert(removeAddr != outstandingAddrs.end()); - outstandingAddrs.erase(removeAddr); - - switch (req->cmd) { - case Read: - if (memcmp(req->data, data, req->size) != 0) { - cerr << name() << ": on read of 0x" << hex << req->paddr - << " (0x" << hex << blockAddr(req->paddr) << ")" - << "@ cycle " << dec << curTick - << ", cache returns 0x"; - printData(cerr, req->data, req->size); - cerr << ", expected 0x"; - printData(cerr, data, req->size); - cerr << endl; - fatal(""); - } - - numReads++; - numReadsStat++; - - if (numReads == nextProgressMessage) { - ccprintf(cerr, "%s: completed %d read accesses @%d\n", - name(), numReads, curTick); - nextProgressMessage += progressInterval; - } - - if (numReads >= maxLoads) - SimExit(curTick, "Maximum number of loads reached!"); - break; - - case Write: - numWritesStat++; - break; - - case Copy: - //Also remove dest from outstanding list - removeAddr = outstandingAddrs.find(req->dest); - assert(removeAddr != outstandingAddrs.end()); - outstandingAddrs.erase(removeAddr); - numCopiesStat++; - break; - - default: - panic("invalid command"); - } - - if (blockAddr(req->paddr) == traceBlockAddr) { - cerr << name() << ": completed " - << (req->cmd.isWrite() ? "write" : "read") - << " access of " - << dec << req->size << " bytes at address 0x" - << hex << req->paddr - << " (0x" << hex << blockAddr(req->paddr) << ")" - << ", value = 0x"; - printData(cerr, req->data, req->size); - cerr << " @ cycle " << dec << curTick; - - cerr << endl; - } - - noResponseCycles = 0; - delete [] data; -} - - -void -MemTest::regStats() -{ - using namespace Stats; - - - numReadsStat - .name(name() + ".num_reads") - .desc("number of read accesses completed") - ; - - numWritesStat - .name(name() + ".num_writes") - .desc("number of write accesses completed") - ; - - numCopiesStat - .name(name() + ".num_copies") - .desc("number of copy accesses completed") - ; -} - -void -MemTest::tick() -{ - if (!tickEvent.scheduled()) - tickEvent.schedule(curTick + cycles(1)); - - if (++noResponseCycles >= 500000) { - cerr << name() << ": deadlocked at cycle " << curTick << endl; - fatal(""); - } - - if (cacheInterface->isBlocked()) { - return; - } - - //make new request - unsigned cmd = random() % 100; - unsigned offset = random() % size; - unsigned base = random() % 2; - uint64_t data = random(); - unsigned access_size = random() % 4; - unsigned cacheable = random() % 100; - - //If we aren't doing copies, use id as offset, and do a false sharing - //mem tester - if (percentCopies == 0) { - //We can eliminate the lower bits of the offset, and then use the id - //to offset within the blks - offset &= ~63; //Not the low order bits - offset += id; - access_size = 0; - } - - MemReqPtr req = new MemReq(); - - if (cacheable < percentUncacheable) { - req->flags |= UNCACHEABLE; - req->paddr = uncacheAddr + offset; - } else { - req->paddr = ((base) ? baseAddr1 : baseAddr2) + offset; - } - // bool probe = (random() % 2 == 1) && !req->isUncacheable(); - bool probe = false; - - req->size = 1 << access_size; - req->data = new uint8_t[req->size]; - req->paddr &= ~(req->size - 1); - req->time = curTick; - req->xc = cpuXC->getProxy(); - - if (cmd < percentReads) { - // read - - //For now we only allow one outstanding request per addreess per tester - //This means we assume CPU does write forwarding to reads that alias something - //in the cpu store buffer. - if (outstandingAddrs.find(req->paddr) != outstandingAddrs.end()) return; - else outstandingAddrs.insert(req->paddr); - - req->cmd = Read; - uint8_t *result = new uint8_t[8]; - checkMem->access(Read, req->paddr, result, req->size); - if (blockAddr(req->paddr) == traceBlockAddr) { - cerr << name() - << ": initiating read " - << ((probe) ? "probe of " : "access of ") - << dec << req->size << " bytes from addr 0x" - << hex << req->paddr - << " (0x" << hex << blockAddr(req->paddr) << ")" - << " at cycle " - << dec << curTick << endl; - } - if (probe) { - cacheInterface->probeAndUpdate(req); - completeRequest(req, result); - } else { - req->completionEvent = new MemCompleteEvent(req, result, this); - cacheInterface->access(req); - } - } else if (cmd < (100 - percentCopies)){ - // write - - //For now we only allow one outstanding request per addreess per tester - //This means we assume CPU does write forwarding to reads that alias something - //in the cpu store buffer. - if (outstandingAddrs.find(req->paddr) != outstandingAddrs.end()) return; - else outstandingAddrs.insert(req->paddr); - - req->cmd = Write; - memcpy(req->data, &data, req->size); - checkMem->access(Write, req->paddr, req->data, req->size); - if (blockAddr(req->paddr) == traceBlockAddr) { - cerr << name() << ": initiating write " - << ((probe)?"probe of ":"access of ") - << dec << req->size << " bytes (value = 0x"; - printData(cerr, req->data, req->size); - cerr << ") to addr 0x" - << hex << req->paddr - << " (0x" << hex << blockAddr(req->paddr) << ")" - << " at cycle " - << dec << curTick << endl; - } - if (probe) { - cacheInterface->probeAndUpdate(req); - completeRequest(req, NULL); - } else { - req->completionEvent = new MemCompleteEvent(req, NULL, this); - cacheInterface->access(req); - } - } else { - // copy - unsigned source_align = random() % 100; - unsigned dest_align = random() % 100; - unsigned offset2 = random() % size; - - Addr source = ((base) ? baseAddr1 : baseAddr2) + offset; - Addr dest = ((base) ? baseAddr2 : baseAddr1) + offset2; - if (outstandingAddrs.find(source) != outstandingAddrs.end()) return; - else outstandingAddrs.insert(source); - if (outstandingAddrs.find(dest) != outstandingAddrs.end()) return; - else outstandingAddrs.insert(dest); - - if (source_align >= percentSourceUnaligned) { - source = blockAddr(source); - } - if (dest_align >= percentDestUnaligned) { - dest = blockAddr(dest); - } - req->cmd = Copy; - req->flags &= ~UNCACHEABLE; - req->paddr = source; - req->dest = dest; - delete [] req->data; - req->data = new uint8_t[blockSize]; - req->size = blockSize; - if (source == traceBlockAddr || dest == traceBlockAddr) { - cerr << name() - << ": initiating copy of " - << dec << req->size << " bytes from addr 0x" - << hex << source - << " (0x" << hex << blockAddr(source) << ")" - << " to addr 0x" - << hex << dest - << " (0x" << hex << blockAddr(dest) << ")" - << " at cycle " - << dec << curTick << endl; - } - cacheInterface->access(req); - uint8_t result[blockSize]; - checkMem->access(Read, source, &result, blockSize); - checkMem->access(Write, dest, &result, blockSize); - } -} - - -void -MemCompleteEvent::process() -{ - tester->completeRequest(req, data); - delete this; -} - - -const char * -MemCompleteEvent::description() -{ - return "memory access completion"; -} - - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(MemTest) - - SimObjectParam<BaseCache *> cache; - SimObjectParam<FunctionalMemory *> main_mem; - SimObjectParam<FunctionalMemory *> check_mem; - Param<unsigned> memory_size; - Param<unsigned> percent_reads; - Param<unsigned> percent_copies; - Param<unsigned> percent_uncacheable; - Param<unsigned> progress_interval; - Param<unsigned> percent_source_unaligned; - Param<unsigned> percent_dest_unaligned; - Param<Addr> trace_addr; - Param<Counter> max_loads; - -END_DECLARE_SIM_OBJECT_PARAMS(MemTest) - - -BEGIN_INIT_SIM_OBJECT_PARAMS(MemTest) - - INIT_PARAM(cache, "L1 cache"), - INIT_PARAM(main_mem, "hierarchical memory"), - INIT_PARAM(check_mem, "check memory"), - INIT_PARAM(memory_size, "memory size"), - INIT_PARAM(percent_reads, "target read percentage"), - INIT_PARAM(percent_copies, "target copy percentage"), - INIT_PARAM(percent_uncacheable, "target uncacheable percentage"), - INIT_PARAM(progress_interval, "progress report interval (in accesses)"), - INIT_PARAM(percent_source_unaligned, - "percent of copy source address that are unaligned"), - INIT_PARAM(percent_dest_unaligned, - "percent of copy dest address that are unaligned"), - INIT_PARAM(trace_addr, "address to trace"), - INIT_PARAM(max_loads, "terminate when we have reached this load count") - -END_INIT_SIM_OBJECT_PARAMS(MemTest) - - -CREATE_SIM_OBJECT(MemTest) -{ - return new MemTest(getInstanceName(), cache->getInterface(), main_mem, - check_mem, memory_size, percent_reads, percent_copies, - percent_uncacheable, progress_interval, - percent_source_unaligned, percent_dest_unaligned, - trace_addr, max_loads); -} - -REGISTER_SIM_OBJECT("MemTest", MemTest) diff --git a/cpu/memtest/memtest.hh b/cpu/memtest/memtest.hh deleted file mode 100644 index cdb40a26a..000000000 --- a/cpu/memtest/memtest.hh +++ /dev/null @@ -1,156 +0,0 @@ -/* - * 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. - */ - -#ifndef __CPU_MEMTEST_MEMTEST_HH__ -#define __CPU_MEMTEST_MEMTEST_HH__ - -#include <set> - -#include "base/statistics.hh" -#include "mem/functional/functional.hh" -#include "mem/mem_interface.hh" -#include "sim/eventq.hh" -#include "sim/sim_exit.hh" -#include "sim/sim_object.hh" -#include "sim/stats.hh" - -class ExecContext; -class MemTest : public SimObject -{ - public: - - MemTest(const std::string &name, - MemInterface *_cache_interface, - FunctionalMemory *main_mem, - FunctionalMemory *check_mem, - unsigned _memorySize, - unsigned _percentReads, - unsigned _percentCopies, - unsigned _percentUncacheable, - unsigned _progressInterval, - unsigned _percentSourceUnaligned, - unsigned _percentDestUnaligned, - Addr _traceAddr, - Counter _max_loads); - - // register statistics - virtual void regStats(); - - inline Tick cycles(int numCycles) const { return numCycles; } - - // main simulation loop (one cycle) - void tick(); - - protected: - class TickEvent : public Event - { - private: - MemTest *cpu; - public: - TickEvent(MemTest *c) - : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) {} - void process() {cpu->tick();} - virtual const char *description() { return "tick event"; } - }; - - TickEvent tickEvent; - - MemInterface *cacheInterface; - FunctionalMemory *mainMem; - FunctionalMemory *checkMem; - CPUExecContext *cpuXC; - - unsigned size; // size of testing memory region - - unsigned percentReads; // target percentage of read accesses - unsigned percentCopies; // target percentage of copy accesses - unsigned percentUncacheable; - - int id; - - std::set<unsigned> outstandingAddrs; - - unsigned blockSize; - - Addr blockAddrMask; - - Addr blockAddr(Addr addr) - { - return (addr & ~blockAddrMask); - } - - Addr traceBlockAddr; - - Addr baseAddr1; // fix this to option - Addr baseAddr2; // fix this to option - Addr uncacheAddr; - - unsigned progressInterval; // frequency of progress reports - Tick nextProgressMessage; // access # for next progress report - - unsigned percentSourceUnaligned; - unsigned percentDestUnaligned; - - Tick noResponseCycles; - - uint64_t numReads; - uint64_t maxLoads; - Stats::Scalar<> numReadsStat; - Stats::Scalar<> numWritesStat; - Stats::Scalar<> numCopiesStat; - - // called by MemCompleteEvent::process() - void completeRequest(MemReqPtr &req, uint8_t *data); - - friend class MemCompleteEvent; -}; - - -class MemCompleteEvent : public Event -{ - MemReqPtr req; - uint8_t *data; - MemTest *tester; - - public: - - MemCompleteEvent(MemReqPtr &_req, uint8_t *_data, MemTest *_tester) - : Event(&mainEventQueue), - req(_req), data(_data), tester(_tester) - { - } - - void process(); - - virtual const char *description(); -}; - -#endif // __CPU_MEMTEST_MEMTEST_HH__ - - - diff --git a/cpu/o3/2bit_local_pred.cc b/cpu/o3/2bit_local_pred.cc deleted file mode 100644 index c3fb2fdb8..000000000 --- a/cpu/o3/2bit_local_pred.cc +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "base/intmath.hh" -#include "base/trace.hh" -#include "cpu/o3/2bit_local_pred.hh" - -DefaultBP::DefaultBP(unsigned _localPredictorSize, - unsigned _localCtrBits, - unsigned _instShiftAmt) - : localPredictorSize(_localPredictorSize), - localCtrBits(_localCtrBits), - instShiftAmt(_instShiftAmt) -{ - if (!isPowerOf2(localPredictorSize)) { - fatal("Invalid local predictor size!\n"); - } - - localPredictorSets = localPredictorSize / localCtrBits; - - if (!isPowerOf2(localPredictorSets)) { - fatal("Invalid number of local predictor sets! Check localCtrBits.\n"); - } - - // Setup the index mask. - indexMask = localPredictorSets - 1; - - DPRINTF(Fetch, "Branch predictor: index mask: %#x\n", indexMask); - - // Setup the array of counters for the local predictor. - localCtrs.resize(localPredictorSets); - - for (int i = 0; i < localPredictorSets; ++i) - localCtrs[i].setBits(_localCtrBits); - - DPRINTF(Fetch, "Branch predictor: local predictor size: %i\n", - localPredictorSize); - - DPRINTF(Fetch, "Branch predictor: local counter bits: %i\n", localCtrBits); - - DPRINTF(Fetch, "Branch predictor: instruction shift amount: %i\n", - instShiftAmt); -} - -void -DefaultBP::reset() -{ - for (int i = 0; i < localPredictorSets; ++i) { - localCtrs[i].reset(); - } -} - -bool -DefaultBP::lookup(Addr &branch_addr) -{ - bool taken; - uint8_t local_prediction; - unsigned local_predictor_idx = getLocalIndex(branch_addr); - - DPRINTF(Fetch, "Branch predictor: Looking up index %#x\n", - local_predictor_idx); - - local_prediction = localCtrs[local_predictor_idx].read(); - - DPRINTF(Fetch, "Branch predictor: prediction is %i.\n", - (int)local_prediction); - - taken = getPrediction(local_prediction); - -#if 0 - // Speculative update. - if (taken) { - DPRINTF(Fetch, "Branch predictor: Branch updated as taken.\n"); - localCtrs[local_predictor_idx].increment(); - } else { - DPRINTF(Fetch, "Branch predictor: Branch updated as not taken.\n"); - localCtrs[local_predictor_idx].decrement(); - } -#endif - - return taken; -} - -void -DefaultBP::update(Addr &branch_addr, bool taken) -{ - unsigned local_predictor_idx; - - // Update the local predictor. - local_predictor_idx = getLocalIndex(branch_addr); - - DPRINTF(Fetch, "Branch predictor: Looking up index %#x\n", - local_predictor_idx); - - if (taken) { - DPRINTF(Fetch, "Branch predictor: Branch updated as taken.\n"); - localCtrs[local_predictor_idx].increment(); - } else { - DPRINTF(Fetch, "Branch predictor: Branch updated as not taken.\n"); - localCtrs[local_predictor_idx].decrement(); - } -} - -inline -bool -DefaultBP::getPrediction(uint8_t &count) -{ - // Get the MSB of the count - return (count >> (localCtrBits - 1)); -} - -inline -unsigned -DefaultBP::getLocalIndex(Addr &branch_addr) -{ - return (branch_addr >> instShiftAmt) & indexMask; -} diff --git a/cpu/o3/2bit_local_pred.hh b/cpu/o3/2bit_local_pred.hh deleted file mode 100644 index cd65978ca..000000000 --- a/cpu/o3/2bit_local_pred.hh +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_2BIT_LOCAL_PRED_HH__ -#define __CPU_O3_2BIT_LOCAL_PRED_HH__ - -// For Addr type. -#include "arch/isa_traits.hh" -#include "cpu/o3/sat_counter.hh" - -#include <vector> - -class DefaultBP -{ - public: - /** - * Default branch predictor constructor. - * @param localPredictorSize Size of the local predictor. - * @param localCtrBits Number of bits per counter. - * @param instShiftAmt Offset amount for instructions to ignore alignment. - */ - DefaultBP(unsigned localPredictorSize, unsigned localCtrBits, - unsigned instShiftAmt); - - /** - * Looks up the given address in the branch predictor and returns - * a true/false value as to whether it is taken. - * @param branch_addr The address of the branch to look up. - * @return Whether or not the branch is taken. - */ - bool lookup(Addr &branch_addr); - - /** - * Updates the branch predictor with the actual result of a branch. - * @param branch_addr The address of the branch to update. - * @param taken Whether or not the branch was taken. - */ - void update(Addr &branch_addr, bool taken); - - void reset(); - - private: - - /** - * Returns the taken/not taken prediction given the value of the - * counter. - * @param count The value of the counter. - * @return The prediction based on the counter value. - */ - inline bool getPrediction(uint8_t &count); - - /** Calculates the local index based on the PC. */ - inline unsigned getLocalIndex(Addr &PC); - - /** Array of counters that make up the local predictor. */ - std::vector<SatCounter> localCtrs; - - /** Size of the local predictor. */ - unsigned localPredictorSize; - - /** Number of sets. */ - unsigned localPredictorSets; - - /** Number of bits of the local predictor's counters. */ - unsigned localCtrBits; - - /** Number of bits to shift the PC when calculating index. */ - unsigned instShiftAmt; - - /** Mask to get index bits. */ - unsigned indexMask; -}; - -#endif // __CPU_O3_2BIT_LOCAL_PRED_HH__ diff --git a/cpu/o3/alpha_cpu.cc b/cpu/o3/alpha_cpu.cc deleted file mode 100644 index 7bc90dae6..000000000 --- a/cpu/o3/alpha_cpu.cc +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/o3/alpha_impl.hh" -#include "cpu/o3/alpha_cpu_impl.hh" -#include "cpu/o3/alpha_dyn_inst.hh" - -// Force instantiation of AlphaFullCPU for all the implemntations that are -// needed. Consider merging this and alpha_dyn_inst.cc, and maybe all -// classes that depend on a certain impl, into one file (alpha_impl.cc?). -template class AlphaFullCPU<AlphaSimpleImpl>; diff --git a/cpu/o3/alpha_cpu.hh b/cpu/o3/alpha_cpu.hh deleted file mode 100644 index 5c89e3462..000000000 --- a/cpu/o3/alpha_cpu.hh +++ /dev/null @@ -1,430 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_ALPHA_FULL_CPU_HH__ -#define __CPU_O3_ALPHA_FULL_CPU_HH__ - -#include "arch/isa_traits.hh" -#include "cpu/exec_context.hh" -#include "cpu/o3/cpu.hh" -#include "sim/byteswap.hh" - -class EndQuiesceEvent; -namespace Kernel { - class Statistics; -}; - -template <class Impl> -class AlphaFullCPU : public FullO3CPU<Impl> -{ - protected: - typedef TheISA::IntReg IntReg; - typedef TheISA::MiscReg MiscReg; - typedef TheISA::RegFile RegFile; - typedef TheISA::MiscRegFile MiscRegFile; - - public: - typedef O3ThreadState<Impl> ImplState; - typedef O3ThreadState<Impl> Thread; - typedef typename Impl::Params Params; - - /** Constructs an AlphaFullCPU with the given parameters. */ - AlphaFullCPU(Params *params); - - class AlphaXC : public ExecContext - { - public: - AlphaFullCPU<Impl> *cpu; - - O3ThreadState<Impl> *thread; - - virtual BaseCPU *getCpuPtr() { return cpu; } - - virtual void setCpuId(int id) { cpu->cpu_id = id; } - - virtual int readCpuId() { return cpu->cpu_id; } - - virtual FunctionalMemory *getMemPtr() { return thread->mem; } - -#if FULL_SYSTEM - virtual System *getSystemPtr() { return cpu->system; } - - virtual PhysicalMemory *getPhysMemPtr() { return cpu->physmem; } - - virtual AlphaITB *getITBPtr() { return cpu->itb; } - - virtual AlphaDTB * getDTBPtr() { return cpu->dtb; } - - virtual Kernel::Statistics *getKernelStats() - { return thread->kernelStats; } -#else - virtual Process *getProcessPtr() { return thread->process; } -#endif - - virtual Status status() const { return thread->status(); } - - virtual void setStatus(Status new_status) - { thread->setStatus(new_status); } - - /// Set the status to Active. Optional delay indicates number of - /// cycles to wait before beginning execution. - virtual void activate(int delay = 1); - - /// Set the status to Suspended. - virtual void suspend(); - - /// Set the status to Unallocated. - virtual void deallocate(); - - /// Set the status to Halted. - virtual void halt(); - -#if FULL_SYSTEM - virtual void dumpFuncProfile(); -#endif - - virtual void takeOverFrom(ExecContext *old_context); - - virtual void regStats(const std::string &name); - - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); - -#if FULL_SYSTEM - virtual EndQuiesceEvent *getQuiesceEvent(); - - virtual Tick readLastActivate(); - virtual Tick readLastSuspend(); - - virtual void profileClear(); - virtual void profileSample(); -#endif - - virtual int getThreadNum() { return thread->tid; } - - virtual TheISA::MachInst getInst(); - - virtual void copyArchRegs(ExecContext *xc); - - virtual void clearArchRegs(); - - virtual uint64_t readIntReg(int reg_idx); - - virtual float readFloatRegSingle(int reg_idx); - - virtual double readFloatRegDouble(int reg_idx); - - virtual uint64_t readFloatRegInt(int reg_idx); - - virtual void setIntReg(int reg_idx, uint64_t val); - - virtual void setFloatRegSingle(int reg_idx, float val); - - virtual void setFloatRegDouble(int reg_idx, double val); - - virtual void setFloatRegInt(int reg_idx, uint64_t val); - - virtual uint64_t readPC() - { return cpu->readPC(thread->tid); } - - virtual void setPC(uint64_t val); - - virtual uint64_t readNextPC() - { return cpu->readNextPC(thread->tid); } - - virtual void setNextPC(uint64_t val); - - virtual MiscReg readMiscReg(int misc_reg) - { return cpu->readMiscReg(misc_reg, thread->tid); } - - virtual MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) - { return cpu->readMiscRegWithEffect(misc_reg, fault, thread->tid); } - - virtual Fault setMiscReg(int misc_reg, const MiscReg &val); - - virtual Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val); - - // @todo: Figure out where these store cond failures should go. - virtual unsigned readStCondFailures() - { return thread->storeCondFailures; } - - virtual void setStCondFailures(unsigned sc_failures) - { thread->storeCondFailures = sc_failures; } - -#if FULL_SYSTEM - virtual bool inPalMode() - { return TheISA::PcPAL(cpu->readPC(thread->tid)); } -#endif - - // 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. - virtual bool misspeculating() { return false; } - -#if !FULL_SYSTEM - virtual IntReg getSyscallArg(int i); - - virtual void setSyscallArg(int i, IntReg val); - - virtual void setSyscallReturn(SyscallReturn return_value); - - virtual void syscall() { return cpu->syscall(thread->tid); } - - virtual Counter readFuncExeInst() { return thread->funcExeInst; } -#endif - }; - -#if FULL_SYSTEM - /** ITB pointer. */ - AlphaITB *itb; - /** DTB pointer. */ - AlphaDTB *dtb; -#endif - - /** Registers statistics. */ - void regStats(); - -#if FULL_SYSTEM - /** Translates instruction requestion. */ - Fault translateInstReq(MemReqPtr &req) - { - return itb->translate(req); - } - - /** Translates data read request. */ - Fault translateDataReadReq(MemReqPtr &req) - { - return dtb->translate(req, false); - } - - /** Translates data write request. */ - Fault translateDataWriteReq(MemReqPtr &req) - { - return dtb->translate(req, true); - } - -#else - Fault dummyTranslation(MemReqPtr &req) - { -#if 0 - assert((req->vaddr >> 48 & 0xffff) == 0); -#endif - - // put the asid in the upper 16 bits of the paddr - req->paddr = req->vaddr & ~((Addr)0xffff << sizeof(Addr) * 8 - 16); - req->paddr = req->paddr | (Addr)req->asid << sizeof(Addr) * 8 - 16; - return NoFault; - } - - /** Translates instruction requestion in syscall emulation mode. */ - Fault translateInstReq(MemReqPtr &req) - { - return dummyTranslation(req); - } - - /** Translates data read request in syscall emulation mode. */ - Fault translateDataReadReq(MemReqPtr &req) - { - return dummyTranslation(req); - } - - /** Translates data write request in syscall emulation mode. */ - Fault translateDataWriteReq(MemReqPtr &req) - { - return dummyTranslation(req); - } - -#endif - MiscReg readMiscReg(int misc_reg, unsigned tid); - - MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault, unsigned tid); - - Fault setMiscReg(int misc_reg, const MiscReg &val, unsigned tid); - - Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val, unsigned tid); - - void squashFromXC(unsigned tid); - -#if FULL_SYSTEM - void post_interrupt(int int_num, int index); - - int readIntrFlag(); - /** Sets the interrupt flags. */ - void setIntrFlag(int val); - /** HW return from error interrupt. */ - Fault hwrei(unsigned tid); - /** Returns if a specific PC is a PAL mode PC. */ - bool inPalMode(uint64_t PC) - { return AlphaISA::PcPAL(PC); } - - /** Traps to handle given fault. */ - void trap(Fault fault, unsigned tid); - bool simPalCheck(int palFunc, unsigned tid); - - /** Processes any interrupts. */ - void processInterrupts(); - - /** Halts the CPU. */ - void halt() { panic("Halt not implemented!\n"); } -#endif - - -#if !FULL_SYSTEM - /** Executes a syscall. - * @todo: Determine if this needs to be virtual. - */ - void syscall(int thread_num); - /** Gets a syscall argument. */ - IntReg getSyscallArg(int i, int tid); - - /** Used to shift args for indirect syscall. */ - void setSyscallArg(int i, IntReg val, int tid); - - /** Sets the return value of a syscall. */ - void setSyscallReturn(SyscallReturn return_value, int tid); -#endif - - /** Read from memory function. */ - template <class T> - Fault read(MemReqPtr &req, T &data) - { -#if 0 -#if FULL_SYSTEM && defined(TARGET_ALPHA) - if (req->flags & LOCKED) { - req->xc->setMiscReg(TheISA::Lock_Addr_DepTag, req->paddr); - req->xc->setMiscReg(TheISA::Lock_Flag_DepTag, true); - } -#endif -#endif - Fault error; - -#if FULL_SYSTEM - // @todo: Fix this LL/SC hack. - if (req->flags & LOCKED) { - lockAddr = req->paddr; - lockFlag = true; - } -#endif - - error = this->mem->read(req, data); - data = gtoh(data); - return error; - } - - /** CPU read function, forwards read to LSQ. */ - template <class T> - Fault read(MemReqPtr &req, T &data, int load_idx) - { - return this->iew.ldstQueue.read(req, data, load_idx); - } - - /** Write to memory function. */ - template <class T> - Fault write(MemReqPtr &req, T &data) - { -#if 0 -#if FULL_SYSTEM && defined(TARGET_ALPHA) - ExecContext *xc; - - // If this is a store conditional, act appropriately - if (req->flags & LOCKED) { - xc = req->xc; - - if (req->flags & UNCACHEABLE) { - // Don't update result register (see stq_c in isa_desc) - req->result = 2; - xc->setStCondFailures(0);//Needed? [RGD] - } else { - bool lock_flag = xc->readMiscReg(TheISA::Lock_Flag_DepTag); - Addr lock_addr = xc->readMiscReg(TheISA::Lock_Addr_DepTag); - req->result = lock_flag; - if (!lock_flag || - ((lock_addr & ~0xf) != (req->paddr & ~0xf))) { - xc->setMiscReg(TheISA::Lock_Flag_DepTag, false); - xc->setStCondFailures(xc->readStCondFailures() + 1); - if (((xc->readStCondFailures()) % 100000) == 0) { - std::cerr << "Warning: " - << xc->readStCondFailures() - << " consecutive store conditional failures " - << "on cpu " << req->xc->readCpuId() - << std::endl; - } - return NoFault; - } - else xc->setStCondFailures(0); - } - } - - // Need to clear any locked flags on other proccessors for - // this address. Only do this for succsful Store Conditionals - // and all other stores (WH64?). Unsuccessful Store - // Conditionals would have returned above, and wouldn't fall - // through. - for (int i = 0; i < this->system->execContexts.size(); i++){ - xc = this->system->execContexts[i]; - if ((xc->readMiscReg(TheISA::Lock_Addr_DepTag) & ~0xf) == - (req->paddr & ~0xf)) { - xc->setMiscReg(TheISA::Lock_Flag_DepTag, false); - } - } - -#endif -#endif - -#if FULL_SYSTEM - // @todo: Fix this LL/SC hack. - if (req->flags & LOCKED) { - if (req->flags & UNCACHEABLE) { - req->result = 2; - } else { - if (this->lockFlag) { - req->result = 1; - } else { - req->result = 0; - return NoFault; - } - } - } -#endif - - return this->mem->write(req, (T)htog(data)); - } - - /** CPU write function, forwards write to LSQ. */ - template <class T> - Fault write(MemReqPtr &req, T &data, int store_idx) - { - return this->iew.ldstQueue.write(req, data, store_idx); - } - - Addr lockAddr; - - bool lockFlag; -}; - -#endif // __CPU_O3_ALPHA_FULL_CPU_HH__ diff --git a/cpu/o3/alpha_cpu_builder.cc b/cpu/o3/alpha_cpu_builder.cc deleted file mode 100644 index b0d812edc..000000000 --- a/cpu/o3/alpha_cpu_builder.cc +++ /dev/null @@ -1,417 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <string> - -#include "cpu/base.hh" -#include "cpu/o3/alpha_cpu.hh" -#include "cpu/o3/alpha_impl.hh" -#include "cpu/o3/alpha_params.hh" -#include "cpu/o3/fu_pool.hh" -#include "mem/cache/base_cache.hh" -#include "sim/builder.hh" - -class DerivAlphaFullCPU : public AlphaFullCPU<AlphaSimpleImpl> -{ - public: - DerivAlphaFullCPU(AlphaSimpleParams *p) - : AlphaFullCPU<AlphaSimpleImpl>(p) - { } -}; - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(DerivAlphaFullCPU) - - Param<int> clock; - Param<int> numThreads; -Param<int> activity; - -#if FULL_SYSTEM -SimObjectParam<System *> system; -Param<int> cpu_id; -SimObjectParam<AlphaITB *> itb; -SimObjectParam<AlphaDTB *> dtb; -#else -SimObjectVectorParam<Process *> workload; -//SimObjectParam<PageTable *> page_table; -#endif // FULL_SYSTEM - -SimObjectParam<FunctionalMemory *> mem; - -SimObjectParam<BaseCPU *> checker; - -Param<Counter> max_insts_any_thread; -Param<Counter> max_insts_all_threads; -Param<Counter> max_loads_any_thread; -Param<Counter> max_loads_all_threads; - -SimObjectParam<BaseCache *> icache; -SimObjectParam<BaseCache *> dcache; - -Param<unsigned> cachePorts; - -Param<unsigned> decodeToFetchDelay; -Param<unsigned> renameToFetchDelay; -Param<unsigned> iewToFetchDelay; -Param<unsigned> commitToFetchDelay; -Param<unsigned> fetchWidth; - -Param<unsigned> renameToDecodeDelay; -Param<unsigned> iewToDecodeDelay; -Param<unsigned> commitToDecodeDelay; -Param<unsigned> fetchToDecodeDelay; -Param<unsigned> decodeWidth; - -Param<unsigned> iewToRenameDelay; -Param<unsigned> commitToRenameDelay; -Param<unsigned> decodeToRenameDelay; -Param<unsigned> renameWidth; - -Param<unsigned> commitToIEWDelay; -Param<unsigned> renameToIEWDelay; -Param<unsigned> issueToExecuteDelay; -Param<unsigned> issueWidth; -Param<unsigned> executeWidth; -Param<unsigned> executeIntWidth; -Param<unsigned> executeFloatWidth; -Param<unsigned> executeBranchWidth; -Param<unsigned> executeMemoryWidth; -SimObjectParam<FUPool *> fuPool; - -Param<unsigned> iewToCommitDelay; -Param<unsigned> renameToROBDelay; -Param<unsigned> commitWidth; -Param<unsigned> squashWidth; -Param<Tick> trapLatency; -Param<Tick> fetchTrapLatency; - -Param<unsigned> localPredictorSize; -Param<unsigned> localCtrBits; -Param<unsigned> localHistoryTableSize; -Param<unsigned> localHistoryBits; -Param<unsigned> globalPredictorSize; -Param<unsigned> globalCtrBits; -Param<unsigned> globalHistoryBits; -Param<unsigned> choicePredictorSize; -Param<unsigned> choiceCtrBits; - -Param<unsigned> BTBEntries; -Param<unsigned> BTBTagSize; - -Param<unsigned> RASSize; - -Param<unsigned> LQEntries; -Param<unsigned> SQEntries; -Param<unsigned> LFSTSize; -Param<unsigned> SSITSize; - -Param<unsigned> numPhysIntRegs; -Param<unsigned> numPhysFloatRegs; -Param<unsigned> numIQEntries; -Param<unsigned> numROBEntries; - -Param<unsigned> smtNumFetchingThreads; -Param<std::string> smtFetchPolicy; -Param<std::string> smtLSQPolicy; -Param<unsigned> smtLSQThreshold; -Param<std::string> smtIQPolicy; -Param<unsigned> smtIQThreshold; -Param<std::string> smtROBPolicy; -Param<unsigned> smtROBThreshold; -Param<std::string> smtCommitPolicy; - -Param<unsigned> instShiftAmt; - -Param<bool> defer_registration; - -Param<bool> function_trace; -Param<Tick> function_trace_start; - -END_DECLARE_SIM_OBJECT_PARAMS(DerivAlphaFullCPU) - -BEGIN_INIT_SIM_OBJECT_PARAMS(DerivAlphaFullCPU) - - INIT_PARAM(clock, "clock speed"), - INIT_PARAM(numThreads, "number of HW thread contexts"), - INIT_PARAM_DFLT(activity, "Initial activity count", 0), - -#if FULL_SYSTEM - INIT_PARAM(system, "System object"), - INIT_PARAM(cpu_id, "processor ID"), - INIT_PARAM(itb, "Instruction translation buffer"), - INIT_PARAM(dtb, "Data translation buffer"), -#else - INIT_PARAM(workload, "Processes to run"), -// INIT_PARAM(page_table, "Page table"), -#endif // FULL_SYSTEM - - INIT_PARAM_DFLT(mem, "Memory", NULL), - - INIT_PARAM_DFLT(checker, "Checker CPU", NULL), - - INIT_PARAM_DFLT(max_insts_any_thread, - "Terminate when any thread reaches this inst count", - 0), - INIT_PARAM_DFLT(max_insts_all_threads, - "Terminate when all threads have reached" - "this inst count", - 0), - INIT_PARAM_DFLT(max_loads_any_thread, - "Terminate when any thread reaches this load count", - 0), - INIT_PARAM_DFLT(max_loads_all_threads, - "Terminate when all threads have reached this load" - "count", - 0), - - INIT_PARAM_DFLT(icache, "L1 instruction cache", NULL), - INIT_PARAM_DFLT(dcache, "L1 data cache", NULL), - - INIT_PARAM_DFLT(cachePorts, "Cache Ports", 200), - - INIT_PARAM(decodeToFetchDelay, "Decode to fetch delay"), - INIT_PARAM(renameToFetchDelay, "Rename to fetch delay"), - INIT_PARAM(iewToFetchDelay, "Issue/Execute/Writeback to fetch" - "delay"), - INIT_PARAM(commitToFetchDelay, "Commit to fetch delay"), - INIT_PARAM(fetchWidth, "Fetch width"), - INIT_PARAM(renameToDecodeDelay, "Rename to decode delay"), - INIT_PARAM(iewToDecodeDelay, "Issue/Execute/Writeback to decode" - "delay"), - INIT_PARAM(commitToDecodeDelay, "Commit to decode delay"), - INIT_PARAM(fetchToDecodeDelay, "Fetch to decode delay"), - INIT_PARAM(decodeWidth, "Decode width"), - - INIT_PARAM(iewToRenameDelay, "Issue/Execute/Writeback to rename" - "delay"), - INIT_PARAM(commitToRenameDelay, "Commit to rename delay"), - INIT_PARAM(decodeToRenameDelay, "Decode to rename delay"), - INIT_PARAM(renameWidth, "Rename width"), - - INIT_PARAM(commitToIEWDelay, "Commit to " - "Issue/Execute/Writeback delay"), - INIT_PARAM(renameToIEWDelay, "Rename to " - "Issue/Execute/Writeback delay"), - INIT_PARAM(issueToExecuteDelay, "Issue to execute delay (internal" - "to the IEW stage)"), - INIT_PARAM(issueWidth, "Issue width"), - INIT_PARAM(executeWidth, "Execute width"), - INIT_PARAM(executeIntWidth, "Integer execute width"), - INIT_PARAM(executeFloatWidth, "Floating point execute width"), - INIT_PARAM(executeBranchWidth, "Branch execute width"), - INIT_PARAM(executeMemoryWidth, "Memory execute width"), - INIT_PARAM_DFLT(fuPool, "Functional unit pool", NULL), - - INIT_PARAM(iewToCommitDelay, "Issue/Execute/Writeback to commit " - "delay"), - INIT_PARAM(renameToROBDelay, "Rename to reorder buffer delay"), - INIT_PARAM(commitWidth, "Commit width"), - INIT_PARAM(squashWidth, "Squash width"), - INIT_PARAM_DFLT(trapLatency, "Number of cycles before the trap is handled", 6), - INIT_PARAM_DFLT(fetchTrapLatency, "Number of cycles before the fetch trap is handled", 12), - - INIT_PARAM(localPredictorSize, "Size of local predictor"), - INIT_PARAM(localCtrBits, "Bits per counter"), - INIT_PARAM(localHistoryTableSize, "Size of local history table"), - INIT_PARAM(localHistoryBits, "Bits for the local history"), - INIT_PARAM(globalPredictorSize, "Size of global predictor"), - INIT_PARAM(globalCtrBits, "Bits per counter"), - INIT_PARAM(globalHistoryBits, "Bits of history"), - INIT_PARAM(choicePredictorSize, "Size of choice predictor"), - INIT_PARAM(choiceCtrBits, "Bits of choice counters"), - - INIT_PARAM(BTBEntries, "Number of BTB entries"), - INIT_PARAM(BTBTagSize, "Size of the BTB tags, in bits"), - - INIT_PARAM(RASSize, "RAS size"), - - INIT_PARAM(LQEntries, "Number of load queue entries"), - INIT_PARAM(SQEntries, "Number of store queue entries"), - INIT_PARAM(LFSTSize, "Last fetched store table size"), - INIT_PARAM(SSITSize, "Store set ID table size"), - - INIT_PARAM(numPhysIntRegs, "Number of physical integer registers"), - INIT_PARAM(numPhysFloatRegs, "Number of physical floating point " - "registers"), - INIT_PARAM(numIQEntries, "Number of instruction queue entries"), - INIT_PARAM(numROBEntries, "Number of reorder buffer entries"), - - INIT_PARAM_DFLT(smtNumFetchingThreads, "SMT Number of Fetching Threads", 1), - INIT_PARAM_DFLT(smtFetchPolicy, "SMT Fetch Policy", "SingleThread"), - INIT_PARAM_DFLT(smtLSQPolicy, "SMT LSQ Sharing Policy", "Partitioned"), - INIT_PARAM_DFLT(smtLSQThreshold,"SMT LSQ Threshold", 100), - INIT_PARAM_DFLT(smtIQPolicy, "SMT IQ Policy", "Partitioned"), - INIT_PARAM_DFLT(smtIQThreshold, "SMT IQ Threshold", 100), - INIT_PARAM_DFLT(smtROBPolicy, "SMT ROB Sharing Policy", "Partitioned"), - INIT_PARAM_DFLT(smtROBThreshold,"SMT ROB Threshold", 100), - INIT_PARAM_DFLT(smtCommitPolicy,"SMT Commit Fetch Policy", "RoundRobin"), - - INIT_PARAM(instShiftAmt, "Number of bits to shift instructions by"), - INIT_PARAM(defer_registration, "defer system registration (for sampling)"), - - INIT_PARAM(function_trace, "Enable function trace"), - INIT_PARAM(function_trace_start, "Cycle to start function trace") - -END_INIT_SIM_OBJECT_PARAMS(DerivAlphaFullCPU) - -CREATE_SIM_OBJECT(DerivAlphaFullCPU) -{ - DerivAlphaFullCPU *cpu; - -#if FULL_SYSTEM - // Full-system only supports a single thread for the moment. - int actual_num_threads = 1; -#else - // In non-full-system mode, we infer the number of threads from - // the workload if it's not explicitly specified. - int actual_num_threads = - numThreads.isValid() ? numThreads : workload.size(); - - if (workload.size() == 0) { - fatal("Must specify at least one workload!"); - } - -#endif - - AlphaSimpleParams *params = new AlphaSimpleParams; - - params->clock = clock; - - params->name = getInstanceName(); - params->numberOfThreads = actual_num_threads; - params->activity = activity; - -#if FULL_SYSTEM - params->system = system; - params->cpu_id = cpu_id; - params->itb = itb; - params->dtb = dtb; -#else - params->workload = workload; -// params->pTable = page_table; -#endif // FULL_SYSTEM - - params->mem = mem; - - params->checker = checker; - - params->max_insts_any_thread = max_insts_any_thread; - params->max_insts_all_threads = max_insts_all_threads; - params->max_loads_any_thread = max_loads_any_thread; - params->max_loads_all_threads = max_loads_all_threads; - - // - // Caches - // - params->icacheInterface = icache ? icache->getInterface() : NULL; - params->dcacheInterface = dcache ? dcache->getInterface() : NULL; - params->cachePorts = cachePorts; - - params->decodeToFetchDelay = decodeToFetchDelay; - params->renameToFetchDelay = renameToFetchDelay; - params->iewToFetchDelay = iewToFetchDelay; - params->commitToFetchDelay = commitToFetchDelay; - params->fetchWidth = fetchWidth; - - params->renameToDecodeDelay = renameToDecodeDelay; - params->iewToDecodeDelay = iewToDecodeDelay; - params->commitToDecodeDelay = commitToDecodeDelay; - params->fetchToDecodeDelay = fetchToDecodeDelay; - params->decodeWidth = decodeWidth; - - params->iewToRenameDelay = iewToRenameDelay; - params->commitToRenameDelay = commitToRenameDelay; - params->decodeToRenameDelay = decodeToRenameDelay; - params->renameWidth = renameWidth; - - params->commitToIEWDelay = commitToIEWDelay; - params->renameToIEWDelay = renameToIEWDelay; - params->issueToExecuteDelay = issueToExecuteDelay; - params->issueWidth = issueWidth; - params->executeWidth = executeWidth; - params->executeIntWidth = executeIntWidth; - params->executeFloatWidth = executeFloatWidth; - params->executeBranchWidth = executeBranchWidth; - params->executeMemoryWidth = executeMemoryWidth; - params->fuPool = fuPool; - - params->iewToCommitDelay = iewToCommitDelay; - params->renameToROBDelay = renameToROBDelay; - params->commitWidth = commitWidth; - params->squashWidth = squashWidth; - params->trapLatency = trapLatency; - params->fetchTrapLatency = fetchTrapLatency; - - params->localPredictorSize = localPredictorSize; - params->localCtrBits = localCtrBits; - params->localHistoryTableSize = localHistoryTableSize; - params->localHistoryBits = localHistoryBits; - params->globalPredictorSize = globalPredictorSize; - params->globalCtrBits = globalCtrBits; - params->globalHistoryBits = globalHistoryBits; - params->choicePredictorSize = choicePredictorSize; - params->choiceCtrBits = choiceCtrBits; - - params->BTBEntries = BTBEntries; - params->BTBTagSize = BTBTagSize; - - params->RASSize = RASSize; - - params->LQEntries = LQEntries; - params->SQEntries = SQEntries; - - params->SSITSize = SSITSize; - params->LFSTSize = LFSTSize; - - params->numPhysIntRegs = numPhysIntRegs; - params->numPhysFloatRegs = numPhysFloatRegs; - params->numIQEntries = numIQEntries; - params->numROBEntries = numROBEntries; - - params->smtNumFetchingThreads = smtNumFetchingThreads; - params->smtFetchPolicy = smtFetchPolicy; - params->smtIQPolicy = smtIQPolicy; - params->smtLSQPolicy = smtLSQPolicy; - params->smtLSQThreshold = smtLSQThreshold; - params->smtROBPolicy = smtROBPolicy; - params->smtROBThreshold = smtROBThreshold; - params->smtCommitPolicy = smtCommitPolicy; - - params->instShiftAmt = 2; - - params->deferRegistration = defer_registration; - - params->functionTrace = function_trace; - params->functionTraceStart = function_trace_start; - - cpu = new DerivAlphaFullCPU(params); - - return cpu; -} - -REGISTER_SIM_OBJECT("DerivAlphaFullCPU", DerivAlphaFullCPU) - diff --git a/cpu/o3/alpha_cpu_impl.hh b/cpu/o3/alpha_cpu_impl.hh deleted file mode 100644 index 91cd3d9e6..000000000 --- a/cpu/o3/alpha_cpu_impl.hh +++ /dev/null @@ -1,776 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "arch/alpha/faults.hh" -#include "base/cprintf.hh" -#include "base/statistics.hh" -#include "base/timebuf.hh" -#include "cpu/checker/exec_context.hh" -#include "mem/mem_interface.hh" -#include "sim/sim_events.hh" -#include "sim/stats.hh" - -#include "cpu/o3/alpha_cpu.hh" -#include "cpu/o3/alpha_params.hh" -#include "cpu/o3/comm.hh" -#include "cpu/o3/thread_state.hh" - -#if FULL_SYSTEM -#include "arch/alpha/osfpal.hh" -#include "arch/isa_traits.hh" -#include "cpu/quiesce_event.hh" -#include "kern/kernel_stats.hh" -#endif - -using namespace TheISA; - -template <class Impl> -AlphaFullCPU<Impl>::AlphaFullCPU(Params *params) -#if FULL_SYSTEM - : FullO3CPU<Impl>(params), itb(params->itb), dtb(params->dtb) -#else - : FullO3CPU<Impl>(params) -#endif -{ - DPRINTF(FullCPU, "AlphaFullCPU: Creating AlphaFullCPU object.\n"); - - this->thread.resize(this->numThreads); - - for (int i = 0; i < this->numThreads; ++i) { -#if FULL_SYSTEM - assert(this->numThreads == 1); - this->thread[i] = new Thread(this, 0, params->mem); - this->thread[i]->setStatus(ExecContext::Suspended); -#else - if (i < params->workload.size()) { - DPRINTF(FullCPU, "FullCPU: Workload[%i]'s starting PC is %#x, " - "process is %#x", - i, params->workload[i]->prog_entry, this->thread[i]); - this->thread[i] = new Thread(this, i, params->workload[i], i); - assert(params->workload[i]->getMemory() != NULL); - - this->thread[i]->setStatus(ExecContext::Suspended); - //usedTids[i] = true; - //threadMap[i] = i; - } else { - //Allocate Empty execution context so M5 can use later - //when scheduling threads to CPU - Process* dummy_proc = NULL; - - this->thread[i] = new Thread(this, i, dummy_proc, i); - //usedTids[i] = false; - } -#endif // !FULL_SYSTEM - - this->thread[i]->numInst = 0; - - ExecContext *xc_proxy; - - AlphaXC *alpha_xc_proxy = new AlphaXC; - - if (params->checker) { - xc_proxy = new CheckerExecContext<AlphaXC>(alpha_xc_proxy, this->checker); - } else { - xc_proxy = alpha_xc_proxy; - } - - alpha_xc_proxy->cpu = this; - alpha_xc_proxy->thread = this->thread[i]; - -#if FULL_SYSTEM - this->thread[i]->quiesceEvent = - new EndQuiesceEvent(xc_proxy); - this->thread[i]->lastActivate = 0; - this->thread[i]->lastSuspend = 0; -#endif - this->thread[i]->xcProxy = xc_proxy; - - this->execContexts.push_back(xc_proxy); - } - - - for (int i=0; i < this->numThreads; i++) { - this->thread[i]->funcExeInst = 0; - } - - // Sets CPU pointers. These must be set at this level because the CPU - // pointers are defined to be the highest level of CPU class. - this->fetch.setCPU(this); - this->decode.setCPU(this); - this->rename.setCPU(this); - this->iew.setCPU(this); - this->commit.setCPU(this); - - this->rob.setCPU(this); - this->regFile.setCPU(this); - - lockAddr = 0; - lockFlag = false; -} - -template <class Impl> -void -AlphaFullCPU<Impl>::regStats() -{ - // Register stats for everything that has stats. - this->fullCPURegStats(); - this->fetch.regStats(); - this->decode.regStats(); - this->rename.regStats(); - this->iew.regStats(); - this->commit.regStats(); -} - -#if FULL_SYSTEM -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::dumpFuncProfile() -{ - // Currently not supported -} -#endif - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::takeOverFrom(ExecContext *old_context) -{ - // some things should already be set up - assert(getMemPtr() == old_context->getMemPtr()); -#if FULL_SYSTEM - assert(getSystemPtr() == old_context->getSystemPtr()); -#else - assert(getProcessPtr() == old_context->getProcessPtr()); -#endif - - // copy over functional state - setStatus(old_context->status()); - copyArchRegs(old_context); - setCpuId(old_context->readCpuId()); -#if !FULL_SYSTEM - thread->funcExeInst = old_context->readFuncExeInst(); -#else - EndQuiesceEvent *other_quiesce = old_context->getQuiesceEvent(); - if (other_quiesce) { - // Point the quiesce event's XC at this XC so that it wakes up - // the proper CPU. - other_quiesce->xc = this; - } - if (thread->quiesceEvent) { - thread->quiesceEvent->xc = this; - } - - // Transfer kernel stats from one CPU to the other. - thread->kernelStats = old_context->getKernelStats(); -// storeCondFailures = 0; - cpu->lockFlag = false; -#endif - - old_context->setStatus(ExecContext::Unallocated); - - thread->inSyscall = false; - thread->trapPending = false; -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::activate(int delay) -{ - DPRINTF(FullCPU, "Calling activate on AlphaXC\n"); - - if (thread->status() == ExecContext::Active) - return; - -#if FULL_SYSTEM - thread->lastActivate = curTick; -#endif - - if (thread->status() == ExecContext::Unallocated) { - cpu->activateWhenReady(thread->tid); - return; - } - - thread->setStatus(ExecContext::Active); - - // status() == Suspended - cpu->activateContext(thread->tid, delay); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::suspend() -{ - DPRINTF(FullCPU, "Calling suspend on AlphaXC\n"); - - if (thread->status() == ExecContext::Suspended) - return; - -#if FULL_SYSTEM - thread->lastActivate = curTick; - thread->lastSuspend = curTick; -#endif -/* -#if FULL_SYSTEM - // Don't change the status from active if there are pending interrupts - if (cpu->check_interrupts()) { - assert(status() == ExecContext::Active); - return; - } -#endif -*/ - thread->setStatus(ExecContext::Suspended); - cpu->suspendContext(thread->tid); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::deallocate() -{ - DPRINTF(FullCPU, "Calling deallocate on AlphaXC\n"); - - if (thread->status() == ExecContext::Unallocated) - return; - - thread->setStatus(ExecContext::Unallocated); - cpu->deallocateContext(thread->tid); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::halt() -{ - DPRINTF(FullCPU, "Calling halt on AlphaXC\n"); - - if (thread->status() == ExecContext::Halted) - return; - - thread->setStatus(ExecContext::Halted); - cpu->haltContext(thread->tid); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::regStats(const std::string &name) -{ -#if FULL_SYSTEM - thread->kernelStats = new Kernel::Statistics(cpu->system); - thread->kernelStats->regStats(name + ".kern"); -#endif -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::serialize(std::ostream &os) -{ -#if FULL_SYSTEM - if (thread->kernelStats) - thread->kernelStats->serialize(os); -#endif - -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::unserialize(Checkpoint *cp, const std::string §ion) -{ -#if FULL_SYSTEM - if (thread->kernelStats) - thread->kernelStats->unserialize(cp, section); -#endif - -} - -#if FULL_SYSTEM -template <class Impl> -EndQuiesceEvent * -AlphaFullCPU<Impl>::AlphaXC::getQuiesceEvent() -{ - return thread->quiesceEvent; -} - -template <class Impl> -Tick -AlphaFullCPU<Impl>::AlphaXC::readLastActivate() -{ - return thread->lastActivate; -} - -template <class Impl> -Tick -AlphaFullCPU<Impl>::AlphaXC::readLastSuspend() -{ - return thread->lastSuspend; -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::profileClear() -{} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::profileSample() -{} -#endif - -template <class Impl> -TheISA::MachInst -AlphaFullCPU<Impl>::AlphaXC:: getInst() -{ - return thread->inst; -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::copyArchRegs(ExecContext *xc) -{ - // This function will mess things up unless the ROB is empty and - // there are no instructions in the pipeline. - unsigned tid = thread->tid; - PhysRegIndex renamed_reg; - - // First loop through the integer registers. - for (int i = 0; i < AlphaISA::NumIntRegs; ++i) { - renamed_reg = cpu->renameMap[tid].lookup(i); - - DPRINTF(FullCPU, "FullCPU: Copying over register %i, had data %lli, " - "now has data %lli.\n", - renamed_reg, cpu->readIntReg(renamed_reg), - xc->readIntReg(i)); - - cpu->setIntReg(renamed_reg, xc->readIntReg(i)); - } - - // Then loop through the floating point registers. - for (int i = 0; i < AlphaISA::NumFloatRegs; ++i) { - renamed_reg = cpu->renameMap[tid].lookup(i + AlphaISA::FP_Base_DepTag); - cpu->setFloatRegDouble(renamed_reg, - xc->readFloatRegDouble(i)); - cpu->setFloatRegInt(renamed_reg, - xc->readFloatRegInt(i)); - } - - // Copy the misc regs. - cpu->regFile.miscRegs[tid].copyMiscRegs(xc); - - // Then finally set the PC and the next PC. - cpu->setPC(xc->readPC(), tid); - cpu->setNextPC(xc->readNextPC(), tid); -#if !FULL_SYSTEM - this->thread->funcExeInst = xc->readFuncExeInst(); -#endif -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::clearArchRegs() -{} - -template <class Impl> -uint64_t -AlphaFullCPU<Impl>::AlphaXC::readIntReg(int reg_idx) -{ - DPRINTF(Fault, "Reading int register through the XC!\n"); - return cpu->readArchIntReg(reg_idx, thread->tid); -} - -template <class Impl> -float -AlphaFullCPU<Impl>::AlphaXC::readFloatRegSingle(int reg_idx) -{ - DPRINTF(Fault, "Reading float register through the XC!\n"); - return cpu->readArchFloatRegSingle(reg_idx, thread->tid); -} - -template <class Impl> -double -AlphaFullCPU<Impl>::AlphaXC::readFloatRegDouble(int reg_idx) -{ - DPRINTF(Fault, "Reading float register through the XC!\n"); - return cpu->readArchFloatRegDouble(reg_idx, thread->tid); -} - -template <class Impl> -uint64_t -AlphaFullCPU<Impl>::AlphaXC::readFloatRegInt(int reg_idx) -{ - DPRINTF(Fault, "Reading floatint register through the XC!\n"); - return cpu->readArchFloatRegInt(reg_idx, thread->tid); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::setIntReg(int reg_idx, uint64_t val) -{ - DPRINTF(Fault, "Setting int register through the XC!\n"); - cpu->setArchIntReg(reg_idx, val, thread->tid); - - if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromXC(thread->tid); - } -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::setFloatRegSingle(int reg_idx, float val) -{ - DPRINTF(Fault, "Setting float register through the XC!\n"); - cpu->setArchFloatRegSingle(reg_idx, val, thread->tid); - - if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromXC(thread->tid); - } -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::setFloatRegDouble(int reg_idx, double val) -{ - DPRINTF(Fault, "Setting float register through the XC!\n"); - cpu->setArchFloatRegDouble(reg_idx, val, thread->tid); - - if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromXC(thread->tid); - } -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::setFloatRegInt(int reg_idx, uint64_t val) -{ - DPRINTF(Fault, "Setting floatint register through the XC!\n"); - cpu->setArchFloatRegInt(reg_idx, val, thread->tid); - - if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromXC(thread->tid); - } -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::setPC(uint64_t val) -{ - cpu->setPC(val, thread->tid); - - if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromXC(thread->tid); - } -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::setNextPC(uint64_t val) -{ - cpu->setNextPC(val, thread->tid); - - if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromXC(thread->tid); - } -} - -template <class Impl> -Fault -AlphaFullCPU<Impl>::AlphaXC::setMiscReg(int misc_reg, const MiscReg &val) -{ - DPRINTF(Fault, "Setting misc register through the XC!\n"); - - Fault ret_fault = cpu->setMiscReg(misc_reg, val, thread->tid); - - if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromXC(thread->tid); - } - - return ret_fault; -} - -template <class Impl> -Fault -AlphaFullCPU<Impl>::AlphaXC::setMiscRegWithEffect(int misc_reg, const MiscReg &val) -{ - DPRINTF(Fault, "Setting misc register through the XC!\n"); - - Fault ret_fault = cpu->setMiscRegWithEffect(misc_reg, val, thread->tid); - - if (!thread->trapPending && !thread->inSyscall) { - cpu->squashFromXC(thread->tid); - } - - return ret_fault; -} - -#if !FULL_SYSTEM - -template <class Impl> -TheISA::IntReg -AlphaFullCPU<Impl>::AlphaXC::getSyscallArg(int i) -{ - return cpu->getSyscallArg(i, thread->tid); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::setSyscallArg(int i, IntReg val) -{ - cpu->setSyscallArg(i, val, thread->tid); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::AlphaXC::setSyscallReturn(SyscallReturn return_value) -{ - cpu->setSyscallReturn(return_value, thread->tid); -} - -#endif // FULL_SYSTEM - -template <class Impl> -MiscReg -AlphaFullCPU<Impl>::readMiscReg(int misc_reg, unsigned tid) -{ - return this->regFile.readMiscReg(misc_reg, tid); -} - -template <class Impl> -MiscReg -AlphaFullCPU<Impl>::readMiscRegWithEffect(int misc_reg, Fault &fault, - unsigned tid) -{ - return this->regFile.readMiscRegWithEffect(misc_reg, fault, tid); -} - -template <class Impl> -Fault -AlphaFullCPU<Impl>::setMiscReg(int misc_reg, const MiscReg &val, unsigned tid) -{ - return this->regFile.setMiscReg(misc_reg, val, tid); -} - -template <class Impl> -Fault -AlphaFullCPU<Impl>::setMiscRegWithEffect(int misc_reg, const MiscReg &val, - unsigned tid) -{ - return this->regFile.setMiscRegWithEffect(misc_reg, val, tid); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::squashFromXC(unsigned tid) -{ - this->thread[tid]->inSyscall = true; - this->commit.generateXCEvent(tid); -} - -#if FULL_SYSTEM - -template <class Impl> -void -AlphaFullCPU<Impl>::post_interrupt(int int_num, int index) -{ - BaseCPU::post_interrupt(int_num, index); - - if (this->thread[0]->status() == ExecContext::Suspended) { - DPRINTF(IPI,"Suspended Processor awoke\n"); -// xcProxies[0]->activate(); - this->execContexts[0]->activate(); - } -} - -template <class Impl> -int -AlphaFullCPU<Impl>::readIntrFlag() -{ - return this->regFile.readIntrFlag(); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::setIntrFlag(int val) -{ - this->regFile.setIntrFlag(val); -} - -template <class Impl> -Fault -AlphaFullCPU<Impl>::hwrei(unsigned tid) -{ - // Need to clear the lock flag upon returning from an interrupt. - this->lockFlag = false; - - this->thread[tid]->kernelStats->hwrei(); - - this->checkInterrupts = true; - - // FIXME: XXX check for interrupts? XXX - return NoFault; -} - -template <class Impl> -bool -AlphaFullCPU<Impl>::simPalCheck(int palFunc, unsigned tid) -{ - if (this->thread[tid]->kernelStats) - this->thread[tid]->kernelStats->callpal(palFunc, - this->execContexts[tid]); - - switch (palFunc) { - case PAL::halt: - halt(); - if (--System::numSystemsRunning == 0) - new SimExitEvent("all cpus halted"); - break; - - case PAL::bpt: - case PAL::bugchk: - if (this->system->breakpoint()) - return false; - break; - } - - return true; -} - -template <class Impl> -void -AlphaFullCPU<Impl>::trap(Fault fault, unsigned tid) -{ - fault->invoke(this->execContexts[tid]); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::processInterrupts() -{ - // Check for interrupts here. For now can copy the code that - // exists within isa_fullsys_traits.hh. Also assume that thread 0 - // is the one that handles the interrupts. - // @todo: Possibly consolidate the interrupt checking code. - // @todo: Allow other threads to handle interrupts. - - // Check if there are any outstanding interrupts - //Handle the interrupts - int ipl = 0; - int summary = 0; - - this->checkInterrupts = false; - - if (this->readMiscReg(IPR_ASTRR, 0)) - panic("asynchronous traps not implemented\n"); - - if (this->readMiscReg(IPR_SIRR, 0)) { - for (int i = INTLEVEL_SOFTWARE_MIN; - i < INTLEVEL_SOFTWARE_MAX; i++) { - if (this->readMiscReg(IPR_SIRR, 0) & (ULL(1) << i)) { - // See table 4-19 of the 21164 hardware reference - ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1; - summary |= (ULL(1) << i); - } - } - } - - uint64_t interrupts = this->intr_status(); - - if (interrupts) { - for (int i = INTLEVEL_EXTERNAL_MIN; - i < INTLEVEL_EXTERNAL_MAX; i++) { - if (interrupts & (ULL(1) << i)) { - // See table 4-19 of the 21164 hardware reference - ipl = i; - summary |= (ULL(1) << i); - } - } - } - - if (ipl && ipl > this->readMiscReg(IPR_IPLR, 0)) { - this->setMiscReg(IPR_ISR, summary, 0); - this->setMiscReg(IPR_INTID, ipl, 0); - if (this->checker) { - this->checker->cpuXCBase()->setMiscReg(IPR_ISR, summary); - this->checker->cpuXCBase()->setMiscReg(IPR_INTID, ipl); - } - this->trap(Fault(new InterruptFault), 0); - DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", - this->readMiscReg(IPR_IPLR, 0), ipl, summary); - } -} - -#endif // FULL_SYSTEM - -#if !FULL_SYSTEM - -template <class Impl> -void -AlphaFullCPU<Impl>::syscall(int tid) -{ - DPRINTF(FullCPU, "AlphaFullCPU: [tid:%i] Executing syscall().\n\n", tid); - - DPRINTF(Activity,"Activity: syscall() called.\n"); - - // Temporarily increase this by one to account for the syscall - // instruction. - ++(this->thread[tid]->funcExeInst); - - // Execute the actual syscall. - this->thread[tid]->syscall(); - - // Decrease funcExeInst by one as the normal commit will handle - // incrementing it. - --(this->thread[tid]->funcExeInst); -} - -template <class Impl> -TheISA::IntReg -AlphaFullCPU<Impl>::getSyscallArg(int i, int tid) -{ - return this->readArchIntReg(AlphaISA::ArgumentReg0 + i, tid); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::setSyscallArg(int i, IntReg val, int tid) -{ - this->setArchIntReg(AlphaISA::ArgumentReg0 + i, val, tid); -} - -template <class Impl> -void -AlphaFullCPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid) -{ - // check for error condition. Alpha syscall convention is to - // indicate success/failure in reg a3 (r19) and put the - // return value itself in the standard return value reg (v0). - if (return_value.successful()) { - // no error - this->setArchIntReg(SyscallSuccessReg, 0, tid); - this->setArchIntReg(ReturnValueReg, return_value.value(), tid); - } else { - // got an error, return details - this->setArchIntReg(SyscallSuccessReg, (IntReg) -1, tid); - this->setArchIntReg(ReturnValueReg, -return_value.value(), tid); - } -} -#endif diff --git a/cpu/o3/alpha_dyn_inst.cc b/cpu/o3/alpha_dyn_inst.cc deleted file mode 100644 index 72ac77d95..000000000 --- a/cpu/o3/alpha_dyn_inst.cc +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/o3/alpha_dyn_inst_impl.hh" -#include "cpu/o3/alpha_impl.hh" - -// Force instantiation of AlphaDynInst for all the implementations that -// are needed. -template class AlphaDynInst<AlphaSimpleImpl>; diff --git a/cpu/o3/alpha_dyn_inst.hh b/cpu/o3/alpha_dyn_inst.hh deleted file mode 100644 index 1c5b738aa..000000000 --- a/cpu/o3/alpha_dyn_inst.hh +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_ALPHA_DYN_INST_HH__ -#define __CPU_O3_ALPHA_DYN_INST_HH__ - -#include "cpu/base_dyn_inst.hh" -#include "cpu/inst_seq.hh" -#include "cpu/o3/alpha_cpu.hh" -#include "cpu/o3/alpha_impl.hh" - -/** - * Mostly implementation & ISA specific AlphaDynInst. As with most - * other classes in the new CPU model, it is templated on the Impl to - * allow for passing in of all types, such as the CPU type and the ISA - * type. The AlphaDynInst serves as the primary interface to the CPU - * for instructions that are executing. - */ -template <class Impl> -class AlphaDynInst : public BaseDynInst<Impl> -{ - public: - /** Typedef for the CPU. */ - typedef typename Impl::FullCPU FullCPU; - - /** Binary machine instruction type. */ - typedef TheISA::MachInst MachInst; - /** Extended machine instruction type. */ - typedef TheISA::ExtMachInst ExtMachInst; - /** Logical register index type. */ - typedef TheISA::RegIndex RegIndex; - /** Integer register index type. */ - typedef TheISA::IntReg IntReg; - /** Misc register index type. */ - typedef TheISA::MiscReg MiscReg; - - enum { - MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs - MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs - }; - - public: - /** BaseDynInst constructor given a binary instruction. */ - AlphaDynInst(ExtMachInst inst, Addr PC, Addr Pred_PC, InstSeqNum seq_num, - FullCPU *cpu); - - /** BaseDynInst constructor given a static inst pointer. */ - AlphaDynInst(StaticInstPtr &_staticInst); - - /** Executes the instruction.*/ - Fault execute(); - - /** Initiates the access. Only valid for memory operations. */ - Fault initiateAcc(); - - /** Completes the access. Only valid for memory operations. */ - Fault completeAcc(); - - private: - /** Initializes variables. */ - void initVars(); - - public: - MiscReg readMiscReg(int misc_reg) - { - return this->cpu->readMiscReg(misc_reg, this->threadNumber); - } - - MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) - { - return this->cpu->readMiscRegWithEffect(misc_reg, fault, - this->threadNumber); - } - - Fault setMiscReg(int misc_reg, const MiscReg &val) - { - this->instResult.integer = val; - return this->cpu->setMiscReg(misc_reg, val, this->threadNumber); - } - - Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) - { - return this->cpu->setMiscRegWithEffect(misc_reg, val, - this->threadNumber); - } - -#if FULL_SYSTEM - /** Calls hardware return from error interrupt. */ - Fault hwrei(); - /** Reads interrupt flag. */ - int readIntrFlag(); - /** Sets interrupt flag. */ - void setIntrFlag(int val); - /** Checks if system is in PAL mode. */ - bool inPalMode(); - /** Traps to handle specified fault. */ - void trap(Fault fault); - bool simPalCheck(int palFunc); -#else - /** Calls a syscall. */ - void syscall(); -#endif - - private: - /** Physical register index of the destination registers of this - * instruction. - */ - PhysRegIndex _destRegIdx[MaxInstDestRegs]; - - /** Physical register index of the source registers of this - * instruction. - */ - PhysRegIndex _srcRegIdx[MaxInstSrcRegs]; - - /** Physical register index of the previous producers of the - * architected destinations. - */ - PhysRegIndex _prevDestRegIdx[MaxInstDestRegs]; - - public: - - // The register accessor methods provide the index of the - // instruction's operand (e.g., 0 or 1), not the architectural - // register index, to simplify the implementation of register - // renaming. We find the architectural register index by indexing - // into the instruction's own operand index table. Note that a - // raw pointer to the StaticInst is provided instead of a - // ref-counted StaticInstPtr to redice overhead. This is fine as - // long as these methods don't copy the pointer into any long-term - // storage (which is pretty hard to imagine they would have reason - // to do). - - uint64_t readIntReg(const StaticInst *si, int idx) - { - return this->cpu->readIntReg(_srcRegIdx[idx]); - } - - float readFloatRegSingle(const StaticInst *si, int idx) - { - return this->cpu->readFloatRegSingle(_srcRegIdx[idx]); - } - - double readFloatRegDouble(const StaticInst *si, int idx) - { - return this->cpu->readFloatRegDouble(_srcRegIdx[idx]); - } - - uint64_t readFloatRegInt(const StaticInst *si, int idx) - { - return this->cpu->readFloatRegInt(_srcRegIdx[idx]); - } - - /** @todo: Make results into arrays so they can handle multiple dest - * registers. - */ - void setIntReg(const StaticInst *si, int idx, uint64_t val) - { - this->cpu->setIntReg(_destRegIdx[idx], val); - BaseDynInst<Impl>::setIntReg(si, idx, val); - } - - void setFloatRegSingle(const StaticInst *si, int idx, float val) - { - this->cpu->setFloatRegSingle(_destRegIdx[idx], val); - BaseDynInst<Impl>::setFloatRegSingle(si, idx, val); - } - - void setFloatRegDouble(const StaticInst *si, int idx, double val) - { - this->cpu->setFloatRegDouble(_destRegIdx[idx], val); - BaseDynInst<Impl>::setFloatRegDouble(si, idx, val); - } - - void setFloatRegInt(const StaticInst *si, int idx, uint64_t val) - { - this->cpu->setFloatRegInt(_destRegIdx[idx], val); - BaseDynInst<Impl>::setFloatRegInt(si, idx, val); - } - - /** Returns the physical register index of the i'th destination - * register. - */ - PhysRegIndex renamedDestRegIdx(int idx) const - { - return _destRegIdx[idx]; - } - - /** Returns the physical register index of the i'th source register. */ - PhysRegIndex renamedSrcRegIdx(int idx) const - { - return _srcRegIdx[idx]; - } - - /** Returns the physical register index of the previous physical register - * that remapped to the same logical register index. - */ - PhysRegIndex prevDestRegIdx(int idx) const - { - return _prevDestRegIdx[idx]; - } - - /** Renames a destination register to a physical register. Also records - * the previous physical register that the logical register mapped to. - */ - void renameDestReg(int idx, - PhysRegIndex renamed_dest, - PhysRegIndex previous_rename) - { - _destRegIdx[idx] = renamed_dest; - _prevDestRegIdx[idx] = previous_rename; - } - - /** Renames a source logical register to the physical register which - * has/will produce that logical register's result. - * @todo: add in whether or not the source register is ready. - */ - void renameSrcReg(int idx, PhysRegIndex renamed_src) - { - _srcRegIdx[idx] = renamed_src; - } - - public: - /** Calculates EA part of a memory instruction. Currently unused, - * though it may be useful in the future if we want to split - * memory operations into EA calculation and memory access parts. - */ - Fault calcEA() - { - return this->staticInst->eaCompInst()->execute(this, this->traceData); - } - - /** Does the memory access part of a memory instruction. Currently unused, - * though it may be useful in the future if we want to split - * memory operations into EA calculation and memory access parts. - */ - Fault memAccess() - { - return this->staticInst->memAccInst()->execute(this, this->traceData); - } -}; - -#endif // __CPU_O3_ALPHA_DYN_INST_HH__ - diff --git a/cpu/o3/alpha_dyn_inst_impl.hh b/cpu/o3/alpha_dyn_inst_impl.hh deleted file mode 100644 index 541d5ab82..000000000 --- a/cpu/o3/alpha_dyn_inst_impl.hh +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/o3/alpha_dyn_inst.hh" - -template <class Impl> -AlphaDynInst<Impl>::AlphaDynInst(ExtMachInst inst, Addr PC, Addr Pred_PC, - InstSeqNum seq_num, FullCPU *cpu) - : BaseDynInst<Impl>(inst, PC, Pred_PC, seq_num, cpu) -{ - initVars(); -} - -template <class Impl> -AlphaDynInst<Impl>::AlphaDynInst(StaticInstPtr &_staticInst) - : BaseDynInst<Impl>(_staticInst) -{ - initVars(); -} - -template <class Impl> -void -AlphaDynInst<Impl>::initVars() -{ - // Make sure to have the renamed register entries set to the same - // as the normal register entries. It will allow the IQ to work - // without any modifications. - for (int i = 0; i < this->staticInst->numDestRegs(); i++) { - _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; - } -} - -template <class Impl> -Fault -AlphaDynInst<Impl>::execute() -{ - // @todo: Pretty convoluted way to avoid squashing from happening when using - // the XC during an instruction's execution (specifically for instructions - // that have sideeffects that use the XC). Fix this. - bool in_syscall = this->thread->inSyscall; - this->thread->inSyscall = true; - - this->fault = this->staticInst->execute(this, this->traceData); - - this->thread->inSyscall = in_syscall; - - return this->fault; -} - -template <class Impl> -Fault -AlphaDynInst<Impl>::initiateAcc() -{ - // @todo: Pretty convoluted way to avoid squashing from happening when using - // the XC during an instruction's execution (specifically for instructions - // that have sideeffects that use the XC). Fix this. - bool in_syscall = this->thread->inSyscall; - this->thread->inSyscall = true; - - this->fault = this->staticInst->initiateAcc(this, this->traceData); - - this->thread->inSyscall = in_syscall; - - return this->fault; -} - -template <class Impl> -Fault -AlphaDynInst<Impl>::completeAcc() -{ - if (this->isLoad()) { - this->fault = this->staticInst->completeAcc(this->req->data, - this, - this->traceData); - } else if (this->isStore()) { - this->fault = this->staticInst->completeAcc((uint8_t*)&this->req->result, - this, - this->traceData); - } else { - panic("Unknown type!"); - } - - return this->fault; -} - -#if FULL_SYSTEM -template <class Impl> -Fault -AlphaDynInst<Impl>::hwrei() -{ - if (!this->cpu->inPalMode(this->readPC())) - return new AlphaISA::UnimplementedOpcodeFault; - - this->setNextPC(this->cpu->readMiscReg(AlphaISA::IPR_EXC_ADDR, - this->threadNumber)); - - // Tell CPU to clear any state it needs to if a hwrei is taken. - this->cpu->hwrei(this->threadNumber); - - // FIXME: XXX check for interrupts? XXX - return NoFault; -} - -template <class Impl> -int -AlphaDynInst<Impl>::readIntrFlag() -{ - return this->cpu->readIntrFlag(); -} - -template <class Impl> -void -AlphaDynInst<Impl>::setIntrFlag(int val) -{ - this->cpu->setIntrFlag(val); -} - -template <class Impl> -bool -AlphaDynInst<Impl>::inPalMode() -{ - return this->cpu->inPalMode(this->PC); -} - -template <class Impl> -void -AlphaDynInst<Impl>::trap(Fault fault) -{ - this->cpu->trap(fault, this->threadNumber); -} - -template <class Impl> -bool -AlphaDynInst<Impl>::simPalCheck(int palFunc) -{ - return this->cpu->simPalCheck(palFunc, this->threadNumber); -} -#else -template <class Impl> -void -AlphaDynInst<Impl>::syscall() -{ - this->cpu->syscall(this->threadNumber); -} -#endif - diff --git a/cpu/o3/alpha_impl.hh b/cpu/o3/alpha_impl.hh deleted file mode 100644 index f404bd3ec..000000000 --- a/cpu/o3/alpha_impl.hh +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_ALPHA_IMPL_HH__ -#define __CPU_O3_ALPHA_IMPL_HH__ - -#include "arch/alpha/isa_traits.hh" - -#include "cpu/o3/alpha_params.hh" -#include "cpu/o3/cpu_policy.hh" - -// Forward declarations. -template <class Impl> -class AlphaDynInst; - -template <class Impl> -class AlphaFullCPU; - -/** Implementation specific struct that defines several key types to the - * CPU, the stages within the CPU, the time buffers, and the DynInst. - * The struct defines the ISA, the CPU policy, the specific DynInst, the - * specific FullCPU, and all of the structs from the time buffers to do - * communication. - * This is one of the key things that must be defined for each hardware - * specific CPU implementation. - */ -struct AlphaSimpleImpl -{ - /** The type of MachInst. */ - typedef TheISA::MachInst MachInst; - - /** The CPU policy to be used, which defines all of the CPU stages. */ - typedef SimpleCPUPolicy<AlphaSimpleImpl> CPUPol; - - /** The DynInst type to be used. */ - typedef AlphaDynInst<AlphaSimpleImpl> DynInst; - - /** The refcounted DynInst pointer to be used. In most cases this is - * what should be used, and not DynInst *. - */ - typedef RefCountingPtr<DynInst> DynInstPtr; - - /** The FullCPU type to be used. */ - typedef AlphaFullCPU<AlphaSimpleImpl> FullCPU; - - /** The Params to be passed to each stage. */ - typedef AlphaSimpleParams Params; - - enum { - MaxWidth = 8, - MaxThreads = 4 - }; -}; - -#endif // __CPU_O3_ALPHA_IMPL_HH__ diff --git a/cpu/o3/alpha_params.hh b/cpu/o3/alpha_params.hh deleted file mode 100644 index e3acf2c05..000000000 --- a/cpu/o3/alpha_params.hh +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_ALPHA_PARAMS_HH__ -#define __CPU_O3_ALPHA_PARAMS_HH__ - -#include "cpu/o3/cpu.hh" - -//Forward declarations -class AlphaDTB; -class AlphaITB; -class FUPool; -class FunctionalMemory; -class MemInterface; -class Process; -class System; - -/** - * This file defines the parameters that will be used for the AlphaFullCPU. - * 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 AlphaSimpleParams : public BaseFullCPU::Params -{ - public: - -#if FULL_SYSTEM - AlphaITB *itb; AlphaDTB *dtb; -#else - std::vector<Process *> workload; - Process *process; -#endif // FULL_SYSTEM - - //Page Table -// PageTable *pTable; - - FunctionalMemory *mem; - - BaseCPU *checker; - - unsigned activity; - - // - // Caches - // - MemInterface *icacheInterface; - MemInterface *dcacheInterface; - - unsigned cachePorts; - - // - // Fetch - // - unsigned decodeToFetchDelay; - unsigned renameToFetchDelay; - unsigned iewToFetchDelay; - unsigned commitToFetchDelay; - unsigned fetchWidth; - - // - // Decode - // - unsigned renameToDecodeDelay; - unsigned iewToDecodeDelay; - unsigned commitToDecodeDelay; - unsigned fetchToDecodeDelay; - unsigned decodeWidth; - - // - // Rename - // - unsigned iewToRenameDelay; - unsigned commitToRenameDelay; - unsigned decodeToRenameDelay; - unsigned renameWidth; - - // - // IEW - // - unsigned commitToIEWDelay; - unsigned renameToIEWDelay; - unsigned issueToExecuteDelay; - unsigned issueWidth; - unsigned executeWidth; - unsigned executeIntWidth; - unsigned executeFloatWidth; - unsigned executeBranchWidth; - unsigned executeMemoryWidth; - FUPool *fuPool; - - // - // Commit - // - unsigned iewToCommitDelay; - unsigned renameToROBDelay; - unsigned commitWidth; - unsigned squashWidth; - Tick trapLatency; - Tick fetchTrapLatency; - - // - // Branch predictor (BP & BTB) - // - unsigned localPredictorSize; - unsigned localCtrBits; - unsigned localHistoryTableSize; - unsigned localHistoryBits; - unsigned globalPredictorSize; - unsigned globalCtrBits; - unsigned globalHistoryBits; - unsigned choicePredictorSize; - unsigned choiceCtrBits; - - unsigned BTBEntries; - unsigned BTBTagSize; - - unsigned RASSize; - - // - // Load store queue - // - unsigned LQEntries; - unsigned SQEntries; - - // - // Memory dependence - // - unsigned SSITSize; - unsigned LFSTSize; - - // - // Miscellaneous - // - unsigned numPhysIntRegs; - unsigned numPhysFloatRegs; - unsigned numIQEntries; - unsigned numROBEntries; - - //SMT Parameters - unsigned smtNumFetchingThreads; - - std::string smtFetchPolicy; - - std::string smtIQPolicy; - unsigned smtIQThreshold; - - std::string smtLSQPolicy; - unsigned smtLSQThreshold; - - std::string smtCommitPolicy; - - std::string smtROBPolicy; - unsigned smtROBThreshold; - - // Probably can get this from somewhere. - unsigned instShiftAmt; -}; - -#endif // __CPU_O3_ALPHA_PARAMS_HH__ diff --git a/cpu/o3/bpred_unit.cc b/cpu/o3/bpred_unit.cc deleted file mode 100644 index 92344111f..000000000 --- a/cpu/o3/bpred_unit.cc +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/o3/bpred_unit_impl.hh" -#include "cpu/o3/alpha_impl.hh" -#include "cpu/o3/alpha_dyn_inst.hh" -#include "cpu/ozone/ozone_impl.hh" -#include "cpu/ozone/simple_impl.hh" - -template class TwobitBPredUnit<AlphaSimpleImpl>; -template class TwobitBPredUnit<OzoneImpl>; -template class TwobitBPredUnit<SimpleImpl>; diff --git a/cpu/o3/bpred_unit.hh b/cpu/o3/bpred_unit.hh deleted file mode 100644 index b7814b2e9..000000000 --- a/cpu/o3/bpred_unit.hh +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_BPRED_UNIT_HH__ -#define __CPU_O3_BPRED_UNIT_HH__ - -// For Addr type. -#include "arch/isa_traits.hh" -#include "base/statistics.hh" -#include "cpu/inst_seq.hh" - -#include "cpu/o3/2bit_local_pred.hh" -#include "cpu/o3/btb.hh" -#include "cpu/o3/ras.hh" -#include "cpu/o3/tournament_pred.hh" - -#include <list> - -/** - * Basically a wrapper class to hold both the branch predictor - * and the BTB. - */ -template<class Impl> -class TwobitBPredUnit -{ - public: - typedef typename Impl::Params Params; - typedef typename Impl::DynInstPtr DynInstPtr; - - /** - * @param params The params object, that has the size of the BP and BTB. - */ - TwobitBPredUnit(Params *params); - - /** - * Registers statistics. - */ - void regStats(); - - void switchOut(); - - void takeOverFrom(); - - /** - * Predicts whether or not the instruction is a taken branch, and the - * target of the branch if it is taken. - * @param inst The branch instruction. - * @param PC The predicted PC is passed back through this parameter. - * @param tid The thread id. - * @return Returns if the branch is taken or not. - */ - bool predict(DynInstPtr &inst, Addr &PC, unsigned tid); - - /** - * Tells the branch predictor to commit any updates until the given - * sequence number. - * @param done_sn The sequence number to commit any older updates up until. - * @param tid The thread id. - */ - void update(const InstSeqNum &done_sn, unsigned tid); - - /** - * Squashes all outstanding updates until a given sequence number. - * @param squashed_sn The sequence number to squash any younger updates up - * until. - * @param tid The thread id. - */ - void squash(const InstSeqNum &squashed_sn, unsigned tid); - - /** - * Squashes all outstanding updates until a given sequence number, and - * corrects that sn's update with the proper address and taken/not taken. - * @param squashed_sn The sequence number to squash any younger updates up - * until. - * @param corr_target The correct branch target. - * @param actually_taken The correct branch direction. - * @param tid The thread id. - */ - void squash(const InstSeqNum &squashed_sn, const Addr &corr_target, - bool actually_taken, unsigned tid); - - /** - * 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. - * @return Whether the branch is taken or not taken. - */ - bool BPLookup(Addr &inst_PC) - { return BP.lookup(inst_PC); } - - /** - * Looks up a given PC in the BTB to see if a matching entry exists. - * @param inst_PC The PC to look up. - * @return Whether the BTB contains the given PC. - */ - bool BTBValid(Addr &inst_PC) - { return BTB.valid(inst_PC, 0); } - - /** - * Looks up a given PC in the BTB to get the predicted target. - * @param inst_PC The PC to look up. - * @return The address of the target of the branch. - */ - Addr BTBLookup(Addr &inst_PC) - { return BTB.lookup(inst_PC, 0); } - - /** - * Updates the BP with taken/not taken information. - * @param inst_PC The branch's PC that will be updated. - * @param taken Whether the branch was taken or not taken. - * @todo Make this update flexible enough to handle a global predictor. - */ - void BPUpdate(Addr &inst_PC, bool taken) - { BP.update(inst_PC, taken); } - - /** - * Updates the BTB with the target of a branch. - * @param inst_PC The branch's PC that will be updated. - * @param target_PC The branch's target that will be added to the BTB. - */ - void BTBUpdate(Addr &inst_PC, Addr &target_PC) - { BTB.update(inst_PC, target_PC,0); } - - private: - struct PredictorHistory { - /** - * Makes a predictor history struct that contains a sequence number, - * the PC of its instruction, and whether or not it was predicted - * taken. - */ - PredictorHistory(const InstSeqNum &seq_num, const Addr &inst_PC, - const bool pred_taken, const unsigned _tid) - : seqNum(seq_num), PC(inst_PC), RASTarget(0), globalHistory(0), - RASIndex(0), tid(_tid), predTaken(pred_taken), usedRAS(0), - wasCall(0) - { } - - /** The sequence number for the predictor history entry. */ - InstSeqNum seqNum; - - /** The PC associated with the sequence number. */ - Addr PC; - - /** The RAS target (only valid if a return). */ - Addr RASTarget; - - /** The global history at the time this entry was created. */ - unsigned globalHistory; - - /** The RAS index of the instruction (only valid if a call). */ - unsigned RASIndex; - - /** The thread id. */ - unsigned tid; - - /** Whether or not it was predicted taken. */ - bool predTaken; - - /** Whether or not the RAS was used. */ - bool usedRAS; - - /** Whether or not the instruction was a call. */ - bool wasCall; - }; - - typedef std::list<PredictorHistory> History; - - /** - * The per-thread predictor history. This is used to update the predictor - * as instructions are committed, or restore it to the proper state after - * a squash. - */ - History predHist[Impl::MaxThreads]; - - /** The branch predictor. */ - DefaultBP BP; - - /** The BTB. */ - DefaultBTB BTB; - - /** The per-thread return address stack. */ - ReturnAddrStack RAS[Impl::MaxThreads]; - - /** Stat for number of BP lookups. */ - Stats::Scalar<> lookups; - /** Stat for number of conditional branches predicted. */ - Stats::Scalar<> condPredicted; - /** Stat for number of conditional branches predicted incorrectly. */ - Stats::Scalar<> condIncorrect; - /** Stat for number of BTB lookups. */ - Stats::Scalar<> BTBLookups; - /** Stat for number of BTB hits. */ - Stats::Scalar<> BTBHits; - /** Stat for number of times the BTB is correct. */ - Stats::Scalar<> BTBCorrect; - /** Stat for number of times the RAS is used to get a target. */ - Stats::Scalar<> usedRAS; - /** Stat for number of times the RAS is incorrect. */ - Stats::Scalar<> RASIncorrect; -}; - -#endif // __CPU_O3_BPRED_UNIT_HH__ diff --git a/cpu/o3/bpred_unit_impl.hh b/cpu/o3/bpred_unit_impl.hh deleted file mode 100644 index c37df606b..000000000 --- a/cpu/o3/bpred_unit_impl.hh +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <list> -#include <vector> - -#include "base/trace.hh" -#include "base/traceflags.hh" -#include "cpu/o3/bpred_unit.hh" - -using namespace std; - -template<class Impl> -TwobitBPredUnit<Impl>::TwobitBPredUnit(Params *params) - : BP(params->localPredictorSize, - params->localCtrBits, - params->instShiftAmt), - BTB(params->BTBEntries, - params->BTBTagSize, - params->instShiftAmt) -{ - for (int i=0; i < Impl::MaxThreads; i++) - RAS[i].init(params->RASSize); -} - -template <class Impl> -void -TwobitBPredUnit<Impl>::regStats() -{ - lookups - .name(name() + ".BPredUnit.lookups") - .desc("Number of BP lookups") - ; - - condPredicted - .name(name() + ".BPredUnit.condPredicted") - .desc("Number of conditional branches predicted") - ; - - condIncorrect - .name(name() + ".BPredUnit.condIncorrect") - .desc("Number of conditional branches incorrect") - ; - - BTBLookups - .name(name() + ".BPredUnit.BTBLookups") - .desc("Number of BTB lookups") - ; - - BTBHits - .name(name() + ".BPredUnit.BTBHits") - .desc("Number of BTB hits") - ; - - BTBCorrect - .name(name() + ".BPredUnit.BTBCorrect") - .desc("Number of correct BTB predictions (this stat may not " - "work properly.") - ; - - usedRAS - .name(name() + ".BPredUnit.usedRAS") - .desc("Number of times the RAS was used to get a target.") - ; - - RASIncorrect - .name(name() + ".BPredUnit.RASInCorrect") - .desc("Number of incorrect RAS predictions.") - ; -} - -template <class Impl> -void -TwobitBPredUnit<Impl>::switchOut() -{ - for (int i = 0; i < Impl::MaxThreads; ++i) { - predHist[i].clear(); - } -} - -template <class Impl> -void -TwobitBPredUnit<Impl>::takeOverFrom() -{ -/* - for (int i = 0; i < Impl::MaxThreads; ++i) - RAS[i].reset(); - - BP.reset(); - BTB.reset(); -*/ -} - -template <class Impl> -bool -TwobitBPredUnit<Impl>::predict(DynInstPtr &inst, Addr &PC, unsigned tid) -{ - // See if branch predictor predicts taken. - // If so, get its target addr either from the BTB or the RAS. - // Once that's done, speculatively update the predictor? - // Save off record of branch stuff so the RAS can be fixed - // up once it's done. - - using TheISA::MachInst; - - bool pred_taken = false; - Addr target; - - ++lookups; - - if (inst->isUncondCtrl()) { - DPRINTF(Fetch, "BranchPred: [tid:%i] Unconditional control.\n", tid); - pred_taken = true; - } else { - ++condPredicted; - - pred_taken = BPLookup(PC); - - DPRINTF(Fetch, "BranchPred: [tid:%i]: Branch predictor predicted %i " - "for PC %#x\n", - tid, pred_taken, inst->readPC()); - } - - PredictorHistory predict_record(inst->seqNum, PC, pred_taken, tid); - - // Now lookup in the BTB or RAS. - if (pred_taken) { - if (inst->isReturn()) { - ++usedRAS; - - // If it's a function return call, then look up the address - // in the RAS. - target = RAS[tid].top(); - - // Record the top entry of the RAS, and its index. - predict_record.usedRAS = true; - predict_record.RASIndex = RAS[tid].topIdx(); - predict_record.RASTarget = target; - - assert(predict_record.RASIndex < 16); - - RAS[tid].pop(); - - DPRINTF(Fetch, "BranchPred: [tid:%i]: Instruction %#x is a return, " - "RAS predicted target: %#x, RAS index: %i.\n", - tid, inst->readPC(), target, predict_record.RASIndex); - } else { - ++BTBLookups; - - if (inst->isCall()) { - RAS[tid].push(PC + sizeof(MachInst)); - - // Record that it was a call so that the top RAS entry can - // be popped off if the speculation is incorrect. - predict_record.wasCall = true; - - DPRINTF(Fetch, "BranchPred: [tid:%i] Instruction %#x was a call" - ", adding %#x to the RAS.\n", - tid, inst->readPC(), PC + sizeof(MachInst)); - } - - if (BTB.valid(PC, tid)) { - ++BTBHits; - - //If it's anything else, use the BTB to get the target addr. - target = BTB.lookup(PC, tid); - - DPRINTF(Fetch, "BranchPred: [tid:%i]: Instruction %#x predicted" - " target is %#x.\n", - tid, inst->readPC(), target); - - } else { - DPRINTF(Fetch, "BranchPred: [tid:%i]: BTB doesn't have a " - "valid entry.\n",tid); - pred_taken = false; - } - - } - } - - if (pred_taken) { - // Set the PC and the instruction's predicted target. - PC = target; - inst->setPredTarg(target); - } else { - PC = PC + sizeof(MachInst); - inst->setPredTarg(PC); - } - - predHist[tid].push_front(predict_record); - - DPRINTF(Fetch, "[tid:%i] predHist.size(): %i\n", tid, predHist[tid].size()); - - return pred_taken; -} - -template <class Impl> -void -TwobitBPredUnit<Impl>::update(const InstSeqNum &done_sn, unsigned tid) -{ - DPRINTF(Fetch, "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. - BP.update(predHist[tid].back().PC, - predHist[tid].back().predTaken); - - predHist[tid].pop_back(); - } -} - -template <class Impl> -void -TwobitBPredUnit<Impl>::squash(const InstSeqNum &squashed_sn, unsigned tid) -{ - History &pred_hist = predHist[tid]; - - while (!pred_hist.empty() && - pred_hist.front().seqNum > squashed_sn) { - if (pred_hist.front().usedRAS) { - DPRINTF(Fetch, "BranchPred: [tid:%i]: Restoring top of RAS to: %i," - " target: %#x.\n", - tid, - pred_hist.front().RASIndex, - pred_hist.front().RASTarget); - - RAS[tid].restore(pred_hist.front().RASIndex, - pred_hist.front().RASTarget); - - } else if (pred_hist.front().wasCall) { - DPRINTF(Fetch, "BranchPred: [tid:%i]: Removing speculative entry added " - "to the RAS.\n",tid); - - RAS[tid].pop(); - } - - pred_hist.pop_front(); - } - -} - -template <class Impl> -void -TwobitBPredUnit<Impl>::squash(const InstSeqNum &squashed_sn, - const Addr &corr_target, - const bool actually_taken, - unsigned tid) -{ - // Now that we know that a branch was mispredicted, we need to undo - // all the branches that have been seen up until this branch and - // fix up everything. - - History &pred_hist = predHist[tid]; - - ++condIncorrect; - - DPRINTF(Fetch, "BranchPred: [tid:%i]: Squashing from sequence number %i, " - "setting target to %#x.\n", - tid, squashed_sn, corr_target); - - while (!pred_hist.empty() && - pred_hist.front().seqNum > squashed_sn) { - if (pred_hist.front().usedRAS) { - DPRINTF(Fetch, "BranchPred: [tid:%i]: Restoring top of RAS to: %i, " - "target: %#x.\n", - tid, - pred_hist.front().RASIndex, - pred_hist.front().RASTarget); - - RAS[tid].restore(pred_hist.front().RASIndex, - pred_hist.front().RASTarget); - } else if (pred_hist.front().wasCall) { - DPRINTF(Fetch, "BranchPred: [tid:%i]: Removing speculative entry" - " added to the RAS.\n", tid); - - RAS[tid].pop(); - } - - pred_hist.pop_front(); - } - - // 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()) { - pred_hist.front().predTaken = actually_taken; - - if (pred_hist.front().usedRAS) { - ++RASIncorrect; - } - - BP.update(pred_hist.front().PC, actually_taken); - - BTB.update(pred_hist.front().PC, corr_target, tid); - pred_hist.pop_front(); - } -} diff --git a/cpu/o3/btb.cc b/cpu/o3/btb.cc deleted file mode 100644 index e5f69043a..000000000 --- a/cpu/o3/btb.cc +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "base/intmath.hh" -#include "base/trace.hh" -#include "cpu/o3/btb.hh" - -using namespace TheISA; - -DefaultBTB::DefaultBTB(unsigned _numEntries, - unsigned _tagBits, - unsigned _instShiftAmt) - : numEntries(_numEntries), - tagBits(_tagBits), - instShiftAmt(_instShiftAmt) -{ - DPRINTF(Fetch, "BTB: Creating BTB object.\n"); - - if (!isPowerOf2(numEntries)) { - fatal("BTB entries is not a power of 2!"); - } - - btb.resize(numEntries); - - for (int i = 0; i < numEntries; ++i) { - btb[i].valid = false; - } - - idxMask = numEntries - 1; - - tagMask = (1 << tagBits) - 1; - - tagShiftAmt = instShiftAmt + floorLog2(numEntries); -} - -void -DefaultBTB::reset() -{ - for (int i = 0; i < numEntries; ++i) { - btb[i].valid = false; - } -} - -inline -unsigned -DefaultBTB::getIndex(const Addr &inst_PC) -{ - // Need to shift PC over by the word offset. - return (inst_PC >> instShiftAmt) & idxMask; -} - -inline -Addr -DefaultBTB::getTag(const Addr &inst_PC) -{ - return (inst_PC >> tagShiftAmt) & tagMask; -} - -bool -DefaultBTB::valid(const Addr &inst_PC, unsigned tid) -{ - unsigned btb_idx = getIndex(inst_PC); - - Addr inst_tag = getTag(inst_PC); - - assert(btb_idx < numEntries); - - if (btb[btb_idx].valid - && inst_tag == btb[btb_idx].tag - && btb[btb_idx].tid == tid) { - return true; - } else { - return false; - } -} - -// @todo Create some sort of return struct that has both whether or not the -// address is valid, and also the address. For now will just use addr = 0 to -// represent invalid entry. -Addr -DefaultBTB::lookup(const Addr &inst_PC, unsigned tid) -{ - unsigned btb_idx = getIndex(inst_PC); - - Addr inst_tag = getTag(inst_PC); - - assert(btb_idx < numEntries); - - if (btb[btb_idx].valid - && inst_tag == btb[btb_idx].tag - && btb[btb_idx].tid == tid) { - return btb[btb_idx].target; - } else { - return 0; - } -} - -void -DefaultBTB::update(const Addr &inst_PC, const Addr &target, unsigned tid) -{ - unsigned btb_idx = getIndex(inst_PC); - - assert(btb_idx < numEntries); - - btb[btb_idx].tid = tid; - btb[btb_idx].valid = true; - btb[btb_idx].target = target; - btb[btb_idx].tag = getTag(inst_PC); -} diff --git a/cpu/o3/btb.hh b/cpu/o3/btb.hh deleted file mode 100644 index b9ff42573..000000000 --- a/cpu/o3/btb.hh +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_BTB_HH__ -#define __CPU_O3_BTB_HH__ - -// For Addr type. -#include "arch/isa_traits.hh" - -class DefaultBTB -{ - private: - struct BTBEntry - { - BTBEntry() - : tag(0), target(0), valid(false) - { - } - - /** The entry's tag. */ - Addr tag; - - /** The entry's target. */ - Addr target; - - /** The entry's thread id. */ - unsigned tid; - - /** Whether or not the entry is valid. */ - bool valid; - }; - - public: - /** Creates a BTB with the given number of entries, number of bits per - * tag, and instruction offset amount. - * @param numEntries Number of entries for the BTB. - * @param tagBits Number of bits for each tag in the BTB. - * @param instShiftAmt Offset amount for instructions to ignore alignment. - */ - DefaultBTB(unsigned numEntries, unsigned tagBits, - unsigned instShiftAmt); - - void reset(); - - /** Looks up an address in the BTB. Must call valid() first on the address. - * @param inst_PC The address of the branch to look up. - * @param tid The thread id. - * @return Returns the target of the branch. - */ - Addr lookup(const Addr &inst_PC, unsigned tid); - - /** Checks if a branch is in the BTB. - * @param inst_PC The address of the branch to look up. - * @param tid The thread id. - * @return Whether or not the branch exists in the BTB. - */ - bool valid(const Addr &inst_PC, unsigned tid); - - /** Updates the BTB with the target of a branch. - * @param inst_PC The address of the branch being updated. - * @param target_PC The target address of the branch. - * @param tid The thread id. - */ - void update(const Addr &inst_PC, const Addr &target_PC, - unsigned tid); - - private: - /** Returns the index into the BTB, based on the branch's PC. - * @param inst_PC The branch to look up. - * @return Returns the index into the BTB. - */ - inline unsigned getIndex(const Addr &inst_PC); - - /** Returns the tag bits of a given address. - * @param inst_PC The branch's address. - * @return Returns the tag bits. - */ - inline Addr getTag(const Addr &inst_PC); - - /** The actual BTB. */ - std::vector<BTBEntry> btb; - - /** The number of entries in the BTB. */ - unsigned numEntries; - - /** The index mask. */ - unsigned idxMask; - - /** The number of tag bits per entry. */ - unsigned tagBits; - - /** The tag mask. */ - unsigned tagMask; - - /** Number of bits to shift PC when calculating index. */ - unsigned instShiftAmt; - - /** Number of bits to shift PC when calculating tag. */ - unsigned tagShiftAmt; -}; - -#endif // __CPU_O3_BTB_HH__ diff --git a/cpu/o3/comm.hh b/cpu/o3/comm.hh deleted file mode 100644 index c36c58d3d..000000000 --- a/cpu/o3/comm.hh +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_COMM_HH__ -#define __CPU_O3_COMM_HH__ - -#include <vector> - -#include "arch/faults.hh" -#include "arch/isa_traits.hh" -#include "cpu/inst_seq.hh" -#include "sim/host.hh" - -// Typedef for physical register index type. Although the Impl would be the -// most likely location for this, there are a few classes that need this -// typedef yet are not templated on the Impl. For now it will be defined here. -typedef short int PhysRegIndex; - -template<class Impl> -struct DefaultFetchDefaultDecode { - typedef typename Impl::DynInstPtr DynInstPtr; - - int size; - - DynInstPtr insts[Impl::MaxWidth]; - Fault fetchFault; - InstSeqNum fetchFaultSN; - bool clearFetchFault; -}; - -template<class Impl> -struct DefaultDecodeDefaultRename { - typedef typename Impl::DynInstPtr DynInstPtr; - - int size; - - DynInstPtr insts[Impl::MaxWidth]; -}; - -template<class Impl> -struct DefaultRenameDefaultIEW { - typedef typename Impl::DynInstPtr DynInstPtr; - - int size; - - DynInstPtr insts[Impl::MaxWidth]; -}; - -template<class Impl> -struct DefaultIEWDefaultCommit { - typedef typename Impl::DynInstPtr DynInstPtr; - - int size; - - DynInstPtr insts[Impl::MaxWidth]; - - bool squash[Impl::MaxThreads]; - bool branchMispredict[Impl::MaxThreads]; - bool branchTaken[Impl::MaxThreads]; - uint64_t mispredPC[Impl::MaxThreads]; - uint64_t nextPC[Impl::MaxThreads]; - InstSeqNum squashedSeqNum[Impl::MaxThreads]; - - bool includeSquashInst[Impl::MaxThreads]; -}; - -template<class Impl> -struct IssueStruct { - typedef typename Impl::DynInstPtr DynInstPtr; - - int size; - - DynInstPtr insts[Impl::MaxWidth]; -}; - -template<class Impl> -struct TimeBufStruct { - struct decodeComm { - bool squash; - bool predIncorrect; - uint64_t branchAddr; - - InstSeqNum doneSeqNum; - - // @todo: Might want to package this kind of branch stuff into a single - // struct as it is used pretty frequently. - bool branchMispredict; - bool branchTaken; - uint64_t mispredPC; - uint64_t nextPC; - - unsigned branchCount; - }; - - decodeComm decodeInfo[Impl::MaxThreads]; - - // Rename can't actually tell anything to squash or send a new PC back - // because it doesn't do anything along those lines. But maybe leave - // these fields in here to keep the stages mostly orthagonal. - struct renameComm { - bool squash; - - uint64_t nextPC; - }; - - renameComm renameInfo[Impl::MaxThreads]; - - struct iewComm { - // Also eventually include skid buffer space. - bool usedIQ; - unsigned freeIQEntries; - bool usedLSQ; - unsigned freeLSQEntries; - - unsigned iqCount; - unsigned ldstqCount; - - unsigned dispatched; - unsigned dispatchedToLSQ; - }; - - iewComm iewInfo[Impl::MaxThreads]; - - struct commitComm { - bool usedROB; - unsigned freeROBEntries; - bool emptyROB; - - bool squash; - bool robSquashing; - - bool branchMispredict; - bool branchTaken; - uint64_t mispredPC; - uint64_t nextPC; - - // Represents the instruction that has either been retired or - // squashed. Similar to having a single bus that broadcasts the - // retired or squashed sequence number. - InstSeqNum doneSeqNum; - - //Just in case we want to do a commit/squash on a cycle - //(necessary for multiple ROBs?) - bool commitInsts; - InstSeqNum squashSeqNum; - - // Communication specifically to the IQ to tell the IQ that it can - // schedule a non-speculative instruction. - InstSeqNum nonSpecSeqNum; - - // Hack for now to send back an uncached access to the IEW stage. - typedef typename Impl::DynInstPtr DynInstPtr; - bool uncached; - DynInstPtr uncachedLoad; - - bool interruptPending; - bool clearInterrupt; - }; - - commitComm commitInfo[Impl::MaxThreads]; - - bool decodeBlock[Impl::MaxThreads]; - bool decodeUnblock[Impl::MaxThreads]; - bool renameBlock[Impl::MaxThreads]; - bool renameUnblock[Impl::MaxThreads]; - bool iewBlock[Impl::MaxThreads]; - bool iewUnblock[Impl::MaxThreads]; - bool commitBlock[Impl::MaxThreads]; - bool commitUnblock[Impl::MaxThreads]; -}; - -#endif //__CPU_O3_COMM_HH__ diff --git a/cpu/o3/commit.cc b/cpu/o3/commit.cc deleted file mode 100644 index fe5e9c1de..000000000 --- a/cpu/o3/commit.cc +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/o3/alpha_dyn_inst.hh" -#include "cpu/o3/alpha_impl.hh" -#include "cpu/o3/commit_impl.hh" - -template class DefaultCommit<AlphaSimpleImpl>; diff --git a/cpu/o3/commit.hh b/cpu/o3/commit.hh deleted file mode 100644 index 66abf8dc6..000000000 --- a/cpu/o3/commit.hh +++ /dev/null @@ -1,424 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_COMMIT_HH__ -#define __CPU_O3_COMMIT_HH__ - -#include "arch/faults.hh" -#include "base/statistics.hh" -#include "base/timebuf.hh" -#include "cpu/exetrace.hh" -#include "cpu/inst_seq.hh" -#include "mem/memory_interface.hh" - -template <class> -class O3ThreadState; - -/** - * DefaultCommit handles single threaded and SMT commit. Its width is - * specified by the parameters; each cycle it tries to commit that - * many instructions. The SMT policy decides which thread it tries to - * commit instructions from. Non- speculative instructions must reach - * the head of the ROB before they are ready to execute; once they - * reach the head, commit will broadcast the instruction's sequence - * number to the previous stages so that they can issue/ execute the - * instruction. Only one non-speculative instruction is handled per - * cycle. Commit is responsible for handling all back-end initiated - * redirects. It receives the redirect, and then broadcasts it to all - * stages, indicating the sequence number they should squash until, - * and any necessary branch misprediction information as well. It - * priortizes redirects by instruction's age, only broadcasting a - * redirect if it corresponds to an instruction that should currently - * be in the ROB. This is done by tracking the sequence number of the - * youngest instruction in the ROB, which gets updated to any - * squashing instruction's sequence number, and only broadcasting a - * redirect if it corresponds to an older instruction. Commit also - * supports multiple cycle squashing, to model a ROB that can only - * remove a certain number of instructions per cycle. - */ -template<class Impl> -class DefaultCommit -{ - public: - // Typedefs from the Impl. - typedef typename Impl::FullCPU FullCPU; - typedef typename Impl::DynInstPtr DynInstPtr; - typedef typename Impl::Params Params; - typedef typename Impl::CPUPol CPUPol; - - typedef typename CPUPol::RenameMap RenameMap; - typedef typename CPUPol::ROB ROB; - - typedef typename CPUPol::TimeStruct TimeStruct; - typedef typename CPUPol::FetchStruct FetchStruct; - typedef typename CPUPol::IEWStruct IEWStruct; - typedef typename CPUPol::RenameStruct RenameStruct; - - typedef typename CPUPol::Fetch Fetch; - typedef typename CPUPol::IEW IEW; - - typedef O3ThreadState<Impl> Thread; - - class TrapEvent : public Event { - private: - DefaultCommit<Impl> *commit; - unsigned tid; - - public: - TrapEvent(DefaultCommit<Impl> *_commit, unsigned _tid); - - void process(); - const char *description(); - }; - - /** Overall commit status. Used to determine if the CPU can deschedule - * itself due to a lack of activity. - */ - enum CommitStatus{ - Active, - Inactive - }; - - /** Individual thread status. */ - enum ThreadStatus { - Running, - Idle, - ROBSquashing, - TrapPending, - FetchTrapPending - }; - - /** Commit policy for SMT mode. */ - enum CommitPolicy { - Aggressive, - RoundRobin, - OldestReady - }; - - private: - /** Overall commit status. */ - CommitStatus _status; - /** Next commit status, to be set at the end of the cycle. */ - CommitStatus _nextStatus; - /** Per-thread status. */ - ThreadStatus commitStatus[Impl::MaxThreads]; - /** Commit policy used in SMT mode. */ - CommitPolicy commitPolicy; - - public: - /** Construct a DefaultCommit with the given parameters. */ - DefaultCommit(Params *params); - - /** Returns the name of the DefaultCommit. */ - std::string name() const; - - /** Registers statistics. */ - void regStats(); - - /** Sets the CPU pointer. */ - void setCPU(FullCPU *cpu_ptr); - - /** Sets the list of threads. */ - void setThreads(std::vector<Thread *> &threads); - - /** Sets the main time buffer pointer, used for backwards communication. */ - void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr); - - void setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr); - - /** Sets the pointer to the queue coming from rename. */ - void setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr); - - /** Sets the pointer to the queue coming from IEW. */ - void setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr); - - void setFetchStage(Fetch *fetch_stage); - - Fetch *fetchStage; - - /** Sets the poitner to the IEW stage. */ - void setIEWStage(IEW *iew_stage); - - /** The pointer to the IEW stage. Used solely to ensure that - * various events (traps, interrupts, syscalls) do not occur until - * all stores have written back. - */ - IEW *iewStage; - - /** Sets pointer to list of active threads. */ - void setActiveThreads(std::list<unsigned> *at_ptr); - - /** Sets pointer to the commited state rename map. */ - void setRenameMap(RenameMap rm_ptr[Impl::MaxThreads]); - - /** Sets pointer to the ROB. */ - void setROB(ROB *rob_ptr); - - /** Initializes stage by sending back the number of free entries. */ - void initStage(); - - void switchOut(); - - void doSwitchOut(); - - void takeOverFrom(); - - /** Ticks the commit stage, which tries to commit instructions. */ - void tick(); - - /** Handles any squashes that are sent from IEW, and adds instructions - * to the ROB and tries to commit instructions. - */ - void commit(); - - /** Returns the number of free ROB entries for a specific thread. */ - unsigned numROBFreeEntries(unsigned tid); - - void generateXCEvent(unsigned tid); - - private: - /** Updates the overall status of commit with the nextStatus, and - * tell the CPU if commit is active/inactive. */ - void updateStatus(); - - /** Sets the next status based on threads' statuses, which becomes the - * current status at the end of the cycle. - */ - void setNextStatus(); - - /** Checks if the ROB is completed with squashing. This is for the case - * where the ROB can take multiple cycles to complete squashing. - */ - bool robDoneSquashing(); - - /** Returns if any of the threads have the number of ROB entries changed - * on this cycle. Used to determine if the number of free ROB entries needs - * to be sent back to previous stages. - */ - bool changedROBEntries(); - - void squashAll(unsigned tid); - - void squashFromTrap(unsigned tid); - - void squashFromXC(unsigned tid); - - /** Commits as many instructions as possible. */ - void commitInsts(); - - /** Tries to commit the head ROB instruction passed in. - * @param head_inst The instruction to be committed. - */ - bool commitHead(DynInstPtr &head_inst, unsigned inst_num); - - void generateTrapEvent(unsigned tid); - - /** Gets instructions from rename and inserts them into the ROB. */ - void getInsts(); - - /** Marks completed instructions using information sent from IEW. */ - void markCompletedInsts(); - - /** Gets the thread to commit, based on the SMT policy. */ - int getCommittingThread(); - - /** Returns the thread ID to use based on a round robin policy. */ - int roundRobin(); - - /** Returns the thread ID to use based on an oldest instruction policy. */ - int oldestReady(); - - public: - /** Returns the PC of the head instruction of the ROB. - * @todo: Probably remove this function as it returns only thread 0. - */ - uint64_t readPC() { return PC[0]; } - - uint64_t readPC(unsigned tid) { return PC[tid]; } - - void setPC(uint64_t val, unsigned tid) { PC[tid] = val; } - - uint64_t readNextPC(unsigned tid) { return nextPC[tid]; } - - void setNextPC(uint64_t val, unsigned tid) { nextPC[tid] = val; } - - private: - /** Time buffer interface. */ - TimeBuffer<TimeStruct> *timeBuffer; - - /** Wire to write information heading to previous stages. */ - typename TimeBuffer<TimeStruct>::wire toIEW; - - /** Wire to read information from IEW (for ROB). */ - typename TimeBuffer<TimeStruct>::wire robInfoFromIEW; - - TimeBuffer<FetchStruct> *fetchQueue; - - typename TimeBuffer<FetchStruct>::wire fromFetch; - - /** IEW instruction queue interface. */ - TimeBuffer<IEWStruct> *iewQueue; - - /** Wire to read information from IEW queue. */ - typename TimeBuffer<IEWStruct>::wire fromIEW; - - /** Rename instruction queue interface, for ROB. */ - TimeBuffer<RenameStruct> *renameQueue; - - /** Wire to read information from rename queue. */ - typename TimeBuffer<RenameStruct>::wire fromRename; - - public: - /** ROB interface. */ - ROB *rob; - - private: - /** Pointer to FullCPU. */ - FullCPU *cpu; - - /** Memory interface. Used for d-cache accesses. */ - MemInterface *dcacheInterface; - - std::vector<Thread *> thread; - - Fault fetchFault; - - int fetchTrapWait; - - /** Records that commit has written to the time buffer this cycle. Used for - * the CPU to determine if it can deschedule itself if there is no activity. - */ - bool wroteToTimeBuffer; - - /** Records if the number of ROB entries has changed this cycle. If it has, - * then the number of free entries must be re-broadcast. - */ - bool changedROBNumEntries[Impl::MaxThreads]; - - /** A counter of how many threads are currently squashing. */ - int squashCounter; - - /** Records if a thread has to squash this cycle due to a trap. */ - bool trapSquash[Impl::MaxThreads]; - - /** Records if a thread has to squash this cycle due to an XC write. */ - bool xcSquash[Impl::MaxThreads]; - - /** Priority List used for Commit Policy */ - std::list<unsigned> priority_list; - - /** IEW to Commit delay, in ticks. */ - unsigned iewToCommitDelay; - - /** Commit to IEW delay, in ticks. */ - unsigned commitToIEWDelay; - - /** Rename to ROB delay, in ticks. */ - unsigned renameToROBDelay; - - unsigned fetchToCommitDelay; - - /** Rename width, in instructions. Used so ROB knows how many - * instructions to get from the rename instruction queue. - */ - unsigned renameWidth; - - /** IEW width, in instructions. Used so ROB knows how many - * instructions to get from the IEW instruction queue. - */ - unsigned iewWidth; - - /** Commit width, in instructions. */ - unsigned commitWidth; - - /** Number of Reorder Buffers */ - unsigned numRobs; - - /** Number of Active Threads */ - unsigned numThreads; - - bool switchPending; - bool switchedOut; - - Tick trapLatency; - - Tick fetchTrapLatency; - - Tick fetchFaultTick; - - Addr PC[Impl::MaxThreads]; - - Addr nextPC[Impl::MaxThreads]; - - /** The sequence number of the youngest valid instruction in the ROB. */ - InstSeqNum youngestSeqNum[Impl::MaxThreads]; - - /** Pointer to the list of active threads. */ - std::list<unsigned> *activeThreads; - - /** Rename map interface. */ - RenameMap *renameMap[Impl::MaxThreads]; - - void updateComInstStats(DynInstPtr &inst); - - /** Stat for the total number of committed instructions. */ - Stats::Scalar<> commitCommittedInsts; - /** Stat for the total number of squashed instructions discarded by commit. - */ - Stats::Scalar<> commitSquashedInsts; - /** Stat for the total number of times commit is told to squash. - * @todo: Actually increment this stat. - */ - Stats::Scalar<> commitSquashEvents; - /** Stat for the total number of times commit has had to stall due to a non- - * speculative instruction reaching the head of the ROB. - */ - Stats::Scalar<> commitNonSpecStalls; - /** Stat for the total number of branch mispredicts that caused a squash. */ - Stats::Scalar<> branchMispredicts; - /** Distribution of the number of committed instructions each cycle. */ - Stats::Distribution<> numCommittedDist; - - /** Total number of instructions committed. */ - Stats::Vector<> statComInst; - /** Total number of software prefetches committed. */ - Stats::Vector<> statComSwp; - /** Stat for the total number of committed memory references. */ - Stats::Vector<> statComRefs; - /** Stat for the total number of committed loads. */ - Stats::Vector<> statComLoads; - /** Total number of committed memory barriers. */ - Stats::Vector<> statComMembars; - /** Total number of committed branches. */ - Stats::Vector<> statComBranches; - - Stats::Scalar<> commitEligibleSamples; - Stats::Vector<> commitEligible; -}; - -#endif // __CPU_O3_COMMIT_HH__ diff --git a/cpu/o3/commit_impl.hh b/cpu/o3/commit_impl.hh deleted file mode 100644 index 346a8bc1c..000000000 --- a/cpu/o3/commit_impl.hh +++ /dev/null @@ -1,1307 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <algorithm> -#include <string> - -#include "base/loader/symtab.hh" -#include "base/timebuf.hh" -#include "cpu/checker/cpu.hh" -#include "cpu/exetrace.hh" -#include "cpu/o3/commit.hh" -#include "cpu/o3/thread_state.hh" - -using namespace std; - -template <class Impl> -DefaultCommit<Impl>::TrapEvent::TrapEvent(DefaultCommit<Impl> *_commit, - unsigned _tid) - : Event(&mainEventQueue, CPU_Tick_Pri), commit(_commit), tid(_tid) -{ - this->setFlags(Event::AutoDelete); -} - -template <class Impl> -void -DefaultCommit<Impl>::TrapEvent::process() -{ - // This will get reset by commit if it was switched out at the - // time of this event processing. - commit->trapSquash[tid] = true; -} - -template <class Impl> -const char * -DefaultCommit<Impl>::TrapEvent::description() -{ - return "Trap event"; -} - -template <class Impl> -DefaultCommit<Impl>::DefaultCommit(Params *params) - : dcacheInterface(params->dcacheInterface), - squashCounter(0), - iewToCommitDelay(params->iewToCommitDelay), - commitToIEWDelay(params->commitToIEWDelay), - renameToROBDelay(params->renameToROBDelay), - fetchToCommitDelay(params->commitToFetchDelay), - renameWidth(params->renameWidth), - iewWidth(params->executeWidth), - commitWidth(params->commitWidth), - numThreads(params->numberOfThreads), - switchedOut(false), - trapLatency(params->trapLatency), - fetchTrapLatency(params->fetchTrapLatency) -{ - _status = Active; - _nextStatus = Inactive; - string policy = params->smtCommitPolicy; - - //Convert string to lowercase - std::transform(policy.begin(), policy.end(), policy.begin(), - (int(*)(int)) tolower); - - //Assign commit policy - if (policy == "aggressive"){ - commitPolicy = Aggressive; - - DPRINTF(Commit,"Commit Policy set to Aggressive."); - } else if (policy == "roundrobin"){ - commitPolicy = RoundRobin; - - //Set-Up Priority List - for (int tid=0; tid < numThreads; tid++) { - priority_list.push_back(tid); - } - - DPRINTF(Commit,"Commit Policy set to Round Robin."); - } else if (policy == "oldestready"){ - commitPolicy = OldestReady; - - DPRINTF(Commit,"Commit Policy set to Oldest Ready."); - } else { - assert(0 && "Invalid SMT Commit Policy. Options Are: {Aggressive," - "RoundRobin,OldestReady}"); - } - - for (int i=0; i < numThreads; i++) { - commitStatus[i] = Idle; - changedROBNumEntries[i] = false; - trapSquash[i] = false; - xcSquash[i] = false; - } - - fetchFaultTick = 0; - fetchTrapWait = 0; -} - -template <class Impl> -std::string -DefaultCommit<Impl>::name() const -{ - return cpu->name() + ".commit"; -} - -template <class Impl> -void -DefaultCommit<Impl>::regStats() -{ - using namespace Stats; - commitCommittedInsts - .name(name() + ".commitCommittedInsts") - .desc("The number of committed instructions") - .prereq(commitCommittedInsts); - commitSquashedInsts - .name(name() + ".commitSquashedInsts") - .desc("The number of squashed insts skipped by commit") - .prereq(commitSquashedInsts); - commitSquashEvents - .name(name() + ".commitSquashEvents") - .desc("The number of times commit is told to squash") - .prereq(commitSquashEvents); - commitNonSpecStalls - .name(name() + ".commitNonSpecStalls") - .desc("The number of times commit has been forced to stall to " - "communicate backwards") - .prereq(commitNonSpecStalls); - branchMispredicts - .name(name() + ".branchMispredicts") - .desc("The number of times a branch was mispredicted") - .prereq(branchMispredicts); - numCommittedDist - .init(0,commitWidth,1) - .name(name() + ".COM:committed_per_cycle") - .desc("Number of insts commited each cycle") - .flags(Stats::pdf) - ; - - statComInst - .init(cpu->number_of_threads) - .name(name() + ".COM:count") - .desc("Number of instructions committed") - .flags(total) - ; - - statComSwp - .init(cpu->number_of_threads) - .name(name() + ".COM:swp_count") - .desc("Number of s/w prefetches committed") - .flags(total) - ; - - statComRefs - .init(cpu->number_of_threads) - .name(name() + ".COM:refs") - .desc("Number of memory references committed") - .flags(total) - ; - - statComLoads - .init(cpu->number_of_threads) - .name(name() + ".COM:loads") - .desc("Number of loads committed") - .flags(total) - ; - - statComMembars - .init(cpu->number_of_threads) - .name(name() + ".COM:membars") - .desc("Number of memory barriers committed") - .flags(total) - ; - - statComBranches - .init(cpu->number_of_threads) - .name(name() + ".COM:branches") - .desc("Number of branches committed") - .flags(total) - ; - - // - // Commit-Eligible instructions... - // - // -> The number of instructions eligible to commit in those - // cycles where we reached our commit BW limit (less the number - // actually committed) - // - // -> The average value is computed over ALL CYCLES... not just - // the BW limited cycles - // - // -> The standard deviation is computed only over cycles where - // we reached the BW limit - // - commitEligible - .init(cpu->number_of_threads) - .name(name() + ".COM:bw_limited") - .desc("number of insts not committed due to BW limits") - .flags(total) - ; - - commitEligibleSamples - .name(name() + ".COM:bw_lim_events") - .desc("number cycles where commit BW limit reached") - ; -} - -template <class Impl> -void -DefaultCommit<Impl>::setCPU(FullCPU *cpu_ptr) -{ - DPRINTF(Commit, "Commit: Setting CPU pointer.\n"); - cpu = cpu_ptr; - - // Commit must broadcast the number of free entries it has at the start of - // the simulation, so it starts as active. - cpu->activateStage(FullCPU::CommitIdx); - - trapLatency = cpu->cycles(trapLatency); - fetchTrapLatency = cpu->cycles(fetchTrapLatency); -} - -template <class Impl> -void -DefaultCommit<Impl>::setThreads(vector<Thread *> &threads) -{ - thread = threads; -} - -template <class Impl> -void -DefaultCommit<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) -{ - DPRINTF(Commit, "Commit: Setting time buffer pointer.\n"); - timeBuffer = tb_ptr; - - // Setup wire to send information back to IEW. - toIEW = timeBuffer->getWire(0); - - // Setup wire to read data from IEW (for the ROB). - robInfoFromIEW = timeBuffer->getWire(-iewToCommitDelay); -} - -template <class Impl> -void -DefaultCommit<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr) -{ - DPRINTF(Commit, "Commit: Setting fetch queue pointer.\n"); - fetchQueue = fq_ptr; - - // Setup wire to get instructions from rename (for the ROB). - fromFetch = fetchQueue->getWire(-fetchToCommitDelay); -} - -template <class Impl> -void -DefaultCommit<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr) -{ - DPRINTF(Commit, "Commit: Setting rename queue pointer.\n"); - renameQueue = rq_ptr; - - // Setup wire to get instructions from rename (for the ROB). - fromRename = renameQueue->getWire(-renameToROBDelay); -} - -template <class Impl> -void -DefaultCommit<Impl>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr) -{ - DPRINTF(Commit, "Commit: Setting IEW queue pointer.\n"); - iewQueue = iq_ptr; - - // Setup wire to get instructions from IEW. - fromIEW = iewQueue->getWire(-iewToCommitDelay); -} - -template <class Impl> -void -DefaultCommit<Impl>::setFetchStage(Fetch *fetch_stage) -{ - fetchStage = fetch_stage; -} - -template <class Impl> -void -DefaultCommit<Impl>::setIEWStage(IEW *iew_stage) -{ - iewStage = iew_stage; -} - -template<class Impl> -void -DefaultCommit<Impl>::setActiveThreads(list<unsigned> *at_ptr) -{ - DPRINTF(Commit, "Commit: Setting active threads list pointer.\n"); - activeThreads = at_ptr; -} - -template <class Impl> -void -DefaultCommit<Impl>::setRenameMap(RenameMap rm_ptr[]) -{ - DPRINTF(Commit, "Setting rename map pointers.\n"); - - for (int i=0; i < numThreads; i++) { - renameMap[i] = &rm_ptr[i]; - } -} - -template <class Impl> -void -DefaultCommit<Impl>::setROB(ROB *rob_ptr) -{ - DPRINTF(Commit, "Commit: Setting ROB pointer.\n"); - rob = rob_ptr; -} - -template <class Impl> -void -DefaultCommit<Impl>::initStage() -{ - rob->setActiveThreads(activeThreads); - rob->resetEntries(); - - // Broadcast the number of free entries. - for (int i=0; i < numThreads; i++) { - toIEW->commitInfo[i].usedROB = true; - toIEW->commitInfo[i].freeROBEntries = rob->numFreeEntries(i); - } - - cpu->activityThisCycle(); -} - -template <class Impl> -void -DefaultCommit<Impl>::switchOut() -{ - switchPending = true; -} - -template <class Impl> -void -DefaultCommit<Impl>::doSwitchOut() -{ - switchedOut = true; - switchPending = false; - rob->switchOut(); -} - -template <class Impl> -void -DefaultCommit<Impl>::takeOverFrom() -{ - switchedOut = false; - _status = Active; - _nextStatus = Inactive; - for (int i=0; i < numThreads; i++) { - commitStatus[i] = Idle; - changedROBNumEntries[i] = false; - trapSquash[i] = false; - xcSquash[i] = false; - } - squashCounter = 0; - rob->takeOverFrom(); -} - -template <class Impl> -void -DefaultCommit<Impl>::updateStatus() -{ - // reset ROB changed variable - list<unsigned>::iterator threads = (*activeThreads).begin(); - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - changedROBNumEntries[tid] = false; - - // Also check if any of the threads has a trap pending - if (commitStatus[tid] == TrapPending || - commitStatus[tid] == FetchTrapPending) { - _nextStatus = Active; - } - } - - if (_nextStatus == Inactive && _status == Active) { - DPRINTF(Activity, "Deactivating stage.\n"); - cpu->deactivateStage(FullCPU::CommitIdx); - } else if (_nextStatus == Active && _status == Inactive) { - DPRINTF(Activity, "Activating stage.\n"); - cpu->activateStage(FullCPU::CommitIdx); - } - - _status = _nextStatus; -} - -template <class Impl> -void -DefaultCommit<Impl>::setNextStatus() -{ - int squashes = 0; - - list<unsigned>::iterator threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - if (commitStatus[tid] == ROBSquashing) { - squashes++; - } - } - - assert(squashes == squashCounter); - - // If commit is currently squashing, then it will have activity for the - // next cycle. Set its next status as active. - if (squashCounter) { - _nextStatus = Active; - } -} - -template <class Impl> -bool -DefaultCommit<Impl>::changedROBEntries() -{ - list<unsigned>::iterator threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - if (changedROBNumEntries[tid]) { - return true; - } - } - - return false; -} - -template <class Impl> -unsigned -DefaultCommit<Impl>::numROBFreeEntries(unsigned tid) -{ - return rob->numFreeEntries(tid); -} - -template <class Impl> -void -DefaultCommit<Impl>::generateTrapEvent(unsigned tid) -{ - DPRINTF(Commit, "Generating trap event for [tid:%i]\n", tid); - - TrapEvent *trap = new TrapEvent(this, tid); - - trap->schedule(curTick + trapLatency); - - thread[tid]->trapPending = true; -} - -template <class Impl> -void -DefaultCommit<Impl>::generateXCEvent(unsigned tid) -{ - DPRINTF(Commit, "Generating XC squash event for [tid:%i]\n", tid); - - xcSquash[tid] = true; -} - -template <class Impl> -void -DefaultCommit<Impl>::squashAll(unsigned tid) -{ - // If we want to include the squashing instruction in the squash, - // then use one older sequence number. - // Hopefully this doesn't mess things up. Basically I want to squash - // all instructions of this thread. - InstSeqNum squashed_inst = rob->isEmpty() ? - 0 : rob->readHeadInst(tid)->seqNum - 1;; - - // All younger instructions will be squashed. Set the sequence - // number as the youngest instruction in the ROB (0 in this case. - // Hopefully nothing breaks.) - youngestSeqNum[tid] = 0; - - rob->squash(squashed_inst, tid); - changedROBNumEntries[tid] = true; - - // Send back the sequence number of the squashed instruction. - toIEW->commitInfo[tid].doneSeqNum = squashed_inst; - - // Send back the squash signal to tell stages that they should - // squash. - toIEW->commitInfo[tid].squash = true; - - // Send back the rob squashing signal so other stages know that - // the ROB is in the process of squashing. - toIEW->commitInfo[tid].robSquashing = true; - - toIEW->commitInfo[tid].branchMispredict = false; - - toIEW->commitInfo[tid].nextPC = PC[tid]; -} - -template <class Impl> -void -DefaultCommit<Impl>::squashFromTrap(unsigned tid) -{ - squashAll(tid); - - DPRINTF(Commit, "Squashing from trap, restarting at PC %#x\n", PC[tid]); - - thread[tid]->trapPending = false; - thread[tid]->inSyscall = false; - - trapSquash[tid] = false; - - commitStatus[tid] = ROBSquashing; - cpu->activityThisCycle(); - - ++squashCounter; -} - -template <class Impl> -void -DefaultCommit<Impl>::squashFromXC(unsigned tid) -{ - squashAll(tid); - - DPRINTF(Commit, "Squashing from XC, restarting at PC %#x\n", PC[tid]); - - thread[tid]->inSyscall = false; - assert(!thread[tid]->trapPending); - - commitStatus[tid] = ROBSquashing; - cpu->activityThisCycle(); - - xcSquash[tid] = false; - - ++squashCounter; -} - -template <class Impl> -void -DefaultCommit<Impl>::tick() -{ - wroteToTimeBuffer = false; - _nextStatus = Inactive; - - if (switchPending && rob->isEmpty() && !iewStage->hasStoresToWB()) { - cpu->signalSwitched(); - return; - } - - list<unsigned>::iterator threads = (*activeThreads).begin(); - - // Check if any of the threads are done squashing. Change the - // status if they are done. - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - if (commitStatus[tid] == ROBSquashing) { - - if (rob->isDoneSquashing(tid)) { - commitStatus[tid] = Running; - --squashCounter; - } else { - DPRINTF(Commit,"[tid:%u]: Still Squashing, cannot commit any" - "insts this cycle.\n", tid); - } - } - } - - commit(); - - markCompletedInsts(); - - threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - if (!rob->isEmpty(tid) && rob->readHeadInst(tid)->readyToCommit()) { - // The ROB has more instructions it can commit. Its next status - // will be active. - _nextStatus = Active; - - DynInstPtr inst = rob->readHeadInst(tid); - - DPRINTF(Commit,"[tid:%i]: Instruction [sn:%lli] PC %#x is head of" - " ROB and ready to commit\n", - tid, inst->seqNum, inst->readPC()); - - } else if (!rob->isEmpty(tid)) { - DynInstPtr inst = rob->readHeadInst(tid); - - DPRINTF(Commit,"[tid:%i]: Can't commit, Instruction [sn:%lli] PC " - "%#x is head of ROB and not ready\n", - tid, inst->seqNum, inst->readPC()); - } - - DPRINTF(Commit, "[tid:%i]: ROB has %d insts & %d free entries.\n", - tid, rob->countInsts(tid), rob->numFreeEntries(tid)); - } - - - if (wroteToTimeBuffer) { - DPRINTF(Activity, "Activity This Cycle.\n"); - cpu->activityThisCycle(); - } - - updateStatus(); -} - -template <class Impl> -void -DefaultCommit<Impl>::commit() -{ - - ////////////////////////////////////// - // Check for interrupts - ////////////////////////////////////// - -#if FULL_SYSTEM - // Process interrupts if interrupts are enabled, not in PAL mode, - // and no other traps or external squashes are currently pending. - // @todo: Allow other threads to handle interrupts. - if (cpu->checkInterrupts && - cpu->check_interrupts() && - !cpu->inPalMode(readPC()) && - !trapSquash[0] && - !xcSquash[0]) { - // Tell fetch that there is an interrupt pending. This will - // make fetch wait until it sees a non PAL-mode PC, at which - // point it stops fetching instructions. - toIEW->commitInfo[0].interruptPending = true; - - // Wait until the ROB is empty and all stores have drained in - // order to enter the interrupt. - if (rob->isEmpty() && !iewStage->hasStoresToWB()) { - // Not sure which thread should be the one to interrupt. For now - // always do thread 0. - assert(!thread[0]->inSyscall); - thread[0]->inSyscall = true; - - // CPU will handle implementation of the interrupt. - cpu->processInterrupts(); - - // Now squash or record that I need to squash this cycle. - commitStatus[0] = TrapPending; - - // Exit state update mode to avoid accidental updating. - thread[0]->inSyscall = false; - - // Generate trap squash event. - generateTrapEvent(0); - - toIEW->commitInfo[0].clearInterrupt = true; - - DPRINTF(Commit, "Interrupt detected.\n"); - } else { - DPRINTF(Commit, "Interrupt pending, waiting for ROB to empty.\n"); - } - } -#endif // FULL_SYSTEM - - //////////////////////////////////// - // Check for any possible squashes, handle them first - //////////////////////////////////// - - list<unsigned>::iterator threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - if (fromFetch->fetchFault && commitStatus[0] != TrapPending) { - // Record the fault. Wait until it's empty in the ROB. - // Then handle the trap. Ignore it if there's already a - // trap pending as fetch will be redirected. - fetchFault = fromFetch->fetchFault; - fetchFaultTick = curTick + fetchTrapLatency; - commitStatus[0] = FetchTrapPending; - DPRINTF(Commit, "Fault from fetch recorded. Will trap if the " - "ROB empties without squashing the fault.\n"); - fetchTrapWait = 0; - } - - // Fetch may tell commit to clear the trap if it's been squashed. - if (fromFetch->clearFetchFault) { - DPRINTF(Commit, "Received clear fetch fault signal\n"); - fetchTrapWait = 0; - if (commitStatus[0] == FetchTrapPending) { - DPRINTF(Commit, "Clearing fault from fetch\n"); - commitStatus[0] = Running; - } - } - - // Not sure which one takes priority. I think if we have - // both, that's a bad sign. - if (trapSquash[tid] == true) { - assert(!xcSquash[tid]); - squashFromTrap(tid); - } else if (xcSquash[tid] == true) { - squashFromXC(tid); - } - - // Squashed sequence number must be older than youngest valid - // instruction in the ROB. This prevents squashes from younger - // instructions overriding squashes from older instructions. - if (fromIEW->squash[tid] && - commitStatus[tid] != TrapPending && - fromIEW->squashedSeqNum[tid] <= youngestSeqNum[tid]) { - - DPRINTF(Commit, "[tid:%i]: Squashing due to PC %#x [sn:%i]\n", - tid, - fromIEW->mispredPC[tid], - fromIEW->squashedSeqNum[tid]); - - DPRINTF(Commit, "[tid:%i]: Redirecting to PC %#x\n", - tid, - fromIEW->nextPC[tid]); - - commitStatus[tid] = ROBSquashing; - - ++squashCounter; - - // If we want to include the squashing instruction in the squash, - // then use one older sequence number. - InstSeqNum squashed_inst = fromIEW->squashedSeqNum[tid]; - - if (fromIEW->includeSquashInst[tid] == true) - squashed_inst--; - - // All younger instructions will be squashed. Set the sequence - // number as the youngest instruction in the ROB. - youngestSeqNum[tid] = squashed_inst; - - rob->squash(squashed_inst, tid); - changedROBNumEntries[tid] = true; - - toIEW->commitInfo[tid].doneSeqNum = squashed_inst; - - toIEW->commitInfo[tid].squash = true; - - // Send back the rob squashing signal so other stages know that - // the ROB is in the process of squashing. - toIEW->commitInfo[tid].robSquashing = true; - - toIEW->commitInfo[tid].branchMispredict = - fromIEW->branchMispredict[tid]; - - toIEW->commitInfo[tid].branchTaken = - fromIEW->branchTaken[tid]; - - toIEW->commitInfo[tid].nextPC = fromIEW->nextPC[tid]; - - toIEW->commitInfo[tid].mispredPC = fromIEW->mispredPC[tid]; - - if (toIEW->commitInfo[tid].branchMispredict) { - ++branchMispredicts; - } - } - - } - - setNextStatus(); - - if (squashCounter != numThreads) { - // If we're not currently squashing, then get instructions. - getInsts(); - - // Try to commit any instructions. - commitInsts(); - } - - //Check for any activity - threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - if (changedROBNumEntries[tid]) { - toIEW->commitInfo[tid].usedROB = true; - toIEW->commitInfo[tid].freeROBEntries = rob->numFreeEntries(tid); - - if (rob->isEmpty(tid)) { - toIEW->commitInfo[tid].emptyROB = true; - } - - wroteToTimeBuffer = true; - changedROBNumEntries[tid] = false; - } - } -} - -template <class Impl> -void -DefaultCommit<Impl>::commitInsts() -{ - //////////////////////////////////// - // Handle commit - // Note that commit will be handled prior to putting new - // instructions in the ROB so that the ROB only tries to commit - // instructions it has in this current cycle, and not instructions - // it is writing in during this cycle. Can't commit and squash - // things at the same time... - //////////////////////////////////// - - DPRINTF(Commit, "Trying to commit instructions in the ROB.\n"); - - unsigned num_committed = 0; - - DynInstPtr head_inst; - - // Commit as many instructions as possible until the commit bandwidth - // limit is reached, or it becomes impossible to commit any more. - while (num_committed < commitWidth) { - int commit_thread = getCommittingThread(); - - if (commit_thread == -1 || !rob->isHeadReady(commit_thread)) - break; - - head_inst = rob->readHeadInst(commit_thread); - - int tid = head_inst->threadNumber; - - assert(tid == commit_thread); - - DPRINTF(Commit, "Trying to commit head instruction, [sn:%i] [tid:%i]\n", - head_inst->seqNum, tid); - - // If the head instruction is squashed, it is ready to retire - // (be removed from the ROB) at any time. - if (head_inst->isSquashed()) { - - DPRINTF(Commit, "Retiring squashed instruction from " - "ROB.\n"); - - rob->retireHead(commit_thread); - - ++commitSquashedInsts; - - // Record that the number of ROB entries has changed. - changedROBNumEntries[tid] = true; - } else { - PC[tid] = head_inst->readPC(); - nextPC[tid] = head_inst->readNextPC(); - - // Increment the total number of non-speculative instructions - // executed. - // Hack for now: it really shouldn't happen until after the - // commit is deemed to be successful, but this count is needed - // for syscalls. - thread[tid]->funcExeInst++; - - // Try to commit the head instruction. - bool commit_success = commitHead(head_inst, num_committed); - - if (commit_success) { - ++num_committed; - - changedROBNumEntries[tid] = true; - - // Set the doneSeqNum to the youngest committed instruction. - toIEW->commitInfo[tid].doneSeqNum = head_inst->seqNum; - - ++commitCommittedInsts; - - // To match the old model, don't count nops and instruction - // prefetches towards the total commit count. - if (!head_inst->isNop() && !head_inst->isInstPrefetch()) { - cpu->instDone(tid); - } - - PC[tid] = nextPC[tid]; - nextPC[tid] = nextPC[tid] + sizeof(TheISA::MachInst); -#if FULL_SYSTEM - int count = 0; - Addr oldpc; - do { - // Debug statement. Checks to make sure we're not - // currently updating state while handling PC events. - if (count == 0) - assert(!thread[tid]->inSyscall && - !thread[tid]->trapPending); - oldpc = PC[tid]; - cpu->system->pcEventQueue.service( - thread[tid]->getXCProxy()); - count++; - } while (oldpc != PC[tid]); - if (count > 1) { - DPRINTF(Commit, "PC skip function event, stopping commit\n"); - break; - } -#endif - } else { - DPRINTF(Commit, "Unable to commit head instruction PC:%#x " - "[tid:%i] [sn:%i].\n", - head_inst->readPC(), tid ,head_inst->seqNum); - break; - } - } - } - - DPRINTF(CommitRate, "%i\n", num_committed); - numCommittedDist.sample(num_committed); - - if (num_committed == commitWidth) { - commitEligible[0]++; - } -} - -template <class Impl> -bool -DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num) -{ - assert(head_inst); - - int tid = head_inst->threadNumber; - - // If the instruction is not executed yet, then it will need extra - // handling. Signal backwards that it should be executed. - if (!head_inst->isExecuted()) { - // Keep this number correct. We have not yet actually executed - // and committed this instruction. - thread[tid]->funcExeInst--; - - head_inst->reachedCommit = true; - - if (head_inst->isNonSpeculative() || - head_inst->isMemBarrier() || - head_inst->isWriteBarrier()) { - - DPRINTF(Commit, "Encountered a barrier or non-speculative " - "instruction [sn:%lli] at the head of the ROB, PC %#x.\n", - head_inst->seqNum, head_inst->readPC()); - -#if !FULL_SYSTEM - // Hack to make sure syscalls/memory barriers/quiesces - // aren't executed until all stores write back their data. - // This direct communication shouldn't be used for - // anything other than this. - if (inst_num > 0 || iewStage->hasStoresToWB()) -#else - if ((head_inst->isMemBarrier() || head_inst->isWriteBarrier() || - head_inst->isQuiesce()) && - iewStage->hasStoresToWB()) -#endif - { - DPRINTF(Commit, "Waiting for all stores to writeback.\n"); - return false; - } - - toIEW->commitInfo[tid].nonSpecSeqNum = head_inst->seqNum; - - // Change the instruction so it won't try to commit again until - // it is executed. - head_inst->clearCanCommit(); - - ++commitNonSpecStalls; - - return false; - } else if (head_inst->isLoad()) { - DPRINTF(Commit, "[sn:%lli]: Uncached load, PC %#x.\n", - head_inst->seqNum, head_inst->readPC()); - - // Send back the non-speculative instruction's sequence - // number. Tell the lsq to re-execute the load. - toIEW->commitInfo[tid].nonSpecSeqNum = head_inst->seqNum; - toIEW->commitInfo[tid].uncached = true; - toIEW->commitInfo[tid].uncachedLoad = head_inst; - - head_inst->clearCanCommit(); - - return false; - } else { - panic("Trying to commit un-executed instruction " - "of unknown type!\n"); - } - } - - if (head_inst->isThreadSync()) { - // Not handled for now. - panic("Thread sync instructions are not handled yet.\n"); - } - - // Stores mark themselves as completed. - if (!head_inst->isStore()) { - head_inst->setCompleted(); - } - - // Use checker prior to updating anything due to traps or PC - // based events. - if (cpu->checker) { - cpu->checker->tick(head_inst); - } - - // Check if the instruction caused a fault. If so, trap. - Fault inst_fault = head_inst->getFault(); - - if (inst_fault != NoFault) { - head_inst->setCompleted(); -#if FULL_SYSTEM - DPRINTF(Commit, "Inst [sn:%lli] PC %#x has a fault\n", - head_inst->seqNum, head_inst->readPC()); - - if (iewStage->hasStoresToWB() || inst_num > 0) { - DPRINTF(Commit, "Stores outstanding, fault must wait.\n"); - return false; - } - - if (cpu->checker && head_inst->isStore()) { - cpu->checker->tick(head_inst); - } - - assert(!thread[tid]->inSyscall); - - // Mark that we're in state update mode so that the trap's - // execution doesn't generate extra squashes. - thread[tid]->inSyscall = true; - - // DTB will sometimes need the machine instruction for when - // faults happen. So we will set it here, prior to the DTB - // possibly needing it for its fault. - thread[tid]->setInst( - static_cast<TheISA::MachInst>(head_inst->staticInst->machInst)); - - // Execute the trap. Although it's slightly unrealistic in - // terms of timing (as it doesn't wait for the full timing of - // the trap event to complete before updating state), it's - // needed to update the state as soon as possible. This - // prevents external agents from changing any specific state - // that the trap need. - cpu->trap(inst_fault, tid); - - // Exit state update mode to avoid accidental updating. - thread[tid]->inSyscall = false; - - commitStatus[tid] = TrapPending; - - // Generate trap squash event. - generateTrapEvent(tid); - - return false; -#else // !FULL_SYSTEM - panic("fault (%d) detected @ PC %08p", inst_fault, - head_inst->PC); -#endif // FULL_SYSTEM - } - - updateComInstStats(head_inst); - - if (head_inst->traceData) { - head_inst->traceData->setFetchSeq(head_inst->seqNum); - head_inst->traceData->setCPSeq(thread[tid]->numInst); - head_inst->traceData->finalize(); - head_inst->traceData = NULL; - } - - // Update the commit rename map - for (int i = 0; i < head_inst->numDestRegs(); i++) { - renameMap[tid]->setEntry(head_inst->destRegIdx(i), - head_inst->renamedDestRegIdx(i)); - } - - // Finally clear the head ROB entry. - rob->retireHead(tid); - - // Return true to indicate that we have committed an instruction. - return true; -} - -template <class Impl> -void -DefaultCommit<Impl>::getInsts() -{ - // Read any renamed instructions and place them into the ROB. - int insts_to_process = min((int)renameWidth, fromRename->size); - - for (int inst_num = 0; inst_num < insts_to_process; ++inst_num) - { - DynInstPtr inst = fromRename->insts[inst_num]; - int tid = inst->threadNumber; - - if (!inst->isSquashed() && - commitStatus[tid] != ROBSquashing) { - changedROBNumEntries[tid] = true; - - DPRINTF(Commit, "Inserting PC %#x [sn:%i] [tid:%i] into ROB.\n", - inst->readPC(), inst->seqNum, tid); - - rob->insertInst(inst); - - assert(rob->getThreadEntries(tid) <= rob->getMaxEntries(tid)); - - youngestSeqNum[tid] = inst->seqNum; - } else { - DPRINTF(Commit, "Instruction PC %#x [sn:%i] [tid:%i] was " - "squashed, skipping.\n", - inst->readPC(), inst->seqNum, tid); - } - } -} - -template <class Impl> -void -DefaultCommit<Impl>::markCompletedInsts() -{ - // Grab completed insts out of the IEW instruction queue, and mark - // instructions completed within the ROB. - for (int inst_num = 0; - inst_num < fromIEW->size && fromIEW->insts[inst_num]; - ++inst_num) - { - if (!fromIEW->insts[inst_num]->isSquashed()) { - DPRINTF(Commit, "[tid:%i]: Marking PC %#x, [sn:%lli] ready " - "within ROB.\n", - fromIEW->insts[inst_num]->threadNumber, - fromIEW->insts[inst_num]->readPC(), - fromIEW->insts[inst_num]->seqNum); - - // Mark the instruction as ready to commit. - fromIEW->insts[inst_num]->setCanCommit(); - } - } -} - -template <class Impl> -bool -DefaultCommit<Impl>::robDoneSquashing() -{ - list<unsigned>::iterator threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - if (!rob->isDoneSquashing(tid)) - return false; - } - - return true; -} - -template <class Impl> -void -DefaultCommit<Impl>::updateComInstStats(DynInstPtr &inst) -{ - unsigned thread = inst->threadNumber; - - // - // Pick off the software prefetches - // -#ifdef TARGET_ALPHA - if (inst->isDataPrefetch()) { - statComSwp[thread]++; - } else { - statComInst[thread]++; - } -#else - statComInst[thread]++; -#endif - - // - // Control Instructions - // - if (inst->isControl()) - statComBranches[thread]++; - - // - // Memory references - // - if (inst->isMemRef()) { - statComRefs[thread]++; - - if (inst->isLoad()) { - statComLoads[thread]++; - } - } - - if (inst->isMemBarrier()) { - statComMembars[thread]++; - } -} - -//////////////////////////////////////// -// // -// SMT COMMIT POLICY MAINTAINED HERE // -// // -//////////////////////////////////////// -template <class Impl> -int -DefaultCommit<Impl>::getCommittingThread() -{ - if (numThreads > 1) { - switch (commitPolicy) { - - case Aggressive: - //If Policy is Aggressive, commit will call - //this function multiple times per - //cycle - return oldestReady(); - - case RoundRobin: - return roundRobin(); - - case OldestReady: - return oldestReady(); - - default: - return -1; - } - } else { - int tid = (*activeThreads).front(); - - if (commitStatus[tid] == Running || - commitStatus[tid] == Idle || - commitStatus[tid] == FetchTrapPending) { - return tid; - } else { - return -1; - } - } -} - -template<class Impl> -int -DefaultCommit<Impl>::roundRobin() -{ - list<unsigned>::iterator pri_iter = priority_list.begin(); - list<unsigned>::iterator end = priority_list.end(); - - while (pri_iter != end) { - unsigned tid = *pri_iter; - - if (commitStatus[tid] == Running || - commitStatus[tid] == Idle) { - - if (rob->isHeadReady(tid)) { - priority_list.erase(pri_iter); - priority_list.push_back(tid); - - return tid; - } - } - - pri_iter++; - } - - return -1; -} - -template<class Impl> -int -DefaultCommit<Impl>::oldestReady() -{ - unsigned oldest = 0; - bool first = true; - - list<unsigned>::iterator threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - if (!rob->isEmpty(tid) && - (commitStatus[tid] == Running || - commitStatus[tid] == Idle || - commitStatus[tid] == FetchTrapPending)) { - - if (rob->isHeadReady(tid)) { - - DynInstPtr head_inst = rob->readHeadInst(tid); - - if (first) { - oldest = tid; - first = false; - } else if (head_inst->seqNum < oldest) { - oldest = tid; - } - } - } - } - - if (!first) { - return oldest; - } else { - return -1; - } -} diff --git a/cpu/o3/cpu.cc b/cpu/o3/cpu.cc deleted file mode 100644 index 8d72bdc41..000000000 --- a/cpu/o3/cpu.cc +++ /dev/null @@ -1,1183 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config/full_system.hh" - -#if FULL_SYSTEM -#include "sim/system.hh" -#else -#include "sim/process.hh" -#endif - -#include "cpu/activity.hh" -#include "cpu/checker/cpu.hh" -#include "cpu/cpu_exec_context.hh" -#include "cpu/exec_context.hh" -#include "cpu/o3/alpha_dyn_inst.hh" -#include "cpu/o3/alpha_impl.hh" -#include "cpu/o3/cpu.hh" - -#include "sim/root.hh" -#include "sim/stat_control.hh" - -using namespace std; - -BaseFullCPU::BaseFullCPU(Params *params) - : BaseCPU(params), cpu_id(0) -{ -} - -void -BaseFullCPU::regStats() -{ - BaseCPU::regStats(); -} - -template <class Impl> -FullO3CPU<Impl>::TickEvent::TickEvent(FullO3CPU<Impl> *c) - : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) -{ -} - -template <class Impl> -void -FullO3CPU<Impl>::TickEvent::process() -{ - cpu->tick(); -} - -template <class Impl> -const char * -FullO3CPU<Impl>::TickEvent::description() -{ - return "FullO3CPU tick event"; -} - -template <class Impl> -FullO3CPU<Impl>::FullO3CPU(Params *params) - : BaseFullCPU(params), - tickEvent(this), - removeInstsThisCycle(false), - fetch(params), - decode(params), - rename(params), - iew(params), - commit(params), - - regFile(params->numPhysIntRegs, params->numPhysFloatRegs), - - freeList(params->numberOfThreads,//number of activeThreads - TheISA::NumIntRegs, params->numPhysIntRegs, - TheISA::NumFloatRegs, params->numPhysFloatRegs), - - rob(params->numROBEntries, params->squashWidth, - params->smtROBPolicy, params->smtROBThreshold, - params->numberOfThreads), - - scoreboard(params->numberOfThreads,//number of activeThreads - TheISA::NumIntRegs, params->numPhysIntRegs, - TheISA::NumFloatRegs, params->numPhysFloatRegs, - TheISA::NumMiscRegs * number_of_threads, - TheISA::ZeroReg), - - // For now just have these time buffers be pretty big. - // @todo: Make these time buffer sizes parameters or derived - // from latencies - timeBuffer(5, 5), - fetchQueue(5, 5), - decodeQueue(5, 5), - renameQueue(5, 5), - iewQueue(5, 5), - activityRec(NumStages, 10, params->activity), - - globalSeqNum(1), - -#if FULL_SYSTEM - system(params->system), - memCtrl(system->memctrl), - physmem(system->physmem), - mem(params->mem), -#else -// pTable(params->pTable), - mem(params->workload[0]->getMemory()), -#endif // FULL_SYSTEM - switchCount(0), - icacheInterface(params->icacheInterface), - dcacheInterface(params->dcacheInterface), - deferRegistration(params->deferRegistration), - numThreads(number_of_threads) -{ - _status = Idle; - - if (params->checker) { - BaseCPU *temp_checker = params->checker; - checker = dynamic_cast<Checker<DynInstPtr> *>(temp_checker); - checker->setMemory(mem); -#if FULL_SYSTEM - checker->setSystem(params->system); -#endif - } else { - checker = NULL; - } - -#if !FULL_SYSTEM - thread.resize(number_of_threads); - tids.resize(number_of_threads); -#endif - - // The stages also need their CPU pointer setup. However this - // must be done at the upper level CPU because they have pointers - // to the upper level CPU, and not this FullO3CPU. - - // Set up Pointers to the activeThreads list for each stage - fetch.setActiveThreads(&activeThreads); - decode.setActiveThreads(&activeThreads); - rename.setActiveThreads(&activeThreads); - iew.setActiveThreads(&activeThreads); - commit.setActiveThreads(&activeThreads); - - // Give each of the stages the time buffer they will use. - fetch.setTimeBuffer(&timeBuffer); - decode.setTimeBuffer(&timeBuffer); - rename.setTimeBuffer(&timeBuffer); - iew.setTimeBuffer(&timeBuffer); - commit.setTimeBuffer(&timeBuffer); - - // Also setup each of the stages' queues. - fetch.setFetchQueue(&fetchQueue); - decode.setFetchQueue(&fetchQueue); - commit.setFetchQueue(&fetchQueue); - decode.setDecodeQueue(&decodeQueue); - rename.setDecodeQueue(&decodeQueue); - rename.setRenameQueue(&renameQueue); - iew.setRenameQueue(&renameQueue); - iew.setIEWQueue(&iewQueue); - commit.setIEWQueue(&iewQueue); - commit.setRenameQueue(&renameQueue); - - commit.setFetchStage(&fetch); - commit.setIEWStage(&iew); - rename.setIEWStage(&iew); - rename.setCommitStage(&commit); - -#if !FULL_SYSTEM - int active_threads = params->workload.size(); -#else - int active_threads = 1; -#endif - - //Make Sure That this a Valid Architeture - assert(params->numPhysIntRegs >= numThreads * TheISA::NumIntRegs); - assert(params->numPhysFloatRegs >= numThreads * TheISA::NumFloatRegs); - - rename.setScoreboard(&scoreboard); - iew.setScoreboard(&scoreboard); - - // Setup the rename map for whichever stages need it. - PhysRegIndex lreg_idx = 0; - PhysRegIndex freg_idx = params->numPhysIntRegs; //Index to 1 after int regs - - for (int tid=0; tid < numThreads; tid++) { - bool bindRegs = (tid <= active_threads - 1); - - commitRenameMap[tid].init(TheISA::NumIntRegs, - params->numPhysIntRegs, - lreg_idx, //Index for Logical. Regs - - TheISA::NumFloatRegs, - params->numPhysFloatRegs, - freg_idx, //Index for Float Regs - - TheISA::NumMiscRegs, - - TheISA::ZeroReg, - TheISA::ZeroReg, - - tid, - false); - - renameMap[tid].init(TheISA::NumIntRegs, - params->numPhysIntRegs, - lreg_idx, //Index for Logical. Regs - - TheISA::NumFloatRegs, - params->numPhysFloatRegs, - freg_idx, //Index for Float Regs - - TheISA::NumMiscRegs, - - TheISA::ZeroReg, - TheISA::ZeroReg, - - tid, - bindRegs); - } - - rename.setRenameMap(renameMap); - commit.setRenameMap(commitRenameMap); - - // Give renameMap & rename stage access to the freeList; - for (int i=0; i < numThreads; i++) { - renameMap[i].setFreeList(&freeList); - } - rename.setFreeList(&freeList); - - // Setup the page table for whichever stages need it. -#if !FULL_SYSTEM -// fetch.setPageTable(pTable); -// iew.setPageTable(pTable); -#endif - - // Setup the ROB for whichever stages need it. - commit.setROB(&rob); - - lastRunningCycle = curTick; - - contextSwitch = false; -} - -template <class Impl> -FullO3CPU<Impl>::~FullO3CPU() -{ -} - -template <class Impl> -void -FullO3CPU<Impl>::fullCPURegStats() -{ - BaseFullCPU::regStats(); - - // Register any of the FullCPU's stats here. - timesIdled - .name(name() + ".timesIdled") - .desc("Number of times that the entire CPU went into an idle state and" - " unscheduled itself") - .prereq(timesIdled); - - idleCycles - .name(name() + ".idleCycles") - .desc("Total number of cycles that the CPU has spent unscheduled due " - "to idling") - .prereq(idleCycles); - - // Number of Instructions simulated - // -------------------------------- - // Should probably be in Base CPU but need templated - // MaxThreads so put in here instead - committedInsts - .init(numThreads) - .name(name() + ".committedInsts") - .desc("Number of Instructions Simulated"); - - totalCommittedInsts - .name(name() + ".committedInsts_total") - .desc("Number of Instructions Simulated"); - - cpi - .name(name() + ".cpi") - .desc("CPI: Cycles Per Instruction") - .precision(6); - cpi = simTicks / committedInsts; - - totalCpi - .name(name() + ".cpi_total") - .desc("CPI: Total CPI of All Threads") - .precision(6); - totalCpi = simTicks / totalCommittedInsts; - - ipc - .name(name() + ".ipc") - .desc("IPC: Instructions Per Cycle") - .precision(6); - ipc = committedInsts / simTicks; - - totalIpc - .name(name() + ".ipc_total") - .desc("IPC: Total IPC of All Threads") - .precision(6); - totalIpc = totalCommittedInsts / simTicks; - -} - -template <class Impl> -void -FullO3CPU<Impl>::tick() -{ - DPRINTF(FullCPU, "\n\nFullCPU: Ticking main, FullO3CPU.\n"); - - ++numCycles; - -// activity = false; - - //Tick each of the stages - fetch.tick(); - - decode.tick(); - - rename.tick(); - - iew.tick(); - - commit.tick(); - -#if !FULL_SYSTEM - doContextSwitch(); -#endif - - // Now advance the time buffers - timeBuffer.advance(); - - fetchQueue.advance(); - decodeQueue.advance(); - renameQueue.advance(); - iewQueue.advance(); - - activityRec.advance(); - - if (removeInstsThisCycle) { - cleanUpRemovedInsts(); - } - - if (!tickEvent.scheduled()) { - if (_status == SwitchedOut) { - // increment stat - lastRunningCycle = curTick; - } else if (!activityRec.active()) { - lastRunningCycle = curTick; - timesIdled++; - } else { - tickEvent.schedule(curTick + cycles(1)); - } - } - -#if !FULL_SYSTEM - updateThreadPriority(); -#endif - -} - -template <class Impl> -void -FullO3CPU<Impl>::init() -{ - if (!deferRegistration) { - registerExecContexts(); - } - - // Set inSyscall so that the CPU doesn't squash when initially - // setting up registers. - for (int i = 0; i < number_of_threads; ++i) - thread[i]->inSyscall = true; - - for (int tid=0; tid < number_of_threads; tid++) { -#if FULL_SYSTEM - ExecContext *src_xc = execContexts[tid]; -#else - ExecContext *src_xc = thread[tid]->getXCProxy(); -#endif - // Threads start in the Suspended State - if (src_xc->status() != ExecContext::Suspended) { - continue; - } - -#if FULL_SYSTEM - TheISA::initCPU(src_xc, src_xc->readCpuId()); -#endif - } - - // Clear inSyscall. - for (int i = 0; i < number_of_threads; ++i) - thread[i]->inSyscall = false; - - // Initialize stages. - fetch.initStage(); - iew.initStage(); - rename.initStage(); - commit.initStage(); - - commit.setThreads(thread); -} - -template <class Impl> -void -FullO3CPU<Impl>::insertThread(unsigned tid) -{ - DPRINTF(FullCPU,"[tid:%i] Initializing thread data"); - // Will change now that the PC and thread state is internal to the CPU - // and not in the CPUExecContext. -#if 0 -#if FULL_SYSTEM - ExecContext *src_xc = system->execContexts[tid]; -#else - CPUExecContext *src_xc = thread[tid]; -#endif - - //Bind Int Regs to Rename Map - for (int ireg = 0; ireg < TheISA::NumIntRegs; ireg++) { - PhysRegIndex phys_reg = freeList.getIntReg(); - - renameMap[tid].setEntry(ireg,phys_reg); - scoreboard.setReg(phys_reg); - } - - //Bind Float Regs to Rename Map - for (int freg = 0; freg < TheISA::NumFloatRegs; freg++) { - PhysRegIndex phys_reg = freeList.getFloatReg(); - - renameMap[tid].setEntry(freg,phys_reg); - scoreboard.setReg(phys_reg); - } - - //Copy Thread Data Into RegFile - this->copyFromXC(tid); - - //Set PC/NPC - regFile.pc[tid] = src_xc->readPC(); - regFile.npc[tid] = src_xc->readNextPC(); - - src_xc->setStatus(ExecContext::Active); - - activateContext(tid,1); - - //Reset ROB/IQ/LSQ Entries - commit.rob->resetEntries(); - iew.resetEntries(); -#endif -} - -template <class Impl> -void -FullO3CPU<Impl>::removeThread(unsigned tid) -{ - DPRINTF(FullCPU,"[tid:%i] Removing thread data"); -#if 0 - //Unbind Int Regs from Rename Map - for (int ireg = 0; ireg < TheISA::NumIntRegs; ireg++) { - PhysRegIndex phys_reg = renameMap[tid].lookup(ireg); - - scoreboard.unsetReg(phys_reg); - freeList.addReg(phys_reg); - } - - //Unbind Float Regs from Rename Map - for (int freg = 0; freg < TheISA::NumFloatRegs; freg++) { - PhysRegIndex phys_reg = renameMap[tid].lookup(freg); - - scoreboard.unsetReg(phys_reg); - freeList.addReg(phys_reg); - } - - //Copy Thread Data From RegFile - /* Fix Me: - * Do we really need to do this if we are removing a thread - * in the sense that it's finished (exiting)? If the thread is just - * being suspended we might... - */ -// this->copyToXC(tid); - - //Squash Throughout Pipeline - fetch.squash(0,tid); - decode.squash(tid); - rename.squash(tid); - - assert(iew.ldstQueue.getCount(tid) == 0); - - //Reset ROB/IQ/LSQ Entries - if (activeThreads.size() >= 1) { - commit.rob->resetEntries(); - iew.resetEntries(); - } -#endif -} - - -template <class Impl> -void -FullO3CPU<Impl>::activateWhenReady(int tid) -{ - DPRINTF(FullCPU,"[tid:%i]: Checking if resources are available for incoming" - "(e.g. PhysRegs/ROB/IQ/LSQ) \n", - tid); - - bool ready = true; - - if (freeList.numFreeIntRegs() >= TheISA::NumIntRegs) { - DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " - "Phys. Int. Regs.\n", - tid); - ready = false; - } else if (freeList.numFreeFloatRegs() >= TheISA::NumFloatRegs) { - DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " - "Phys. Float. Regs.\n", - tid); - ready = false; - } else if (commit.rob->numFreeEntries() >= - commit.rob->entryAmount(activeThreads.size() + 1)) { - DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " - "ROB entries.\n", - tid); - ready = false; - } else if (iew.instQueue.numFreeEntries() >= - iew.instQueue.entryAmount(activeThreads.size() + 1)) { - DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " - "IQ entries.\n", - tid); - ready = false; - } else if (iew.ldstQueue.numFreeEntries() >= - iew.ldstQueue.entryAmount(activeThreads.size() + 1)) { - DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " - "LSQ entries.\n", - tid); - ready = false; - } - - if (ready) { - insertThread(tid); - - contextSwitch = false; - - cpuWaitList.remove(tid); - } else { - suspendContext(tid); - - //blocks fetch - contextSwitch = true; - - //do waitlist - cpuWaitList.push_back(tid); - } -} - -template <class Impl> -void -FullO3CPU<Impl>::activateContext(int tid, int delay) -{ - // Needs to set each stage to running as well. - list<unsigned>::iterator isActive = find( - activeThreads.begin(), activeThreads.end(), tid); - - if (isActive == activeThreads.end()) { - //May Need to Re-code this if the delay variable is the - //delay needed for thread to activate - DPRINTF(FullCPU, "Adding Thread %i to active threads list\n", - tid); - - activeThreads.push_back(tid); - } - - assert(_status == Idle || _status == SwitchedOut); - - scheduleTickEvent(delay); - - // Be sure to signal that there's some activity so the CPU doesn't - // deschedule itself. - activityRec.activity(); - fetch.wakeFromQuiesce(); - - _status = Running; -} - -template <class Impl> -void -FullO3CPU<Impl>::suspendContext(int tid) -{ - DPRINTF(FullCPU,"[tid: %i]: Suspended ...\n", tid); - unscheduleTickEvent(); - _status = Idle; -/* - //Remove From Active List, if Active - list<unsigned>::iterator isActive = find( - activeThreads.begin(), activeThreads.end(), tid); - - if (isActive != activeThreads.end()) { - DPRINTF(FullCPU,"[tid:%i]: Removing from active threads list\n", - tid); - activeThreads.erase(isActive); - } -*/ -} - -template <class Impl> -void -FullO3CPU<Impl>::deallocateContext(int tid) -{ - DPRINTF(FullCPU,"[tid:%i]: Deallocating ...", tid); -/* - //Remove From Active List, if Active - list<unsigned>::iterator isActive = find( - activeThreads.begin(), activeThreads.end(), tid); - - if (isActive != activeThreads.end()) { - DPRINTF(FullCPU,"[tid:%i]: Removing from active threads list\n", - tid); - activeThreads.erase(isActive); - - removeThread(tid); - } -*/ -} - -template <class Impl> -void -FullO3CPU<Impl>::haltContext(int tid) -{ - DPRINTF(FullCPU,"[tid:%i]: Halted ...", tid); -/* - //Remove From Active List, if Active - list<unsigned>::iterator isActive = find( - activeThreads.begin(), activeThreads.end(), tid); - - if (isActive != activeThreads.end()) { - DPRINTF(FullCPU,"[tid:%i]: Removing from active threads list\n", - tid); - activeThreads.erase(isActive); - - removeThread(tid); - } -*/ -} - -template <class Impl> -void -FullO3CPU<Impl>::switchOut(Sampler *_sampler) -{ - sampler = _sampler; - switchCount = 0; - fetch.switchOut(); - decode.switchOut(); - rename.switchOut(); - iew.switchOut(); - commit.switchOut(); - - // Wake the CPU and record activity so everything can drain out if - // the CPU is currently idle. - wakeCPU(); - activityRec.activity(); -} - -template <class Impl> -void -FullO3CPU<Impl>::signalSwitched() -{ - if (++switchCount == NumStages) { - fetch.doSwitchOut(); - rename.doSwitchOut(); - commit.doSwitchOut(); - instList.clear(); - while (!removeList.empty()) { - removeList.pop(); - } - - if (checker) - checker->switchOut(sampler); - - if (tickEvent.scheduled()) - tickEvent.squash(); - sampler->signalSwitched(); - _status = SwitchedOut; - } - assert(switchCount <= 5); -} - -template <class Impl> -void -FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU) -{ - // Flush out any old data from the time buffers. - for (int i = 0; i < 10; ++i) { - timeBuffer.advance(); - fetchQueue.advance(); - decodeQueue.advance(); - renameQueue.advance(); - iewQueue.advance(); - } - - activityRec.reset(); - - BaseCPU::takeOverFrom(oldCPU); - - fetch.takeOverFrom(); - decode.takeOverFrom(); - rename.takeOverFrom(); - iew.takeOverFrom(); - commit.takeOverFrom(); - - assert(!tickEvent.scheduled()); - - // @todo: Figure out how to properly select the tid to put onto - // the active threads list. - int tid = 0; - - list<unsigned>::iterator isActive = find( - activeThreads.begin(), activeThreads.end(), tid); - - if (isActive == activeThreads.end()) { - //May Need to Re-code this if the delay variable is the delay - //needed for thread to activate - DPRINTF(FullCPU, "Adding Thread %i to active threads list\n", - tid); - - activeThreads.push_back(tid); - } - - // Set all statuses to active, schedule the CPU's tick event. - // @todo: Fix up statuses so this is handled properly - for (int i = 0; i < execContexts.size(); ++i) { - ExecContext *xc = execContexts[i]; - if (xc->status() == ExecContext::Active && _status != Running) { - _status = Running; - tickEvent.schedule(curTick); - } - } - if (!tickEvent.scheduled()) - tickEvent.schedule(curTick); -} - -template <class Impl> -uint64_t -FullO3CPU<Impl>::readIntReg(int reg_idx) -{ - return regFile.readIntReg(reg_idx); -} - -template <class Impl> -float -FullO3CPU<Impl>::readFloatRegSingle(int reg_idx) -{ - return regFile.readFloatRegSingle(reg_idx); -} - -template <class Impl> -double -FullO3CPU<Impl>::readFloatRegDouble(int reg_idx) -{ - return regFile.readFloatRegDouble(reg_idx); -} - -template <class Impl> -uint64_t -FullO3CPU<Impl>::readFloatRegInt(int reg_idx) -{ - return regFile.readFloatRegInt(reg_idx); -} - -template <class Impl> -void -FullO3CPU<Impl>::setIntReg(int reg_idx, uint64_t val) -{ - regFile.setIntReg(reg_idx, val); -} - -template <class Impl> -void -FullO3CPU<Impl>::setFloatRegSingle(int reg_idx, float val) -{ - regFile.setFloatRegSingle(reg_idx, val); -} - -template <class Impl> -void -FullO3CPU<Impl>::setFloatRegDouble(int reg_idx, double val) -{ - regFile.setFloatRegDouble(reg_idx, val); -} - -template <class Impl> -void -FullO3CPU<Impl>::setFloatRegInt(int reg_idx, uint64_t val) -{ - regFile.setFloatRegInt(reg_idx, val); -} - -template <class Impl> -uint64_t -FullO3CPU<Impl>::readArchIntReg(int reg_idx, unsigned tid) -{ - PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); - - return regFile.readIntReg(phys_reg); -} - -template <class Impl> -float -FullO3CPU<Impl>::readArchFloatRegSingle(int reg_idx, unsigned tid) -{ - int idx = reg_idx + TheISA::FP_Base_DepTag; - PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx); - - return regFile.readFloatRegSingle(phys_reg); -} - -template <class Impl> -double -FullO3CPU<Impl>::readArchFloatRegDouble(int reg_idx, unsigned tid) -{ - int idx = reg_idx + TheISA::FP_Base_DepTag; - PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx); - - return regFile.readFloatRegDouble(phys_reg); -} - -template <class Impl> -uint64_t -FullO3CPU<Impl>::readArchFloatRegInt(int reg_idx, unsigned tid) -{ - int idx = reg_idx + TheISA::FP_Base_DepTag; - PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx); - - return regFile.readFloatRegInt(phys_reg); -} - -template <class Impl> -void -FullO3CPU<Impl>::setArchIntReg(int reg_idx, uint64_t val, unsigned tid) -{ - PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); - - regFile.setIntReg(phys_reg, val); -} - -template <class Impl> -void -FullO3CPU<Impl>::setArchFloatRegSingle(int reg_idx, float val, unsigned tid) -{ - PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); - - regFile.setFloatRegSingle(phys_reg, val); -} - -template <class Impl> -void -FullO3CPU<Impl>::setArchFloatRegDouble(int reg_idx, double val, unsigned tid) -{ - PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); - - regFile.setFloatRegDouble(phys_reg, val); -} - -template <class Impl> -void -FullO3CPU<Impl>::setArchFloatRegInt(int reg_idx, uint64_t val, unsigned tid) -{ - PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); - - regFile.setFloatRegInt(phys_reg, val); -} - -template <class Impl> -uint64_t -FullO3CPU<Impl>::readPC(unsigned tid) -{ - return commit.readPC(tid); -} - -template <class Impl> -void -FullO3CPU<Impl>::setPC(Addr new_PC,unsigned tid) -{ - commit.setPC(new_PC, tid); -} - -template <class Impl> -uint64_t -FullO3CPU<Impl>::readNextPC(unsigned tid) -{ - return commit.readNextPC(tid); -} - -template <class Impl> -void -FullO3CPU<Impl>::setNextPC(uint64_t val,unsigned tid) -{ - commit.setNextPC(val, tid); -} - -template <class Impl> -typename FullO3CPU<Impl>::ListIt -FullO3CPU<Impl>::addInst(DynInstPtr &inst) -{ - instList.push_back(inst); - - return --(instList.end()); -} - -template <class Impl> -void -FullO3CPU<Impl>::instDone(unsigned tid) -{ - // Keep an instruction count. - thread[tid]->numInst++; - thread[tid]->numInsts++; - committedInsts[tid]++; - totalCommittedInsts++; - - // Check for instruction-count-based events. - comInstEventQueue[tid]->serviceEvents(thread[tid]->numInst); -} - -template <class Impl> -void -FullO3CPU<Impl>::addToRemoveList(DynInstPtr &inst) -{ - removeInstsThisCycle = true; - - removeList.push(inst->getInstListIt()); -} - -template <class Impl> -void -FullO3CPU<Impl>::removeFrontInst(DynInstPtr &inst) -{ - DPRINTF(FullCPU, "FullCPU: Removing committed instruction [tid:%i] PC %#x " - "[sn:%lli]\n", - inst->threadNumber, inst->readPC(), inst->seqNum); - - removeInstsThisCycle = true; - - // Remove the front instruction. - removeList.push(inst->getInstListIt()); -} - -template <class Impl> -void -FullO3CPU<Impl>::removeInstsNotInROB(unsigned tid) -{ - DPRINTF(FullCPU, "FullCPU: Thread %i: Deleting instructions from instruction" - " list.\n", tid); - - ListIt end_it; - - bool rob_empty = false; - - if (instList.empty()) { - return; - } else if (rob.isEmpty(/*tid*/)) { - DPRINTF(FullCPU, "FullCPU: ROB is empty, squashing all insts.\n"); - end_it = instList.begin(); - rob_empty = true; - } else { - end_it = (rob.readTailInst(tid))->getInstListIt(); - DPRINTF(FullCPU, "FullCPU: ROB is not empty, squashing insts not in ROB.\n"); - } - - removeInstsThisCycle = true; - - ListIt inst_it = instList.end(); - - inst_it--; - - // Walk through the instruction list, removing any instructions - // that were inserted after the given instruction iterator, end_it. - while (inst_it != end_it) { - assert(!instList.empty()); - - squashInstIt(inst_it, tid); - - inst_it--; - } - - // If the ROB was empty, then we actually need to remove the first - // instruction as well. - if (rob_empty) { - squashInstIt(inst_it, tid); - } -} - -template <class Impl> -void -FullO3CPU<Impl>::removeInstsUntil(const InstSeqNum &seq_num, - unsigned tid) -{ - assert(!instList.empty()); - - removeInstsThisCycle = true; - - ListIt inst_iter = instList.end(); - - inst_iter--; - - DPRINTF(FullCPU, "FullCPU: Deleting instructions from instruction " - "list that are from [tid:%i] and above [sn:%lli] (end=%lli).\n", - tid, seq_num, (*inst_iter)->seqNum); - - while ((*inst_iter)->seqNum > seq_num) { - - bool break_loop = (inst_iter == instList.begin()); - - squashInstIt(inst_iter, tid); - - inst_iter--; - - if (break_loop) - break; - } -} - -template <class Impl> -inline void -FullO3CPU<Impl>::squashInstIt(const ListIt &instIt, const unsigned &tid) -{ - if ((*instIt)->threadNumber == tid) { - DPRINTF(FullCPU, "FullCPU: Squashing instruction, " - "[tid:%i] [sn:%lli] PC %#x\n", - (*instIt)->threadNumber, - (*instIt)->seqNum, - (*instIt)->readPC()); - - // Mark it as squashed. - (*instIt)->setSquashed(); - - // @todo: Formulate a consistent method for deleting - // instructions from the instruction list - // Remove the instruction from the list. - removeList.push(instIt); - } -} - -template <class Impl> -void -FullO3CPU<Impl>::cleanUpRemovedInsts() -{ - while (!removeList.empty()) { - DPRINTF(FullCPU, "FullCPU: Removing instruction, " - "[tid:%i] [sn:%lli] PC %#x\n", - (*removeList.front())->threadNumber, - (*removeList.front())->seqNum, - (*removeList.front())->readPC()); - - instList.erase(removeList.front()); - - removeList.pop(); - } - - removeInstsThisCycle = false; -} -/* -template <class Impl> -void -FullO3CPU<Impl>::removeAllInsts() -{ - instList.clear(); -} -*/ -template <class Impl> -void -FullO3CPU<Impl>::dumpInsts() -{ - int num = 0; - - ListIt inst_list_it = instList.begin(); - - cprintf("Dumping Instruction List\n"); - - while (inst_list_it != instList.end()) { - cprintf("Instruction:%i\nPC:%#x\n[tid:%i]\n[sn:%lli]\nIssued:%i\n" - "Squashed:%i\n\n", - num, (*inst_list_it)->readPC(), (*inst_list_it)->threadNumber, - (*inst_list_it)->seqNum, (*inst_list_it)->isIssued(), - (*inst_list_it)->isSquashed()); - inst_list_it++; - ++num; - } -} -/* -template <class Impl> -void -FullO3CPU<Impl>::wakeDependents(DynInstPtr &inst) -{ - iew.wakeDependents(inst); -} -*/ -template <class Impl> -void -FullO3CPU<Impl>::wakeCPU() -{ - if (activityRec.active() || tickEvent.scheduled()) { - DPRINTF(Activity, "CPU already running.\n"); - return; - } - - DPRINTF(Activity, "Waking up CPU\n"); - - idleCycles += (curTick - 1) - lastRunningCycle; - - tickEvent.schedule(curTick); -} - -template <class Impl> -int -FullO3CPU<Impl>::getFreeTid() -{ - for (int i=0; i < numThreads; i++) { - if (!tids[i]) { - tids[i] = true; - return i; - } - } - - return -1; -} - -template <class Impl> -void -FullO3CPU<Impl>::doContextSwitch() -{ - if (contextSwitch) { - - //ADD CODE TO DEACTIVE THREAD HERE (???) - - for (int tid=0; tid < cpuWaitList.size(); tid++) { - activateWhenReady(tid); - } - - if (cpuWaitList.size() == 0) - contextSwitch = true; - } -} - -template <class Impl> -void -FullO3CPU<Impl>::updateThreadPriority() -{ - if (activeThreads.size() > 1) - { - //DEFAULT TO ROUND ROBIN SCHEME - //e.g. Move highest priority to end of thread list - list<unsigned>::iterator list_begin = activeThreads.begin(); - list<unsigned>::iterator list_end = activeThreads.end(); - - unsigned high_thread = *list_begin; - - activeThreads.erase(list_begin); - - activeThreads.push_back(high_thread); - } -} - -// Forward declaration of FullO3CPU. -template class FullO3CPU<AlphaSimpleImpl>; diff --git a/cpu/o3/cpu.hh b/cpu/o3/cpu.hh deleted file mode 100644 index 8db65d501..000000000 --- a/cpu/o3/cpu.hh +++ /dev/null @@ -1,521 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_CPU_HH__ -#define __CPU_O3_CPU_HH__ - -#include <iostream> -#include <list> -#include <queue> -#include <set> -#include <vector> - -#include "base/statistics.hh" -#include "base/timebuf.hh" -#include "config/full_system.hh" -#include "cpu/activity.hh" -#include "cpu/base.hh" -#include "cpu/cpu_exec_context.hh" -#include "cpu/o3/comm.hh" -#include "cpu/o3/cpu_policy.hh" -#include "cpu/o3/scoreboard.hh" -#include "cpu/o3/thread_state.hh" -#include "sim/process.hh" - -template <class> -class Checker; -class ExecContext; -class MemInterface; -class Process; - -class BaseFullCPU : public BaseCPU -{ - //Stuff that's pretty ISA independent will go here. - public: - typedef BaseCPU::Params Params; - - BaseFullCPU(Params *params); - - void regStats(); - - protected: - int cpu_id; -}; - -template <class Impl> -class FullO3CPU : public BaseFullCPU -{ - public: - // Typedefs from the Impl here. - typedef typename Impl::CPUPol CPUPolicy; - typedef typename Impl::Params Params; - typedef typename Impl::DynInstPtr DynInstPtr; - - typedef O3ThreadState<Impl> Thread; - - typedef typename std::list<DynInstPtr>::iterator ListIt; - - public: - enum Status { - Running, - Idle, - Halted, - Blocked, - SwitchedOut - }; - - /** Overall CPU status. */ - Status _status; - - private: - class TickEvent : public Event - { - private: - /** Pointer to the CPU. */ - FullO3CPU<Impl> *cpu; - - public: - /** Constructs a tick event. */ - TickEvent(FullO3CPU<Impl> *c); - - /** Processes a tick event, calling tick() on the CPU. */ - void process(); - /** Returns the description of the tick event. */ - const char *description(); - }; - - /** The tick event used for scheduling CPU ticks. */ - TickEvent tickEvent; - - /** Schedule tick event, regardless of its current state. */ - void scheduleTickEvent(int delay) - { - if (tickEvent.squashed()) - tickEvent.reschedule(curTick + cycles(delay)); - else if (!tickEvent.scheduled()) - tickEvent.schedule(curTick + cycles(delay)); - } - - /** Unschedule tick event, regardless of its current state. */ - void unscheduleTickEvent() - { - if (tickEvent.scheduled()) - tickEvent.squash(); - } - - public: - /** Constructs a CPU with the given parameters. */ - FullO3CPU(Params *params); - /** Destructor. */ - ~FullO3CPU(); - - /** Registers statistics. */ - void fullCPURegStats(); - - /** 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(); - - /** Setup CPU to insert a thread's context */ - void insertThread(unsigned tid); - - /** Remove all of a thread's context from CPU */ - void removeThread(unsigned tid); - - /** Count the Total Instructions Committed in the CPU. */ - virtual Counter totalInstructions() const - { - Counter total(0); - - for (int i=0; i < thread.size(); i++) - total += thread[i]->numInst; - - return total; - } - - /** Add Thread to Active Threads List. */ - void activateContext(int tid, int delay); - - /** Remove Thread from Active Threads List */ - void suspendContext(int tid); - - /** Remove Thread from Active Threads List && - * Remove Thread Context from CPU. - */ - void deallocateContext(int tid); - - /** Remove Thread from Active Threads List && - * Remove Thread Context from CPU. - */ - void haltContext(int tid); - - /** Activate a Thread When CPU Resources are Available. */ - void activateWhenReady(int tid); - - /** Add or Remove a Thread Context in the CPU. */ - void doContextSwitch(); - - /** Update The Order In Which We Process Threads. */ - void updateThreadPriority(); - - /** Executes a syscall on this cycle. - * --------------------------------------- - * Note: this is a virtual function. CPU-Specific - * functionality defined in derived classes - */ - virtual void syscall(int tid) { panic("Unimplemented!"); } - - /** Check if there are any system calls pending. */ - void checkSyscalls(); - - /** Switches out this CPU. - */ - void switchOut(Sampler *sampler); - - void signalSwitched(); - - /** Takes over from another CPU. - */ - void takeOverFrom(BaseCPU *oldCPU); - - /** Get the current instruction sequence number, and increment it. */ - InstSeqNum getAndIncrementInstSeq() - { return globalSeqNum++; } - -#if FULL_SYSTEM - /** 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; } - - /** Get instruction asid. */ - int getInstAsid(unsigned tid) - { return regFile.miscRegs[tid].getInstAsid(); } - - /** Get data asid. */ - int getDataAsid(unsigned tid) - { return regFile.miscRegs[tid].getDataAsid(); } -#else - /** Check if this address is a valid instruction address. */ - bool validInstAddr(Addr addr,unsigned tid) - { return thread[tid]->validInstAddr(addr); } - - /** Check if this address is a valid data address. */ - bool validDataAddr(Addr addr,unsigned tid) - { return thread[tid]->validDataAddr(addr); } - - /** Get instruction asid. */ - int getInstAsid(unsigned tid) - { return thread[tid]->asid; } - - /** Get data asid. */ - int getDataAsid(unsigned tid) - { return thread[tid]->asid; } - -#endif - - // - // New accessors for new decoder. - // - uint64_t readIntReg(int reg_idx); - - float readFloatRegSingle(int reg_idx); - - double readFloatRegDouble(int reg_idx); - - uint64_t readFloatRegInt(int reg_idx); - - void setIntReg(int reg_idx, uint64_t val); - - void setFloatRegSingle(int reg_idx, float val); - - void setFloatRegDouble(int reg_idx, double val); - - void setFloatRegInt(int reg_idx, uint64_t val); - - uint64_t readArchIntReg(int reg_idx, unsigned tid); - - float readArchFloatRegSingle(int reg_idx, unsigned tid); - - double readArchFloatRegDouble(int reg_idx, unsigned tid); - - uint64_t readArchFloatRegInt(int reg_idx, unsigned tid); - - void setArchIntReg(int reg_idx, uint64_t val, unsigned tid); - - void setArchFloatRegSingle(int reg_idx, float val, unsigned tid); - - void setArchFloatRegDouble(int reg_idx, double val, unsigned tid); - - void setArchFloatRegInt(int reg_idx, uint64_t val, unsigned tid); - - uint64_t readPC(unsigned tid); - - void setPC(Addr new_PC,unsigned tid); - - uint64_t readNextPC(unsigned tid); - - void setNextPC(uint64_t val,unsigned tid); - - /** Function to add instruction onto the head of the list of the - * instructions. Used when new instructions are fetched. - */ - ListIt addInst(DynInstPtr &inst); - - /** Function to tell the CPU that an instruction has completed. */ - void instDone(unsigned tid); - - /** Add Instructions to the CPU Remove List*/ - void addToRemoveList(DynInstPtr &inst); - - /** Remove an instruction from the front end of the list. There's - * no restriction on location of the instruction. - */ - void removeFrontInst(DynInstPtr &inst); - - /** Remove all instructions that are not currently in the ROB. */ - void removeInstsNotInROB(unsigned tid); - - /** Remove all instructions younger than the given sequence number. */ - void removeInstsUntil(const InstSeqNum &seq_num,unsigned tid); - - inline void squashInstIt(const ListIt &instIt, const unsigned &tid); - - void cleanUpRemovedInsts(); - - /** Remove all instructions from the list. */ -// void removeAllInsts(); - - void dumpInsts(); - - /** Basically a wrapper function so that instructions executed at - * commit can tell the instruction queue that they have - * completed. Eventually this hack should be removed. - */ -// void wakeDependents(DynInstPtr &inst); - - public: - /** List of all the instructions in flight. */ - std::list<DynInstPtr> instList; - - /** List of all the instructions that will be removed at the end of this - * cycle. - */ - std::queue<ListIt> removeList; - -#ifdef DEBUG - std::set<InstSeqNum> snList; -#endif - - /** Records if instructions need to be removed this cycle due to - * being retired or squashed. - */ - bool removeInstsThisCycle; - - protected: - /** The fetch stage. */ - typename CPUPolicy::Fetch fetch; - - /** The decode stage. */ - typename CPUPolicy::Decode decode; - - /** The dispatch stage. */ - typename CPUPolicy::Rename rename; - - /** The issue/execute/writeback stages. */ - typename CPUPolicy::IEW iew; - - /** The commit stage. */ - typename CPUPolicy::Commit commit; - - /** The register file. */ - typename CPUPolicy::RegFile regFile; - - /** The free list. */ - typename CPUPolicy::FreeList freeList; - - /** The rename map. */ - typename CPUPolicy::RenameMap renameMap[Impl::MaxThreads]; - - /** The commit rename map. */ - typename CPUPolicy::RenameMap commitRenameMap[Impl::MaxThreads]; - - /** The re-order buffer. */ - typename CPUPolicy::ROB rob; - - /** Active Threads List */ - std::list<unsigned> activeThreads; - - /** Integer Register Scoreboard */ - Scoreboard scoreboard; - - public: - /** Enum to give each stage a specific index, so when calling - * activateStage() or deactivateStage(), they can specify which stage - * is being activated/deactivated. - */ - enum StageIdx { - FetchIdx, - DecodeIdx, - RenameIdx, - IEWIdx, - CommitIdx, - NumStages }; - - /** Typedefs from the Impl to get the structs that each of the - * time buffers should use. - */ - typedef typename CPUPolicy::TimeStruct TimeStruct; - - typedef typename CPUPolicy::FetchStruct FetchStruct; - - typedef typename CPUPolicy::DecodeStruct DecodeStruct; - - typedef typename CPUPolicy::RenameStruct RenameStruct; - - typedef typename CPUPolicy::IEWStruct IEWStruct; - - /** The main time buffer to do backwards communication. */ - TimeBuffer<TimeStruct> timeBuffer; - - /** The fetch stage's instruction queue. */ - TimeBuffer<FetchStruct> fetchQueue; - - /** The decode stage's instruction queue. */ - TimeBuffer<DecodeStruct> decodeQueue; - - /** The rename stage's instruction queue. */ - TimeBuffer<RenameStruct> renameQueue; - - /** The IEW stage's instruction queue. */ - TimeBuffer<IEWStruct> iewQueue; - - public: - ActivityRecorder activityRec; - - void activityThisCycle() { activityRec.activity(); } - - void activateStage(const StageIdx idx) - { activityRec.activateStage(idx); } - - void deactivateStage(const StageIdx idx) - { activityRec.deactivateStage(idx); } - - /** Wakes the CPU, rescheduling the CPU if it's not already active. */ - void wakeCPU(); - - /** Gets a free thread id. Use if thread ids change across system. */ - int getFreeTid(); - - public: - /** Temporary function to get pointer to exec context. */ - ExecContext *xcBase(unsigned tid) - { - return thread[tid]->getXCProxy(); - } - - /** The global sequence number counter. */ - InstSeqNum globalSeqNum; - - Checker<DynInstPtr> *checker; - -#if FULL_SYSTEM - /** Pointer to the system. */ - System *system; - - /** Pointer to the memory controller. */ - MemoryController *memCtrl; - /** Pointer to physical memory. */ - PhysicalMemory *physmem; -#endif - - /** Pointer to memory. */ - FunctionalMemory *mem; - - Sampler *sampler; - - int switchCount; - - // List of all ExecContexts. - std::vector<Thread *> thread; - -#if 0 - /** Page table pointer. */ - PageTable *pTable; -#endif - - /** Pointer to the icache interface. */ - MemInterface *icacheInterface; - /** Pointer to the dcache interface. */ - MemInterface *dcacheInterface; - - /** Whether or not the CPU should defer its registration. */ - bool deferRegistration; - - /** Is there a context switch pending? */ - bool contextSwitch; - - /** Threads Scheduled to Enter CPU */ - std::list<int> cpuWaitList; - - /** The cycle that the CPU was last running, used for statistics. */ - Tick lastRunningCycle; - - /** Number of Threads CPU can process */ - unsigned numThreads; - - /** Mapping for system thread id to cpu id */ - std::map<unsigned,unsigned> threadMap; - - /** Available thread ids in the cpu*/ - std::vector<unsigned> tids; - - /** Stat for total number of times the CPU is descheduled. */ - Stats::Scalar<> timesIdled; - /** Stat for total number of cycles the CPU spends descheduled. */ - Stats::Scalar<> idleCycles; - /** Stat for the number of committed instructions per thread. */ - Stats::Vector<> committedInsts; - /** Stat for the total number of committed instructions. */ - Stats::Scalar<> totalCommittedInsts; - /** Stat for the CPI per thread. */ - Stats::Formula cpi; - /** Stat for the total CPI. */ - Stats::Formula totalCpi; - /** Stat for the IPC per thread. */ - Stats::Formula ipc; - /** Stat for the total IPC. */ - Stats::Formula totalIpc; -}; - -#endif // __CPU_O3_CPU_HH__ diff --git a/cpu/o3/cpu_policy.hh b/cpu/o3/cpu_policy.hh deleted file mode 100644 index 52227013e..000000000 --- a/cpu/o3/cpu_policy.hh +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_CPU_POLICY_HH__ -#define __CPU_O3_CPU_POLICY_HH__ - -#include "cpu/o3/bpred_unit.hh" -#include "cpu/o3/free_list.hh" -#include "cpu/o3/inst_queue.hh" -#include "cpu/o3/lsq.hh" -#include "cpu/o3/lsq_unit.hh" -#include "cpu/o3/mem_dep_unit.hh" -#include "cpu/o3/regfile.hh" -#include "cpu/o3/rename_map.hh" -#include "cpu/o3/rob.hh" -#include "cpu/o3/store_set.hh" - -#include "cpu/o3/commit.hh" -#include "cpu/o3/decode.hh" -#include "cpu/o3/fetch.hh" -#include "cpu/o3/iew.hh" -#include "cpu/o3/rename.hh" - -#include "cpu/o3/comm.hh" - -template<class Impl> -struct SimpleCPUPolicy -{ - typedef TwobitBPredUnit<Impl> BPredUnit; - typedef PhysRegFile<Impl> RegFile; - typedef SimpleFreeList FreeList; - typedef SimpleRenameMap RenameMap; - typedef ROB<Impl> ROB; - typedef InstructionQueue<Impl> IQ; - typedef MemDepUnit<StoreSet, Impl> MemDepUnit; - typedef LSQ<Impl> LSQ; - typedef LSQUnit<Impl> LSQUnit; - - - typedef DefaultFetch<Impl> Fetch; - typedef DefaultDecode<Impl> Decode; - typedef DefaultRename<Impl> Rename; - typedef DefaultIEW<Impl> IEW; - typedef DefaultCommit<Impl> Commit; - - /** The struct for communication between fetch and decode. */ - typedef DefaultFetchDefaultDecode<Impl> FetchStruct; - - /** The struct for communication between decode and rename. */ - typedef DefaultDecodeDefaultRename<Impl> DecodeStruct; - - /** The struct for communication between rename and IEW. */ - typedef DefaultRenameDefaultIEW<Impl> RenameStruct; - - /** The struct for communication between IEW and commit. */ - typedef DefaultIEWDefaultCommit<Impl> IEWStruct; - - /** The struct for communication within the IEW stage. */ - typedef IssueStruct<Impl> IssueStruct; - - /** The struct for all backwards communication. */ - typedef TimeBufStruct<Impl> TimeStruct; - -}; - -#endif //__CPU_O3_CPU_POLICY_HH__ diff --git a/cpu/o3/decode.cc b/cpu/o3/decode.cc deleted file mode 100644 index b14fbb7a3..000000000 --- a/cpu/o3/decode.cc +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/o3/alpha_dyn_inst.hh" -#include "cpu/o3/alpha_impl.hh" -#include "cpu/o3/decode_impl.hh" - -template class DefaultDecode<AlphaSimpleImpl>; diff --git a/cpu/o3/decode.hh b/cpu/o3/decode.hh deleted file mode 100644 index 3035b3387..000000000 --- a/cpu/o3/decode.hh +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_DECODE_HH__ -#define __CPU_O3_DECODE_HH__ - -#include <queue> - -#include "base/statistics.hh" -#include "base/timebuf.hh" - -/** - * DefaultDecode class handles both single threaded and SMT - * decode. Its width is specified by the parameters; each cycles it - * tries to decode that many instructions. Because instructions are - * actually decoded when the StaticInst is created, this stage does - * not do much other than check any PC-relative branches. - */ -template<class Impl> -class DefaultDecode -{ - private: - // Typedefs from the Impl. - typedef typename Impl::FullCPU FullCPU; - typedef typename Impl::DynInstPtr DynInstPtr; - typedef typename Impl::Params Params; - typedef typename Impl::CPUPol CPUPol; - - // Typedefs from the CPU policy. - typedef typename CPUPol::FetchStruct FetchStruct; - typedef typename CPUPol::DecodeStruct DecodeStruct; - typedef typename CPUPol::TimeStruct TimeStruct; - - public: - /** Overall decode stage status. Used to determine if the CPU can - * deschedule itself due to a lack of activity. - */ - enum DecodeStatus { - Active, - Inactive - }; - - /** Individual thread status. */ - enum ThreadStatus { - Running, - Idle, - StartSquash, - Squashing, - Blocked, - Unblocking - }; - - private: - /** Decode status. */ - DecodeStatus _status; - - /** Per-thread status. */ - ThreadStatus decodeStatus[Impl::MaxThreads]; - - public: - /** DefaultDecode constructor. */ - DefaultDecode(Params *params); - - /** Returns the name of decode. */ - std::string name() const; - - /** Registers statistics. */ - void regStats(); - - /** Sets CPU pointer. */ - void setCPU(FullCPU *cpu_ptr); - - /** Sets the main backwards communication time buffer pointer. */ - void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr); - - /** Sets pointer to time buffer used to communicate to the next stage. */ - void setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr); - - /** Sets pointer to time buffer coming from fetch. */ - void setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr); - - /** Sets pointer to list of active threads. */ - void setActiveThreads(std::list<unsigned> *at_ptr); - - void switchOut(); - - void takeOverFrom(); - /** Ticks decode, processing all input signals and decoding as many - * instructions as possible. - */ - void tick(); - - /** Determines what to do based on decode's current status. - * @param status_change decode() sets this variable if there was a status - * change (ie switching from from blocking to unblocking). - * @param tid Thread id to decode instructions from. - */ - void decode(bool &status_change, unsigned tid); - - /** Processes instructions from fetch and passes them on to rename. - * Decoding of instructions actually happens when they are created in - * fetch, so this function mostly checks if PC-relative branches are - * correct. - */ - void decodeInsts(unsigned tid); - - private: - /** Inserts a thread's instructions into the skid buffer, to be decoded - * once decode unblocks. - */ - void skidInsert(unsigned tid); - - /** Returns if all of the skid buffers are empty. */ - bool skidsEmpty(); - - /** Updates overall decode 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(unsigned tid); - - /** Checks all input signals and updates decode's status appropriately. */ - bool checkSignalsAndUpdate(unsigned tid); - - /** Checks all stall signals, and returns if any are true. */ - bool checkStall(unsigned tid) const; - - /** Returns if there any instructions from fetch on this cycle. */ - inline bool fetchInstsValid(); - - /** Switches decode to blocking, and signals back that decode has - * become blocked. - * @return Returns true if there is a status change. - */ - bool block(unsigned tid); - - /** Switches decode to unblocking if the skid buffer is empty, and - * signals back that decode has unblocked. - * @return Returns true if there is a status change. - */ - bool unblock(unsigned tid); - - /** Squashes if there is a PC-relative branch that was predicted - * incorrectly. Sends squash information back to fetch. - */ - void squash(DynInstPtr &inst, unsigned tid); - - public: - /** Squashes due to commit signalling a squash. Changes status to - * squashing and clears block/unblock signals as needed. - */ - unsigned squash(unsigned tid); - - private: - // Interfaces to objects outside of decode. - /** CPU interface. */ - FullCPU *cpu; - - /** Time buffer interface. */ - TimeBuffer<TimeStruct> *timeBuffer; - - /** Wire to get rename's output from backwards time buffer. */ - typename TimeBuffer<TimeStruct>::wire fromRename; - - /** Wire to get iew's information from backwards time buffer. */ - typename TimeBuffer<TimeStruct>::wire fromIEW; - - /** Wire to get commit's information from backwards time buffer. */ - typename TimeBuffer<TimeStruct>::wire fromCommit; - - /** Wire to write information heading to previous stages. */ - // Might not be the best name as not only fetch will read it. - typename TimeBuffer<TimeStruct>::wire toFetch; - - /** Decode instruction queue. */ - TimeBuffer<DecodeStruct> *decodeQueue; - - /** Wire used to write any information heading to rename. */ - typename TimeBuffer<DecodeStruct>::wire toRename; - - /** Fetch instruction queue interface. */ - TimeBuffer<FetchStruct> *fetchQueue; - - /** Wire to get fetch's output from fetch queue. */ - typename TimeBuffer<FetchStruct>::wire fromFetch; - - /** Queue of all instructions coming from fetch this cycle. */ - std::queue<DynInstPtr> insts[Impl::MaxThreads]; - - /** Skid buffer between fetch and decode. */ - std::queue<DynInstPtr> skidBuffer[Impl::MaxThreads]; - - /** Variable that tracks if decode has written to the time buffer this - * cycle. Used to tell CPU if there is activity this cycle. - */ - bool wroteToTimeBuffer; - - /** Source of possible stalls. */ - struct Stalls { - bool rename; - bool iew; - bool commit; - }; - - /** Tracks which stages are telling decode to stall. */ - Stalls stalls[Impl::MaxThreads]; - - /** Rename to decode delay, in ticks. */ - unsigned renameToDecodeDelay; - - /** IEW to decode delay, in ticks. */ - unsigned iewToDecodeDelay; - - /** Commit to decode delay, in ticks. */ - unsigned commitToDecodeDelay; - - /** Fetch to decode delay, in ticks. */ - unsigned fetchToDecodeDelay; - - /** The width of decode, in instructions. */ - unsigned decodeWidth; - - /** Index of instructions being sent to rename. */ - unsigned toRenameIndex; - - /** number of Active Threads*/ - unsigned numThreads; - - /** List of active thread ids */ - std::list<unsigned> *activeThreads; - - /** Number of branches in flight. */ - unsigned branchCount[Impl::MaxThreads]; - - /** Maximum size of the skid buffer. */ - unsigned skidBufferMax; - - /** Stat for total number of idle cycles. */ - Stats::Scalar<> decodeIdleCycles; - /** Stat for total number of blocked cycles. */ - Stats::Scalar<> decodeBlockedCycles; - /** Stat for total number of normal running cycles. */ - Stats::Scalar<> decodeRunCycles; - /** Stat for total number of unblocking cycles. */ - Stats::Scalar<> decodeUnblockCycles; - /** Stat for total number of squashing cycles. */ - Stats::Scalar<> decodeSquashCycles; - /** Stat for number of times a branch is resolved at decode. */ - Stats::Scalar<> decodeBranchResolved; - /** Stat for number of times a branch mispredict is detected. */ - Stats::Scalar<> decodeBranchMispred; - /** Stat for number of times decode detected a non-control instruction - * incorrectly predicted as a branch. - */ - Stats::Scalar<> decodeControlMispred; - /** Stat for total number of decoded instructions. */ - Stats::Scalar<> decodeDecodedInsts; - /** Stat for total number of squashed instructions. */ - Stats::Scalar<> decodeSquashedInsts; -}; - -#endif // __CPU_O3_DECODE_HH__ diff --git a/cpu/o3/decode_impl.hh b/cpu/o3/decode_impl.hh deleted file mode 100644 index 2ed7ec6fc..000000000 --- a/cpu/o3/decode_impl.hh +++ /dev/null @@ -1,741 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/o3/decode.hh" - -using namespace std; - -template<class Impl> -DefaultDecode<Impl>::DefaultDecode(Params *params) - : renameToDecodeDelay(params->renameToDecodeDelay), - iewToDecodeDelay(params->iewToDecodeDelay), - commitToDecodeDelay(params->commitToDecodeDelay), - fetchToDecodeDelay(params->fetchToDecodeDelay), - decodeWidth(params->decodeWidth), - numThreads(params->numberOfThreads) -{ - _status = Inactive; - - for (int i = 0; i < numThreads; ++i) { - decodeStatus[i] = Idle; - - stalls[i].rename = false; - stalls[i].iew = false; - stalls[i].commit = false; - } - - // @todo: Make into a parameter - skidBufferMax = (fetchToDecodeDelay * params->fetchWidth) + decodeWidth; -} - -template <class Impl> -std::string -DefaultDecode<Impl>::name() const -{ - return cpu->name() + ".decode"; -} - -template <class Impl> -void -DefaultDecode<Impl>::regStats() -{ - decodeIdleCycles - .name(name() + ".DECODE:IdleCycles") - .desc("Number of cycles decode is idle") - .prereq(decodeIdleCycles); - decodeBlockedCycles - .name(name() + ".DECODE:BlockedCycles") - .desc("Number of cycles decode is blocked") - .prereq(decodeBlockedCycles); - decodeRunCycles - .name(name() + ".DECODE:RunCycles") - .desc("Number of cycles decode is running") - .prereq(decodeRunCycles); - decodeUnblockCycles - .name(name() + ".DECODE:UnblockCycles") - .desc("Number of cycles decode is unblocking") - .prereq(decodeUnblockCycles); - decodeSquashCycles - .name(name() + ".DECODE:SquashCycles") - .desc("Number of cycles decode is squashing") - .prereq(decodeSquashCycles); - decodeBranchResolved - .name(name() + ".DECODE:BranchResolved") - .desc("Number of times decode resolved a branch") - .prereq(decodeBranchResolved); - decodeBranchMispred - .name(name() + ".DECODE:BranchMispred") - .desc("Number of times decode detected a branch misprediction") - .prereq(decodeBranchMispred); - decodeControlMispred - .name(name() + ".DECODE:ControlMispred") - .desc("Number of times decode detected an instruction incorrectly" - " predicted as a control") - .prereq(decodeControlMispred); - decodeDecodedInsts - .name(name() + ".DECODE:DecodedInsts") - .desc("Number of instructions handled by decode") - .prereq(decodeDecodedInsts); - decodeSquashedInsts - .name(name() + ".DECODE:SquashedInsts") - .desc("Number of squashed instructions handled by decode") - .prereq(decodeSquashedInsts); -} - -template<class Impl> -void -DefaultDecode<Impl>::setCPU(FullCPU *cpu_ptr) -{ - DPRINTF(Decode, "Setting CPU pointer.\n"); - cpu = cpu_ptr; -} - -template<class Impl> -void -DefaultDecode<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) -{ - DPRINTF(Decode, "Setting time buffer pointer.\n"); - timeBuffer = tb_ptr; - - // Setup wire to write information back to fetch. - toFetch = timeBuffer->getWire(0); - - // Create wires to get information from proper places in time buffer. - fromRename = timeBuffer->getWire(-renameToDecodeDelay); - fromIEW = timeBuffer->getWire(-iewToDecodeDelay); - fromCommit = timeBuffer->getWire(-commitToDecodeDelay); -} - -template<class Impl> -void -DefaultDecode<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr) -{ - DPRINTF(Decode, "Setting decode queue pointer.\n"); - decodeQueue = dq_ptr; - - // Setup wire to write information to proper place in decode queue. - toRename = decodeQueue->getWire(0); -} - -template<class Impl> -void -DefaultDecode<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr) -{ - DPRINTF(Decode, "Setting fetch queue pointer.\n"); - fetchQueue = fq_ptr; - - // Setup wire to read information from fetch queue. - fromFetch = fetchQueue->getWire(-fetchToDecodeDelay); -} - -template<class Impl> -void -DefaultDecode<Impl>::setActiveThreads(list<unsigned> *at_ptr) -{ - DPRINTF(Decode, "Setting active threads list pointer.\n"); - activeThreads = at_ptr; -} - -template <class Impl> -void -DefaultDecode<Impl>::switchOut() -{ - cpu->signalSwitched(); -} - -template <class Impl> -void -DefaultDecode<Impl>::takeOverFrom() -{ - _status = Inactive; - - for (int i = 0; i < numThreads; ++i) { - decodeStatus[i] = Idle; - - stalls[i].rename = false; - stalls[i].iew = false; - stalls[i].commit = false; - while (!insts[i].empty()) - insts[i].pop(); - while (!skidBuffer[i].empty()) - skidBuffer[i].pop(); - branchCount[i] = 0; - } - wroteToTimeBuffer = false; -} - -template<class Impl> -bool -DefaultDecode<Impl>::checkStall(unsigned tid) const -{ - bool ret_val = false; - - if (stalls[tid].rename) { - DPRINTF(Decode,"[tid:%i]: Stall fom Rename stage detected.\n", tid); - ret_val = true; - } else if (stalls[tid].iew) { - DPRINTF(Decode,"[tid:%i]: Stall fom IEW stage detected.\n", tid); - ret_val = true; - } else if (stalls[tid].commit) { - DPRINTF(Decode,"[tid:%i]: Stall fom Commit stage detected.\n", tid); - ret_val = true; - } - - return ret_val; -} - -template<class Impl> -inline bool -DefaultDecode<Impl>::fetchInstsValid() -{ - return fromFetch->size > 0; -} - -template<class Impl> -bool -DefaultDecode<Impl>::block(unsigned tid) -{ - DPRINTF(Decode, "[tid:%u]: Blocking.\n", tid); - - // If the decode status is blocked or unblocking then decode has not yet - // signalled fetch to unblock. In that case, there is no need to tell - // fetch to block. - if (decodeStatus[tid] != Blocked && - decodeStatus[tid] != Unblocking) { - toFetch->decodeBlock[tid] = true; - wroteToTimeBuffer = true; - } - - // Add the current inputs to the skid buffer so they can be - // reprocessed when this stage unblocks. - skidInsert(tid); - - if (decodeStatus[tid] != Blocked) { - // Set the status to Blocked. - decodeStatus[tid] = Blocked; - return true; - } - - return false; -} - -template<class Impl> -bool -DefaultDecode<Impl>::unblock(unsigned tid) -{ - // Decode is done unblocking only if the skid buffer is empty. - if (skidBuffer[tid].empty()) { - DPRINTF(Decode, "[tid:%u]: Done unblocking.\n", tid); - toFetch->decodeUnblock[tid] = true; - wroteToTimeBuffer = true; - - decodeStatus[tid] = Running; - return true; - } - - DPRINTF(Decode, "[tid:%u]: Currently unblocking.\n", tid); - - return false; -} - -template<class Impl> -void -DefaultDecode<Impl>::squash(DynInstPtr &inst, unsigned tid) -{ - DPRINTF(Decode, "[tid:%i]: Squashing due to incorrect branch prediction " - "detected at decode.\n", tid); - - toFetch->decodeInfo[tid].branchMispredict = true; - toFetch->decodeInfo[tid].doneSeqNum = inst->seqNum; - toFetch->decodeInfo[tid].predIncorrect = true; - toFetch->decodeInfo[tid].squash = true; - toFetch->decodeInfo[tid].nextPC = inst->readNextPC(); - toFetch->decodeInfo[tid].branchTaken = true; - - if (decodeStatus[tid] == Blocked || - decodeStatus[tid] == Unblocking) { - toFetch->decodeUnblock[tid] = 1; - } - - // Set status to squashing. - decodeStatus[tid] = Squashing; - - for (int i=0; i<fromFetch->size; i++) { - if (fromFetch->insts[i]->threadNumber == tid && - fromFetch->insts[i]->seqNum > inst->seqNum) { - fromFetch->insts[i]->squashed = true; - } - } - - while (!insts[tid].empty()) { - insts[tid].pop(); - } - - // Clear the skid buffer in case it has any data in it. - while (!skidBuffer[tid].empty()) { - skidBuffer[tid].pop(); - } - - // Squash instructions up until this one - cpu->removeInstsUntil(inst->seqNum, tid); -} - -template<class Impl> -unsigned -DefaultDecode<Impl>::squash(unsigned tid) -{ - DPRINTF(Decode, "[tid:%i]: Squashing.\n",tid); - - if (decodeStatus[tid] == Blocked || - decodeStatus[tid] == Unblocking) { -#if !FULL_SYSTEM - // In syscall emulation, we can have both a block and a squash due - // to a syscall in the same cycle. This would cause both signals to - // be high. This shouldn't happen in full system. - // @todo: Determine if this still happens. - if (toFetch->decodeBlock[tid]) { - toFetch->decodeBlock[tid] = 0; - } else { - toFetch->decodeUnblock[tid] = 1; - } -#else - toFetch->decodeUnblock[tid] = 1; -#endif - } - - // Set status to squashing. - decodeStatus[tid] = Squashing; - - // Go through incoming instructions from fetch and squash them. - unsigned squash_count = 0; - - for (int i=0; i<fromFetch->size; i++) { - if (fromFetch->insts[i]->threadNumber == tid) { - fromFetch->insts[i]->squashed = true; - squash_count++; - } - } - - while (!insts[tid].empty()) { - insts[tid].pop(); - } - - // Clear the skid buffer in case it has any data in it. - while (!skidBuffer[tid].empty()) { - skidBuffer[tid].pop(); - } - - return squash_count; -} - -template<class Impl> -void -DefaultDecode<Impl>::skidInsert(unsigned tid) -{ - DynInstPtr inst = NULL; - - while (!insts[tid].empty()) { - inst = insts[tid].front(); - - insts[tid].pop(); - - assert(tid == inst->threadNumber); - - DPRINTF(Decode,"Inserting [sn:%lli] PC:%#x into decode skidBuffer %i\n", - inst->seqNum, inst->readPC(), inst->threadNumber); - - skidBuffer[tid].push(inst); - } - - // @todo: Eventually need to enforce this by not letting a thread - // fetch past its skidbuffer - assert(skidBuffer[tid].size() <= skidBufferMax); -} - -template<class Impl> -bool -DefaultDecode<Impl>::skidsEmpty() -{ - list<unsigned>::iterator threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - if (!skidBuffer[*threads++].empty()) - return false; - } - - return true; -} - -template<class Impl> -void -DefaultDecode<Impl>::updateStatus() -{ - bool any_unblocking = false; - - list<unsigned>::iterator threads = (*activeThreads).begin(); - - threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - if (decodeStatus[tid] == Unblocking) { - any_unblocking = true; - break; - } - } - - // Decode will have activity if it's unblocking. - if (any_unblocking) { - if (_status == Inactive) { - _status = Active; - - DPRINTF(Activity, "Activating stage.\n"); - - cpu->activateStage(FullCPU::DecodeIdx); - } - } else { - // If it's not unblocking, then decode will not have any internal - // activity. Switch it to inactive. - if (_status == Active) { - _status = Inactive; - DPRINTF(Activity, "Deactivating stage.\n"); - - cpu->deactivateStage(FullCPU::DecodeIdx); - } - } -} - -template <class Impl> -void -DefaultDecode<Impl>::sortInsts() -{ - int insts_from_fetch = fromFetch->size; -#ifdef DEBUG - for (int i=0; i < numThreads; i++) - assert(insts[i].empty()); -#endif - for (int i = 0; i < insts_from_fetch; ++i) { - insts[fromFetch->insts[i]->threadNumber].push(fromFetch->insts[i]); - } -} - -template<class Impl> -void -DefaultDecode<Impl>::readStallSignals(unsigned tid) -{ - if (fromRename->renameBlock[tid]) { - stalls[tid].rename = true; - } - - if (fromRename->renameUnblock[tid]) { - assert(stalls[tid].rename); - stalls[tid].rename = false; - } - - if (fromIEW->iewBlock[tid]) { - stalls[tid].iew = true; - } - - if (fromIEW->iewUnblock[tid]) { - assert(stalls[tid].iew); - stalls[tid].iew = false; - } - - if (fromCommit->commitBlock[tid]) { - stalls[tid].commit = true; - } - - if (fromCommit->commitUnblock[tid]) { - assert(stalls[tid].commit); - stalls[tid].commit = false; - } -} - -template <class Impl> -bool -DefaultDecode<Impl>::checkSignalsAndUpdate(unsigned tid) -{ - // Check if there's a squash signal, squash if there is. - // Check stall signals, block if necessary. - // If status was blocked - // Check if stall conditions have passed - // if so then go to unblocking - // If status was Squashing - // check if squashing is not high. Switch to running this cycle. - - // Update the per thread stall statuses. - readStallSignals(tid); - - // Check squash signals from commit. - if (fromCommit->commitInfo[tid].squash) { - - DPRINTF(Decode, "[tid:%u]: Squashing instructions due to squash " - "from commit.\n", tid); - - squash(tid); - - return true; - } - - // Check ROB squash signals from commit. - if (fromCommit->commitInfo[tid].robSquashing) { - DPRINTF(Decode, "[tid:%]: ROB is still squashing.\n",tid); - - // Continue to squash. - decodeStatus[tid] = Squashing; - - return true; - } - - if (checkStall(tid)) { - return block(tid); - } - - if (decodeStatus[tid] == Blocked) { - DPRINTF(Decode, "[tid:%u]: Done blocking, switching to unblocking.\n", - tid); - - decodeStatus[tid] = Unblocking; - - unblock(tid); - - return true; - } - - if (decodeStatus[tid] == Squashing) { - // Switch status to running if decode isn't being told to block or - // squash this cycle. - DPRINTF(Decode, "[tid:%u]: Done squashing, switching to running.\n", - tid); - - decodeStatus[tid] = Running; - - return false; - } - - // If we've reached this point, we have not gotten any signals that - // cause decode to change its status. Decode remains the same as before. - return false; -} - -template<class Impl> -void -DefaultDecode<Impl>::tick() -{ - wroteToTimeBuffer = false; - - bool status_change = false; - - toRenameIndex = 0; - - list<unsigned>::iterator threads = (*activeThreads).begin(); - - sortInsts(); - - //Check stall and squash signals. - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - DPRINTF(Decode,"Processing [tid:%i]\n",tid); - status_change = checkSignalsAndUpdate(tid) || status_change; - - decode(status_change, tid); - } - - if (status_change) { - updateStatus(); - } - - if (wroteToTimeBuffer) { - DPRINTF(Activity, "Activity this cycle.\n"); - - cpu->activityThisCycle(); - } -} - -template<class Impl> -void -DefaultDecode<Impl>::decode(bool &status_change, unsigned tid) -{ - // If status is Running or idle, - // call decodeInsts() - // If status is Unblocking, - // buffer any instructions coming from fetch - // continue trying to empty skid buffer - // check if stall conditions have passed - - if (decodeStatus[tid] == Blocked) { - ++decodeBlockedCycles; - } else if (decodeStatus[tid] == Squashing) { - ++decodeSquashCycles; - } - - // Decode should try to decode as many instructions as its bandwidth - // will allow, as long as it is not currently blocked. - if (decodeStatus[tid] == Running || - decodeStatus[tid] == Idle) { - DPRINTF(Decode, "[tid:%u] Not blocked, so attempting to run " - "stage.\n",tid); - - decodeInsts(tid); - } else if (decodeStatus[tid] == Unblocking) { - // Make sure that the skid buffer has something in it if the - // status is unblocking. - assert(!skidsEmpty()); - - // If the status was unblocking, then instructions from the skid - // buffer were used. Remove those instructions and handle - // the rest of unblocking. - decodeInsts(tid); - - if (fetchInstsValid()) { - // Add the current inputs to the skid buffer so they can be - // reprocessed when this stage unblocks. - skidInsert(tid); - } - - status_change = unblock(tid) || status_change; - } -} - -template <class Impl> -void -DefaultDecode<Impl>::decodeInsts(unsigned tid) -{ - // Instructions can come either from the skid buffer or the list of - // instructions coming from fetch, depending on decode's status. - int insts_available = decodeStatus[tid] == Unblocking ? - skidBuffer[tid].size() : insts[tid].size(); - - if (insts_available == 0) { - DPRINTF(Decode, "[tid:%u] Nothing to do, breaking out" - " early.\n",tid); - // Should I change the status to idle? - ++decodeIdleCycles; - return; - } else if (decodeStatus[tid] == Unblocking) { - DPRINTF(Decode, "[tid:%u] Unblocking, removing insts from skid " - "buffer.\n",tid); - ++decodeUnblockCycles; - } else if (decodeStatus[tid] == Running) { - ++decodeRunCycles; - } - - DynInstPtr inst; - - std::queue<DynInstPtr> - &insts_to_decode = decodeStatus[tid] == Unblocking ? - skidBuffer[tid] : insts[tid]; - - DPRINTF(Decode, "[tid:%u]: Sending instruction to rename.\n",tid); - - while (insts_available > 0 && toRenameIndex < decodeWidth) { - assert(!insts_to_decode.empty()); - - inst = insts_to_decode.front(); - - insts_to_decode.pop(); - - DPRINTF(Decode, "[tid:%u]: Processing instruction [sn:%lli] with " - "PC %#x\n", - tid, inst->seqNum, inst->readPC()); - - if (inst->isSquashed()) { - DPRINTF(Decode, "[tid:%u]: Instruction %i with PC %#x is " - "squashed, skipping.\n", - tid, inst->seqNum, inst->readPC()); - - ++decodeSquashedInsts; - - --insts_available; - - continue; - } - - // Also check if instructions have no source registers. Mark - // them as ready to issue at any time. Not sure if this check - // should exist here or at a later stage; however it doesn't matter - // too much for function correctness. - if (inst->numSrcRegs() == 0) { - inst->setCanIssue(); - } - - // This current instruction is valid, so add it into the decode - // queue. The next instruction may not be valid, so check to - // see if branches were predicted correctly. - toRename->insts[toRenameIndex] = inst; - - ++(toRename->size); - ++toRenameIndex; - ++decodeDecodedInsts; - --insts_available; - - // Ensure that if it was predicted as a branch, it really is a - // branch. - if (inst->predTaken() && !inst->isControl()) { - panic("Instruction predicted as a branch!"); - - ++decodeControlMispred; - - // Might want to set some sort of boolean and just do - // a check at the end - squash(inst, inst->threadNumber); - - break; - } - - // Go ahead and compute any PC-relative branches. - if (inst->isDirectCtrl() && inst->isUncondCtrl()) { - ++decodeBranchResolved; - inst->setNextPC(inst->branchTarget()); - - if (inst->mispredicted()) { - ++decodeBranchMispred; - - // Might want to set some sort of boolean and just do - // a check at the end - squash(inst, inst->threadNumber); - - break; - } - } - } - - // If we didn't process all instructions, then we will need to block - // and put all those instructions into the skid buffer. - if (!insts_to_decode.empty()) { - block(tid); - } - - // Record that decode has written to the time buffer for activity - // tracking. - if (toRenameIndex) { - wroteToTimeBuffer = true; - } -} diff --git a/cpu/o3/dep_graph.hh b/cpu/o3/dep_graph.hh deleted file mode 100644 index f8ae38da4..000000000 --- a/cpu/o3/dep_graph.hh +++ /dev/null @@ -1,213 +0,0 @@ - -#ifndef __CPU_O3_DEP_GRAPH_HH__ -#define __CPU_O3_DEP_GRAPH_HH__ - -#include "cpu/o3/comm.hh" - -template <class DynInstPtr> -class DependencyEntry -{ - public: - DependencyEntry() - : inst(NULL), next(NULL) - { } - - DynInstPtr inst; - //Might want to include data about what arch. register the - //dependence is waiting on. - DependencyEntry<DynInstPtr> *next; -}; - -template <class DynInstPtr> -class DependencyGraph -{ - public: - typedef DependencyEntry<DynInstPtr> DepEntry; - - DependencyGraph() - : numEntries(0), memAllocCounter(0), nodesTraversed(0), nodesRemoved(0) - { } - - void resize(int num_entries); - - void reset(); - - void insert(PhysRegIndex idx, DynInstPtr &new_inst); - - void setInst(PhysRegIndex idx, DynInstPtr &new_inst) - { dependGraph[idx].inst = new_inst; } - - void clearInst(PhysRegIndex idx) - { dependGraph[idx].inst = NULL; } - - void remove(PhysRegIndex idx, DynInstPtr &inst_to_remove); - - DynInstPtr pop(PhysRegIndex idx); - - bool empty(PhysRegIndex idx) { return !dependGraph[idx].next; } - - /** Debugging function to dump out the dependency graph. - */ - void dump(); - - private: - /** Array of linked lists. Each linked list is a list of all the - * instructions that depend upon a given register. The actual - * register's index is used to index into the graph; ie all - * instructions in flight that are dependent upon r34 will be - * in the linked list of dependGraph[34]. - */ - DepEntry *dependGraph; - - int numEntries; - - // Debug variable, remove when done testing. - unsigned memAllocCounter; - - public: - uint64_t nodesTraversed; - uint64_t nodesRemoved; -}; - -template <class DynInstPtr> -void -DependencyGraph<DynInstPtr>::resize(int num_entries) -{ - numEntries = num_entries; - dependGraph = new DepEntry[numEntries]; -} - -template <class DynInstPtr> -void -DependencyGraph<DynInstPtr>::reset() -{ - // Clear the dependency graph - DepEntry *curr; - DepEntry *prev; - - for (int i = 0; i < numEntries; ++i) { - curr = dependGraph[i].next; - - while (curr) { - memAllocCounter--; - - prev = curr; - curr = prev->next; - prev->inst = NULL; - - delete prev; - } - - if (dependGraph[i].inst) { - dependGraph[i].inst = NULL; - } - - dependGraph[i].next = NULL; - } -} - -template <class DynInstPtr> -void -DependencyGraph<DynInstPtr>::insert(PhysRegIndex idx, DynInstPtr &new_inst) -{ - //Add this new, dependent instruction at the head of the dependency - //chain. - - // First create the entry that will be added to the head of the - // dependency chain. - DepEntry *new_entry = new DepEntry; - new_entry->next = dependGraph[idx].next; - new_entry->inst = new_inst; - - // Then actually add it to the chain. - dependGraph[idx].next = new_entry; - - ++memAllocCounter; -} - - -template <class DynInstPtr> -void -DependencyGraph<DynInstPtr>::remove(PhysRegIndex idx, - DynInstPtr &inst_to_remove) -{ - DepEntry *prev = &dependGraph[idx]; - DepEntry *curr = dependGraph[idx].next; - - // Make sure curr isn't NULL. Because this instruction is being - // removed from a dependency list, it must have been placed there at - // an earlier time. The dependency chain should not be empty, - // unless the instruction dependent upon it is already ready. - if (curr == NULL) { - return; - } - - nodesRemoved++; - - // Find the instruction to remove within the dependency linked list. - while (curr->inst != inst_to_remove) { - prev = curr; - curr = curr->next; - nodesTraversed++; - - assert(curr != NULL); - } - - // Now remove this instruction from the list. - prev->next = curr->next; - - --memAllocCounter; - - // Could push this off to the destructor of DependencyEntry - curr->inst = NULL; - - delete curr; -} - -template <class DynInstPtr> -DynInstPtr -DependencyGraph<DynInstPtr>::pop(PhysRegIndex idx) -{ - DepEntry *node; - node = dependGraph[idx].next; - DynInstPtr inst = NULL; - if (node) { - inst = node->inst; - dependGraph[idx].next = node->next; - node->inst = NULL; - memAllocCounter--; - delete node; - } - return inst; -} - -template <class DynInstPtr> -void -DependencyGraph<DynInstPtr>::dump() -{ - DepEntry *curr; - - for (int i = 0; i < numEntries; ++i) - { - curr = &dependGraph[i]; - - if (curr->inst) { - cprintf("dependGraph[%i]: producer: %#x [sn:%lli] consumer: ", - i, curr->inst->readPC(), curr->inst->seqNum); - } else { - cprintf("dependGraph[%i]: No producer. consumer: ", i); - } - - while (curr->next != NULL) { - curr = curr->next; - - cprintf("%#x [sn:%lli] ", - curr->inst->readPC(), curr->inst->seqNum); - } - - cprintf("\n"); - } - cprintf("memAllocCounter: %i\n", memAllocCounter); -} - -#endif // __CPU_O3_DEP_GRAPH_HH__ diff --git a/cpu/o3/fetch.cc b/cpu/o3/fetch.cc deleted file mode 100644 index 7959416be..000000000 --- a/cpu/o3/fetch.cc +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/o3/alpha_dyn_inst.hh" -#include "cpu/o3/alpha_impl.hh" -#include "cpu/o3/fetch_impl.hh" - -template class DefaultFetch<AlphaSimpleImpl>; diff --git a/cpu/o3/fetch.hh b/cpu/o3/fetch.hh deleted file mode 100644 index 3fcfdc3a1..000000000 --- a/cpu/o3/fetch.hh +++ /dev/null @@ -1,411 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_FETCH_HH__ -#define __CPU_O3_FETCH_HH__ - -#include "base/statistics.hh" -#include "base/timebuf.hh" -#include "cpu/pc_event.hh" -#include "mem/mem_interface.hh" -#include "sim/eventq.hh" - -class Sampler; - -/** - * DefaultFetch class handles both single threaded and SMT fetch. Its - * width is specified by the parameters; each cycle it tries to fetch - * that many instructions. It supports using a branch predictor to - * predict direction and targets. - * It supports the idling functionalitiy of the CPU by indicating to - * the CPU when it is active and inactive. - */ -template <class Impl> -class DefaultFetch -{ - public: - /** Typedefs from Impl. */ - typedef typename Impl::CPUPol CPUPol; - typedef typename Impl::DynInst DynInst; - typedef typename Impl::DynInstPtr DynInstPtr; - typedef typename Impl::FullCPU FullCPU; - typedef typename Impl::Params Params; - - /** Typedefs from the CPU policy. */ - typedef typename CPUPol::BPredUnit BPredUnit; - typedef typename CPUPol::FetchStruct FetchStruct; - typedef typename CPUPol::TimeStruct TimeStruct; - - /** Typedefs from ISA. */ - typedef TheISA::MachInst MachInst; - typedef TheISA::ExtMachInst ExtMachInst; - - public: - /** Overall fetch status. Used to determine if the CPU can - * deschedule itsef due to a lack of activity. - */ - enum FetchStatus { - Active, - Inactive - }; - - /** Individual thread status. */ - enum ThreadStatus { - Running, - Idle, - Squashing, - Blocked, - Fetching, - TrapPending, - QuiescePending, - SwitchOut, - IcacheMissStall, - IcacheMissComplete - }; - - /** Fetching Policy, Add new policies here.*/ - enum FetchPriority { - SingleThread, - RoundRobin, - Branch, - IQ, - LSQ - }; - - private: - /** Fetch status. */ - FetchStatus _status; - - /** Per-thread status. */ - ThreadStatus fetchStatus[Impl::MaxThreads]; - - /** Fetch policy. */ - FetchPriority fetchPolicy; - - /** List that has the threads organized by priority. */ - std::list<unsigned> priorityList; - - public: - class CacheCompletionEvent : public Event - { - private: - MemReqPtr req; - /** Pointer to fetch. */ - DefaultFetch *fetch; - /** Thread id. */ -// unsigned threadId; - - public: - /** Constructs a cache completion event, which tells fetch when the - * cache miss is complete. - */ - CacheCompletionEvent(MemReqPtr &_req, DefaultFetch *_fetch); - - /** Processes cache completion event. */ - virtual void process(); - /** Returns the description of the cache completion event. */ - virtual const char *description(); - }; - - public: - /** DefaultFetch constructor. */ - DefaultFetch(Params *params); - - /** Returns the name of fetch. */ - std::string name() const; - - /** Registers statistics. */ - void regStats(); - - /** Sets CPU pointer. */ - void setCPU(FullCPU *cpu_ptr); - - /** Sets the main backwards communication time buffer pointer. */ - void setTimeBuffer(TimeBuffer<TimeStruct> *time_buffer); - - /** Sets pointer to list of active threads. */ - void setActiveThreads(std::list<unsigned> *at_ptr); - - /** Sets pointer to time buffer used to communicate to the next stage. */ - void setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr); - - /** Sets pointer to page table. */ -// void setPageTable(PageTable *pt_ptr); - - /** Initialize stage. */ - void initStage(); - - /** Processes cache completion event. */ - void processCacheCompletion(MemReqPtr &req); - - void switchOut(); - - void doSwitchOut(); - - void takeOverFrom(); - - bool isSwitchedOut() { return switchedOut; } - - void wakeFromQuiesce(); - - private: - /** 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(); - - /** - * Looks up in the branch predictor to see if the next PC should be - * either next PC+=MachInst or a branch target. - * @param next_PC Next PC variable passed in by reference. It is - * expected to be set to the current PC; it will be updated with what - * the next PC will be. - * @return Whether or not a branch was predicted as taken. - */ - bool lookupAndUpdateNextPC(DynInstPtr &inst, Addr &next_PC); - - /** - * Fetches the cache line that contains fetch_PC. Returns any - * fault that happened. Puts the data into the class variable - * cacheData. - * @param fetch_PC The PC address that is being fetched from. - * @param ret_fault The fault reference that will be set to the result of - * the icache access. - * @param tid Thread id. - * @return Any fault that occured. - */ - bool fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid); - - /** Squashes a specific thread and resets the PC. */ - inline void doSquash(const Addr &new_PC, unsigned tid); - - /** Squashes a specific thread and resets the PC. Also tells the CPU to - * remove any instructions between fetch and decode that should be sqaushed. - */ - void squashFromDecode(const Addr &new_PC, const InstSeqNum &seq_num, - unsigned tid); - - /** Checks if a thread is stalled. */ - bool checkStall(unsigned tid) const; - - /** Updates overall fetch stage status; to be called at the end of each - * cycle. */ - FetchStatus updateFetchStatus(); - - public: - /** Squashes a specific thread and resets the PC. Also tells the CPU to - * remove any instructions that are not in the ROB. The source of this - * squash should be the commit stage. - */ - void squash(const Addr &new_PC, unsigned tid); - - /** Ticks the fetch stage, processing all inputs signals and fetching - * as many instructions as possible. - */ - void tick(); - - /** Checks all input signals and updates the status as necessary. - * @return: Returns if the status has changed due to input signals. - */ - bool checkSignalsAndUpdate(unsigned tid); - - /** Does the actual fetching of instructions and passing them on to the - * next stage. - * @param status_change fetch() sets this variable if there was a status - * change (ie switching to IcacheMissStall). - */ - void fetch(bool &status_change); - - /** Align a PC to the start of an I-cache block. */ - Addr icacheBlockAlignPC(Addr addr) - { - addr = TheISA::realPCToFetchPC(addr); - return (addr & ~(cacheBlkMask)); - } - - private: - /** Returns the appropriate thread to fetch, given the fetch policy. */ - int getFetchingThread(FetchPriority &fetch_priority); - - /** Returns the appropriate thread to fetch using a round robin policy. */ - int roundRobin(); - - /** Returns the appropriate thread to fetch using the IQ count policy. */ - int iqCount(); - - /** Returns the appropriate thread to fetch using the LSQ count policy. */ - int lsqCount(); - - /** Returns the appropriate thread to fetch using the branch count policy. */ - int branchCount(); - - private: - /** Pointer to the FullCPU. */ - FullCPU *cpu; - - /** Time buffer interface. */ - TimeBuffer<TimeStruct> *timeBuffer; - - /** Wire to get decode's information from backwards time buffer. */ - typename TimeBuffer<TimeStruct>::wire fromDecode; - - /** Wire to get rename's information from backwards time buffer. */ - typename TimeBuffer<TimeStruct>::wire fromRename; - - /** Wire to get iew's information from backwards time buffer. */ - typename TimeBuffer<TimeStruct>::wire fromIEW; - - /** Wire to get commit's information from backwards time buffer. */ - typename TimeBuffer<TimeStruct>::wire fromCommit; - - /** Internal fetch instruction queue. */ - TimeBuffer<FetchStruct> *fetchQueue; - - //Might be annoying how this name is different than the queue. - /** Wire used to write any information heading to decode. */ - typename TimeBuffer<FetchStruct>::wire toDecode; - - /** Icache interface. */ - MemInterface *icacheInterface; - - /** BPredUnit. */ - BPredUnit branchPred; - - Addr PC[Impl::MaxThreads]; - - Addr nextPC[Impl::MaxThreads]; - - /** Memory request used to access cache. */ - MemReqPtr memReq[Impl::MaxThreads]; - - /** Variable that tracks if fetch has written to the time buffer this - * cycle. Used to tell CPU if there is activity this cycle. - */ - bool wroteToTimeBuffer; - - /** Tracks how many instructions has been fetched this cycle. */ - int numInst; - - /** Source of possible stalls. */ - struct Stalls { - bool decode; - bool rename; - bool iew; - bool commit; - }; - - /** Tracks which stages are telling fetch to stall. */ - Stalls stalls[Impl::MaxThreads]; - - /** Decode to fetch delay, in ticks. */ - unsigned decodeToFetchDelay; - - /** Rename to fetch delay, in ticks. */ - unsigned renameToFetchDelay; - - /** IEW to fetch delay, in ticks. */ - unsigned iewToFetchDelay; - - /** Commit to fetch delay, in ticks. */ - unsigned commitToFetchDelay; - - /** The width of fetch in instructions. */ - unsigned fetchWidth; - - /** Cache block size. */ - int cacheBlkSize; - - /** Mask to get a cache block's address. */ - Addr cacheBlkMask; - - /** The cache line being fetched. */ - uint8_t *cacheData[Impl::MaxThreads]; - - /** Size of instructions. */ - int instSize; - - /** Icache stall statistics. */ - Counter lastIcacheStall[Impl::MaxThreads]; - - /** List of Active Threads */ - std::list<unsigned> *activeThreads; - - /** Number of threads. */ - unsigned numThreads; - - /** Number of threads that are actively fetching. */ - unsigned numFetchingThreads; - - /** Thread ID being fetched. */ - int threadFetched; - - bool interruptPending; - - bool switchedOut; - -#if !FULL_SYSTEM - /** Page table pointer. */ -// PageTable *pTable; -#endif - - // @todo: Consider making these vectors and tracking on a per thread basis. - /** Stat for total number of cycles stalled due to an icache miss. */ - Stats::Scalar<> icacheStallCycles; - /** Stat for total number of fetched instructions. */ - Stats::Scalar<> fetchedInsts; - Stats::Scalar<> fetchedBranches; - /** Stat for total number of predicted branches. */ - Stats::Scalar<> predictedBranches; - /** Stat for total number of cycles spent fetching. */ - Stats::Scalar<> fetchCycles; - /** Stat for total number of cycles spent squashing. */ - Stats::Scalar<> fetchSquashCycles; - /** Stat for total number of cycles spent blocked due to other stages in - * the pipeline. - */ - Stats::Scalar<> fetchIdleCycles; - Stats::Scalar<> fetchBlockedCycles; - - Stats::Scalar<> fetchMiscStallCycles; - /** Stat for total number of fetched cache lines. */ - Stats::Scalar<> fetchedCacheLines; - - Stats::Scalar<> fetchIcacheSquashes; - /** Distribution of number of instructions fetched each cycle. */ - Stats::Distribution<> fetchNisnDist; - Stats::Formula idleRate; - Stats::Formula branchRate; - Stats::Formula fetchRate; -}; - -#endif //__CPU_O3_FETCH_HH__ diff --git a/cpu/o3/fetch_impl.hh b/cpu/o3/fetch_impl.hh deleted file mode 100644 index 1c5e508f6..000000000 --- a/cpu/o3/fetch_impl.hh +++ /dev/null @@ -1,1219 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "arch/isa_traits.hh" -#include "cpu/exetrace.hh" -#include "cpu/o3/fetch.hh" -#include "mem/base_mem.hh" -#include "mem/mem_interface.hh" -#include "mem/mem_req.hh" -#include "sim/byteswap.hh" -#include "sim/root.hh" - -#if FULL_SYSTEM -#include "arch/tlb.hh" -#include "arch/vtophys.hh" -#include "base/remote_gdb.hh" -#include "mem/functional/memory_control.hh" -#include "mem/functional/physical.hh" -#include "sim/system.hh" -#else // !FULL_SYSTEM -#include "mem/functional/functional.hh" -#endif // FULL_SYSTEM - -#include <algorithm> - -using namespace std; - -template<class Impl> -DefaultFetch<Impl>::CacheCompletionEvent::CacheCompletionEvent(MemReqPtr &_req, - DefaultFetch *_fetch) - : Event(&mainEventQueue, Delayed_Writeback_Pri), - req(_req), - fetch(_fetch) -{ - this->setFlags(Event::AutoDelete); -} - -template<class Impl> -void -DefaultFetch<Impl>::CacheCompletionEvent::process() -{ - fetch->processCacheCompletion(req); -} - -template<class Impl> -const char * -DefaultFetch<Impl>::CacheCompletionEvent::description() -{ - return "DefaultFetch cache completion event"; -} - -template<class Impl> -DefaultFetch<Impl>::DefaultFetch(Params *params) - : icacheInterface(params->icacheInterface), - branchPred(params), - decodeToFetchDelay(params->decodeToFetchDelay), - renameToFetchDelay(params->renameToFetchDelay), - iewToFetchDelay(params->iewToFetchDelay), - commitToFetchDelay(params->commitToFetchDelay), - fetchWidth(params->fetchWidth), - numThreads(params->numberOfThreads), - numFetchingThreads(params->smtNumFetchingThreads), - interruptPending(false) -{ - if (numThreads > Impl::MaxThreads) - fatal("numThreads is not a valid value\n"); - - DPRINTF(Fetch, "Fetch constructor called\n"); - - // Set fetch stage's status to inactive. - _status = Inactive; - - string policy = params->smtFetchPolicy; - - // Convert string to lowercase - std::transform(policy.begin(), policy.end(), policy.begin(), - (int(*)(int)) tolower); - - // Figure out fetch policy - if (policy == "singlethread") { - fetchPolicy = SingleThread; - } else if (policy == "roundrobin") { - fetchPolicy = RoundRobin; - DPRINTF(Fetch, "Fetch policy set to Round Robin\n"); - } else if (policy == "branch") { - fetchPolicy = Branch; - DPRINTF(Fetch, "Fetch policy set to Branch Count\n"); - } else if (policy == "iqcount") { - fetchPolicy = IQ; - DPRINTF(Fetch, "Fetch policy set to IQ count\n"); - } else if (policy == "lsqcount") { - fetchPolicy = LSQ; - DPRINTF(Fetch, "Fetch policy set to LSQ count\n"); - } else { - fatal("Invalid Fetch Policy. Options Are: {SingleThread," - " RoundRobin,LSQcount,IQcount}\n"); - } - - // Size of cache block. - cacheBlkSize = icacheInterface ? icacheInterface->getBlockSize() : 64; - - // Create mask to get rid of offset bits. - cacheBlkMask = (cacheBlkSize - 1); - - for (int tid=0; tid < numThreads; tid++) { - - fetchStatus[tid] = Running; - - priorityList.push_back(tid); - - // Create a new memory request. - memReq[tid] = NULL; - - // Create space to store a cache line. - cacheData[tid] = new uint8_t[cacheBlkSize]; - - stalls[tid].decode = 0; - stalls[tid].rename = 0; - stalls[tid].iew = 0; - stalls[tid].commit = 0; - } - - // Get the size of an instruction. - instSize = sizeof(MachInst); -} - -template <class Impl> -std::string -DefaultFetch<Impl>::name() const -{ - return cpu->name() + ".fetch"; -} - -template <class Impl> -void -DefaultFetch<Impl>::regStats() -{ - icacheStallCycles - .name(name() + ".FETCH:icacheStallCycles") - .desc("Number of cycles fetch is stalled on an Icache miss") - .prereq(icacheStallCycles); - - fetchedInsts - .name(name() + ".FETCH:Insts") - .desc("Number of instructions fetch has processed") - .prereq(fetchedInsts); - - fetchedBranches - .name(name() + ".FETCH:Branches") - .desc("Number of branches that fetch encountered") - .prereq(fetchedBranches); - - predictedBranches - .name(name() + ".FETCH:predictedBranches") - .desc("Number of branches that fetch has predicted taken") - .prereq(predictedBranches); - - fetchCycles - .name(name() + ".FETCH:Cycles") - .desc("Number of cycles fetch has run and was not squashing or" - " blocked") - .prereq(fetchCycles); - - fetchSquashCycles - .name(name() + ".FETCH:SquashCycles") - .desc("Number of cycles fetch has spent squashing") - .prereq(fetchSquashCycles); - - fetchIdleCycles - .name(name() + ".FETCH:IdleCycles") - .desc("Number of cycles fetch was idle") - .prereq(fetchIdleCycles); - - fetchBlockedCycles - .name(name() + ".FETCH:BlockedCycles") - .desc("Number of cycles fetch has spent blocked") - .prereq(fetchBlockedCycles); - - fetchedCacheLines - .name(name() + ".FETCH:CacheLines") - .desc("Number of cache lines fetched") - .prereq(fetchedCacheLines); - - fetchMiscStallCycles - .name(name() + ".FETCH:MiscStallCycles") - .desc("Number of cycles fetch has spent waiting on interrupts, or " - "bad addresses, or out of MSHRs") - .prereq(fetchMiscStallCycles); - - fetchIcacheSquashes - .name(name() + ".FETCH:IcacheSquashes") - .desc("Number of outstanding Icache misses that were squashed") - .prereq(fetchIcacheSquashes); - - fetchNisnDist - .init(/* base value */ 0, - /* last value */ fetchWidth, - /* bucket size */ 1) - .name(name() + ".FETCH:rateDist") - .desc("Number of instructions fetched each cycle (Total)") - .flags(Stats::pdf); - - idleRate - .name(name() + ".FETCH:idleRate") - .desc("Percent of cycles fetch was idle") - .prereq(idleRate); - idleRate = fetchIdleCycles * 100 / cpu->numCycles; - - branchRate - .name(name() + ".FETCH:branchRate") - .desc("Number of branch fetches per cycle") - .flags(Stats::total); - branchRate = predictedBranches / cpu->numCycles; - - fetchRate - .name(name() + ".FETCH:rate") - .desc("Number of inst fetches per cycle") - .flags(Stats::total); - fetchRate = fetchedInsts / cpu->numCycles; - - branchPred.regStats(); -} - -template<class Impl> -void -DefaultFetch<Impl>::setCPU(FullCPU *cpu_ptr) -{ - DPRINTF(Fetch, "Setting the CPU pointer.\n"); - cpu = cpu_ptr; - - // Fetch needs to start fetching instructions at the very beginning, - // so it must start up in active state. - switchToActive(); -} - -template<class Impl> -void -DefaultFetch<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *time_buffer) -{ - DPRINTF(Fetch, "Setting the time buffer pointer.\n"); - timeBuffer = time_buffer; - - // Create wires to get information from proper places in time buffer. - fromDecode = timeBuffer->getWire(-decodeToFetchDelay); - fromRename = timeBuffer->getWire(-renameToFetchDelay); - fromIEW = timeBuffer->getWire(-iewToFetchDelay); - fromCommit = timeBuffer->getWire(-commitToFetchDelay); -} - -template<class Impl> -void -DefaultFetch<Impl>::setActiveThreads(list<unsigned> *at_ptr) -{ - DPRINTF(Fetch, "Setting active threads list pointer.\n"); - activeThreads = at_ptr; -} - -template<class Impl> -void -DefaultFetch<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr) -{ - DPRINTF(Fetch, "Setting the fetch queue pointer.\n"); - fetchQueue = fq_ptr; - - // Create wire to write information to proper place in fetch queue. - toDecode = fetchQueue->getWire(0); -} - -#if 0 -template<class Impl> -void -DefaultFetch<Impl>::setPageTable(PageTable *pt_ptr) -{ - DPRINTF(Fetch, "Setting the page table pointer.\n"); -#if !FULL_SYSTEM - pTable = pt_ptr; -#endif -} -#endif - -template<class Impl> -void -DefaultFetch<Impl>::initStage() -{ - for (int tid = 0; tid < numThreads; tid++) { - PC[tid] = cpu->readPC(tid); - nextPC[tid] = cpu->readNextPC(tid); - } -} - -template<class Impl> -void -DefaultFetch<Impl>::processCacheCompletion(MemReqPtr &req) -{ - unsigned tid = req->thread_num; - - DPRINTF(Fetch, "[tid:%u] Waking up from cache miss.\n",tid); - - // Only change the status if it's still waiting on the icache access - // to return. - // Can keep track of how many cache accesses go unused due to - // misspeculation here. - if (fetchStatus[tid] != IcacheMissStall || - req != memReq[tid] || - isSwitchedOut()) { - ++fetchIcacheSquashes; - return; - } - - // Wake up the CPU (if it went to sleep and was waiting on this completion - // event). - cpu->wakeCPU(); - - DPRINTF(Activity, "[tid:%u] Activating fetch due to cache completion\n", - tid); - - switchToActive(); - - // Only switch to IcacheMissComplete if we're not stalled as well. - if (checkStall(tid)) { - fetchStatus[tid] = Blocked; - } else { - fetchStatus[tid] = IcacheMissComplete; - } - -// memcpy(cacheData[tid], memReq[tid]->data, memReq[tid]->size); - - // Reset the mem req to NULL. - memReq[tid] = NULL; -} - -template <class Impl> -void -DefaultFetch<Impl>::switchOut() -{ - switchedOut = true; - cpu->signalSwitched(); -} - -template <class Impl> -void -DefaultFetch<Impl>::doSwitchOut() -{ - branchPred.switchOut(); -} - -template <class Impl> -void -DefaultFetch<Impl>::takeOverFrom() -{ - // Reset all state - for (int i = 0; i < Impl::MaxThreads; ++i) { - stalls[i].decode = 0; - stalls[i].rename = 0; - stalls[i].iew = 0; - stalls[i].commit = 0; - PC[i] = cpu->readPC(i); - nextPC[i] = cpu->readNextPC(i); - fetchStatus[i] = Running; - } - numInst = 0; - wroteToTimeBuffer = false; - _status = Inactive; - switchedOut = false; - branchPred.takeOverFrom(); -} - -template <class Impl> -void -DefaultFetch<Impl>::wakeFromQuiesce() -{ - DPRINTF(Fetch, "Waking up from quiesce\n"); - // Hopefully this is safe - fetchStatus[0] = Running; -} - -template <class Impl> -inline void -DefaultFetch<Impl>::switchToActive() -{ - if (_status == Inactive) { - DPRINTF(Activity, "Activating stage.\n"); - - cpu->activateStage(FullCPU::FetchIdx); - - _status = Active; - } -} - -template <class Impl> -inline void -DefaultFetch<Impl>::switchToInactive() -{ - if (_status == Active) { - DPRINTF(Activity, "Deactivating stage.\n"); - - cpu->deactivateStage(FullCPU::FetchIdx); - - _status = Inactive; - } -} - -template <class Impl> -bool -DefaultFetch<Impl>::lookupAndUpdateNextPC(DynInstPtr &inst, Addr &next_PC) -{ - // Do branch prediction check here. - // A bit of a misnomer...next_PC is actually the current PC until - // this function updates it. - bool predict_taken; - - if (!inst->isControl()) { - next_PC = next_PC + instSize; - inst->setPredTarg(next_PC); - return false; - } - - predict_taken = branchPred.predict(inst, next_PC, inst->threadNumber); - - ++fetchedBranches; - - if (predict_taken) { - ++predictedBranches; - } - - return predict_taken; -} - -template <class Impl> -bool -DefaultFetch<Impl>::fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid) -{ - Fault fault = NoFault; - -#if FULL_SYSTEM - // Flag to say whether or not address is physical addr. - unsigned flags = cpu->inPalMode(fetch_PC) ? PHYSICAL : 0; -#else - unsigned flags = 0; -#endif // FULL_SYSTEM - - if (interruptPending && flags == 0 || switchedOut) { - // Hold off fetch from getting new instructions while an interrupt - // is pending. - return false; - } - - // Align the fetch PC so it's at the start of a cache block. - fetch_PC = icacheBlockAlignPC(fetch_PC); - - // Setup the memReq to do a read of the first instruction's address. - // Set the appropriate read size and flags as well. - memReq[tid] = new MemReq(); - - memReq[tid]->asid = tid; - memReq[tid]->thread_num = tid; - memReq[tid]->data = new uint8_t[64]; - memReq[tid]->xc = cpu->xcBase(tid); - memReq[tid]->cmd = Read; - memReq[tid]->reset(fetch_PC, cacheBlkSize, flags); - - // Translate the instruction request. -//#if FULL_SYSTEM - fault = cpu->translateInstReq(memReq[tid]); -//#else -// fault = pTable->translate(memReq[tid]); -//#endif - - // In the case of faults, the fetch stage may need to stall and wait - // for the ITB miss to be handled. - - // If translation was successful, attempt to read the first - // instruction. - if (fault == NoFault) { -#if FULL_SYSTEM - if (cpu->system->memctrl->badaddr(memReq[tid]->paddr) || - memReq[tid]->flags & UNCACHEABLE) { - DPRINTF(Fetch, "Fetch: Bad address %#x (hopefully on a " - "misspeculating path)!", - memReq[tid]->paddr); - ret_fault = TheISA::genMachineCheckFault(); - return false; - } -#endif - - DPRINTF(Fetch, "Fetch: Doing instruction read.\n"); - fault = cpu->mem->read(memReq[tid], cacheData[tid]); - // This read may change when the mem interface changes. - - // Now do the timing access to see whether or not the instruction - // exists within the cache. - if (icacheInterface && !icacheInterface->isBlocked()) { - DPRINTF(Fetch, "Doing cache access.\n"); - - memReq[tid]->completionEvent = NULL; - - memReq[tid]->time = curTick; - - MemAccessResult result = icacheInterface->access(memReq[tid]); - - fetchedCacheLines++; - - // If the cache missed, then schedule an event to wake - // up this stage once the cache miss completes. - // @todo: Possibly allow for longer than 1 cycle cache hits. - if (result != MA_HIT && icacheInterface->doEvents()) { - - memReq[tid]->completionEvent = - new CacheCompletionEvent(memReq[tid], this); - - lastIcacheStall[tid] = curTick; - - DPRINTF(Activity, "[tid:%i]: Activity: Stalling due to I-cache " - "miss.\n", tid); - - fetchStatus[tid] = IcacheMissStall; - } else { - DPRINTF(Fetch, "[tid:%i]: I-Cache hit. Doing Instruction " - "read.\n", tid); - -// memcpy(cacheData[tid], memReq[tid]->data, memReq[tid]->size); - } - } else { - DPRINTF(Fetch, "[tid:%i] Out of MSHRs!\n", tid); - ret_fault = NoFault; - return false; - } - } - - ret_fault = fault; - return true; -} - -template <class Impl> -inline void -DefaultFetch<Impl>::doSquash(const Addr &new_PC, unsigned tid) -{ - DPRINTF(Fetch, "[tid:%i]: Squashing, setting PC to: %#x.\n", - tid, new_PC); - - PC[tid] = new_PC; - nextPC[tid] = new_PC + instSize; - - // Clear the icache miss if it's outstanding. - if (fetchStatus[tid] == IcacheMissStall && icacheInterface) { - DPRINTF(Fetch, "[tid:%i]: Squashing outstanding Icache miss.\n", - tid); - memReq[tid] = NULL; - } - - fetchStatus[tid] = Squashing; - - ++fetchSquashCycles; -} - -template<class Impl> -void -DefaultFetch<Impl>::squashFromDecode(const Addr &new_PC, - const InstSeqNum &seq_num, - unsigned tid) -{ - DPRINTF(Fetch, "[tid:%i]: Squashing from decode.\n",tid); - - doSquash(new_PC, tid); - - // Tell the CPU to remove any instructions that are in flight between - // fetch and decode. - cpu->removeInstsUntil(seq_num, tid); -} - -template<class Impl> -bool -DefaultFetch<Impl>::checkStall(unsigned tid) const -{ - bool ret_val = false; - - if (cpu->contextSwitch) { - DPRINTF(Fetch,"[tid:%i]: Stalling for a context switch.\n",tid); - ret_val = true; - } else if (stalls[tid].decode) { - DPRINTF(Fetch,"[tid:%i]: Stall from Decode stage detected.\n",tid); - ret_val = true; - } else if (stalls[tid].rename) { - DPRINTF(Fetch,"[tid:%i]: Stall from Rename stage detected.\n",tid); - ret_val = true; - } else if (stalls[tid].iew) { - DPRINTF(Fetch,"[tid:%i]: Stall from IEW stage detected.\n",tid); - ret_val = true; - } else if (stalls[tid].commit) { - DPRINTF(Fetch,"[tid:%i]: Stall from Commit stage detected.\n",tid); - ret_val = true; - } - - return ret_val; -} - -template<class Impl> -typename DefaultFetch<Impl>::FetchStatus -DefaultFetch<Impl>::updateFetchStatus() -{ - //Check Running - list<unsigned>::iterator threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - - unsigned tid = *threads++; - - if (fetchStatus[tid] == Running || - fetchStatus[tid] == Squashing || - fetchStatus[tid] == IcacheMissComplete) { - - if (_status == Inactive) { - DPRINTF(Activity, "[tid:%i]: Activating stage.\n",tid); - - if (fetchStatus[tid] == IcacheMissComplete) { - DPRINTF(Activity, "[tid:%i]: Activating fetch due to cache" - "completion\n",tid); - } - - cpu->activateStage(FullCPU::FetchIdx); - } - - return Active; - } - } - - // Stage is switching from active to inactive, notify CPU of it. - if (_status == Active) { - DPRINTF(Activity, "Deactivating stage.\n"); - - cpu->deactivateStage(FullCPU::FetchIdx); - } - - return Inactive; -} - -template <class Impl> -void -DefaultFetch<Impl>::squash(const Addr &new_PC, unsigned tid) -{ - DPRINTF(Fetch, "[tid:%u]: Squash from commit.\n",tid); - - doSquash(new_PC, tid); - - // Tell the CPU to remove any instructions that are not in the ROB. - cpu->removeInstsNotInROB(tid); -} - -template <class Impl> -void -DefaultFetch<Impl>::tick() -{ - list<unsigned>::iterator threads = (*activeThreads).begin(); - bool status_change = false; - - wroteToTimeBuffer = false; - - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - // Check the signals for each thread to determine the proper status - // for each thread. - bool updated_status = checkSignalsAndUpdate(tid); - status_change = status_change || updated_status; - } - - DPRINTF(Fetch, "Running stage.\n"); - - // Reset the number of the instruction we're fetching. - numInst = 0; - - if (fromCommit->commitInfo[0].interruptPending) { - interruptPending = true; - } - if (fromCommit->commitInfo[0].clearInterrupt) { - interruptPending = false; - } - - for (threadFetched = 0; threadFetched < numFetchingThreads; - threadFetched++) { - // Fetch each of the actively fetching threads. - fetch(status_change); - } - - // Record number of instructions fetched this cycle for distribution. - fetchNisnDist.sample(numInst); - - if (status_change) { - // Change the fetch stage status if there was a status change. - _status = updateFetchStatus(); - } - - // If there was activity this cycle, inform the CPU of it. - if (wroteToTimeBuffer || cpu->contextSwitch) { - DPRINTF(Activity, "Activity this cycle.\n"); - - cpu->activityThisCycle(); - } -} - -template <class Impl> -bool -DefaultFetch<Impl>::checkSignalsAndUpdate(unsigned tid) -{ - // Update the per thread stall statuses. - if (fromDecode->decodeBlock[tid]) { - stalls[tid].decode = true; - } - - if (fromDecode->decodeUnblock[tid]) { - assert(stalls[tid].decode); - assert(!fromDecode->decodeBlock[tid]); - stalls[tid].decode = false; - } - - if (fromRename->renameBlock[tid]) { - stalls[tid].rename = true; - } - - if (fromRename->renameUnblock[tid]) { - assert(stalls[tid].rename); - assert(!fromRename->renameBlock[tid]); - stalls[tid].rename = false; - } - - if (fromIEW->iewBlock[tid]) { - stalls[tid].iew = true; - } - - if (fromIEW->iewUnblock[tid]) { - assert(stalls[tid].iew); - assert(!fromIEW->iewBlock[tid]); - stalls[tid].iew = false; - } - - if (fromCommit->commitBlock[tid]) { - stalls[tid].commit = true; - } - - if (fromCommit->commitUnblock[tid]) { - assert(stalls[tid].commit); - assert(!fromCommit->commitBlock[tid]); - stalls[tid].commit = false; - } - - // Check squash signals from commit. - if (fromCommit->commitInfo[tid].squash) { - - DPRINTF(Fetch, "[tid:%u]: Squashing instructions due to squash " - "from commit.\n",tid); - - // In any case, squash. - squash(fromCommit->commitInfo[tid].nextPC,tid); - - // Also check if there's a mispredict that happened. - if (fromCommit->commitInfo[tid].branchMispredict) { - branchPred.squash(fromCommit->commitInfo[tid].doneSeqNum, - fromCommit->commitInfo[tid].nextPC, - fromCommit->commitInfo[tid].branchTaken, - tid); - } else { - branchPred.squash(fromCommit->commitInfo[tid].doneSeqNum, - tid); - } - - return true; - } else if (fromCommit->commitInfo[tid].doneSeqNum) { - // Update the branch predictor if it wasn't a squashed instruction - // that was broadcasted. - branchPred.update(fromCommit->commitInfo[tid].doneSeqNum, tid); - } - - // Check ROB squash signals from commit. - if (fromCommit->commitInfo[tid].robSquashing) { - DPRINTF(Fetch, "[tid:%u]: ROB is still squashing Thread %u.\n", tid); - - // Continue to squash. - fetchStatus[tid] = Squashing; - - return true; - } - - // Check squash signals from decode. - if (fromDecode->decodeInfo[tid].squash) { - DPRINTF(Fetch, "[tid:%u]: Squashing instructions due to squash " - "from decode.\n",tid); - - // Update the branch predictor. - if (fromDecode->decodeInfo[tid].branchMispredict) { - branchPred.squash(fromDecode->decodeInfo[tid].doneSeqNum, - fromDecode->decodeInfo[tid].nextPC, - fromDecode->decodeInfo[tid].branchTaken, - tid); - } else { - branchPred.squash(fromDecode->decodeInfo[tid].doneSeqNum, - tid); - } - - if (fetchStatus[tid] != Squashing) { - // Squash unless we're already squashing - squashFromDecode(fromDecode->decodeInfo[tid].nextPC, - fromDecode->decodeInfo[tid].doneSeqNum, - tid); - - return true; - } - } - - if (checkStall(tid) && fetchStatus[tid] != IcacheMissStall) { - DPRINTF(Fetch, "[tid:%i]: Setting to blocked\n",tid); - - fetchStatus[tid] = Blocked; - - return true; - } - - if (fetchStatus[tid] == Blocked || - fetchStatus[tid] == Squashing) { - // Switch status to running if fetch isn't being told to block or - // squash this cycle. - DPRINTF(Fetch, "[tid:%i]: Done squashing, switching to running.\n", - tid); - - fetchStatus[tid] = Running; - - return true; - } - - // If we've reached this point, we have not gotten any signals that - // cause fetch to change its status. Fetch remains the same as before. - return false; -} - -template<class Impl> -void -DefaultFetch<Impl>::fetch(bool &status_change) -{ - ////////////////////////////////////////// - // Start actual fetch - ////////////////////////////////////////// - int tid = getFetchingThread(fetchPolicy); - - if (tid == -1) { - DPRINTF(Fetch,"There are no more threads available to fetch from.\n"); - - // Breaks looping condition in tick() - threadFetched = numFetchingThreads; - return; - } - - // The current PC. - Addr &fetch_PC = PC[tid]; - - // Fault code for memory access. - Fault fault = NoFault; - - // If returning from the delay of a cache miss, then update the status - // to running, otherwise do the cache access. Possibly move this up - // to tick() function. - if (fetchStatus[tid] == IcacheMissComplete) { - DPRINTF(Fetch, "[tid:%i]: Icache miss is complete.\n", - tid); - - fetchStatus[tid] = Running; - status_change = true; - } else if (fetchStatus[tid] == Running) { - DPRINTF(Fetch, "[tid:%i]: Attempting to translate and read " - "instruction, starting at PC %08p.\n", - tid, fetch_PC); - - bool fetch_success = fetchCacheLine(fetch_PC, fault, tid); - if (!fetch_success) { - ++fetchMiscStallCycles; - return; - } - } else { - if (fetchStatus[tid] == Idle) { - ++fetchIdleCycles; - } else if (fetchStatus[tid] == Blocked) { - ++fetchBlockedCycles; - } else if (fetchStatus[tid] == Squashing) { - ++fetchSquashCycles; - } else if (fetchStatus[tid] == IcacheMissStall) { - ++icacheStallCycles; - } - - // Status is Idle, Squashing, Blocked, or IcacheMissStall, so - // fetch should do nothing. - return; - } - - ++fetchCycles; - - // If we had a stall due to an icache miss, then return. - if (fetchStatus[tid] == IcacheMissStall) { - ++icacheStallCycles; - status_change = true; - return; - } - - Addr next_PC = fetch_PC; - InstSeqNum inst_seq; - MachInst inst; - ExtMachInst ext_inst; - // @todo: Fix this hack. - unsigned offset = (fetch_PC & cacheBlkMask) & ~3; - - if (fault == NoFault) { - // If the read of the first instruction was successful, then grab the - // instructions from the rest of the cache line and put them into the - // queue heading to decode. - - DPRINTF(Fetch, "[tid:%i]: Adding instructions to queue to " - "decode.\n",tid); - - // Need to keep track of whether or not a predicted branch - // ended this fetch block. - bool predicted_branch = false; - - for (; - offset < cacheBlkSize && - numInst < fetchWidth && - !predicted_branch; - ++numInst) { - - // Get a sequence number. - inst_seq = cpu->getAndIncrementInstSeq(); - - // Make sure this is a valid index. - assert(offset <= cacheBlkSize - instSize); - - // Get the instruction from the array of the cache line. - inst = gtoh(*reinterpret_cast<MachInst *> - (&cacheData[tid][offset])); - - ext_inst = TheISA::makeExtMI(inst, fetch_PC); - - // Create a new DynInst from the instruction fetched. - DynInstPtr instruction = new DynInst(ext_inst, fetch_PC, - next_PC, - inst_seq, cpu); - instruction->setThread(tid); - - instruction->setASID(tid); - - instruction->setState(cpu->thread[tid]); - - DPRINTF(Fetch, "[tid:%i]: Instruction PC %#x created " - "[sn:%lli]\n", - tid, instruction->readPC(), inst_seq); - - DPRINTF(Fetch, "[tid:%i]: Instruction is: %s\n", - tid, instruction->staticInst->disassemble(fetch_PC)); - - instruction->traceData = - Trace::getInstRecord(curTick, cpu->xcBase(tid), cpu, - instruction->staticInst, - instruction->readPC(),tid); - - predicted_branch = lookupAndUpdateNextPC(instruction, next_PC); - - // Add instruction to the CPU's list of instructions. - instruction->setInstListIt(cpu->addInst(instruction)); - - // Write the instruction to the first slot in the queue - // that heads to decode. - toDecode->insts[numInst] = instruction; - - toDecode->size++; - - // Increment stat of fetched instructions. - ++fetchedInsts; - - // Move to the next instruction, unless we have a branch. - fetch_PC = next_PC; - - if (instruction->isQuiesce()) { - warn("%lli: Quiesce instruction encountered, halting fetch!", - curTick); - fetchStatus[tid] = QuiescePending; - ++numInst; - status_change = true; - break; - } - - offset+= instSize; - } - } - - if (numInst > 0) { - wroteToTimeBuffer = true; - } - - // Now that fetching is completed, update the PC to signify what the next - // cycle will be. - if (fault == NoFault) { - DPRINTF(Fetch, "[tid:%i]: Setting PC to %08p.\n",tid, next_PC); - - PC[tid] = next_PC; - nextPC[tid] = next_PC + instSize; - } else { - // We shouldn't be in an icache miss and also have a fault (an ITB - // miss) - if (fetchStatus[tid] == IcacheMissStall) { - panic("Fetch should have exited prior to this!"); - } - - // Send the fault to commit. This thread will not do anything - // until commit handles the fault. The only other way it can - // wake up is if a squash comes along and changes the PC. -#if FULL_SYSTEM - assert(numInst != fetchWidth); - // Get a sequence number. - inst_seq = cpu->getAndIncrementInstSeq(); - // We will use a nop in order to carry the fault. - ext_inst = TheISA::NoopMachInst; - - // Create a new DynInst from the dummy nop. - DynInstPtr instruction = new DynInst(ext_inst, fetch_PC, - next_PC, - inst_seq, cpu); - instruction->setPredTarg(next_PC + instSize); - instruction->setThread(tid); - - instruction->setASID(tid); - - instruction->setState(cpu->thread[tid]); - - instruction->traceData = NULL; - - instruction->setInstListIt(cpu->addInst(instruction)); - - instruction->fault = fault; - - toDecode->insts[numInst] = instruction; - toDecode->size++; - - DPRINTF(Fetch, "[tid:%i]: Blocked, need to handle the trap.\n",tid); - - fetchStatus[tid] = TrapPending; - status_change = true; - - warn("%lli fault (%d) detected @ PC %08p", curTick, fault, PC[tid]); -#else // !FULL_SYSTEM - fatal("fault (%d) detected @ PC %08p", fault, PC[tid]); -#endif // FULL_SYSTEM - } -} - - -/////////////////////////////////////// -// // -// SMT FETCH POLICY MAINTAINED HERE // -// // -/////////////////////////////////////// -template<class Impl> -int -DefaultFetch<Impl>::getFetchingThread(FetchPriority &fetch_priority) -{ - if (numThreads > 1) { - switch (fetch_priority) { - - case SingleThread: - return 0; - - case RoundRobin: - return roundRobin(); - - case IQ: - return iqCount(); - - case LSQ: - return lsqCount(); - - case Branch: - return branchCount(); - - default: - return -1; - } - } else { - int tid = *((*activeThreads).begin()); - - if (fetchStatus[tid] == Running || - fetchStatus[tid] == IcacheMissComplete || - fetchStatus[tid] == Idle) { - return tid; - } else { - return -1; - } - } - -} - - -template<class Impl> -int -DefaultFetch<Impl>::roundRobin() -{ - list<unsigned>::iterator pri_iter = priorityList.begin(); - list<unsigned>::iterator end = priorityList.end(); - - int high_pri; - - while (pri_iter != end) { - high_pri = *pri_iter; - - assert(high_pri <= numThreads); - - if (fetchStatus[high_pri] == Running || - fetchStatus[high_pri] == IcacheMissComplete || - fetchStatus[high_pri] == Idle) { - - priorityList.erase(pri_iter); - priorityList.push_back(high_pri); - - return high_pri; - } - - pri_iter++; - } - - return -1; -} - -template<class Impl> -int -DefaultFetch<Impl>::iqCount() -{ - priority_queue<unsigned> PQ; - - list<unsigned>::iterator threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - PQ.push(fromIEW->iewInfo[tid].iqCount); - } - - while (!PQ.empty()) { - - unsigned high_pri = PQ.top(); - - if (fetchStatus[high_pri] == Running || - fetchStatus[high_pri] == IcacheMissComplete || - fetchStatus[high_pri] == Idle) - return high_pri; - else - PQ.pop(); - - } - - return -1; -} - -template<class Impl> -int -DefaultFetch<Impl>::lsqCount() -{ - priority_queue<unsigned> PQ; - - - list<unsigned>::iterator threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - PQ.push(fromIEW->iewInfo[tid].ldstqCount); - } - - while (!PQ.empty()) { - - unsigned high_pri = PQ.top(); - - if (fetchStatus[high_pri] == Running || - fetchStatus[high_pri] == IcacheMissComplete || - fetchStatus[high_pri] == Idle) - return high_pri; - else - PQ.pop(); - - } - - return -1; -} - -template<class Impl> -int -DefaultFetch<Impl>::branchCount() -{ - list<unsigned>::iterator threads = (*activeThreads).begin(); - - return *threads; -} diff --git a/cpu/o3/free_list.cc b/cpu/o3/free_list.cc deleted file mode 100644 index bd0f4f034..000000000 --- a/cpu/o3/free_list.cc +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "base/trace.hh" - -#include "cpu/o3/free_list.hh" - -SimpleFreeList::SimpleFreeList(unsigned activeThreads, - unsigned _numLogicalIntRegs, - unsigned _numPhysicalIntRegs, - unsigned _numLogicalFloatRegs, - unsigned _numPhysicalFloatRegs) - : numLogicalIntRegs(_numLogicalIntRegs), - numPhysicalIntRegs(_numPhysicalIntRegs), - numLogicalFloatRegs(_numLogicalFloatRegs), - numPhysicalFloatRegs(_numPhysicalFloatRegs), - numPhysicalRegs(numPhysicalIntRegs + numPhysicalFloatRegs) -{ - DPRINTF(FreeList, "Creating new free list object.\n"); - - // Put all of the extra physical registers onto the free list. This - // means excluding all of the base logical registers. - for (PhysRegIndex i = numLogicalIntRegs * activeThreads; - i < numPhysicalIntRegs; ++i) - { - freeIntRegs.push(i); - } - - // Put all of the extra physical registers onto the free list. This - // means excluding all of the base logical registers. Because the - // float registers' indices start where the physical registers end, - // some math must be done to determine where the free registers start. - PhysRegIndex i = numPhysicalIntRegs + (numLogicalFloatRegs * activeThreads); - - for ( ; i < numPhysicalRegs; ++i) - { - freeFloatRegs.push(i); - } -} - -std::string -SimpleFreeList::name() const -{ - return "cpu.freelist"; -} diff --git a/cpu/o3/free_list.hh b/cpu/o3/free_list.hh deleted file mode 100644 index 29e84cd44..000000000 --- a/cpu/o3/free_list.hh +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_FREE_LIST_HH__ -#define __CPU_O3_FREE_LIST_HH__ - -#include <iostream> -#include <queue> - -#include "arch/isa_traits.hh" -#include "base/trace.hh" -#include "base/traceflags.hh" -#include "cpu/o3/comm.hh" - -/** - * FreeList class that simply holds the list of free integer and floating - * point registers. Can request for a free register of either type, and - * also send back free registers of either type. This is a very simple - * class, but it should be sufficient for most implementations. Like all - * other classes, it assumes that the indices for the floating point - * registers starts after the integer registers end. Hence the variable - * numPhysicalIntRegs is logically equivalent to the baseFP dependency. - * Note that while this most likely should be called FreeList, the name - * "FreeList" is used in a typedef within the CPU Policy, and therefore no - * class can be named simply "FreeList". - * @todo: Give a better name to the base FP dependency. - */ -class SimpleFreeList -{ - private: - /** The list of free integer registers. */ - std::queue<PhysRegIndex> freeIntRegs; - - /** The list of free floating point registers. */ - std::queue<PhysRegIndex> freeFloatRegs; - - /** Number of logical integer registers. */ - int numLogicalIntRegs; - - /** Number of physical integer registers. */ - int numPhysicalIntRegs; - - /** Number of logical floating point registers. */ - int numLogicalFloatRegs; - - /** Number of physical floating point registers. */ - int numPhysicalFloatRegs; - - /** Total number of physical registers. */ - int numPhysicalRegs; - - public: - /** Constructs a free list. - * @param activeThreads Number of active threads. - * @param _numLogicalIntRegs Number of logical integer registers. - * @param _numPhysicalIntRegs Number of physical integer registers. - * @param _numLogicalFloatRegs Number of logical fp registers. - * @param _numPhysicalFloatRegs Number of physical fp registers. - */ - SimpleFreeList(unsigned activeThreads, - unsigned _numLogicalIntRegs, - unsigned _numPhysicalIntRegs, - unsigned _numLogicalFloatRegs, - unsigned _numPhysicalFloatRegs); - - /** Gives the name of the freelist. */ - std::string name() const; - - /** Gets a free integer register. */ - inline PhysRegIndex getIntReg(); - - /** Gets a free fp register. */ - inline PhysRegIndex getFloatReg(); - - /** Adds a register back to the free list. */ - inline void addReg(PhysRegIndex freed_reg); - - /** Adds an integer register back to the free list. */ - inline void addIntReg(PhysRegIndex freed_reg); - - /** Adds a fp register back to the free list. */ - inline void addFloatReg(PhysRegIndex freed_reg); - - /** Checks if there are any free integer registers. */ - bool hasFreeIntRegs() - { return !freeIntRegs.empty(); } - - /** Checks if there are any free fp registers. */ - bool hasFreeFloatRegs() - { return !freeFloatRegs.empty(); } - - /** Returns the number of free integer registers. */ - int numFreeIntRegs() - { return freeIntRegs.size(); } - - /** Returns the number of free fp registers. */ - int numFreeFloatRegs() - { return freeFloatRegs.size(); } -}; - -inline PhysRegIndex -SimpleFreeList::getIntReg() -{ - DPRINTF(FreeList, "Trying to get free integer register.\n"); - - if (freeIntRegs.empty()) { - panic("No free integer registers!"); - } - - PhysRegIndex free_reg = freeIntRegs.front(); - - freeIntRegs.pop(); - - return(free_reg); -} - -inline PhysRegIndex -SimpleFreeList::getFloatReg() -{ - DPRINTF(FreeList, "Trying to get free float register.\n"); - - if (freeFloatRegs.empty()) { - panic("No free integer registers!"); - } - - PhysRegIndex free_reg = freeFloatRegs.front(); - - freeFloatRegs.pop(); - - return(free_reg); -} - -inline void -SimpleFreeList::addReg(PhysRegIndex freed_reg) -{ - DPRINTF(FreeList,"Freeing register %i.\n", freed_reg); - //Might want to add in a check for whether or not this register is - //already in there. A bit vector or something similar would be useful. - if (freed_reg < numPhysicalIntRegs) { - if (freed_reg != TheISA::ZeroReg) - freeIntRegs.push(freed_reg); - } else if (freed_reg < numPhysicalRegs) { - if (freed_reg != (TheISA::ZeroReg + numPhysicalIntRegs)) - freeFloatRegs.push(freed_reg); - } -} - -inline void -SimpleFreeList::addIntReg(PhysRegIndex freed_reg) -{ - DPRINTF(FreeList,"Freeing int register %i.\n", freed_reg); - - freeIntRegs.push(freed_reg); -} - -inline void -SimpleFreeList::addFloatReg(PhysRegIndex freed_reg) -{ - DPRINTF(FreeList,"Freeing float register %i.\n", freed_reg); - - freeFloatRegs.push(freed_reg); -} - -#endif // __CPU_O3_FREE_LIST_HH__ diff --git a/cpu/o3/fu_pool.cc b/cpu/o3/fu_pool.cc deleted file mode 100644 index fb2b5c00d..000000000 --- a/cpu/o3/fu_pool.cc +++ /dev/null @@ -1,295 +0,0 @@ -/* - * 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. - */ - -#include <sstream> - -#include "cpu/o3/fu_pool.hh" -#include "encumbered/cpu/full/fu_pool.hh" -#include "sim/builder.hh" - -using namespace std; - -//////////////////////////////////////////////////////////////////////////// -// -// A pool of function units -// - -inline void -FUPool::FUIdxQueue::addFU(int fu_idx) -{ - funcUnitsIdx.push_back(fu_idx); - ++size; -} - -inline int -FUPool::FUIdxQueue::getFU() -{ - int retval = funcUnitsIdx[idx++]; - - if (idx == size) - idx = 0; - - return retval; -} - -FUPool::~FUPool() -{ - fuListIterator i = funcUnits.begin(); - fuListIterator end = funcUnits.end(); - for (; i != end; ++i) - delete *i; -} - - -// Constructor -FUPool::FUPool(string name, vector<FUDesc *> paramList) - : SimObject(name) -{ - numFU = 0; - - funcUnits.clear(); - - for (int i = 0; i < Num_OpClasses; ++i) { - maxOpLatencies[i] = 0; - maxIssueLatencies[i] = 0; - } - - // - // Iterate through the list of FUDescData structures - // - for (FUDDiterator i = paramList.begin(); i != paramList.end(); ++i) { - - // - // Don't bother with this if we're not going to create any FU's - // - if ((*i)->number) { - // - // Create the FuncUnit object from this structure - // - add the capabilities listed in the FU's operation - // description - // - // We create the first unit, then duplicate it as needed - // - FuncUnit *fu = new FuncUnit; - - OPDDiterator j = (*i)->opDescList.begin(); - OPDDiterator end = (*i)->opDescList.end(); - for (; j != end; ++j) { - // indicate that this pool has this capability - capabilityList.set((*j)->opClass); - - // Add each of the FU's that will have this capability to the - // appropriate queue. - for (int k = 0; k < (*i)->number; ++k) - fuPerCapList[(*j)->opClass].addFU(numFU + k); - - // indicate that this FU has the capability - fu->addCapability((*j)->opClass, (*j)->opLat, (*j)->issueLat); - - if ((*j)->opLat > maxOpLatencies[(*j)->opClass]) - maxOpLatencies[(*j)->opClass] = (*j)->opLat; - - if ((*j)->issueLat > maxIssueLatencies[(*j)->opClass]) - maxIssueLatencies[(*j)->opClass] = (*j)->issueLat; - } - - numFU++; - - // Add the appropriate number of copies of this FU to the list - ostringstream s; - - s << (*i)->name() << "(0)"; - fu->name = s.str(); - funcUnits.push_back(fu); - - for (int c = 1; c < (*i)->number; ++c) { - ostringstream s; - numFU++; - FuncUnit *fu2 = new FuncUnit(*fu); - - s << (*i)->name() << "(" << c << ")"; - fu2->name = s.str(); - funcUnits.push_back(fu2); - } - } - } - - unitBusy.resize(numFU); - - for (int i = 0; i < numFU; i++) { - unitBusy[i] = false; - } -} - -void -FUPool::annotateMemoryUnits(unsigned hit_latency) -{ - maxOpLatencies[MemReadOp] = hit_latency; - - fuListIterator i = funcUnits.begin(); - fuListIterator iend = funcUnits.end(); - for (; i != iend; ++i) { - if ((*i)->provides(MemReadOp)) - (*i)->opLatency(MemReadOp) = hit_latency; - - if ((*i)->provides(MemWriteOp)) - (*i)->opLatency(MemWriteOp) = hit_latency; - } -} - -int -FUPool::getUnit(OpClass capability) -{ - // If this pool doesn't have the specified capability, - // return this information to the caller - if (!capabilityList[capability]) - return -2; - - int fu_idx = fuPerCapList[capability].getFU(); - int start_idx = fu_idx; - - // Iterate through the circular queue if needed, stopping if we've reached - // the first element again. - while (unitBusy[fu_idx]) { - fu_idx = fuPerCapList[capability].getFU(); - if (fu_idx == start_idx) { - // No FU available - return -1; - } - } - - unitBusy[fu_idx] = true; - - return fu_idx; -} - -void -FUPool::freeUnitNextCycle(int fu_idx) -{ - assert(unitBusy[fu_idx]); - unitsToBeFreed.push_back(fu_idx); -} - -void -FUPool::processFreeUnits() -{ - while (!unitsToBeFreed.empty()) { - int fu_idx = unitsToBeFreed.back(); - unitsToBeFreed.pop_back(); - - assert(unitBusy[fu_idx]); - - unitBusy[fu_idx] = false; - } -} - -void -FUPool::dump() -{ - cout << "Function Unit Pool (" << name() << ")\n"; - cout << "======================================\n"; - cout << "Free List:\n"; - - for (int i = 0; i < numFU; ++i) { - if (unitBusy[i]) { - continue; - } - - cout << " [" << i << "] : "; - - cout << funcUnits[i]->name << " "; - - cout << "\n"; - } - - cout << "======================================\n"; - cout << "Busy List:\n"; - for (int i = 0; i < numFU; ++i) { - if (!unitBusy[i]) { - continue; - } - - cout << " [" << i << "] : "; - - cout << funcUnits[i]->name << " "; - - cout << "\n"; - } -} - -void -FUPool::switchOut() -{ -} - -void -FUPool::takeOverFrom() -{ - for (int i = 0; i < numFU; i++) { - unitBusy[i] = false; - } - unitsToBeFreed.clear(); -} - -// - -//////////////////////////////////////////////////////////////////////////// -// -// The SimObjects we use to get the FU information into the simulator -// -//////////////////////////////////////////////////////////////////////////// - -// -// FUPool - Contails a list of FUDesc objects to make available -// - -// -// The FuPool object -// - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(FUPool) - - SimObjectVectorParam<FUDesc *> FUList; - -END_DECLARE_SIM_OBJECT_PARAMS(FUPool) - - -BEGIN_INIT_SIM_OBJECT_PARAMS(FUPool) - - INIT_PARAM(FUList, "list of FU's for this pool") - -END_INIT_SIM_OBJECT_PARAMS(FUPool) - - -CREATE_SIM_OBJECT(FUPool) -{ - return new FUPool(getInstanceName(), FUList); -} - -REGISTER_SIM_OBJECT("FUPool", FUPool) - diff --git a/cpu/o3/fu_pool.hh b/cpu/o3/fu_pool.hh deleted file mode 100644 index da6fdc802..000000000 --- a/cpu/o3/fu_pool.hh +++ /dev/null @@ -1,162 +0,0 @@ -/* - * 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. - */ - -#ifndef __CPU_O3_FU_POOL_HH__ -#define __CPU_O3_FU_POOL_HH__ - -#include <bitset> -#include <list> -#include <string> -#include <vector> - -#include "base/sched_list.hh" -#include "encumbered/cpu/full/op_class.hh" -#include "sim/sim_object.hh" - -class FUDesc; -class FuncUnit; - -/** - * Pool of FU's, specific to the new CPU model. The old FU pool had lists of - * free units and busy units, and whenever a FU was needed it would iterate - * through the free units to find a FU that provided the capability. This pool - * has lists of units specific to each of the capabilities, and whenever a FU - * is needed, it iterates through that list to find a free unit. The previous - * FU pool would have to be ticked each cycle to update which units became - * free. This FU pool lets the IEW stage handle freeing units, which frees - * them as their scheduled execution events complete. This limits units in this - * model to either have identical issue and op latencies, or 1 cycle issue - * latencies. - */ -class FUPool : public SimObject -{ - private: - /** Maximum op execution latencies, per op class. */ - unsigned maxOpLatencies[Num_OpClasses]; - /** Maximum issue latencies, per op class. */ - unsigned maxIssueLatencies[Num_OpClasses]; - - /** Bitvector listing capabilities of this FU pool. */ - std::bitset<Num_OpClasses> capabilityList; - - /** Bitvector listing which FUs are busy. */ - std::vector<bool> unitBusy; - - /** List of units to be freed at the end of this cycle. */ - std::vector<int> unitsToBeFreed; - - /** - * Class that implements a circular queue to hold FU indices. The hope is - * that FUs that have been just used will be moved to the end of the queue - * by iterating through it, thus leaving free units at the head of the - * queue. - */ - class FUIdxQueue { - public: - /** Constructs a circular queue of FU indices. */ - FUIdxQueue() - : idx(0), size(0) - { } - - /** Adds a FU to the queue. */ - inline void addFU(int fu_idx); - - /** Returns the index of the FU at the head of the queue, and changes - * the index to the next element. - */ - inline int getFU(); - - private: - /** Circular queue index. */ - int idx; - - /** Size of the queue. */ - int size; - - /** Queue of FU indices. */ - std::vector<int> funcUnitsIdx; - }; - - /** Per op class queues of FUs that provide that capability. */ - FUIdxQueue fuPerCapList[Num_OpClasses]; - - /** Number of FUs. */ - int numFU; - - /** Functional units. */ - std::vector<FuncUnit *> funcUnits; - - typedef std::vector<FuncUnit *>::iterator fuListIterator; - - public: - - /** Constructs a FU pool. */ - FUPool(std::string name, std::vector<FUDesc *> l); - ~FUPool(); - - /** Annotates units that provide memory operations. Included only because - * old FU pool provided this function. - */ - void annotateMemoryUnits(unsigned hit_latency); - - /** - * Gets a FU providing the requested capability. Will mark the unit as busy, - * but leaves the freeing of the unit up to the IEW stage. - * @param capability The capability requested. - * @return Returns -2 if the FU pool does not have the capability, -1 if - * there is no free FU, and the FU's index otherwise. - */ - int getUnit(OpClass capability); - - /** Frees a FU at the end of this cycle. */ - void freeUnitNextCycle(int fu_idx); - - /** Frees all FUs on the list. */ - void processFreeUnits(); - - /** Returns the total number of FUs. */ - int size() { return numFU; } - - /** Debugging function used to dump FU information. */ - void dump(); - - /** Returns the operation execution latency of the given capability. */ - unsigned getOpLatency(OpClass capability) { - return maxOpLatencies[capability]; - } - - /** Returns the issue latency of the given capability. */ - unsigned getIssueLatency(OpClass capability) { - return maxIssueLatencies[capability]; - } - - void switchOut(); - void takeOverFrom(); -}; - -#endif // __CPU_O3_FU_POOL_HH__ diff --git a/cpu/o3/iew.cc b/cpu/o3/iew.cc deleted file mode 100644 index 90d035f71..000000000 --- a/cpu/o3/iew.cc +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/o3/alpha_dyn_inst.hh" -#include "cpu/o3/alpha_impl.hh" -#include "cpu/o3/iew_impl.hh" -#include "cpu/o3/inst_queue.hh" - -template class DefaultIEW<AlphaSimpleImpl>; diff --git a/cpu/o3/iew.hh b/cpu/o3/iew.hh deleted file mode 100644 index 935320628..000000000 --- a/cpu/o3/iew.hh +++ /dev/null @@ -1,501 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_IEW_HH__ -#define __CPU_O3_IEW_HH__ - -#include <queue> - -#include "base/statistics.hh" -#include "base/timebuf.hh" -#include "config/full_system.hh" -#include "cpu/o3/comm.hh" -#include "cpu/o3/scoreboard.hh" -#include "cpu/o3/lsq.hh" - -class FUPool; - -/** - * DefaultIEW handles both single threaded and SMT IEW - * (issue/execute/writeback). It handles the dispatching of - * instructions to the LSQ/IQ as part of the issue stage, and has the - * IQ try to issue instructions each cycle. The execute latency is - * actually tied into the issue latency to allow the IQ to be able to - * do back-to-back scheduling without having to speculatively schedule - * instructions. This happens by having the IQ have access to the - * functional units, and the IQ gets the execution latencies from the - * FUs when it issues instructions. Instructions reach the execute - * stage on the last cycle of their execution, which is when the IQ - * knows to wake up any dependent instructions, allowing back to back - * scheduling. The execute portion of IEW separates memory - * instructions from non-memory instructions, either telling the LSQ - * to execute the instruction, or executing the instruction directly. - * The writeback portion of IEW completes the instructions by waking - * up any dependents, and marking the register ready on the - * scoreboard. - */ -template<class Impl> -class DefaultIEW -{ - private: - //Typedefs from Impl - typedef typename Impl::CPUPol CPUPol; - typedef typename Impl::DynInstPtr DynInstPtr; - typedef typename Impl::FullCPU FullCPU; - typedef typename Impl::Params Params; - - typedef typename CPUPol::IQ IQ; - typedef typename CPUPol::RenameMap RenameMap; - typedef typename CPUPol::LSQ LSQ; - - typedef typename CPUPol::TimeStruct TimeStruct; - typedef typename CPUPol::IEWStruct IEWStruct; - typedef typename CPUPol::RenameStruct RenameStruct; - typedef typename CPUPol::IssueStruct IssueStruct; - - friend class Impl::FullCPU; - friend class CPUPol::IQ; - - public: - /** Overall IEW stage status. Used to determine if the CPU can - * deschedule itself due to a lack of activity. - */ - enum Status { - Active, - Inactive - }; - - /** Status for Issue, Execute, and Writeback stages. */ - enum StageStatus { - Running, - Blocked, - Idle, - StartSquash, - Squashing, - Unblocking - }; - - private: - /** Overall stage status. */ - Status _status; - /** Dispatch status. */ - StageStatus dispatchStatus[Impl::MaxThreads]; - /** Execute status. */ - StageStatus exeStatus; - /** Writeback status. */ - StageStatus wbStatus; - - public: - /** LdWriteback event for a load completion. */ - class LdWritebackEvent : public Event { - private: - /** Instruction that is writing back data to the register file. */ - DynInstPtr inst; - /** Pointer to IEW stage. */ - DefaultIEW<Impl> *iewStage; - - public: - /** Constructs a load writeback event. */ - LdWritebackEvent(DynInstPtr &_inst, DefaultIEW<Impl> *_iew); - - /** Processes writeback event. */ - virtual void process(); - /** Returns the description of the writeback event. */ - virtual const char *description(); - }; - - public: - /** Constructs a DefaultIEW with the given parameters. */ - DefaultIEW(Params *params); - - /** Returns the name of the DefaultIEW stage. */ - std::string name() const; - - /** Registers statistics. */ - void regStats(); - - /** Initializes stage; sends back the number of free IQ and LSQ entries. */ - void initStage(); - - /** Sets CPU pointer for IEW, IQ, and LSQ. */ - void setCPU(FullCPU *cpu_ptr); - - /** Sets main time buffer used for backwards communication. */ - void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr); - - /** Sets time buffer for getting instructions coming from rename. */ - void setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr); - - /** Sets time buffer to pass on instructions to commit. */ - void setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr); - - /** Sets pointer to list of active threads. */ - void setActiveThreads(std::list<unsigned> *at_ptr); - - /** Sets pointer to the scoreboard. */ - void setScoreboard(Scoreboard *sb_ptr); - - void switchOut(); - - void doSwitchOut(); - - void takeOverFrom(); - - bool isSwitchedOut() { return switchedOut; } - - /** Sets page table pointer within LSQ. */ -// void setPageTable(PageTable *pt_ptr); - - /** Squashes instructions in IEW for a specific thread. */ - void squash(unsigned tid); - - /** Wakes all dependents of a completed instruction. */ - void wakeDependents(DynInstPtr &inst); - - /** Tells memory dependence unit that a memory instruction needs to be - * rescheduled. It will re-execute once replayMemInst() is called. - */ - void rescheduleMemInst(DynInstPtr &inst); - - /** Re-executes all rescheduled memory instructions. */ - void replayMemInst(DynInstPtr &inst); - - /** Sends an instruction to commit through the time buffer. */ - void instToCommit(DynInstPtr &inst); - - /** Inserts unused instructions of a thread into the skid buffer. */ - void skidInsert(unsigned tid); - - /** Returns the max of the number of entries in all of the skid buffers. */ - int skidCount(); - - /** Returns if all of the skid buffers are empty. */ - bool skidsEmpty(); - - /** Updates overall IEW status based on all of the stages' statuses. */ - void updateStatus(); - - /** Resets entries of the IQ and the LSQ. */ - void resetEntries(); - - /** Tells the CPU to wakeup if it has descheduled itself due to no - * activity. Used mainly by the LdWritebackEvent. - */ - void wakeCPU(); - - /** Reports to the CPU that there is activity this cycle. */ - void activityThisCycle(); - - /** Tells CPU that the IEW stage is active and running. */ - inline void activateStage(); - - /** Tells CPU that the IEW stage is inactive and idle. */ - inline void deactivateStage(); - - /** Returns if the LSQ has any stores to writeback. */ - bool hasStoresToWB() { return ldstQueue.hasStoresToWB(); } - - private: - /** Sends commit proper information for a squash due to a branch - * mispredict. - */ - void squashDueToBranch(DynInstPtr &inst, unsigned thread_id); - - /** Sends commit proper information for a squash due to a memory order - * violation. - */ - void squashDueToMemOrder(DynInstPtr &inst, unsigned thread_id); - - /** Sends commit proper information for a squash due to memory becoming - * blocked (younger issued instructions must be retried). - */ - void squashDueToMemBlocked(DynInstPtr &inst, unsigned thread_id); - - /** Sets Dispatch to blocked, and signals back to other stages to block. */ - void block(unsigned thread_id); - - /** Unblocks Dispatch if the skid buffer is empty, and signals back to - * other stages to unblock. - */ - void unblock(unsigned thread_id); - - /** Determines proper actions to take given Dispatch's status. */ - void dispatch(unsigned tid); - - /** Dispatches instructions to IQ and LSQ. */ - void dispatchInsts(unsigned tid); - - /** Executes instructions. In the case of memory operations, it informs the - * LSQ to execute the instructions. Also handles any redirects that occur - * due to the executed instructions. - */ - void executeInsts(); - - /** Writebacks instructions. In our model, the instruction's execute() - * function atomically reads registers, executes, and writes registers. - * Thus this writeback only wakes up dependent instructions, and informs - * the scoreboard of registers becoming ready. - */ - void writebackInsts(); - - /** Returns the number of valid, non-squashed instructions coming from - * rename to dispatch. - */ - unsigned validInstsFromRename(); - - /** Reads the stall signals. */ - void readStallSignals(unsigned tid); - - /** Checks if any of the stall conditions are currently true. */ - bool checkStall(unsigned tid); - - /** Processes inputs and changes state accordingly. */ - void checkSignalsAndUpdate(unsigned tid); - - /** Sorts instructions coming from rename into lists separated by thread. */ - void sortInsts(); - - public: - /** Ticks IEW stage, causing Dispatch, the IQ, the LSQ, Execute, and - * Writeback to run for one cycle. - */ - void tick(); - - private: - void updateExeInstStats(DynInstPtr &inst); - - /** Pointer to main time buffer used for backwards communication. */ - TimeBuffer<TimeStruct> *timeBuffer; - - /** Wire to write information heading to previous stages. */ - typename TimeBuffer<TimeStruct>::wire toFetch; - - /** Wire to get commit's output from backwards time buffer. */ - typename TimeBuffer<TimeStruct>::wire fromCommit; - - /** Wire to write information heading to previous stages. */ - typename TimeBuffer<TimeStruct>::wire toRename; - - /** Rename instruction queue interface. */ - TimeBuffer<RenameStruct> *renameQueue; - - /** Wire to get rename's output from rename queue. */ - typename TimeBuffer<RenameStruct>::wire fromRename; - - /** Issue stage queue. */ - TimeBuffer<IssueStruct> issueToExecQueue; - - /** Wire to read information from the issue stage time queue. */ - typename TimeBuffer<IssueStruct>::wire fromIssue; - - /** - * IEW stage time buffer. Holds ROB indices of instructions that - * can be marked as completed. - */ - TimeBuffer<IEWStruct> *iewQueue; - - /** Wire to write infromation heading to commit. */ - typename TimeBuffer<IEWStruct>::wire toCommit; - - /** Queue of all instructions coming from rename this cycle. */ - std::queue<DynInstPtr> insts[Impl::MaxThreads]; - - /** Skid buffer between rename and IEW. */ - std::queue<DynInstPtr> skidBuffer[Impl::MaxThreads]; - - /** Scoreboard pointer. */ - Scoreboard* scoreboard; - - public: - /** Instruction queue. */ - IQ instQueue; - - /** Load / store queue. */ - LSQ ldstQueue; - - /** Pointer to the functional unit pool. */ - FUPool *fuPool; - - private: - /** CPU pointer. */ - FullCPU *cpu; - - /** Records if IEW has written to the time buffer this cycle, so that the - * CPU can deschedule itself if there is no activity. - */ - bool wroteToTimeBuffer; - - /** Source of possible stalls. */ - struct Stalls { - bool commit; - }; - - /** Stages that are telling IEW to stall. */ - Stalls stalls[Impl::MaxThreads]; - - /** Debug function to print instructions that are issued this cycle. */ - void printAvailableInsts(); - - public: - /** Records if the LSQ needs to be updated on the next cycle, so that - * IEW knows if there will be activity on the next cycle. - */ - bool updateLSQNextCycle; - - private: - /** Records if there is a fetch redirect on this cycle for each thread. */ - bool fetchRedirect[Impl::MaxThreads]; - - /** Used to track if all instructions have been dispatched this cycle. - * If they have not, then blocking must have occurred, and the instructions - * would already be added to the skid buffer. - * @todo: Fix this hack. - */ - bool dispatchedAllInsts; - - /** Records if the queues have been changed (inserted or issued insts), - * so that IEW knows to broadcast the updated amount of free entries. - */ - bool updatedQueues; - - /** Commit to IEW delay, in ticks. */ - unsigned commitToIEWDelay; - - /** Rename to IEW delay, in ticks. */ - unsigned renameToIEWDelay; - - /** - * Issue to execute delay, in ticks. What this actually represents is - * the amount of time it takes for an instruction to wake up, be - * scheduled, and sent to a FU for execution. - */ - unsigned issueToExecuteDelay; - - /** Width of issue's read path, in instructions. The read path is both - * the skid buffer and the rename instruction queue. - * Note to self: is this really different than issueWidth? - */ - unsigned issueReadWidth; - - /** Width of issue, in instructions. */ - unsigned issueWidth; - - /** Width of execute, in instructions. Might make more sense to break - * down into FP vs int. - */ - unsigned executeWidth; - - /** Index into queue of instructions being written back. */ - unsigned wbNumInst; - - /** Cycle number within the queue of instructions being written back. - * Used in case there are too many instructions writing back at the current - * cycle and writesbacks need to be scheduled for the future. See comments - * in instToCommit(). - */ - unsigned wbCycle; - - /** Number of active threads. */ - unsigned numThreads; - - /** Pointer to list of active threads. */ - std::list<unsigned> *activeThreads; - - /** Maximum size of the skid buffer. */ - unsigned skidBufferMax; - - bool switchedOut; - - /** Stat for total number of idle cycles. */ - Stats::Scalar<> iewIdleCycles; - /** Stat for total number of squashing cycles. */ - Stats::Scalar<> iewSquashCycles; - /** Stat for total number of blocking cycles. */ - Stats::Scalar<> iewBlockCycles; - /** Stat for total number of unblocking cycles. */ - Stats::Scalar<> iewUnblockCycles; - /** Stat for total number of instructions dispatched. */ - Stats::Scalar<> iewDispatchedInsts; - /** Stat for total number of squashed instructions dispatch skips. */ - Stats::Scalar<> iewDispSquashedInsts; - /** Stat for total number of dispatched load instructions. */ - Stats::Scalar<> iewDispLoadInsts; - /** Stat for total number of dispatched store instructions. */ - Stats::Scalar<> iewDispStoreInsts; - /** Stat for total number of dispatched non speculative instructions. */ - Stats::Scalar<> iewDispNonSpecInsts; - /** Stat for number of times the IQ becomes full. */ - Stats::Scalar<> iewIQFullEvents; - /** Stat for number of times the LSQ becomes full. */ - Stats::Scalar<> iewLSQFullEvents; - /** Stat for total number of executed instructions. */ - Stats::Scalar<> iewExecutedInsts; - /** Stat for total number of executed load instructions. */ - Stats::Vector<> iewExecLoadInsts; - /** Stat for total number of executed store instructions. */ -// Stats::Scalar<> iewExecStoreInsts; - /** Stat for total number of squashed instructions skipped at execute. */ - Stats::Scalar<> iewExecSquashedInsts; - /** Stat for total number of memory ordering violation events. */ - Stats::Scalar<> memOrderViolationEvents; - /** Stat for total number of incorrect predicted taken branches. */ - Stats::Scalar<> predictedTakenIncorrect; - /** Stat for total number of incorrect predicted not taken branches. */ - Stats::Scalar<> predictedNotTakenIncorrect; - /** Stat for total number of mispredicted branches detected at execute. */ - Stats::Formula branchMispredicts; - - Stats::Vector<> exeSwp; - Stats::Vector<> exeNop; - Stats::Vector<> exeRefs; - Stats::Vector<> exeBranches; - -// Stats::Vector<> issued_ops; -/* - Stats::Vector<> stat_fu_busy; - Stats::Vector2d<> stat_fuBusy; - Stats::Vector<> dist_unissued; - Stats::Vector2d<> stat_issued_inst_type; -*/ - Stats::Formula issueRate; - Stats::Formula iewExecStoreInsts; -// Stats::Formula issue_op_rate; -// Stats::Formula fu_busy_rate; - - Stats::Vector<> iewInstsToCommit; - Stats::Vector<> writebackCount; - Stats::Vector<> producerInst; - Stats::Vector<> consumerInst; - Stats::Vector<> wbPenalized; - - Stats::Formula wbRate; - Stats::Formula wbFanout; - Stats::Formula wbPenalizedRate; -}; - -#endif // __CPU_O3_IEW_HH__ diff --git a/cpu/o3/iew_impl.hh b/cpu/o3/iew_impl.hh deleted file mode 100644 index b0137d7fc..000000000 --- a/cpu/o3/iew_impl.hh +++ /dev/null @@ -1,1578 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// @todo: Fix the instantaneous communication among all the stages within -// iew. There's a clear delay between issue and execute, yet backwards -// communication happens simultaneously. - -#include <queue> - -#include "base/timebuf.hh" -#include "cpu/o3/fu_pool.hh" -#include "cpu/o3/iew.hh" - -using namespace std; - -template<class Impl> -DefaultIEW<Impl>::LdWritebackEvent::LdWritebackEvent(DynInstPtr &_inst, - DefaultIEW<Impl> *_iew) - : Event(&mainEventQueue), inst(_inst), iewStage(_iew) -{ - this->setFlags(Event::AutoDelete); -} - -template<class Impl> -void -DefaultIEW<Impl>::LdWritebackEvent::process() -{ - DPRINTF(IEW, "Load writeback event [sn:%lli]\n", inst->seqNum); - DPRINTF(Activity, "Activity: Ld Writeback event [sn:%lli]\n", inst->seqNum); - - //iewStage->ldstQueue.removeMSHR(inst->threadNumber,inst->seqNum); - - if (iewStage->isSwitchedOut()) { - inst = NULL; - return; - } else if (inst->isSquashed()) { - iewStage->wakeCPU(); - inst = NULL; - return; - } - - iewStage->wakeCPU(); - - if (!inst->isExecuted()) { - inst->setExecuted(); - - // Complete access to copy data to proper place. - if (inst->isStore()) { - inst->completeAcc(); - } - } - - // Need to insert instruction into queue to commit - iewStage->instToCommit(inst); - - iewStage->activityThisCycle(); - - inst = NULL; -} - -template<class Impl> -const char * -DefaultIEW<Impl>::LdWritebackEvent::description() -{ - return "Load writeback event"; -} - -template<class Impl> -DefaultIEW<Impl>::DefaultIEW(Params *params) - : // @todo: Make this into a parameter. - issueToExecQueue(5, 5), - instQueue(params), - ldstQueue(params), - fuPool(params->fuPool), - commitToIEWDelay(params->commitToIEWDelay), - renameToIEWDelay(params->renameToIEWDelay), - issueToExecuteDelay(params->issueToExecuteDelay), - issueReadWidth(params->issueWidth), - issueWidth(params->issueWidth), - executeWidth(params->executeWidth), - numThreads(params->numberOfThreads), - switchedOut(false) -{ - _status = Active; - exeStatus = Running; - wbStatus = Idle; - - // Setup wire to read instructions coming from issue. - fromIssue = issueToExecQueue.getWire(-issueToExecuteDelay); - - // Instruction queue needs the queue between issue and execute. - instQueue.setIssueToExecuteQueue(&issueToExecQueue); - - instQueue.setIEW(this); - ldstQueue.setIEW(this); - - for (int i=0; i < numThreads; i++) { - dispatchStatus[i] = Running; - stalls[i].commit = false; - fetchRedirect[i] = false; - } - - updateLSQNextCycle = false; - - skidBufferMax = (3 * (renameToIEWDelay * params->renameWidth)) + issueWidth; -} - -template <class Impl> -std::string -DefaultIEW<Impl>::name() const -{ - return cpu->name() + ".iew"; -} - -template <class Impl> -void -DefaultIEW<Impl>::regStats() -{ - using namespace Stats; - - instQueue.regStats(); - - iewIdleCycles - .name(name() + ".iewIdleCycles") - .desc("Number of cycles IEW is idle"); - - iewSquashCycles - .name(name() + ".iewSquashCycles") - .desc("Number of cycles IEW is squashing"); - - iewBlockCycles - .name(name() + ".iewBlockCycles") - .desc("Number of cycles IEW is blocking"); - - iewUnblockCycles - .name(name() + ".iewUnblockCycles") - .desc("Number of cycles IEW is unblocking"); - - iewDispatchedInsts - .name(name() + ".iewDispatchedInsts") - .desc("Number of instructions dispatched to IQ"); - - iewDispSquashedInsts - .name(name() + ".iewDispSquashedInsts") - .desc("Number of squashed instructions skipped by dispatch"); - - iewDispLoadInsts - .name(name() + ".iewDispLoadInsts") - .desc("Number of dispatched load instructions"); - - iewDispStoreInsts - .name(name() + ".iewDispStoreInsts") - .desc("Number of dispatched store instructions"); - - iewDispNonSpecInsts - .name(name() + ".iewDispNonSpecInsts") - .desc("Number of dispatched non-speculative instructions"); - - iewIQFullEvents - .name(name() + ".iewIQFullEvents") - .desc("Number of times the IQ has become full, causing a stall"); - - iewLSQFullEvents - .name(name() + ".iewLSQFullEvents") - .desc("Number of times the LSQ has become full, causing a stall"); - - iewExecutedInsts - .name(name() + ".iewExecutedInsts") - .desc("Number of executed instructions"); - - iewExecLoadInsts - .init(cpu->number_of_threads) - .name(name() + ".iewExecLoadInsts") - .desc("Number of load instructions executed") - .flags(total); - - iewExecSquashedInsts - .name(name() + ".iewExecSquashedInsts") - .desc("Number of squashed instructions skipped in execute"); - - memOrderViolationEvents - .name(name() + ".memOrderViolationEvents") - .desc("Number of memory order violations"); - - predictedTakenIncorrect - .name(name() + ".predictedTakenIncorrect") - .desc("Number of branches that were predicted taken incorrectly"); - - predictedNotTakenIncorrect - .name(name() + ".predictedNotTakenIncorrect") - .desc("Number of branches that were predicted not taken incorrectly"); - - branchMispredicts - .name(name() + ".branchMispredicts") - .desc("Number of branch mispredicts detected at execute"); - - branchMispredicts = predictedTakenIncorrect + predictedNotTakenIncorrect; - - exeSwp - .init(cpu->number_of_threads) - .name(name() + ".EXEC:swp") - .desc("number of swp insts executed") - .flags(total) - ; - - exeNop - .init(cpu->number_of_threads) - .name(name() + ".EXEC:nop") - .desc("number of nop insts executed") - .flags(total) - ; - - exeRefs - .init(cpu->number_of_threads) - .name(name() + ".EXEC:refs") - .desc("number of memory reference insts executed") - .flags(total) - ; - - exeBranches - .init(cpu->number_of_threads) - .name(name() + ".EXEC:branches") - .desc("Number of branches executed") - .flags(total) - ; - - issueRate - .name(name() + ".EXEC:rate") - .desc("Inst execution rate") - .flags(total) - ; - issueRate = iewExecutedInsts / cpu->numCycles; - - iewExecStoreInsts - .name(name() + ".EXEC:stores") - .desc("Number of stores executed") - .flags(total) - ; - iewExecStoreInsts = exeRefs - iewExecLoadInsts; -/* - for (int i=0; i<Num_OpClasses; ++i) { - stringstream subname; - subname << opClassStrings[i] << "_delay"; - issue_delay_dist.subname(i, subname.str()); - } -*/ - // - // Other stats - // - - iewInstsToCommit - .init(cpu->number_of_threads) - .name(name() + ".WB:sent") - .desc("cumulative count of insts sent to commit") - .flags(total) - ; - - writebackCount - .init(cpu->number_of_threads) - .name(name() + ".WB:count") - .desc("cumulative count of insts written-back") - .flags(total) - ; - - producerInst - .init(cpu->number_of_threads) - .name(name() + ".WB:producers") - .desc("num instructions producing a value") - .flags(total) - ; - - consumerInst - .init(cpu->number_of_threads) - .name(name() + ".WB:consumers") - .desc("num instructions consuming a value") - .flags(total) - ; - - wbPenalized - .init(cpu->number_of_threads) - .name(name() + ".WB:penalized") - .desc("number of instrctions required to write to 'other' IQ") - .flags(total) - ; - - wbPenalizedRate - .name(name() + ".WB:penalized_rate") - .desc ("fraction of instructions written-back that wrote to 'other' IQ") - .flags(total) - ; - - wbPenalizedRate = wbPenalized / writebackCount; - - wbFanout - .name(name() + ".WB:fanout") - .desc("average fanout of values written-back") - .flags(total) - ; - - wbFanout = producerInst / consumerInst; - - wbRate - .name(name() + ".WB:rate") - .desc("insts written-back per cycle") - .flags(total) - ; - wbRate = writebackCount / cpu->numCycles; -} - -template<class Impl> -void -DefaultIEW<Impl>::initStage() -{ - for (int tid=0; tid < numThreads; tid++) { - toRename->iewInfo[tid].usedIQ = true; - toRename->iewInfo[tid].freeIQEntries = - instQueue.numFreeEntries(tid); - - toRename->iewInfo[tid].usedLSQ = true; - toRename->iewInfo[tid].freeLSQEntries = - ldstQueue.numFreeEntries(tid); - } -} - -template<class Impl> -void -DefaultIEW<Impl>::setCPU(FullCPU *cpu_ptr) -{ - DPRINTF(IEW, "Setting CPU pointer.\n"); - cpu = cpu_ptr; - - instQueue.setCPU(cpu_ptr); - ldstQueue.setCPU(cpu_ptr); - - cpu->activateStage(FullCPU::IEWIdx); -} - -template<class Impl> -void -DefaultIEW<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) -{ - DPRINTF(IEW, "Setting time buffer pointer.\n"); - timeBuffer = tb_ptr; - - // Setup wire to read information from time buffer, from commit. - fromCommit = timeBuffer->getWire(-commitToIEWDelay); - - // Setup wire to write information back to previous stages. - toRename = timeBuffer->getWire(0); - - toFetch = timeBuffer->getWire(0); - - // Instruction queue also needs main time buffer. - instQueue.setTimeBuffer(tb_ptr); -} - -template<class Impl> -void -DefaultIEW<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr) -{ - DPRINTF(IEW, "Setting rename queue pointer.\n"); - renameQueue = rq_ptr; - - // Setup wire to read information from rename queue. - fromRename = renameQueue->getWire(-renameToIEWDelay); -} - -template<class Impl> -void -DefaultIEW<Impl>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr) -{ - DPRINTF(IEW, "Setting IEW queue pointer.\n"); - iewQueue = iq_ptr; - - // Setup wire to write instructions to commit. - toCommit = iewQueue->getWire(0); -} - -template<class Impl> -void -DefaultIEW<Impl>::setActiveThreads(list<unsigned> *at_ptr) -{ - DPRINTF(IEW, "Setting active threads list pointer.\n"); - activeThreads = at_ptr; - - ldstQueue.setActiveThreads(at_ptr); - instQueue.setActiveThreads(at_ptr); -} - -template<class Impl> -void -DefaultIEW<Impl>::setScoreboard(Scoreboard *sb_ptr) -{ - DPRINTF(IEW, "Setting scoreboard pointer.\n"); - scoreboard = sb_ptr; -} - -#if 0 -template<class Impl> -void -DefaultIEW<Impl>::setPageTable(PageTable *pt_ptr) -{ - ldstQueue.setPageTable(pt_ptr); -} -#endif - -template <class Impl> -void -DefaultIEW<Impl>::switchOut() -{ - cpu->signalSwitched(); -} - -template <class Impl> -void -DefaultIEW<Impl>::doSwitchOut() -{ - switchedOut = true; - - instQueue.switchOut(); - ldstQueue.switchOut(); - fuPool->switchOut(); - - for (int i = 0; i < numThreads; i++) { - while (!insts[i].empty()) - insts[i].pop(); - while (!skidBuffer[i].empty()) - skidBuffer[i].pop(); - } -} - -template <class Impl> -void -DefaultIEW<Impl>::takeOverFrom() -{ - _status = Active; - exeStatus = Running; - wbStatus = Idle; - switchedOut = false; - - instQueue.takeOverFrom(); - ldstQueue.takeOverFrom(); - fuPool->takeOverFrom(); - - initStage(); - cpu->activityThisCycle(); - - for (int i=0; i < numThreads; i++) { - dispatchStatus[i] = Running; - stalls[i].commit = false; - fetchRedirect[i] = false; - } - - updateLSQNextCycle = false; - - // @todo: Fix hardcoded number - for (int i = 0; i < 6; ++i) { - issueToExecQueue.advance(); - } -} - -template<class Impl> -void -DefaultIEW<Impl>::squash(unsigned tid) -{ - DPRINTF(IEW, "[tid:%i]: Squashing all instructions.\n", - tid); - - // Tell the IQ to start squashing. - instQueue.squash(tid); - - // Tell the LDSTQ to start squashing. - ldstQueue.squash(fromCommit->commitInfo[tid].doneSeqNum, tid); - - updatedQueues = true; - - // Clear the skid buffer in case it has any data in it. - while (!skidBuffer[tid].empty()) { - - if (skidBuffer[tid].front()->isLoad() || - skidBuffer[tid].front()->isStore() ) { - toRename->iewInfo[tid].dispatchedToLSQ++; - } - - toRename->iewInfo[tid].dispatched++; - - skidBuffer[tid].pop(); - } - - while (!insts[tid].empty()) { - if (insts[tid].front()->isLoad() || - insts[tid].front()->isStore() ) { - toRename->iewInfo[tid].dispatchedToLSQ++; - } - - toRename->iewInfo[tid].dispatched++; - - insts[tid].pop(); - } -} - -template<class Impl> -void -DefaultIEW<Impl>::squashDueToBranch(DynInstPtr &inst, unsigned tid) -{ - DPRINTF(IEW, "[tid:%i]: Squashing from a specific instruction, PC: %#x " - "[sn:%i].\n", tid, inst->readPC(), inst->seqNum); - - toCommit->squash[tid] = true; - toCommit->squashedSeqNum[tid] = inst->seqNum; - toCommit->mispredPC[tid] = inst->readPC(); - toCommit->nextPC[tid] = inst->readNextPC(); - toCommit->branchMispredict[tid] = true; - toCommit->branchTaken[tid] = inst->readNextPC() != - (inst->readPC() + sizeof(TheISA::MachInst)); - - toCommit->includeSquashInst[tid] = false; - - wroteToTimeBuffer = true; -} - -template<class Impl> -void -DefaultIEW<Impl>::squashDueToMemOrder(DynInstPtr &inst, unsigned tid) -{ - DPRINTF(IEW, "[tid:%i]: Squashing from a specific instruction, " - "PC: %#x [sn:%i].\n", tid, inst->readPC(), inst->seqNum); - - toCommit->squash[tid] = true; - toCommit->squashedSeqNum[tid] = inst->seqNum; - toCommit->nextPC[tid] = inst->readNextPC(); - - toCommit->includeSquashInst[tid] = false; - - wroteToTimeBuffer = true; -} - -template<class Impl> -void -DefaultIEW<Impl>::squashDueToMemBlocked(DynInstPtr &inst, unsigned tid) -{ - DPRINTF(IEW, "[tid:%i]: Memory blocked, squashing load and younger insts, " - "PC: %#x [sn:%i].\n", tid, inst->readPC(), inst->seqNum); - - toCommit->squash[tid] = true; - toCommit->squashedSeqNum[tid] = inst->seqNum; - toCommit->nextPC[tid] = inst->readPC(); - - toCommit->includeSquashInst[tid] = true; - - ldstQueue.setLoadBlockedHandled(tid); - - wroteToTimeBuffer = true; -} - -template<class Impl> -void -DefaultIEW<Impl>::block(unsigned tid) -{ - DPRINTF(IEW, "[tid:%u]: Blocking.\n", tid); - - if (dispatchStatus[tid] != Blocked && - dispatchStatus[tid] != Unblocking) { - toRename->iewBlock[tid] = true; - wroteToTimeBuffer = true; - } - - // Add the current inputs to the skid buffer so they can be - // reprocessed when this stage unblocks. - skidInsert(tid); - - dispatchStatus[tid] = Blocked; -} - -template<class Impl> -void -DefaultIEW<Impl>::unblock(unsigned tid) -{ - DPRINTF(IEW, "[tid:%i]: Reading instructions out of the skid " - "buffer %u.\n",tid, tid); - - // If the skid bufffer is empty, signal back to previous stages to unblock. - // Also switch status to running. - if (skidBuffer[tid].empty()) { - toRename->iewUnblock[tid] = true; - wroteToTimeBuffer = true; - DPRINTF(IEW, "[tid:%i]: Done unblocking.\n",tid); - dispatchStatus[tid] = Running; - } -} - -template<class Impl> -void -DefaultIEW<Impl>::wakeDependents(DynInstPtr &inst) -{ - instQueue.wakeDependents(inst); -} - -template<class Impl> -void -DefaultIEW<Impl>::rescheduleMemInst(DynInstPtr &inst) -{ - instQueue.rescheduleMemInst(inst); -} - -template<class Impl> -void -DefaultIEW<Impl>::replayMemInst(DynInstPtr &inst) -{ - instQueue.replayMemInst(inst); -} - -template<class Impl> -void -DefaultIEW<Impl>::instToCommit(DynInstPtr &inst) -{ - // First check the time slot that this instruction will write - // to. If there are free write ports at the time, then go ahead - // and write the instruction to that time. If there are not, - // keep looking back to see where's the first time there's a - // free slot. - while ((*iewQueue)[wbCycle].insts[wbNumInst]) { - ++wbNumInst; - if (wbNumInst == issueWidth) { - ++wbCycle; - wbNumInst = 0; - } - - assert(wbCycle < 5); - } - - // Add finished instruction to queue to commit. - (*iewQueue)[wbCycle].insts[wbNumInst] = inst; - (*iewQueue)[wbCycle].size++; -} - -template <class Impl> -unsigned -DefaultIEW<Impl>::validInstsFromRename() -{ - unsigned inst_count = 0; - - for (int i=0; i<fromRename->size; i++) { - if (!fromRename->insts[i]->squashed) - inst_count++; - } - - return inst_count; -} - -template<class Impl> -void -DefaultIEW<Impl>::skidInsert(unsigned tid) -{ - DynInstPtr inst = NULL; - - while (!insts[tid].empty()) { - inst = insts[tid].front(); - - insts[tid].pop(); - - DPRINTF(Decode,"[tid:%i]: Inserting [sn:%lli] PC:%#x into " - "dispatch skidBuffer %i\n",tid, inst->seqNum, - inst->readPC(),tid); - - skidBuffer[tid].push(inst); - } - - assert(skidBuffer[tid].size() <= skidBufferMax && - "Skidbuffer Exceeded Max Size"); -} - -template<class Impl> -int -DefaultIEW<Impl>::skidCount() -{ - int max=0; - - list<unsigned>::iterator threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned thread_count = skidBuffer[*threads++].size(); - if (max < thread_count) - max = thread_count; - } - - return max; -} - -template<class Impl> -bool -DefaultIEW<Impl>::skidsEmpty() -{ - list<unsigned>::iterator threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - if (!skidBuffer[*threads++].empty()) - return false; - } - - return true; -} - -template <class Impl> -void -DefaultIEW<Impl>::updateStatus() -{ - bool any_unblocking = false; - - list<unsigned>::iterator threads = (*activeThreads).begin(); - - threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - if (dispatchStatus[tid] == Unblocking) { - any_unblocking = true; - break; - } - } - - // If there are no ready instructions waiting to be scheduled by the IQ, - // and there's no stores waiting to write back, and dispatch is not - // unblocking, then there is no internal activity for the IEW stage. - if (_status == Active && !instQueue.hasReadyInsts() && - !ldstQueue.willWB() && !any_unblocking) { - DPRINTF(IEW, "IEW switching to idle\n"); - - deactivateStage(); - - _status = Inactive; - } else if (_status == Inactive && (instQueue.hasReadyInsts() || - ldstQueue.willWB() || - any_unblocking)) { - // Otherwise there is internal activity. Set to active. - DPRINTF(IEW, "IEW switching to active\n"); - - activateStage(); - - _status = Active; - } -} - -template <class Impl> -void -DefaultIEW<Impl>::resetEntries() -{ - instQueue.resetEntries(); - ldstQueue.resetEntries(); -} - -template <class Impl> -void -DefaultIEW<Impl>::readStallSignals(unsigned tid) -{ - if (fromCommit->commitBlock[tid]) { - stalls[tid].commit = true; - } - - if (fromCommit->commitUnblock[tid]) { - assert(stalls[tid].commit); - stalls[tid].commit = false; - } -} - -template <class Impl> -bool -DefaultIEW<Impl>::checkStall(unsigned tid) -{ - bool ret_val(false); - - if (stalls[tid].commit) { - DPRINTF(IEW,"[tid:%i]: Stall from Commit stage detected.\n",tid); - ret_val = true; - } else if (instQueue.isFull(tid)) { - DPRINTF(IEW,"[tid:%i]: Stall: IQ is full.\n",tid); - ret_val = true; - } else if (ldstQueue.isFull(tid)) { - DPRINTF(IEW,"[tid:%i]: Stall: LSQ is full\n",tid); - - if (ldstQueue.numLoads(tid) > 0 ) { - - DPRINTF(IEW,"[tid:%i]: LSQ oldest load: [sn:%i] \n", - tid,ldstQueue.getLoadHeadSeqNum(tid)); - } - - if (ldstQueue.numStores(tid) > 0) { - - DPRINTF(IEW,"[tid:%i]: LSQ oldest store: [sn:%i] \n", - tid,ldstQueue.getStoreHeadSeqNum(tid)); - } - - ret_val = true; - } else if (ldstQueue.isStalled(tid)) { - DPRINTF(IEW,"[tid:%i]: Stall: LSQ stall detected.\n",tid); - ret_val = true; - } - - return ret_val; -} - -template <class Impl> -void -DefaultIEW<Impl>::checkSignalsAndUpdate(unsigned tid) -{ - // Check if there's a squash signal, squash if there is - // Check stall signals, block if there is. - // If status was Blocked - // if so then go to unblocking - // If status was Squashing - // check if squashing is not high. Switch to running this cycle. - - readStallSignals(tid); - - if (fromCommit->commitInfo[tid].squash) { - squash(tid); - - if (dispatchStatus[tid] == Blocked || - dispatchStatus[tid] == Unblocking) { - toRename->iewUnblock[tid] = true; - wroteToTimeBuffer = true; - } - - dispatchStatus[tid] = Squashing; - - fetchRedirect[tid] = false; - return; - } - - if (fromCommit->commitInfo[tid].robSquashing) { - DPRINTF(IEW, "[tid:%i]: ROB is still squashing.\n"); - - dispatchStatus[tid] = Squashing; - - return; - } - - if (checkStall(tid)) { - block(tid); - dispatchStatus[tid] = Blocked; - return; - } - - if (dispatchStatus[tid] == Blocked) { - // Status from previous cycle was blocked, but there are no more stall - // conditions. Switch over to unblocking. - DPRINTF(IEW, "[tid:%i]: Done blocking, switching to unblocking.\n", - tid); - - dispatchStatus[tid] = Unblocking; - - unblock(tid); - - return; - } - - if (dispatchStatus[tid] == Squashing) { - // Switch status to running if rename isn't being told to block or - // squash this cycle. - DPRINTF(IEW, "[tid:%i]: Done squashing, switching to running.\n", - tid); - - dispatchStatus[tid] = Running; - - return; - } -} - -template <class Impl> -void -DefaultIEW<Impl>::sortInsts() -{ - int insts_from_rename = fromRename->size; -#ifdef DEBUG - for (int i = 0; i < numThreads; i++) - assert(insts[i].empty()); -#endif - for (int i = 0; i < insts_from_rename; ++i) { - insts[fromRename->insts[i]->threadNumber].push(fromRename->insts[i]); - } -} - -template <class Impl> -void -DefaultIEW<Impl>::wakeCPU() -{ - cpu->wakeCPU(); -} - -template <class Impl> -void -DefaultIEW<Impl>::activityThisCycle() -{ - DPRINTF(Activity, "Activity this cycle.\n"); - cpu->activityThisCycle(); -} - -template <class Impl> -inline void -DefaultIEW<Impl>::activateStage() -{ - DPRINTF(Activity, "Activating stage.\n"); - cpu->activateStage(FullCPU::IEWIdx); -} - -template <class Impl> -inline void -DefaultIEW<Impl>::deactivateStage() -{ - DPRINTF(Activity, "Deactivating stage.\n"); - cpu->deactivateStage(FullCPU::IEWIdx); -} - -template<class Impl> -void -DefaultIEW<Impl>::dispatch(unsigned tid) -{ - // If status is Running or idle, - // call dispatchInsts() - // If status is Unblocking, - // buffer any instructions coming from rename - // continue trying to empty skid buffer - // check if stall conditions have passed - - if (dispatchStatus[tid] == Blocked) { - ++iewBlockCycles; - - } else if (dispatchStatus[tid] == Squashing) { - ++iewSquashCycles; - } - - // Dispatch should try to dispatch as many instructions as its bandwidth - // will allow, as long as it is not currently blocked. - if (dispatchStatus[tid] == Running || - dispatchStatus[tid] == Idle) { - DPRINTF(IEW, "[tid:%i] Not blocked, so attempting to run " - "dispatch.\n", tid); - - dispatchInsts(tid); - } else if (dispatchStatus[tid] == Unblocking) { - // Make sure that the skid buffer has something in it if the - // status is unblocking. - assert(!skidsEmpty()); - - // If the status was unblocking, then instructions from the skid - // buffer were used. Remove those instructions and handle - // the rest of unblocking. - dispatchInsts(tid); - - ++iewUnblockCycles; - - if (validInstsFromRename() && dispatchedAllInsts) { - // Add the current inputs to the skid buffer so they can be - // reprocessed when this stage unblocks. - skidInsert(tid); - } - - unblock(tid); - } -} - -template <class Impl> -void -DefaultIEW<Impl>::dispatchInsts(unsigned tid) -{ - dispatchedAllInsts = true; - - // Obtain instructions from skid buffer if unblocking, or queue from rename - // otherwise. - std::queue<DynInstPtr> &insts_to_dispatch = - dispatchStatus[tid] == Unblocking ? - skidBuffer[tid] : insts[tid]; - - int insts_to_add = insts_to_dispatch.size(); - - DynInstPtr inst; - bool add_to_iq = false; - int dis_num_inst = 0; - - // Loop through the instructions, putting them in the instruction - // queue. - for ( ; dis_num_inst < insts_to_add && - dis_num_inst < issueReadWidth; - ++dis_num_inst) - { - inst = insts_to_dispatch.front(); - - if (dispatchStatus[tid] == Unblocking) { - DPRINTF(IEW, "[tid:%i]: Issue: Examining instruction from skid " - "buffer\n", tid); - } - - // Make sure there's a valid instruction there. - assert(inst); - - DPRINTF(IEW, "[tid:%i]: Issue: Adding PC %#x [sn:%lli] [tid:%i] to " - "IQ.\n", - tid, inst->readPC(), inst->seqNum, inst->threadNumber); - - // Be sure to mark these instructions as ready so that the - // commit stage can go ahead and execute them, and mark - // them as issued so the IQ doesn't reprocess them. - - // Check for squashed instructions. - if (inst->isSquashed()) { - DPRINTF(IEW, "[tid:%i]: Issue: Squashed instruction encountered, " - "not adding to IQ.\n", tid); - - ++iewDispSquashedInsts; - - insts_to_dispatch.pop(); - - //Tell Rename That An Instruction has been processed - if (inst->isLoad() || inst->isStore()) { - toRename->iewInfo[tid].dispatchedToLSQ++; - } - toRename->iewInfo[tid].dispatched++; - - continue; - } - - // Check for full conditions. - if (instQueue.isFull(tid)) { - DPRINTF(IEW, "[tid:%i]: Issue: IQ has become full.\n", tid); - - // Call function to start blocking. - block(tid); - - // Set unblock to false. Special case where we are using - // skidbuffer (unblocking) instructions but then we still - // get full in the IQ. - toRename->iewUnblock[tid] = false; - - dispatchedAllInsts = false; - - ++iewIQFullEvents; - break; - } else if (ldstQueue.isFull(tid)) { - DPRINTF(IEW, "[tid:%i]: Issue: LSQ has become full.\n",tid); - - // Call function to start blocking. - block(tid); - - // Set unblock to false. Special case where we are using - // skidbuffer (unblocking) instructions but then we still - // get full in the IQ. - toRename->iewUnblock[tid] = false; - - dispatchedAllInsts = false; - - ++iewLSQFullEvents; - break; - } - - // Otherwise issue the instruction just fine. - if (inst->isLoad()) { - DPRINTF(IEW, "[tid:%i]: Issue: Memory instruction " - "encountered, adding to LSQ.\n", tid); - - // Reserve a spot in the load store queue for this - // memory access. - ldstQueue.insertLoad(inst); - - ++iewDispLoadInsts; - - add_to_iq = true; - - toRename->iewInfo[tid].dispatchedToLSQ++; - } else if (inst->isStore()) { - DPRINTF(IEW, "[tid:%i]: Issue: Memory instruction " - "encountered, adding to LSQ.\n", tid); - - ldstQueue.insertStore(inst); - - ++iewDispStoreInsts; - - if (inst->isStoreConditional()) { - // Store conditionals need to be set as "canCommit()" - // so that commit can process them when they reach the - // head of commit. - inst->setCanCommit(); - instQueue.insertNonSpec(inst); - add_to_iq = false; - - ++iewDispNonSpecInsts; - } else { - add_to_iq = true; - } - - toRename->iewInfo[tid].dispatchedToLSQ++; -#if FULL_SYSTEM - } else if (inst->isMemBarrier() || inst->isWriteBarrier()) { - // Same as non-speculative stores. - inst->setCanCommit(); - instQueue.insertBarrier(inst); - add_to_iq = false; -#endif - } else if (inst->isNonSpeculative()) { - DPRINTF(IEW, "[tid:%i]: Issue: Nonspeculative instruction " - "encountered, skipping.\n", tid); - - // Same as non-speculative stores. - inst->setCanCommit(); - - // Specifically insert it as nonspeculative. - instQueue.insertNonSpec(inst); - - ++iewDispNonSpecInsts; - - add_to_iq = false; - } else if (inst->isNop()) { - DPRINTF(IEW, "[tid:%i]: Issue: Nop instruction encountered, " - "skipping.\n", tid); - - inst->setIssued(); - inst->setExecuted(); - inst->setCanCommit(); - - instQueue.recordProducer(inst); - - exeNop[tid]++; - - add_to_iq = false; - } else if (inst->isExecuted()) { - assert(0 && "Instruction shouldn't be executed.\n"); - DPRINTF(IEW, "Issue: Executed branch encountered, " - "skipping.\n"); - - inst->setIssued(); - inst->setCanCommit(); - - instQueue.recordProducer(inst); - - add_to_iq = false; - } else { - add_to_iq = true; - } - - // If the instruction queue is not full, then add the - // instruction. - if (add_to_iq) { - instQueue.insert(inst); - } - - insts_to_dispatch.pop(); - - toRename->iewInfo[tid].dispatched++; - - ++iewDispatchedInsts; - } - - if (!insts_to_dispatch.empty()) { - DPRINTF(IEW,"[tid:%i]: Issue: Bandwidth Full. Blocking.\n"); - block(tid); - toRename->iewUnblock[tid] = false; - } - - if (dispatchStatus[tid] == Idle && dis_num_inst) { - dispatchStatus[tid] = Running; - - updatedQueues = true; - } - - dis_num_inst = 0; -} - -template <class Impl> -void -DefaultIEW<Impl>::printAvailableInsts() -{ - int inst = 0; - - cout << "Available Instructions: "; - - while (fromIssue->insts[inst]) { - - if (inst%3==0) cout << "\n\t"; - - cout << "PC: " << fromIssue->insts[inst]->readPC() - << " TN: " << fromIssue->insts[inst]->threadNumber - << " SN: " << fromIssue->insts[inst]->seqNum << " | "; - - inst++; - - } - - cout << "\n"; -} - -template <class Impl> -void -DefaultIEW<Impl>::executeInsts() -{ - wbNumInst = 0; - wbCycle = 0; - - list<unsigned>::iterator threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - fetchRedirect[tid] = false; - } - -#if 0 - printAvailableInsts(); -#endif - - // Execute/writeback any instructions that are available. - int insts_to_execute = fromIssue->size; - int inst_num = 0; - for (; inst_num < insts_to_execute; - ++inst_num) { - - DPRINTF(IEW, "Execute: Executing instructions from IQ.\n"); - - DynInstPtr inst = instQueue.getInstToExecute(); - - DPRINTF(IEW, "Execute: Processing PC %#x, [tid:%i] [sn:%i].\n", - inst->readPC(), inst->threadNumber,inst->seqNum); - - // Check if the instruction is squashed; if so then skip it - if (inst->isSquashed()) { - DPRINTF(IEW, "Execute: Instruction was squashed.\n"); - - // Consider this instruction executed so that commit can go - // ahead and retire the instruction. - inst->setExecuted(); - - // Not sure if I should set this here or just let commit try to - // commit any squashed instructions. I like the latter a bit more. - inst->setCanCommit(); - - ++iewExecSquashedInsts; - - continue; - } - - Fault fault = NoFault; - - // Execute instruction. - // Note that if the instruction faults, it will be handled - // at the commit stage. - if (inst->isMemRef() && - (!inst->isDataPrefetch() && !inst->isInstPrefetch())) { - DPRINTF(IEW, "Execute: Calculating address for memory " - "reference.\n"); - - // Tell the LDSTQ to execute this instruction (if it is a load). - if (inst->isLoad()) { - // Loads will mark themselves as executed, and their writeback - // event adds the instruction to the queue to commit - fault = ldstQueue.executeLoad(inst); - } else if (inst->isStore()) { - ldstQueue.executeStore(inst); - - // If the store had a fault then it may not have a mem req - if (inst->req && !(inst->req->flags & LOCKED)) { - inst->setExecuted(); - - instToCommit(inst); - } - - // Store conditionals will mark themselves as - // executed, and their writeback event will add the - // instruction to the queue to commit. - } else { - panic("Unexpected memory type!\n"); - } - - } else { - inst->execute(); - - inst->setExecuted(); - - instToCommit(inst); - } - - updateExeInstStats(inst); - - // Check if branch prediction was correct, if not then we need - // to tell commit to squash in flight instructions. Only - // handle this if there hasn't already been something that - // redirects fetch in this group of instructions. - - // This probably needs to prioritize the redirects if a different - // scheduler is used. Currently the scheduler schedules the oldest - // instruction first, so the branch resolution order will be correct. - unsigned tid = inst->threadNumber; - - if (!fetchRedirect[tid]) { - - if (inst->mispredicted()) { - fetchRedirect[tid] = true; - - DPRINTF(IEW, "Execute: Branch mispredict detected.\n"); - DPRINTF(IEW, "Execute: Redirecting fetch to PC: %#x.\n", - inst->nextPC); - - // If incorrect, then signal the ROB that it must be squashed. - squashDueToBranch(inst, tid); - - if (inst->predTaken()) { - predictedTakenIncorrect++; - } else { - predictedNotTakenIncorrect++; - } - } else if (ldstQueue.violation(tid)) { - fetchRedirect[tid] = true; - - // If there was an ordering violation, then get the - // DynInst that caused the violation. Note that this - // clears the violation signal. - DynInstPtr violator; - violator = ldstQueue.getMemDepViolator(tid); - - DPRINTF(IEW, "LDSTQ detected a violation. Violator PC: " - "%#x, inst PC: %#x. Addr is: %#x.\n", - violator->readPC(), inst->readPC(), inst->physEffAddr); - - // Tell the instruction queue that a violation has occured. - instQueue.violation(inst, violator); - - // Squash. - squashDueToMemOrder(inst,tid); - - ++memOrderViolationEvents; - } else if (ldstQueue.loadBlocked(tid) && - !ldstQueue.isLoadBlockedHandled(tid)) { - fetchRedirect[tid] = true; - - DPRINTF(IEW, "Load operation couldn't execute because the " - "memory system is blocked. PC: %#x [sn:%lli]\n", - inst->readPC(), inst->seqNum); - - squashDueToMemBlocked(inst, tid); - } - } - } - - if (inst_num) { - if (exeStatus == Idle) { - exeStatus = Running; - } - - updatedQueues = true; - - cpu->activityThisCycle(); - } - - // Need to reset this in case a writeback event needs to write into the - // iew queue. That way the writeback event will write into the correct - // spot in the queue. - wbNumInst = 0; -} - -template <class Impl> -void -DefaultIEW<Impl>::writebackInsts() -{ - // Loop through the head of the time buffer and wake any - // dependents. These instructions are about to write back. Also - // mark scoreboard that this instruction is finally complete. - // Either have IEW have direct access to scoreboard, or have this - // as part of backwards communication. - for (int inst_num = 0; inst_num < issueWidth && - toCommit->insts[inst_num]; inst_num++) { - DynInstPtr inst = toCommit->insts[inst_num]; - int tid = inst->threadNumber; - - DPRINTF(IEW, "Sending instructions to commit, PC %#x.\n", - inst->readPC()); - - iewInstsToCommit[tid]++; - - // Some instructions will be sent to commit without having - // executed because they need commit to handle them. - // E.g. Uncached loads have not actually executed when they - // are first sent to commit. Instead commit must tell the LSQ - // when it's ready to execute the uncached load. - if (!inst->isSquashed() && inst->isExecuted()) { - int dependents = instQueue.wakeDependents(inst); - - for (int i = 0; i < inst->numDestRegs(); i++) { - //mark as Ready - DPRINTF(IEW,"Setting Destination Register %i\n", - inst->renamedDestRegIdx(i)); - scoreboard->setReg(inst->renamedDestRegIdx(i)); - } - - producerInst[tid]++; - consumerInst[tid]+= dependents; - writebackCount[tid]++; - } - } -} - -template<class Impl> -void -DefaultIEW<Impl>::tick() -{ - wbNumInst = 0; - wbCycle = 0; - - wroteToTimeBuffer = false; - updatedQueues = false; - - sortInsts(); - - // Free function units marked as being freed this cycle. - fuPool->processFreeUnits(); - - list<unsigned>::iterator threads = (*activeThreads).begin(); - - // Check stall and squash signals, dispatch any instructions. - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - DPRINTF(IEW,"Issue: Processing [tid:%i]\n",tid); - - checkSignalsAndUpdate(tid); - dispatch(tid); - } - - if (exeStatus != Squashing) { - executeInsts(); - - writebackInsts(); - - // Have the instruction queue try to schedule any ready instructions. - // (In actuality, this scheduling is for instructions that will - // be executed next cycle.) - instQueue.scheduleReadyInsts(); - - // Also should advance its own time buffers if the stage ran. - // Not the best place for it, but this works (hopefully). - issueToExecQueue.advance(); - } - - bool broadcast_free_entries = false; - - if (updatedQueues || exeStatus == Running || updateLSQNextCycle) { - exeStatus = Idle; - updateLSQNextCycle = false; - - broadcast_free_entries = true; - } - - // Writeback any stores using any leftover bandwidth. - ldstQueue.writebackStores(); - - // Check the committed load/store signals to see if there's a load - // or store to commit. Also check if it's being told to execute a - // nonspeculative instruction. - // This is pretty inefficient... - - threads = (*activeThreads).begin(); - while (threads != (*activeThreads).end()) { - unsigned tid = (*threads++); - - DPRINTF(IEW,"Processing [tid:%i]\n",tid); - - if (fromCommit->commitInfo[tid].doneSeqNum != 0 && - !fromCommit->commitInfo[tid].squash && - !fromCommit->commitInfo[tid].robSquashing) { - - ldstQueue.commitStores(fromCommit->commitInfo[tid].doneSeqNum,tid); - - ldstQueue.commitLoads(fromCommit->commitInfo[tid].doneSeqNum,tid); - - updateLSQNextCycle = true; - instQueue.commit(fromCommit->commitInfo[tid].doneSeqNum,tid); - } - - if (fromCommit->commitInfo[tid].nonSpecSeqNum != 0) { - - //DPRINTF(IEW,"NonspecInst from thread %i",tid); - if (fromCommit->commitInfo[tid].uncached) { - instQueue.replayMemInst(fromCommit->commitInfo[tid].uncachedLoad); - } else { - instQueue.scheduleNonSpec( - fromCommit->commitInfo[tid].nonSpecSeqNum); - } - } - - if (broadcast_free_entries) { - toFetch->iewInfo[tid].iqCount = - instQueue.getCount(tid); - toFetch->iewInfo[tid].ldstqCount = - ldstQueue.getCount(tid); - - toRename->iewInfo[tid].usedIQ = true; - toRename->iewInfo[tid].freeIQEntries = - instQueue.numFreeEntries(); - toRename->iewInfo[tid].usedLSQ = true; - toRename->iewInfo[tid].freeLSQEntries = - ldstQueue.numFreeEntries(tid); - - wroteToTimeBuffer = true; - } - - DPRINTF(IEW, "[tid:%i], Dispatch dispatched %i instructions.\n", - tid, toRename->iewInfo[tid].dispatched); - } - - DPRINTF(IEW, "IQ has %i free entries (Can schedule: %i). " - "LSQ has %i free entries.\n", - instQueue.numFreeEntries(), instQueue.hasReadyInsts(), - ldstQueue.numFreeEntries()); - - updateStatus(); - - if (wroteToTimeBuffer) { - DPRINTF(Activity, "Activity this cycle.\n"); - cpu->activityThisCycle(); - } -} - -template <class Impl> -void -DefaultIEW<Impl>::updateExeInstStats(DynInstPtr &inst) -{ - int thread_number = inst->threadNumber; - - // - // Pick off the software prefetches - // -#ifdef TARGET_ALPHA - if (inst->isDataPrefetch()) - exeSwp[thread_number]++; - else - iewExecutedInsts++; -#else - iewExecutedInsts[thread_number]++; -#endif - - // - // Control operations - // - if (inst->isControl()) - exeBranches[thread_number]++; - - // - // Memory operations - // - if (inst->isMemRef()) { - exeRefs[thread_number]++; - - if (inst->isLoad()) { - iewExecLoadInsts[thread_number]++; - } - } -} diff --git a/cpu/o3/inst_queue.cc b/cpu/o3/inst_queue.cc deleted file mode 100644 index 95ae2b699..000000000 --- a/cpu/o3/inst_queue.cc +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/o3/alpha_dyn_inst.hh" -#include "cpu/o3/alpha_impl.hh" -#include "cpu/o3/inst_queue_impl.hh" - -// Force instantiation of InstructionQueue. -template class InstructionQueue<AlphaSimpleImpl>; diff --git a/cpu/o3/inst_queue.hh b/cpu/o3/inst_queue.hh deleted file mode 100644 index 518de73d9..000000000 --- a/cpu/o3/inst_queue.hh +++ /dev/null @@ -1,479 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_INST_QUEUE_HH__ -#define __CPU_O3_INST_QUEUE_HH__ - -#include <list> -#include <map> -#include <queue> -#include <vector> - -#include "base/statistics.hh" -#include "base/timebuf.hh" -#include "cpu/inst_seq.hh" -#include "cpu/o3/dep_graph.hh" -#include "encumbered/cpu/full/op_class.hh" -#include "sim/host.hh" - -class FUPool; -class MemInterface; - -/** - * A standard instruction queue class. It holds ready instructions, in - * order, in seperate priority queues to facilitate the scheduling of - * instructions. The IQ uses a separate linked list to track dependencies. - * Similar to the rename map and the free list, it expects that - * floating point registers have their indices start after the integer - * registers (ie with 96 int and 96 fp registers, regs 0-95 are integer - * and 96-191 are fp). This remains true even for both logical and - * physical register indices. The IQ depends on the memory dependence unit to - * track when memory operations are ready in terms of ordering; register - * dependencies are tracked normally. Right now the IQ also handles the - * execution timing; this is mainly to allow back-to-back scheduling without - * requiring IEW to be able to peek into the IQ. At the end of the execution - * latency, the instruction is put into the queue to execute, where it will - * have the execute() function called on it. - * @todo: Make IQ able to handle multiple FU pools. - */ -template <class Impl> -class InstructionQueue -{ - public: - //Typedefs from the Impl. - typedef typename Impl::FullCPU FullCPU; - typedef typename Impl::DynInstPtr DynInstPtr; - typedef typename Impl::Params Params; - - typedef typename Impl::CPUPol::IEW IEW; - typedef typename Impl::CPUPol::MemDepUnit MemDepUnit; - typedef typename Impl::CPUPol::IssueStruct IssueStruct; - typedef typename Impl::CPUPol::TimeStruct TimeStruct; - - // Typedef of iterator through the list of instructions. - typedef typename std::list<DynInstPtr>::iterator ListIt; - - friend class Impl::FullCPU; - - /** FU completion event class. */ - class FUCompletion : public Event { - private: - /** Executing instruction. */ - DynInstPtr inst; - - /** Index of the FU used for executing. */ - int fuIdx; - - /** Pointer back to the instruction queue. */ - InstructionQueue<Impl> *iqPtr; - - bool freeFU; - - public: - /** Construct a FU completion event. */ - FUCompletion(DynInstPtr &_inst, int fu_idx, - InstructionQueue<Impl> *iq_ptr); - - virtual void process(); - virtual const char *description(); - void setFreeFU() { freeFU = true; } - }; - - /** Constructs an IQ. */ - InstructionQueue(Params *params); - - /** Destructs the IQ. */ - ~InstructionQueue(); - - /** Returns the name of the IQ. */ - std::string name() const; - - /** Registers statistics. */ - void regStats(); - - void resetState(); - - /** Sets CPU pointer. */ - void setCPU(FullCPU *_cpu) { cpu = _cpu; } - - /** Sets active threads list. */ - void setActiveThreads(std::list<unsigned> *at_ptr); - - /** Sets the IEW pointer. */ - void setIEW(IEW *iew_ptr) { iewStage = iew_ptr; } - - /** Sets the timer buffer between issue and execute. */ - void setIssueToExecuteQueue(TimeBuffer<IssueStruct> *i2eQueue); - - /** Sets the global time buffer. */ - void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr); - - void switchOut(); - - void takeOverFrom(); - - bool isSwitchedOut() { return switchedOut; } - - /** Number of entries needed for given amount of threads. */ - int entryAmount(int num_threads); - - /** Resets max entries for all threads. */ - void resetEntries(); - - /** Returns total number of free entries. */ - unsigned numFreeEntries(); - - /** Returns number of free entries for a thread. */ - unsigned numFreeEntries(unsigned tid); - - /** Returns whether or not the IQ is full. */ - bool isFull(); - - /** Returns whether or not the IQ is full for a specific thread. */ - bool isFull(unsigned tid); - - /** Returns if there are any ready instructions in the IQ. */ - bool hasReadyInsts(); - - /** Inserts a new instruction into the IQ. */ - void insert(DynInstPtr &new_inst); - - /** Inserts a new, non-speculative instruction into the IQ. */ - void insertNonSpec(DynInstPtr &new_inst); - - /** Inserts a memory or write barrier into the IQ to make sure - * loads and stores are ordered properly. - */ - void insertBarrier(DynInstPtr &barr_inst); - - DynInstPtr getInstToExecute(); - - /** - * Records the instruction as the producer of a register without - * adding it to the rest of the IQ. - */ - void recordProducer(DynInstPtr &inst) - { addToProducers(inst); } - - /** Process FU completion event. */ - void processFUCompletion(DynInstPtr &inst, int fu_idx); - - /** - * Schedules ready instructions, adding the ready ones (oldest first) to - * the queue to execute. - */ - void scheduleReadyInsts(); - - /** Schedules a single specific non-speculative instruction. */ - void scheduleNonSpec(const InstSeqNum &inst); - - /** - * Commits all instructions up to and including the given sequence number, - * for a specific thread. - */ - void commit(const InstSeqNum &inst, unsigned tid = 0); - - /** Wakes all dependents of a completed instruction. */ - int wakeDependents(DynInstPtr &completed_inst); - - /** Adds a ready memory instruction to the ready list. */ - void addReadyMemInst(DynInstPtr &ready_inst); - - /** - * Reschedules a memory instruction. It will be ready to issue once - * replayMemInst() is called. - */ - void rescheduleMemInst(DynInstPtr &resched_inst); - - /** Replays a memory instruction. It must be rescheduled first. */ - void replayMemInst(DynInstPtr &replay_inst); - - /** Completes a memory operation. */ - void completeMemInst(DynInstPtr &completed_inst); - - /** Indicates an ordering violation between a store and a load. */ - void violation(DynInstPtr &store, DynInstPtr &faulting_load); - - /** - * Squashes instructions for a thread. Squashing information is obtained - * from the time buffer. - */ - void squash(unsigned tid); - - /** Returns the number of used entries for a thread. */ - unsigned getCount(unsigned tid) { return count[tid]; }; - - /** Debug function to print all instructions. */ - void printInsts(); - - private: - /** Does the actual squashing. */ - void doSquash(unsigned tid); - - ///////////////////////// - // Various pointers - ///////////////////////// - - /** Pointer to the CPU. */ - FullCPU *cpu; - - /** Cache interface. */ - MemInterface *dcacheInterface; - - /** Pointer to IEW stage. */ - IEW *iewStage; - - /** The memory dependence unit, which tracks/predicts memory dependences - * between instructions. - */ - MemDepUnit memDepUnit[Impl::MaxThreads]; - - /** The queue to the execute stage. Issued instructions will be written - * into it. - */ - TimeBuffer<IssueStruct> *issueToExecuteQueue; - - /** The backwards time buffer. */ - TimeBuffer<TimeStruct> *timeBuffer; - - /** Wire to read information from timebuffer. */ - typename TimeBuffer<TimeStruct>::wire fromCommit; - - /** Function unit pool. */ - FUPool *fuPool; - - ////////////////////////////////////// - // Instruction lists, ready queues, and ordering - ////////////////////////////////////// - - /** List of all the instructions in the IQ (some of which may be issued). */ - std::list<DynInstPtr> instList[Impl::MaxThreads]; - - std::list<DynInstPtr> instsToExecute; - - /** - * Struct for comparing entries to be added to the priority queue. This - * gives reverse ordering to the instructions in terms of sequence - * numbers: the instructions with smaller sequence numbers (and hence - * are older) will be at the top of the priority queue. - */ - struct pqCompare { - bool operator() (const DynInstPtr &lhs, const DynInstPtr &rhs) const - { - return lhs->seqNum > rhs->seqNum; - } - }; - - typedef std::priority_queue<DynInstPtr, std::vector<DynInstPtr>, pqCompare> - ReadyInstQueue; - - /** List of ready instructions, per op class. They are separated by op - * class to allow for easy mapping to FUs. - */ - ReadyInstQueue readyInsts[Num_OpClasses]; - - /** List of non-speculative instructions that will be scheduled - * once the IQ gets a signal from commit. While it's redundant to - * have the key be a part of the value (the sequence number is stored - * inside of DynInst), when these instructions are woken up only - * the sequence number will be available. Thus it is most efficient to be - * able to search by the sequence number alone. - */ - std::map<InstSeqNum, DynInstPtr> nonSpecInsts; - - typedef typename std::map<InstSeqNum, DynInstPtr>::iterator NonSpecMapIt; - - /** Entry for the list age ordering by op class. */ - struct ListOrderEntry { - OpClass queueType; - InstSeqNum oldestInst; - }; - - /** List that contains the age order of the oldest instruction of each - * ready queue. Used to select the oldest instruction available - * among op classes. - * @todo: Might be better to just move these entries around instead - * of creating new ones every time the position changes due to an - * instruction issuing. Not sure std::list supports this. - */ - std::list<ListOrderEntry> listOrder; - - typedef typename std::list<ListOrderEntry>::iterator ListOrderIt; - - /** Tracks if each ready queue is on the age order list. */ - bool queueOnList[Num_OpClasses]; - - /** Iterators of each ready queue. Points to their spot in the age order - * list. - */ - ListOrderIt readyIt[Num_OpClasses]; - - /** Add an op class to the age order list. */ - void addToOrderList(OpClass op_class); - - /** - * Called when the oldest instruction has been removed from a ready queue; - * this places that ready queue into the proper spot in the age order list. - */ - void moveToYoungerInst(ListOrderIt age_order_it); - - DependencyGraph<DynInstPtr> dependGraph; - - ////////////////////////////////////// - // Various parameters - ////////////////////////////////////// - - /** IQ Resource Sharing Policy */ - enum IQPolicy { - Dynamic, - Partitioned, - Threshold - }; - - /** IQ sharing policy for SMT. */ - IQPolicy iqPolicy; - - /** Number of Total Threads*/ - unsigned numThreads; - - /** Pointer to list of active threads. */ - std::list<unsigned> *activeThreads; - - /** Per Thread IQ count */ - unsigned count[Impl::MaxThreads]; - - /** Max IQ Entries Per Thread */ - unsigned maxEntries[Impl::MaxThreads]; - - /** Number of free IQ entries left. */ - unsigned freeEntries; - - /** The number of entries in the instruction queue. */ - unsigned numEntries; - - /** The total number of instructions that can be issued in one cycle. */ - unsigned totalWidth; - - /** The number of physical registers in the CPU. */ - unsigned numPhysRegs; - - /** The number of physical integer registers in the CPU. */ - unsigned numPhysIntRegs; - - /** The number of floating point registers in the CPU. */ - unsigned numPhysFloatRegs; - - /** Delay between commit stage and the IQ. - * @todo: Make there be a distinction between the delays within IEW. - */ - unsigned commitToIEWDelay; - - bool switchedOut; - - /** The sequence number of the squashed instruction. */ - InstSeqNum squashedSeqNum[Impl::MaxThreads]; - - /** A cache of the recently woken registers. It is 1 if the register - * has been woken up recently, and 0 if the register has been added - * to the dependency graph and has not yet received its value. It - * is basically a secondary scoreboard, and should pretty much mirror - * the scoreboard that exists in the rename map. - */ - std::vector<bool> regScoreboard; - - /** Adds an instruction to the dependency graph, as a consumer. */ - bool addToDependents(DynInstPtr &new_inst); - - /** Adds an instruction to the dependency graph, as a producer. */ - void addToProducers(DynInstPtr &new_inst); - - /** Moves an instruction to the ready queue if it is ready. */ - void addIfReady(DynInstPtr &inst); - - /** Debugging function to count how many entries are in the IQ. It does - * a linear walk through the instructions, so do not call this function - * during normal execution. - */ - int countInsts(); - - /** Debugging function to dump all the list sizes, as well as print - * out the list of nonspeculative instructions. Should not be used - * in any other capacity, but it has no harmful sideaffects. - */ - void dumpLists(); - - /** Debugging function to dump out all instructions that are in the - * IQ. - */ - void dumpInsts(); - - /** Stat for number of instructions added. */ - Stats::Scalar<> iqInstsAdded; - /** Stat for number of non-speculative instructions added. */ - Stats::Scalar<> iqNonSpecInstsAdded; - - Stats::Scalar<> iqInstsIssued; - /** Stat for number of integer instructions issued. */ - Stats::Scalar<> iqIntInstsIssued; - /** Stat for number of floating point instructions issued. */ - Stats::Scalar<> iqFloatInstsIssued; - /** Stat for number of branch instructions issued. */ - Stats::Scalar<> iqBranchInstsIssued; - /** Stat for number of memory instructions issued. */ - Stats::Scalar<> iqMemInstsIssued; - /** Stat for number of miscellaneous instructions issued. */ - Stats::Scalar<> iqMiscInstsIssued; - /** Stat for number of squashed instructions that were ready to issue. */ - Stats::Scalar<> iqSquashedInstsIssued; - /** Stat for number of squashed instructions examined when squashing. */ - Stats::Scalar<> iqSquashedInstsExamined; - /** Stat for number of squashed instruction operands examined when - * squashing. - */ - Stats::Scalar<> iqSquashedOperandsExamined; - /** Stat for number of non-speculative instructions removed due to a squash. - */ - Stats::Scalar<> iqSquashedNonSpecRemoved; - - Stats::VectorDistribution<> queueResDist; - Stats::Distribution<> numIssuedDist; - Stats::VectorDistribution<> issueDelayDist; - - Stats::Vector<> statFuBusy; -// Stats::Vector<> dist_unissued; - Stats::Vector2d<> statIssuedInstType; - - Stats::Formula issueRate; -// Stats::Formula issue_stores; -// Stats::Formula issue_op_rate; - Stats::Vector<> fuBusy; //cumulative fu busy - - Stats::Formula fuBusyRate; -}; - -#endif //__CPU_O3_INST_QUEUE_HH__ diff --git a/cpu/o3/inst_queue_impl.hh b/cpu/o3/inst_queue_impl.hh deleted file mode 100644 index f1dc4e01f..000000000 --- a/cpu/o3/inst_queue_impl.hh +++ /dev/null @@ -1,1367 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <limits> -#include <vector> - -#include "sim/root.hh" - -#include "cpu/o3/fu_pool.hh" -#include "cpu/o3/inst_queue.hh" - -using namespace std; - -template <class Impl> -InstructionQueue<Impl>::FUCompletion::FUCompletion(DynInstPtr &_inst, - int fu_idx, - InstructionQueue<Impl> *iq_ptr) - : Event(&mainEventQueue, Stat_Event_Pri), - inst(_inst), fuIdx(fu_idx), iqPtr(iq_ptr), freeFU(false) -{ - this->setFlags(Event::AutoDelete); -} - -template <class Impl> -void -InstructionQueue<Impl>::FUCompletion::process() -{ - iqPtr->processFUCompletion(inst, freeFU ? fuIdx : -1); - inst = NULL; -} - - -template <class Impl> -const char * -InstructionQueue<Impl>::FUCompletion::description() -{ - return "Functional unit completion event"; -} - -template <class Impl> -InstructionQueue<Impl>::InstructionQueue(Params *params) - : dcacheInterface(params->dcacheInterface), - fuPool(params->fuPool), - numEntries(params->numIQEntries), - totalWidth(params->issueWidth), - numPhysIntRegs(params->numPhysIntRegs), - numPhysFloatRegs(params->numPhysFloatRegs), - commitToIEWDelay(params->commitToIEWDelay) -{ - assert(fuPool); - - switchedOut = false; - - numThreads = params->numberOfThreads; - - // Set the number of physical registers as the number of int + float - numPhysRegs = numPhysIntRegs + numPhysFloatRegs; - - DPRINTF(IQ, "There are %i physical registers.\n", numPhysRegs); - - //Create an entry for each physical register within the - //dependency graph. - dependGraph.resize(numPhysRegs); - - // Resize the register scoreboard. - regScoreboard.resize(numPhysRegs); - - //Initialize Mem Dependence Units - for (int i = 0; i < numThreads; i++) { - memDepUnit[i].init(params,i); - memDepUnit[i].setIQ(this); - } - - resetState(); - - string policy = params->smtIQPolicy; - - //Convert string to lowercase - std::transform(policy.begin(), policy.end(), policy.begin(), - (int(*)(int)) tolower); - - //Figure out resource sharing policy - if (policy == "dynamic") { - iqPolicy = Dynamic; - - //Set Max Entries to Total ROB Capacity - for (int i = 0; i < numThreads; i++) { - maxEntries[i] = numEntries; - } - - } else if (policy == "partitioned") { - iqPolicy = Partitioned; - - //@todo:make work if part_amt doesnt divide evenly. - int part_amt = numEntries / numThreads; - - //Divide ROB up evenly - for (int i = 0; i < numThreads; i++) { - maxEntries[i] = part_amt; - } - - DPRINTF(Fetch, "IQ sharing policy set to Partitioned:" - "%i entries per thread.\n",part_amt); - - } else if (policy == "threshold") { - iqPolicy = Threshold; - - double threshold = (double)params->smtIQThreshold / 100; - - int thresholdIQ = (int)((double)threshold * numEntries); - - //Divide up by threshold amount - for (int i = 0; i < numThreads; i++) { - maxEntries[i] = thresholdIQ; - } - - DPRINTF(Fetch, "IQ sharing policy set to Threshold:" - "%i entries per thread.\n",thresholdIQ); - } else { - assert(0 && "Invalid IQ Sharing Policy.Options Are:{Dynamic," - "Partitioned, Threshold}"); - } -} - -template <class Impl> -InstructionQueue<Impl>::~InstructionQueue() -{ - dependGraph.reset(); - cprintf("Nodes traversed: %i, removed: %i\n", - dependGraph.nodesTraversed, dependGraph.nodesRemoved); -} - -template <class Impl> -std::string -InstructionQueue<Impl>::name() const -{ - return cpu->name() + ".iq"; -} - -template <class Impl> -void -InstructionQueue<Impl>::regStats() -{ - using namespace Stats; - iqInstsAdded - .name(name() + ".iqInstsAdded") - .desc("Number of instructions added to the IQ (excludes non-spec)") - .prereq(iqInstsAdded); - - iqNonSpecInstsAdded - .name(name() + ".iqNonSpecInstsAdded") - .desc("Number of non-speculative instructions added to the IQ") - .prereq(iqNonSpecInstsAdded); - - iqInstsIssued - .name(name() + ".iqInstsIssued") - .desc("Number of instructions issued") - .prereq(iqInstsIssued); - - iqIntInstsIssued - .name(name() + ".iqIntInstsIssued") - .desc("Number of integer instructions issued") - .prereq(iqIntInstsIssued); - - iqFloatInstsIssued - .name(name() + ".iqFloatInstsIssued") - .desc("Number of float instructions issued") - .prereq(iqFloatInstsIssued); - - iqBranchInstsIssued - .name(name() + ".iqBranchInstsIssued") - .desc("Number of branch instructions issued") - .prereq(iqBranchInstsIssued); - - iqMemInstsIssued - .name(name() + ".iqMemInstsIssued") - .desc("Number of memory instructions issued") - .prereq(iqMemInstsIssued); - - iqMiscInstsIssued - .name(name() + ".iqMiscInstsIssued") - .desc("Number of miscellaneous instructions issued") - .prereq(iqMiscInstsIssued); - - iqSquashedInstsIssued - .name(name() + ".iqSquashedInstsIssued") - .desc("Number of squashed instructions issued") - .prereq(iqSquashedInstsIssued); - - iqSquashedInstsExamined - .name(name() + ".iqSquashedInstsExamined") - .desc("Number of squashed instructions iterated over during squash;" - " mainly for profiling") - .prereq(iqSquashedInstsExamined); - - iqSquashedOperandsExamined - .name(name() + ".iqSquashedOperandsExamined") - .desc("Number of squashed operands that are examined and possibly " - "removed from graph") - .prereq(iqSquashedOperandsExamined); - - iqSquashedNonSpecRemoved - .name(name() + ".iqSquashedNonSpecRemoved") - .desc("Number of squashed non-spec instructions that were removed") - .prereq(iqSquashedNonSpecRemoved); - - queueResDist - .init(Num_OpClasses, 0, 99, 2) - .name(name() + ".IQ:residence:") - .desc("cycles from dispatch to issue") - .flags(total | pdf | cdf ) - ; - for (int i = 0; i < Num_OpClasses; ++i) { - queueResDist.subname(i, opClassStrings[i]); - } - numIssuedDist - .init(0,totalWidth,1) - .name(name() + ".ISSUE:issued_per_cycle") - .desc("Number of insts issued each cycle") - .flags(pdf) - ; -/* - dist_unissued - .init(Num_OpClasses+2) - .name(name() + ".ISSUE:unissued_cause") - .desc("Reason ready instruction not issued") - .flags(pdf | dist) - ; - for (int i=0; i < (Num_OpClasses + 2); ++i) { - dist_unissued.subname(i, unissued_names[i]); - } -*/ - statIssuedInstType - .init(numThreads,Num_OpClasses) - .name(name() + ".ISSUE:FU_type") - .desc("Type of FU issued") - .flags(total | pdf | dist) - ; - statIssuedInstType.ysubnames(opClassStrings); - - // - // How long did instructions for a particular FU type wait prior to issue - // - - issueDelayDist - .init(Num_OpClasses,0,99,2) - .name(name() + ".ISSUE:") - .desc("cycles from operands ready to issue") - .flags(pdf | cdf) - ; - - for (int i=0; i<Num_OpClasses; ++i) { - stringstream subname; - subname << opClassStrings[i] << "_delay"; - issueDelayDist.subname(i, subname.str()); - } - - issueRate - .name(name() + ".ISSUE:rate") - .desc("Inst issue rate") - .flags(total) - ; - issueRate = iqInstsIssued / cpu->numCycles; -/* - issue_stores - .name(name() + ".ISSUE:stores") - .desc("Number of stores issued") - .flags(total) - ; - issue_stores = exe_refs - exe_loads; -*/ -/* - issue_op_rate - .name(name() + ".ISSUE:op_rate") - .desc("Operation issue rate") - .flags(total) - ; - issue_op_rate = issued_ops / numCycles; -*/ - statFuBusy - .init(Num_OpClasses) - .name(name() + ".ISSUE:fu_full") - .desc("attempts to use FU when none available") - .flags(pdf | dist) - ; - for (int i=0; i < Num_OpClasses; ++i) { - statFuBusy.subname(i, opClassStrings[i]); - } - - fuBusy - .init(numThreads) - .name(name() + ".ISSUE:fu_busy_cnt") - .desc("FU busy when requested") - .flags(total) - ; - - fuBusyRate - .name(name() + ".ISSUE:fu_busy_rate") - .desc("FU busy rate (busy events/executed inst)") - .flags(total) - ; - fuBusyRate = fuBusy / iqInstsIssued; - - for ( int i=0; i < numThreads; i++) { - // Tell mem dependence unit to reg stats as well. - memDepUnit[i].regStats(); - } -} - -template <class Impl> -void -InstructionQueue<Impl>::resetState() -{ - //Initialize thread IQ counts - for (int i = 0; i <numThreads; i++) { - count[i] = 0; - instList[i].clear(); - } - - // Initialize the number of free IQ entries. - freeEntries = numEntries; - - // Note that in actuality, the registers corresponding to the logical - // registers start off as ready. However this doesn't matter for the - // IQ as the instruction should have been correctly told if those - // registers are ready in rename. Thus it can all be initialized as - // unready. - for (int i = 0; i < numPhysRegs; ++i) { - regScoreboard[i] = false; - } - - for (int i = 0; i < numThreads; ++i) { - squashedSeqNum[i] = 0; - } - - for (int i = 0; i < Num_OpClasses; ++i) { - while (!readyInsts[i].empty()) - readyInsts[i].pop(); - queueOnList[i] = false; - readyIt[i] = listOrder.end(); - } - nonSpecInsts.clear(); - listOrder.clear(); -} - -template <class Impl> -void -InstructionQueue<Impl>::setActiveThreads(list<unsigned> *at_ptr) -{ - DPRINTF(IQ, "Setting active threads list pointer.\n"); - activeThreads = at_ptr; -} - -template <class Impl> -void -InstructionQueue<Impl>::setIssueToExecuteQueue(TimeBuffer<IssueStruct> *i2e_ptr) -{ - DPRINTF(IQ, "Set the issue to execute queue.\n"); - issueToExecuteQueue = i2e_ptr; -} - -template <class Impl> -void -InstructionQueue<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) -{ - DPRINTF(IQ, "Set the time buffer.\n"); - timeBuffer = tb_ptr; - - fromCommit = timeBuffer->getWire(-commitToIEWDelay); -} - -template <class Impl> -void -InstructionQueue<Impl>::switchOut() -{ - resetState(); - dependGraph.reset(); - switchedOut = true; - for (int i = 0; i < numThreads; ++i) { - memDepUnit[i].switchOut(); - } -} - -template <class Impl> -void -InstructionQueue<Impl>::takeOverFrom() -{ - switchedOut = false; -} - -template <class Impl> -int -InstructionQueue<Impl>::entryAmount(int num_threads) -{ - if (iqPolicy == Partitioned) { - return numEntries / num_threads; - } else { - return 0; - } -} - - -template <class Impl> -void -InstructionQueue<Impl>::resetEntries() -{ - if (iqPolicy != Dynamic || numThreads > 1) { - int active_threads = (*activeThreads).size(); - - list<unsigned>::iterator threads = (*activeThreads).begin(); - list<unsigned>::iterator list_end = (*activeThreads).end(); - - while (threads != list_end) { - if (iqPolicy == Partitioned) { - maxEntries[*threads++] = numEntries / active_threads; - } else if(iqPolicy == Threshold && active_threads == 1) { - maxEntries[*threads++] = numEntries; - } - } - } -} - -template <class Impl> -unsigned -InstructionQueue<Impl>::numFreeEntries() -{ - return freeEntries; -} - -template <class Impl> -unsigned -InstructionQueue<Impl>::numFreeEntries(unsigned tid) -{ - return maxEntries[tid] - count[tid]; -} - -// Might want to do something more complex if it knows how many instructions -// will be issued this cycle. -template <class Impl> -bool -InstructionQueue<Impl>::isFull() -{ - if (freeEntries == 0) { - return(true); - } else { - return(false); - } -} - -template <class Impl> -bool -InstructionQueue<Impl>::isFull(unsigned tid) -{ - if (numFreeEntries(tid) == 0) { - return(true); - } else { - return(false); - } -} - -template <class Impl> -bool -InstructionQueue<Impl>::hasReadyInsts() -{ - if (!listOrder.empty()) { - return true; - } - - for (int i = 0; i < Num_OpClasses; ++i) { - if (!readyInsts[i].empty()) { - return true; - } - } - - return false; -} - -template <class Impl> -void -InstructionQueue<Impl>::insert(DynInstPtr &new_inst) -{ - // Make sure the instruction is valid - assert(new_inst); - - DPRINTF(IQ, "Adding instruction [sn:%lli] PC %#x to the IQ.\n", - new_inst->seqNum, new_inst->readPC()); - - assert(freeEntries != 0); - - instList[new_inst->threadNumber].push_back(new_inst); - - --freeEntries; - - new_inst->setInIQ(); - - // Look through its source registers (physical regs), and mark any - // dependencies. - addToDependents(new_inst); - - // Have this instruction set itself as the producer of its destination - // register(s). - addToProducers(new_inst); - - if (new_inst->isMemRef()) { - memDepUnit[new_inst->threadNumber].insert(new_inst); - } else { - addIfReady(new_inst); - } - - ++iqInstsAdded; - - count[new_inst->threadNumber]++; - - assert(freeEntries == (numEntries - countInsts())); -} - -template <class Impl> -void -InstructionQueue<Impl>::insertNonSpec(DynInstPtr &new_inst) -{ - // @todo: Clean up this code; can do it by setting inst as unable - // to issue, then calling normal insert on the inst. - - assert(new_inst); - - nonSpecInsts[new_inst->seqNum] = new_inst; - - DPRINTF(IQ, "Adding non-speculative instruction [sn:%lli] PC %#x " - "to the IQ.\n", - new_inst->seqNum, new_inst->readPC()); - - assert(freeEntries != 0); - - instList[new_inst->threadNumber].push_back(new_inst); - - --freeEntries; - - new_inst->setInIQ(); - - // Have this instruction set itself as the producer of its destination - // register(s). - addToProducers(new_inst); - - // If it's a memory instruction, add it to the memory dependency - // unit. - if (new_inst->isMemRef()) { - memDepUnit[new_inst->threadNumber].insertNonSpec(new_inst); - } - - ++iqNonSpecInstsAdded; - - count[new_inst->threadNumber]++; - - assert(freeEntries == (numEntries - countInsts())); -} - -template <class Impl> -void -InstructionQueue<Impl>::insertBarrier(DynInstPtr &barr_inst) -{ - memDepUnit[barr_inst->threadNumber].insertBarrier(barr_inst); - - insertNonSpec(barr_inst); -} - -template <class Impl> -typename Impl::DynInstPtr -InstructionQueue<Impl>::getInstToExecute() -{ - assert(!instsToExecute.empty()); - DynInstPtr inst = instsToExecute.front(); - instsToExecute.pop_front(); - return inst; -} - -template <class Impl> -void -InstructionQueue<Impl>::addToOrderList(OpClass op_class) -{ - assert(!readyInsts[op_class].empty()); - - ListOrderEntry queue_entry; - - queue_entry.queueType = op_class; - - queue_entry.oldestInst = readyInsts[op_class].top()->seqNum; - - ListOrderIt list_it = listOrder.begin(); - ListOrderIt list_end_it = listOrder.end(); - - while (list_it != list_end_it) { - if ((*list_it).oldestInst > queue_entry.oldestInst) { - break; - } - - list_it++; - } - - readyIt[op_class] = listOrder.insert(list_it, queue_entry); - queueOnList[op_class] = true; -} - -template <class Impl> -void -InstructionQueue<Impl>::moveToYoungerInst(ListOrderIt list_order_it) -{ - // Get iterator of next item on the list - // Delete the original iterator - // Determine if the next item is either the end of the list or younger - // than the new instruction. If so, then add in a new iterator right here. - // If not, then move along. - ListOrderEntry queue_entry; - OpClass op_class = (*list_order_it).queueType; - ListOrderIt next_it = list_order_it; - - ++next_it; - - queue_entry.queueType = op_class; - queue_entry.oldestInst = readyInsts[op_class].top()->seqNum; - - while (next_it != listOrder.end() && - (*next_it).oldestInst < queue_entry.oldestInst) { - ++next_it; - } - - readyIt[op_class] = listOrder.insert(next_it, queue_entry); -} - -template <class Impl> -void -InstructionQueue<Impl>::processFUCompletion(DynInstPtr &inst, int fu_idx) -{ - // The CPU could have been sleeping until this op completed (*extremely* - // long latency op). Wake it if it was. This may be overkill. - if (isSwitchedOut()) { - return; - } - - iewStage->wakeCPU(); - - if (fu_idx > -1) - fuPool->freeUnitNextCycle(fu_idx); - - // @todo: Ensure that these FU Completions happen at the beginning - // of a cycle, otherwise they could add too many instructions to - // the queue. - // @todo: This could break if there's multiple multi-cycle ops - // finishing on this cycle. Maybe implement something like - // instToCommit in iew_impl.hh. - issueToExecuteQueue->access(0)->size++; - instsToExecute.push_back(inst); -// int &size = issueToExecuteQueue->access(0)->size; - -// issueToExecuteQueue->access(0)->insts[size++] = inst; -} - -// @todo: Figure out a better way to remove the squashed items from the -// lists. Checking the top item of each list to see if it's squashed -// wastes time and forces jumps. -template <class Impl> -void -InstructionQueue<Impl>::scheduleReadyInsts() -{ - DPRINTF(IQ, "Attempting to schedule ready instructions from " - "the IQ.\n"); - - IssueStruct *i2e_info = issueToExecuteQueue->access(0); - - // Have iterator to head of the list - // While I haven't exceeded bandwidth or reached the end of the list, - // Try to get a FU that can do what this op needs. - // If successful, change the oldestInst to the new top of the list, put - // the queue in the proper place in the list. - // Increment the iterator. - // This will avoid trying to schedule a certain op class if there are no - // FUs that handle it. - ListOrderIt order_it = listOrder.begin(); - ListOrderIt order_end_it = listOrder.end(); - int total_issued = 0; - - while (total_issued < totalWidth && - order_it != order_end_it) { - OpClass op_class = (*order_it).queueType; - - assert(!readyInsts[op_class].empty()); - - DynInstPtr issuing_inst = readyInsts[op_class].top(); - - assert(issuing_inst->seqNum == (*order_it).oldestInst); - - if (issuing_inst->isSquashed()) { - readyInsts[op_class].pop(); - - if (!readyInsts[op_class].empty()) { - moveToYoungerInst(order_it); - } else { - readyIt[op_class] = listOrder.end(); - queueOnList[op_class] = false; - } - - listOrder.erase(order_it++); - - ++iqSquashedInstsIssued; - - continue; - } - - int idx = -2; - int op_latency = 1; - int tid = issuing_inst->threadNumber; - - if (op_class != No_OpClass) { - idx = fuPool->getUnit(op_class); - - if (idx > -1) { - op_latency = fuPool->getOpLatency(op_class); - } - } - - if (idx == -2 || idx != -1) { - if (op_latency == 1) { -// i2e_info->insts[exec_queue_slot++] = issuing_inst; - i2e_info->size++; - instsToExecute.push_back(issuing_inst); - - // Add the FU onto the list of FU's to be freed next - // cycle if we used one. - if (idx >= 0) - fuPool->freeUnitNextCycle(idx); - } else { - int issue_latency = fuPool->getIssueLatency(op_class); - // Generate completion event for the FU - FUCompletion *execution = new FUCompletion(issuing_inst, - idx, this); - - execution->schedule(curTick + cpu->cycles(issue_latency - 1)); - - // @todo: Enforce that issue_latency == 1 or op_latency - if (issue_latency > 1) { - execution->setFreeFU(); - } else { - // @todo: Not sure I'm accounting for the - // multi-cycle op in a pipelined FU properly, or - // the number of instructions issued in one cycle. -// i2e_info->insts[exec_queue_slot++] = issuing_inst; -// i2e_info->size++; - - // Add the FU onto the list of FU's to be freed next cycle. - fuPool->freeUnitNextCycle(idx); - } - } - - DPRINTF(IQ, "Thread %i: Issuing instruction PC %#x " - "[sn:%lli]\n", - tid, issuing_inst->readPC(), - issuing_inst->seqNum); - - readyInsts[op_class].pop(); - - if (!readyInsts[op_class].empty()) { - moveToYoungerInst(order_it); - } else { - readyIt[op_class] = listOrder.end(); - queueOnList[op_class] = false; - } - - issuing_inst->setIssued(); - ++total_issued; - - if (!issuing_inst->isMemRef()) { - // Memory instructions can not be freed from the IQ until they - // complete. - ++freeEntries; - count[tid]--; - issuing_inst->removeInIQ(); - } else { - memDepUnit[tid].issue(issuing_inst); - } - - listOrder.erase(order_it++); - statIssuedInstType[tid][op_class]++; - } else { - statFuBusy[op_class]++; - fuBusy[tid]++; - ++order_it; - } - } - - numIssuedDist.sample(total_issued); - iqInstsIssued+= total_issued; - - if (total_issued) { - cpu->activityThisCycle(); - } else { - DPRINTF(IQ, "Not able to schedule any instructions.\n"); - } -} - -template <class Impl> -void -InstructionQueue<Impl>::scheduleNonSpec(const InstSeqNum &inst) -{ - DPRINTF(IQ, "Marking nonspeculative instruction [sn:%lli] as ready " - "to execute.\n", inst); - - NonSpecMapIt inst_it = nonSpecInsts.find(inst); - - assert(inst_it != nonSpecInsts.end()); - - unsigned tid = (*inst_it).second->threadNumber; - - (*inst_it).second->setCanIssue(); - - if (!(*inst_it).second->isMemRef()) { - addIfReady((*inst_it).second); - } else { - memDepUnit[tid].nonSpecInstReady((*inst_it).second); - } - - (*inst_it).second = NULL; - - nonSpecInsts.erase(inst_it); -} - -template <class Impl> -void -InstructionQueue<Impl>::commit(const InstSeqNum &inst, unsigned tid) -{ - DPRINTF(IQ, "[tid:%i]: Committing instructions older than [sn:%i]\n", - tid,inst); - - ListIt iq_it = instList[tid].begin(); - - while (iq_it != instList[tid].end() && - (*iq_it)->seqNum <= inst) { - ++iq_it; - instList[tid].pop_front(); - } - - assert(freeEntries == (numEntries - countInsts())); -} - -template <class Impl> -int -InstructionQueue<Impl>::wakeDependents(DynInstPtr &completed_inst) -{ - int dependents = 0; - - DPRINTF(IQ, "Waking dependents of completed instruction.\n"); - - assert(!completed_inst->isSquashed()); - - // Tell the memory dependence unit to wake any dependents on this - // instruction if it is a memory instruction. Also complete the memory - // instruction at this point since we know it executed without issues. - // @todo: Might want to rename "completeMemInst" to something that - // indicates that it won't need to be replayed, and call this - // earlier. Might not be a big deal. - if (completed_inst->isMemRef()) { - memDepUnit[completed_inst->threadNumber].wakeDependents(completed_inst); - completeMemInst(completed_inst); - } else if (completed_inst->isMemBarrier() || - completed_inst->isWriteBarrier()) { - memDepUnit[completed_inst->threadNumber].completeBarrier(completed_inst); - } - - for (int dest_reg_idx = 0; - dest_reg_idx < completed_inst->numDestRegs(); - dest_reg_idx++) - { - PhysRegIndex dest_reg = - completed_inst->renamedDestRegIdx(dest_reg_idx); - - // Special case of uniq or control registers. They are not - // handled by the IQ and thus have no dependency graph entry. - // @todo Figure out a cleaner way to handle this. - if (dest_reg >= numPhysRegs) { - continue; - } - - DPRINTF(IQ, "Waking any dependents on register %i.\n", - (int) dest_reg); - - //Go through the dependency chain, marking the registers as - //ready within the waiting instructions. - DynInstPtr dep_inst = dependGraph.pop(dest_reg); - - while (dep_inst) { - DPRINTF(IQ, "Waking up a dependent instruction, PC%#x.\n", - dep_inst->readPC()); - - // Might want to give more information to the instruction - // so that it knows which of its source registers is - // ready. However that would mean that the dependency - // graph entries would need to hold the src_reg_idx. - dep_inst->markSrcRegReady(); - - addIfReady(dep_inst); - - dep_inst = dependGraph.pop(dest_reg); - - ++dependents; - } - - // Reset the head node now that all of its dependents have - // been woken up. - assert(dependGraph.empty(dest_reg)); - dependGraph.clearInst(dest_reg); - - // Mark the scoreboard as having that register ready. - regScoreboard[dest_reg] = true; - } - return dependents; -} - -template <class Impl> -void -InstructionQueue<Impl>::addReadyMemInst(DynInstPtr &ready_inst) -{ - OpClass op_class = ready_inst->opClass(); - - readyInsts[op_class].push(ready_inst); - - // Will need to reorder the list if either a queue is not on the list, - // or it has an older instruction than last time. - if (!queueOnList[op_class]) { - addToOrderList(op_class); - } else if (readyInsts[op_class].top()->seqNum < - (*readyIt[op_class]).oldestInst) { - listOrder.erase(readyIt[op_class]); - addToOrderList(op_class); - } - - DPRINTF(IQ, "Instruction is ready to issue, putting it onto " - "the ready list, PC %#x opclass:%i [sn:%lli].\n", - ready_inst->readPC(), op_class, ready_inst->seqNum); -} - -template <class Impl> -void -InstructionQueue<Impl>::rescheduleMemInst(DynInstPtr &resched_inst) -{ - memDepUnit[resched_inst->threadNumber].reschedule(resched_inst); -} - -template <class Impl> -void -InstructionQueue<Impl>::replayMemInst(DynInstPtr &replay_inst) -{ - memDepUnit[replay_inst->threadNumber].replay(replay_inst); -} - -template <class Impl> -void -InstructionQueue<Impl>::completeMemInst(DynInstPtr &completed_inst) -{ - int tid = completed_inst->threadNumber; - - DPRINTF(IQ, "Completing mem instruction PC:%#x [sn:%lli]\n", - completed_inst->readPC(), completed_inst->seqNum); - - ++freeEntries; - - completed_inst->memOpDone = true; - - memDepUnit[tid].completed(completed_inst); - - count[tid]--; -} - -template <class Impl> -void -InstructionQueue<Impl>::violation(DynInstPtr &store, - DynInstPtr &faulting_load) -{ - memDepUnit[store->threadNumber].violation(store, faulting_load); -} - -template <class Impl> -void -InstructionQueue<Impl>::squash(unsigned tid) -{ - DPRINTF(IQ, "[tid:%i]: Starting to squash instructions in " - "the IQ.\n", tid); - - // Read instruction sequence number of last instruction out of the - // time buffer. - squashedSeqNum[tid] = fromCommit->commitInfo[tid].doneSeqNum; - - // Call doSquash if there are insts in the IQ - if (count[tid] > 0) { - doSquash(tid); - } - - // Also tell the memory dependence unit to squash. - memDepUnit[tid].squash(squashedSeqNum[tid], tid); -} - -template <class Impl> -void -InstructionQueue<Impl>::doSquash(unsigned tid) -{ - // Start at the tail. - ListIt squash_it = instList[tid].end(); - --squash_it; - - DPRINTF(IQ, "[tid:%i]: Squashing until sequence number %i!\n", - tid, squashedSeqNum[tid]); - - // Squash any instructions younger than the squashed sequence number - // given. - while (squash_it != instList[tid].end() && - (*squash_it)->seqNum > squashedSeqNum[tid]) { - - DynInstPtr squashed_inst = (*squash_it); - - // Only handle the instruction if it actually is in the IQ and - // hasn't already been squashed in the IQ. - if (squashed_inst->threadNumber != tid || - squashed_inst->isSquashedInIQ()) { - --squash_it; - continue; - } - - if (!squashed_inst->isIssued() || - (squashed_inst->isMemRef() && - !squashed_inst->memOpDone)) { - - // Remove the instruction from the dependency list. - if (!squashed_inst->isNonSpeculative() && - !squashed_inst->isStoreConditional() && - !squashed_inst->isMemBarrier() && - !squashed_inst->isWriteBarrier()) { - - for (int src_reg_idx = 0; - src_reg_idx < squashed_inst->numSrcRegs(); - src_reg_idx++) - { - PhysRegIndex src_reg = - squashed_inst->renamedSrcRegIdx(src_reg_idx); - - // Only remove it from the dependency graph if it - // was placed there in the first place. - - // Instead of doing a linked list traversal, we - // can just remove these squashed instructions - // either at issue time, or when the register is - // overwritten. The only downside to this is it - // leaves more room for error. - - if (!squashed_inst->isReadySrcRegIdx(src_reg_idx) && - src_reg < numPhysRegs) { - dependGraph.remove(src_reg, squashed_inst); - } - - - ++iqSquashedOperandsExamined; - } - } else { - NonSpecMapIt ns_inst_it = - nonSpecInsts.find(squashed_inst->seqNum); - assert(ns_inst_it != nonSpecInsts.end()); - - (*ns_inst_it).second = NULL; - - nonSpecInsts.erase(ns_inst_it); - - ++iqSquashedNonSpecRemoved; - } - - // Might want to also clear out the head of the dependency graph. - - // Mark it as squashed within the IQ. - squashed_inst->setSquashedInIQ(); - - // @todo: Remove this hack where several statuses are set so the - // inst will flow through the rest of the pipeline. - squashed_inst->setIssued(); - squashed_inst->setCanCommit(); - squashed_inst->removeInIQ(); - - //Update Thread IQ Count - count[squashed_inst->threadNumber]--; - - ++freeEntries; - - DPRINTF(IQ, "[tid:%i]: Instruction [sn:%lli] PC %#x " - "squashed.\n", - tid, squashed_inst->seqNum, squashed_inst->readPC()); - } - - instList[tid].erase(squash_it--); - ++iqSquashedInstsExamined; - } -} - -template <class Impl> -bool -InstructionQueue<Impl>::addToDependents(DynInstPtr &new_inst) -{ - // Loop through the instruction's source registers, adding - // them to the dependency list if they are not ready. - int8_t total_src_regs = new_inst->numSrcRegs(); - bool return_val = false; - - for (int src_reg_idx = 0; - src_reg_idx < total_src_regs; - src_reg_idx++) - { - // Only add it to the dependency graph if it's not ready. - if (!new_inst->isReadySrcRegIdx(src_reg_idx)) { - PhysRegIndex src_reg = new_inst->renamedSrcRegIdx(src_reg_idx); - - // Check the IQ's scoreboard to make sure the register - // hasn't become ready while the instruction was in flight - // between stages. Only if it really isn't ready should - // it be added to the dependency graph. - if (src_reg >= numPhysRegs) { - continue; - } else if (regScoreboard[src_reg] == false) { - DPRINTF(IQ, "Instruction PC %#x has src reg %i that " - "is being added to the dependency chain.\n", - new_inst->readPC(), src_reg); - - dependGraph.insert(src_reg, new_inst); - - // Change the return value to indicate that something - // was added to the dependency graph. - return_val = true; - } else { - DPRINTF(IQ, "Instruction PC %#x has src reg %i that " - "became ready before it reached the IQ.\n", - new_inst->readPC(), src_reg); - // Mark a register ready within the instruction. - new_inst->markSrcRegReady(src_reg_idx); - } - } - } - - return return_val; -} - -template <class Impl> -void -InstructionQueue<Impl>::addToProducers(DynInstPtr &new_inst) -{ - // Nothing really needs to be marked when an instruction becomes - // the producer of a register's value, but for convenience a ptr - // to the producing instruction will be placed in the head node of - // the dependency links. - int8_t total_dest_regs = new_inst->numDestRegs(); - - for (int dest_reg_idx = 0; - dest_reg_idx < total_dest_regs; - dest_reg_idx++) - { - PhysRegIndex dest_reg = new_inst->renamedDestRegIdx(dest_reg_idx); - - // Instructions that use the misc regs will have a reg number - // higher than the normal physical registers. In this case these - // registers are not renamed, and there is no need to track - // dependencies as these instructions must be executed at commit. - if (dest_reg >= numPhysRegs) { - continue; - } - - if (!dependGraph.empty(dest_reg)) { - dependGraph.dump(); - panic("Dependency graph %i not empty!", dest_reg); - } - - dependGraph.setInst(dest_reg, new_inst); - - // Mark the scoreboard to say it's not yet ready. - regScoreboard[dest_reg] = false; - } -} - -template <class Impl> -void -InstructionQueue<Impl>::addIfReady(DynInstPtr &inst) -{ - // If the instruction now has all of its source registers - // available, then add it to the list of ready instructions. - if (inst->readyToIssue()) { - - //Add the instruction to the proper ready list. - if (inst->isMemRef()) { - - DPRINTF(IQ, "Checking if memory instruction can issue.\n"); - - // Message to the mem dependence unit that this instruction has - // its registers ready. - memDepUnit[inst->threadNumber].regsReady(inst); - - return; - } - - OpClass op_class = inst->opClass(); - - DPRINTF(IQ, "Instruction is ready to issue, putting it onto " - "the ready list, PC %#x opclass:%i [sn:%lli].\n", - inst->readPC(), op_class, inst->seqNum); - - readyInsts[op_class].push(inst); - - // Will need to reorder the list if either a queue is not on the list, - // or it has an older instruction than last time. - if (!queueOnList[op_class]) { - addToOrderList(op_class); - } else if (readyInsts[op_class].top()->seqNum < - (*readyIt[op_class]).oldestInst) { - listOrder.erase(readyIt[op_class]); - addToOrderList(op_class); - } - } -} - -template <class Impl> -int -InstructionQueue<Impl>::countInsts() -{ - //ksewell:This works but definitely could use a cleaner write - //with a more intuitive way of counting. Right now it's - //just brute force .... - -#if 0 - int total_insts = 0; - - for (int i = 0; i < numThreads; ++i) { - ListIt count_it = instList[i].begin(); - - while (count_it != instList[i].end()) { - if (!(*count_it)->isSquashed() && !(*count_it)->isSquashedInIQ()) { - if (!(*count_it)->isIssued()) { - ++total_insts; - } else if ((*count_it)->isMemRef() && - !(*count_it)->memOpDone) { - // Loads that have not been marked as executed still count - // towards the total instructions. - ++total_insts; - } - } - - ++count_it; - } - } - - return total_insts; -#else - return numEntries - freeEntries; -#endif -} - -template <class Impl> -void -InstructionQueue<Impl>::dumpLists() -{ - for (int i = 0; i < Num_OpClasses; ++i) { - cprintf("Ready list %i size: %i\n", i, readyInsts[i].size()); - - cprintf("\n"); - } - - cprintf("Non speculative list size: %i\n", nonSpecInsts.size()); - - NonSpecMapIt non_spec_it = nonSpecInsts.begin(); - NonSpecMapIt non_spec_end_it = nonSpecInsts.end(); - - cprintf("Non speculative list: "); - - while (non_spec_it != non_spec_end_it) { - cprintf("%#x [sn:%lli]", (*non_spec_it).second->readPC(), - (*non_spec_it).second->seqNum); - ++non_spec_it; - } - - cprintf("\n"); - - ListOrderIt list_order_it = listOrder.begin(); - ListOrderIt list_order_end_it = listOrder.end(); - int i = 1; - - cprintf("List order: "); - - while (list_order_it != list_order_end_it) { - cprintf("%i OpClass:%i [sn:%lli] ", i, (*list_order_it).queueType, - (*list_order_it).oldestInst); - - ++list_order_it; - ++i; - } - - cprintf("\n"); -} - - -template <class Impl> -void -InstructionQueue<Impl>::dumpInsts() -{ - for (int i = 0; i < numThreads; ++i) { - int num = 0; - int valid_num = 0; - ListIt inst_list_it = instList[i].begin(); - - while (inst_list_it != instList[i].end()) - { - cprintf("Instruction:%i\n", - num); - if (!(*inst_list_it)->isSquashed()) { - if (!(*inst_list_it)->isIssued()) { - ++valid_num; - cprintf("Count:%i\n", valid_num); - } else if ((*inst_list_it)->isMemRef() && - !(*inst_list_it)->memOpDone) { - // Loads that have not been marked as executed - // still count towards the total instructions. - ++valid_num; - cprintf("Count:%i\n", valid_num); - } - } - - cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" - "Issued:%i\nSquashed:%i\n", - (*inst_list_it)->readPC(), - (*inst_list_it)->seqNum, - (*inst_list_it)->threadNumber, - (*inst_list_it)->isIssued(), - (*inst_list_it)->isSquashed()); - - if ((*inst_list_it)->isMemRef()) { - cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone); - } - - cprintf("\n"); - - inst_list_it++; - ++num; - } - } -} diff --git a/cpu/o3/lsq.cc b/cpu/o3/lsq.cc deleted file mode 100644 index 8991ab8f8..000000000 --- a/cpu/o3/lsq.cc +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/o3/alpha_dyn_inst.hh" -#include "cpu/o3/alpha_cpu.hh" -#include "cpu/o3/alpha_impl.hh" -#include "cpu/o3/lsq_impl.hh" - -// Force the instantiation of LDSTQ for all the implementations we care about. -template class LSQ<AlphaSimpleImpl>; - diff --git a/cpu/o3/lsq.hh b/cpu/o3/lsq.hh deleted file mode 100644 index a1eeccbe7..000000000 --- a/cpu/o3/lsq.hh +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_LSQ_HH__ -#define __CPU_O3_LSQ_HH__ - -#include <map> -#include <queue> - -#include "config/full_system.hh" -#include "cpu/inst_seq.hh" -//#include "cpu/o3/cpu_policy.hh" -#include "cpu/o3/lsq_unit.hh" -#include "mem/mem_interface.hh" -//#include "mem/page_table.hh" -#include "sim/sim_object.hh" - -template <class Impl> -class LSQ { - public: - typedef typename Impl::Params Params; - typedef typename Impl::FullCPU FullCPU; - typedef typename Impl::DynInstPtr DynInstPtr; - typedef typename Impl::CPUPol::IEW IEW; - typedef typename Impl::CPUPol::LSQUnit LSQUnit; - - enum LSQPolicy { - Dynamic, - Partitioned, - Threshold - }; - - /** Constructs an LSQ with the given parameters. */ - LSQ(Params *params); - - /** Returns the name of the LSQ. */ - std::string name() const; - - /** Sets the pointer to the list of active threads. */ - void setActiveThreads(std::list<unsigned> *at_ptr); - /** Sets the CPU pointer. */ - void setCPU(FullCPU *cpu_ptr); - /** Sets the IEW stage pointer. */ - void setIEW(IEW *iew_ptr); - /** Sets the page table pointer. */ -// void setPageTable(PageTable *pt_ptr); - - void switchOut(); - void takeOverFrom(); - - /** Number of entries needed for the given amount of threads.*/ - int entryAmount(int num_threads); - void removeEntries(unsigned tid); - /** Reset the max entries for each thread. */ - void resetEntries(); - /** Resize the max entries for a thread. */ - void resizeEntries(unsigned size, unsigned tid); - - /** Ticks the LSQ. */ - void tick(); - /** Ticks a specific LSQ Unit. */ - void tick(unsigned tid) - { thread[tid].tick(); } - - /** Inserts a load into the LSQ. */ - void insertLoad(DynInstPtr &load_inst); - /** Inserts a store into the LSQ. */ - void insertStore(DynInstPtr &store_inst); - - /** Executes a load. */ - Fault executeLoad(DynInstPtr &inst); - - Fault executeLoad(int lq_idx, unsigned tid) - { return thread[tid].executeLoad(lq_idx); } - - /** Executes a store. */ - Fault executeStore(DynInstPtr &inst); - - /** - * Commits loads up until the given sequence number for a specific thread. - */ - void commitLoads(InstSeqNum &youngest_inst, unsigned tid) - { thread[tid].commitLoads(youngest_inst); } - - /** - * Commits stores up until the given sequence number for a specific thread. - */ - void commitStores(InstSeqNum &youngest_inst, unsigned tid) - { thread[tid].commitStores(youngest_inst); } - - /** - * Attempts to write back stores until all cache ports are used or the - * interface becomes blocked. - */ - void writebackStores(); - /** Same as above, but only for one thread. */ - void writebackStores(unsigned tid); - - /** - * Squash instructions from a thread until the specified sequence number. - */ - void squash(const InstSeqNum &squashed_num, unsigned tid) - { thread[tid].squash(squashed_num); } - - /** Returns whether or not there was a memory ordering violation. */ - bool violation(); - /** - * Returns whether or not there was a memory ordering violation for a - * specific thread. - */ - bool violation(unsigned tid) - { return thread[tid].violation(); } - - /** Returns if a load is blocked due to the memory system for a specific - * thread. - */ - bool loadBlocked(unsigned tid) - { return thread[tid].loadBlocked(); } - - bool isLoadBlockedHandled(unsigned tid) - { return thread[tid].isLoadBlockedHandled(); } - - void setLoadBlockedHandled(unsigned tid) - { thread[tid].setLoadBlockedHandled(); } - - /** Gets the instruction that caused the memory ordering violation. */ - DynInstPtr getMemDepViolator(unsigned tid) - { return thread[tid].getMemDepViolator(); } - - /** Returns the head index of the load queue for a specific thread. */ - int getLoadHead(unsigned tid) - { return thread[tid].getLoadHead(); } - - /** Returns the sequence number of the head of the load queue. */ - InstSeqNum getLoadHeadSeqNum(unsigned tid) - { - return thread[tid].getLoadHeadSeqNum(); - } - - /** Returns the head index of the store queue. */ - int getStoreHead(unsigned tid) - { return thread[tid].getStoreHead(); } - - /** Returns the sequence number of the head of the store queue. */ - InstSeqNum getStoreHeadSeqNum(unsigned tid) - { - return thread[tid].getStoreHeadSeqNum(); - } - - /** Returns the number of instructions in all of the queues. */ - int getCount(); - /** Returns the number of instructions in the queues of one thread. */ - int getCount(unsigned tid) - { return thread[tid].getCount(); } - - /** Returns the total number of loads in the load queue. */ - int numLoads(); - /** Returns the total number of loads for a single thread. */ - int numLoads(unsigned tid) - { return thread[tid].numLoads(); } - - /** Returns the total number of stores in the store queue. */ - int numStores(); - /** Returns the total number of stores for a single thread. */ - int numStores(unsigned tid) - { return thread[tid].numStores(); } - - /** Returns the total number of loads that are ready. */ - int numLoadsReady(); - /** Returns the number of loads that are ready for a single thread. */ - int numLoadsReady(unsigned tid) - { return thread[tid].numLoadsReady(); } - - /** Returns the number of free entries. */ - unsigned numFreeEntries(); - /** Returns the number of free entries for a specific thread. */ - unsigned numFreeEntries(unsigned tid); - - /** Returns if the LSQ is full (either LQ or SQ is full). */ - bool isFull(); - /** - * Returns if the LSQ is full for a specific thread (either LQ or SQ is - * full). - */ - bool isFull(unsigned tid); - - /** Returns if any of the LQs are full. */ - bool lqFull(); - /** Returns if the LQ of a given thread is full. */ - bool lqFull(unsigned tid); - - /** Returns if any of the SQs are full. */ - bool sqFull(); - /** Returns if the SQ of a given thread is full. */ - bool sqFull(unsigned tid); - - /** - * Returns if the LSQ is stalled due to a memory operation that must be - * replayed. - */ - bool isStalled(); - /** - * Returns if the LSQ of a specific thread is stalled due to a memory - * operation that must be replayed. - */ - bool isStalled(unsigned tid); - - /** Returns whether or not there are any stores to write back to memory. */ - bool hasStoresToWB(); - - /** Returns whether or not a specific thread has any stores to write back - * to memory. - */ - bool hasStoresToWB(unsigned tid) - { return thread[tid].hasStoresToWB(); } - - /** Returns the number of stores a specific thread has to write back. */ - int numStoresToWB(unsigned tid) - { return thread[tid].numStoresToWB(); } - - /** Returns if the LSQ will write back to memory this cycle. */ - bool willWB(); - /** Returns if the LSQ of a specific thread will write back to memory this - * cycle. - */ - bool willWB(unsigned tid) - { return thread[tid].willWB(); } - - /** Debugging function to print out all instructions. */ - void dumpInsts(); - /** Debugging function to print out instructions from a specific thread. */ - void dumpInsts(unsigned tid) - { thread[tid].dumpInsts(); } - - /** Executes a read operation, using the load specified at the load index. */ - template <class T> - Fault read(MemReqPtr &req, T &data, int load_idx); - - /** Executes a store operation, using the store specified at the store - * index. - */ - template <class T> - Fault write(MemReqPtr &req, T &data, int store_idx); - - private: - /** The LSQ policy for SMT mode. */ - LSQPolicy lsqPolicy; - - /** The LSQ units for individual threads. */ - LSQUnit thread[Impl::MaxThreads]; - - /** The CPU pointer. */ - FullCPU *cpu; - - /** The IEW stage pointer. */ - IEW *iewStage; - - /** The pointer to the page table. */ -// PageTable *pTable; - - /** List of Active Threads in System. */ - std::list<unsigned> *activeThreads; - - /** Total Size of LQ Entries. */ - unsigned LQEntries; - /** Total Size of SQ Entries. */ - unsigned SQEntries; - - /** Max LQ Size - Used to Enforce Sharing Policies. */ - unsigned maxLQEntries; - - /** Max SQ Size - Used to Enforce Sharing Policies. */ - unsigned maxSQEntries; - - /** Number of Threads. */ - unsigned numThreads; -}; - -template <class Impl> -template <class T> -Fault -LSQ<Impl>::read(MemReqPtr &req, T &data, int load_idx) -{ - unsigned tid = req->thread_num; - - return thread[tid].read(req, data, load_idx); -} - -template <class Impl> -template <class T> -Fault -LSQ<Impl>::write(MemReqPtr &req, T &data, int store_idx) -{ - unsigned tid = req->thread_num; - - return thread[tid].write(req, data, store_idx); -} - -#endif // __CPU_O3_LSQ_HH__ diff --git a/cpu/o3/lsq_impl.hh b/cpu/o3/lsq_impl.hh deleted file mode 100644 index a6ad27522..000000000 --- a/cpu/o3/lsq_impl.hh +++ /dev/null @@ -1,538 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <algorithm> -#include <string> - -#include "cpu/o3/lsq.hh" - -using namespace std; - -template <class Impl> -LSQ<Impl>::LSQ(Params *params) - : LQEntries(params->LQEntries), SQEntries(params->SQEntries), - numThreads(params->numberOfThreads) -{ - DPRINTF(LSQ, "Creating LSQ object.\n"); - - //**********************************************/ - //************ Handle SMT Parameters ***********/ - //**********************************************/ - string policy = params->smtLSQPolicy; - - //Convert string to lowercase - std::transform(policy.begin(), policy.end(), policy.begin(), - (int(*)(int)) tolower); - - //Figure out fetch policy - if (policy == "dynamic") { - lsqPolicy = Dynamic; - - maxLQEntries = LQEntries; - maxSQEntries = SQEntries; - - DPRINTF(LSQ, "LSQ sharing policy set to Dynamic\n"); - - } else if (policy == "partitioned") { - lsqPolicy = Partitioned; - - //@todo:make work if part_amt doesnt divide evenly. - maxLQEntries = LQEntries / numThreads; - maxSQEntries = SQEntries / numThreads; - - DPRINTF(Fetch, "LSQ sharing policy set to Partitioned: " - "%i entries per LQ | %i entries per SQ", - maxLQEntries,maxSQEntries); - - } else if (policy == "threshold") { - lsqPolicy = Threshold; - - assert(params->smtLSQThreshold > LQEntries); - assert(params->smtLSQThreshold > SQEntries); - - //Divide up by threshold amount - //@todo: Should threads check the max and the total - //amount of the LSQ - maxLQEntries = params->smtLSQThreshold; - maxSQEntries = params->smtLSQThreshold; - - DPRINTF(LSQ, "LSQ sharing policy set to Threshold: " - "%i entries per LQ | %i entries per SQ", - maxLQEntries,maxSQEntries); - - } else { - assert(0 && "Invalid LSQ Sharing Policy.Options Are:{Dynamic," - "Partitioned, Threshold}"); - } - - //Initialize LSQs - for (int tid=0; tid < numThreads; tid++) { - thread[tid].init(params, maxLQEntries, maxSQEntries, tid); - } -} - - -template<class Impl> -std::string -LSQ<Impl>::name() const -{ - return iewStage->name() + ".lsq"; -} - -template<class Impl> -void -LSQ<Impl>::setActiveThreads(list<unsigned> *at_ptr) -{ - activeThreads = at_ptr; - assert(activeThreads != 0); -} - -template<class Impl> -void -LSQ<Impl>::setCPU(FullCPU *cpu_ptr) -{ - cpu = cpu_ptr; - - for (int tid=0; tid < numThreads; tid++) { - thread[tid].setCPU(cpu_ptr); - } -} - -template<class Impl> -void -LSQ<Impl>::setIEW(IEW *iew_ptr) -{ - iewStage = iew_ptr; - - for (int tid=0; tid < numThreads; tid++) { - thread[tid].setIEW(iew_ptr); - } -} - -#if 0 -template<class Impl> -void -LSQ<Impl>::setPageTable(PageTable *pt_ptr) -{ - for (int tid=0; tid < numThreads; tid++) { - thread[tid].setPageTable(pt_ptr); - } -} -#endif - -template <class Impl> -void -LSQ<Impl>::switchOut() -{ - for (int tid = 0; tid < numThreads; tid++) { - thread[tid].switchOut(); - } -} - -template <class Impl> -void -LSQ<Impl>::takeOverFrom() -{ - for (int tid = 0; tid < numThreads; tid++) { - thread[tid].takeOverFrom(); - } -} - -template <class Impl> -int -LSQ<Impl>::entryAmount(int num_threads) -{ - if (lsqPolicy == Partitioned) { - return LQEntries / num_threads; - } else { - return 0; - } -} - -template <class Impl> -void -LSQ<Impl>::resetEntries() -{ - if (lsqPolicy != Dynamic || numThreads > 1) { - int active_threads = (*activeThreads).size(); - - list<unsigned>::iterator threads = (*activeThreads).begin(); - list<unsigned>::iterator list_end = (*activeThreads).end(); - - int maxEntries; - - if (lsqPolicy == Partitioned) { - maxEntries = LQEntries / active_threads; - } else if (lsqPolicy == Threshold && active_threads == 1) { - maxEntries = LQEntries; - } else { - maxEntries = LQEntries; - } - - while (threads != list_end) { - resizeEntries(maxEntries,*threads++); - } - } -} - -template<class Impl> -void -LSQ<Impl>::removeEntries(unsigned tid) -{ - thread[tid].clearLQ(); - thread[tid].clearSQ(); -} - -template<class Impl> -void -LSQ<Impl>::resizeEntries(unsigned size,unsigned tid) -{ - thread[tid].resizeLQ(size); - thread[tid].resizeSQ(size); -} - -template<class Impl> -void -LSQ<Impl>::tick() -{ - list<unsigned>::iterator active_threads = (*activeThreads).begin(); - - while (active_threads != (*activeThreads).end()) { - unsigned tid = *active_threads++; - - thread[tid].tick(); - } -} - -template<class Impl> -void -LSQ<Impl>::insertLoad(DynInstPtr &load_inst) -{ - unsigned tid = load_inst->threadNumber; - - thread[tid].insertLoad(load_inst); -} - -template<class Impl> -void -LSQ<Impl>::insertStore(DynInstPtr &store_inst) -{ - unsigned tid = store_inst->threadNumber; - - thread[tid].insertStore(store_inst); -} - -template<class Impl> -Fault -LSQ<Impl>::executeLoad(DynInstPtr &inst) -{ - unsigned tid = inst->threadNumber; - - return thread[tid].executeLoad(inst); -} - -template<class Impl> -Fault -LSQ<Impl>::executeStore(DynInstPtr &inst) -{ - unsigned tid = inst->threadNumber; - - return thread[tid].executeStore(inst); -} - -template<class Impl> -void -LSQ<Impl>::writebackStores() -{ - list<unsigned>::iterator active_threads = (*activeThreads).begin(); - - while (active_threads != (*activeThreads).end()) { - unsigned tid = *active_threads++; - - if (numStoresToWB(tid) > 0) { - DPRINTF(Writeback,"[tid:%i] Writing back stores. %i stores " - "available for Writeback.\n", tid, numStoresToWB(tid)); - } - - thread[tid].writebackStores(); - } -} - -template<class Impl> -bool -LSQ<Impl>::violation() -{ - /* Answers: Does Anybody Have a Violation?*/ - list<unsigned>::iterator active_threads = (*activeThreads).begin(); - - while (active_threads != (*activeThreads).end()) { - unsigned tid = *active_threads++; - if (thread[tid].violation()) - return true; - } - - return false; -} - -template<class Impl> -int -LSQ<Impl>::getCount() -{ - unsigned total = 0; - - list<unsigned>::iterator active_threads = (*activeThreads).begin(); - - while (active_threads != (*activeThreads).end()) { - unsigned tid = *active_threads++; - total += getCount(tid); - } - - return total; -} - -template<class Impl> -int -LSQ<Impl>::numLoads() -{ - unsigned total = 0; - - list<unsigned>::iterator active_threads = (*activeThreads).begin(); - - while (active_threads != (*activeThreads).end()) { - unsigned tid = *active_threads++; - total += numLoads(tid); - } - - return total; -} - -template<class Impl> -int -LSQ<Impl>::numStores() -{ - unsigned total = 0; - - list<unsigned>::iterator active_threads = (*activeThreads).begin(); - - while (active_threads != (*activeThreads).end()) { - unsigned tid = *active_threads++; - total += thread[tid].numStores(); - } - - return total; -} - -template<class Impl> -int -LSQ<Impl>::numLoadsReady() -{ - unsigned total = 0; - - list<unsigned>::iterator active_threads = (*activeThreads).begin(); - - while (active_threads != (*activeThreads).end()) { - unsigned tid = *active_threads++; - total += thread[tid].numLoadsReady(); - } - - return total; -} - -template<class Impl> -unsigned -LSQ<Impl>::numFreeEntries() -{ - unsigned total = 0; - - list<unsigned>::iterator active_threads = (*activeThreads).begin(); - - while (active_threads != (*activeThreads).end()) { - unsigned tid = *active_threads++; - total += thread[tid].numFreeEntries(); - } - - return total; -} - -template<class Impl> -unsigned -LSQ<Impl>::numFreeEntries(unsigned tid) -{ - //if( lsqPolicy == Dynamic ) - //return numFreeEntries(); - //else - return thread[tid].numFreeEntries(); -} - -template<class Impl> -bool -LSQ<Impl>::isFull() -{ - list<unsigned>::iterator active_threads = (*activeThreads).begin(); - - while (active_threads != (*activeThreads).end()) { - unsigned tid = *active_threads++; - if (! (thread[tid].lqFull() || thread[tid].sqFull()) ) - return false; - } - - return true; -} - -template<class Impl> -bool -LSQ<Impl>::isFull(unsigned tid) -{ - //@todo: Change to Calculate All Entries for - //Dynamic Policy - if( lsqPolicy == Dynamic ) - return isFull(); - else - return thread[tid].lqFull() || thread[tid].sqFull(); -} - -template<class Impl> -bool -LSQ<Impl>::lqFull() -{ - list<unsigned>::iterator active_threads = (*activeThreads).begin(); - - while (active_threads != (*activeThreads).end()) { - unsigned tid = *active_threads++; - if (!thread[tid].lqFull()) - return false; - } - - return true; -} - -template<class Impl> -bool -LSQ<Impl>::lqFull(unsigned tid) -{ - //@todo: Change to Calculate All Entries for - //Dynamic Policy - if( lsqPolicy == Dynamic ) - return lqFull(); - else - return thread[tid].lqFull(); -} - -template<class Impl> -bool -LSQ<Impl>::sqFull() -{ - list<unsigned>::iterator active_threads = (*activeThreads).begin(); - - while (active_threads != (*activeThreads).end()) { - unsigned tid = *active_threads++; - if (!sqFull(tid)) - return false; - } - - return true; -} - -template<class Impl> -bool -LSQ<Impl>::sqFull(unsigned tid) -{ - //@todo: Change to Calculate All Entries for - //Dynamic Policy - if( lsqPolicy == Dynamic ) - return sqFull(); - else - return thread[tid].sqFull(); -} - -template<class Impl> -bool -LSQ<Impl>::isStalled() -{ - list<unsigned>::iterator active_threads = (*activeThreads).begin(); - - while (active_threads != (*activeThreads).end()) { - unsigned tid = *active_threads++; - if (!thread[tid].isStalled()) - return false; - } - - return true; -} - -template<class Impl> -bool -LSQ<Impl>::isStalled(unsigned tid) -{ - if( lsqPolicy == Dynamic ) - return isStalled(); - else - return thread[tid].isStalled(); -} - -template<class Impl> -bool -LSQ<Impl>::hasStoresToWB() -{ - list<unsigned>::iterator active_threads = (*activeThreads).begin(); - - while (active_threads != (*activeThreads).end()) { - unsigned tid = *active_threads++; - if (!hasStoresToWB(tid)) - return false; - } - - return true; -} - -template<class Impl> -bool -LSQ<Impl>::willWB() -{ - list<unsigned>::iterator active_threads = (*activeThreads).begin(); - - while (active_threads != (*activeThreads).end()) { - unsigned tid = *active_threads++; - if (!willWB(tid)) - return false; - } - - return true; -} - -template<class Impl> -void -LSQ<Impl>::dumpInsts() -{ - list<unsigned>::iterator active_threads = (*activeThreads).begin(); - - while (active_threads != (*activeThreads).end()) { - unsigned tid = *active_threads++; - thread[tid].dumpInsts(); - } -} diff --git a/cpu/o3/lsq_unit.cc b/cpu/o3/lsq_unit.cc deleted file mode 100644 index dd29007bc..000000000 --- a/cpu/o3/lsq_unit.cc +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/o3/alpha_dyn_inst.hh" -#include "cpu/o3/alpha_cpu.hh" -#include "cpu/o3/alpha_impl.hh" -#include "cpu/o3/lsq_unit_impl.hh" - -// Force the instantiation of LDSTQ for all the implementations we care about. -template class LSQUnit<AlphaSimpleImpl>; - diff --git a/cpu/o3/lsq_unit.hh b/cpu/o3/lsq_unit.hh deleted file mode 100644 index 942b4583d..000000000 --- a/cpu/o3/lsq_unit.hh +++ /dev/null @@ -1,632 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_LSQ_UNIT_HH__ -#define __CPU_O3_LSQ_UNIT_HH__ - -#include <algorithm> -#include <map> -#include <queue> - -#include "arch/faults.hh" -#include "config/full_system.hh" -#include "base/hashmap.hh" -#include "cpu/inst_seq.hh" -#include "mem/mem_interface.hh" -//#include "mem/page_table.hh" -//#include "sim/debug.hh" -//#include "sim/sim_object.hh" - -/** - * Class that implements the actual LQ and SQ for each specific - * thread. Both are circular queues; load entries are freed upon - * committing, while store entries are freed once they writeback. The - * LSQUnit tracks if there are memory ordering violations, and also - * detects partial load to store forwarding cases (a store only has - * part of a load's data) that requires the load to wait until the - * store writes back. In the former case it holds onto the instruction - * until the dependence unit looks at it, and in the latter it stalls - * the LSQ until the store writes back. At that point the load is - * replayed. - */ -template <class Impl> -class LSQUnit { - protected: - typedef TheISA::IntReg IntReg; - public: - typedef typename Impl::Params Params; - typedef typename Impl::FullCPU FullCPU; - typedef typename Impl::DynInstPtr DynInstPtr; - typedef typename Impl::CPUPol::IEW IEW; - typedef typename Impl::CPUPol::IssueStruct IssueStruct; - - private: - class StoreCompletionEvent : public Event { - public: - /** Constructs a store completion event. */ - StoreCompletionEvent(int store_idx, Event *wb_event, LSQUnit *lsq_ptr); - - /** Processes the store completion event. */ - void process(); - - /** Returns the description of this event. */ - const char *description(); - - /** The writeback event for the store. Needed for store - * conditionals. - */ - Event *wbEvent; - - private: - /** The store index of the store being written back. */ - int storeIdx; - private: - /** The pointer to the LSQ unit that issued the store. */ - LSQUnit<Impl> *lsqPtr; - }; - - public: - /** Constructs an LSQ unit. init() must be called prior to use. */ - LSQUnit(); - - /** Initializes the LSQ unit with the specified number of entries. */ - void init(Params *params, unsigned maxLQEntries, - unsigned maxSQEntries, unsigned id); - - /** Returns the name of the LSQ unit. */ - std::string name() const; - - /** Sets the CPU pointer. */ - void setCPU(FullCPU *cpu_ptr) - { cpu = cpu_ptr; } - - /** Sets the IEW stage pointer. */ - void setIEW(IEW *iew_ptr) - { iewStage = iew_ptr; } - - /** Sets the page table pointer. */ -// void setPageTable(PageTable *pt_ptr); - - void switchOut(); - - void takeOverFrom(); - - bool isSwitchedOut() { return switchedOut; } - - /** Ticks the LSQ unit, which in this case only resets the number of - * used cache ports. - * @todo: Move the number of used ports up to the LSQ level so it can - * be shared by all LSQ units. - */ - void tick() { usedPorts = 0; } - - /** Inserts an instruction. */ - void insert(DynInstPtr &inst); - /** Inserts a load instruction. */ - void insertLoad(DynInstPtr &load_inst); - /** Inserts a store instruction. */ - void insertStore(DynInstPtr &store_inst); - - /** Executes a load instruction. */ - Fault executeLoad(DynInstPtr &inst); - - Fault executeLoad(int lq_idx) { panic("Not implemented"); return NoFault; } - /** Executes a store instruction. */ - Fault executeStore(DynInstPtr &inst); - - /** Commits the head load. */ - void commitLoad(); - /** Commits loads older than a specific sequence number. */ - void commitLoads(InstSeqNum &youngest_inst); - - /** Commits stores older than a specific sequence number. */ - void commitStores(InstSeqNum &youngest_inst); - - /** Writes back stores. */ - void writebackStores(); - - // @todo: Include stats in the LSQ unit. - //void regStats(); - - /** Clears all the entries in the LQ. */ - void clearLQ(); - - /** Clears all the entries in the SQ. */ - void clearSQ(); - - /** Resizes the LQ to a given size. */ - void resizeLQ(unsigned size); - - /** Resizes the SQ to a given size. */ - void resizeSQ(unsigned size); - - /** Squashes all instructions younger than a specific sequence number. */ - void squash(const InstSeqNum &squashed_num); - - /** Returns if there is a memory ordering violation. Value is reset upon - * call to getMemDepViolator(). - */ - bool violation() { return memDepViolator; } - - /** Returns the memory ordering violator. */ - DynInstPtr getMemDepViolator(); - - /** Returns if a load became blocked due to the memory system. */ - bool loadBlocked() - { return isLoadBlocked; } - - void clearLoadBlocked() - { isLoadBlocked = false; } - - bool isLoadBlockedHandled() - { return loadBlockedHandled; } - - void setLoadBlockedHandled() - { loadBlockedHandled = true; } - - /** Returns the number of free entries (min of free LQ and SQ entries). */ - unsigned numFreeEntries(); - - /** Returns the number of loads ready to execute. */ - int numLoadsReady(); - - /** Returns the number of loads in the LQ. */ - int numLoads() { return loads; } - - /** Returns the number of stores in the SQ. */ - int numStores() { return stores; } - - /** Returns if either the LQ or SQ is full. */ - bool isFull() { return lqFull() || sqFull(); } - - /** Returns if the LQ is full. */ - bool lqFull() { return loads >= (LQEntries - 1); } - - /** Returns if the SQ is full. */ - bool sqFull() { return stores >= (SQEntries - 1); } - - /** Returns the number of instructions in the LSQ. */ - unsigned getCount() { return loads + stores; } - - /** Returns if there are any stores to writeback. */ - bool hasStoresToWB() { return storesToWB; } - - /** Returns the number of stores to writeback. */ - int numStoresToWB() { return storesToWB; } - - /** Returns if the LSQ unit will writeback on this cycle. */ - bool willWB() { return storeQueue[storeWBIdx].canWB && - !storeQueue[storeWBIdx].completed && - !dcacheInterface->isBlocked(); } - - private: - /** Completes the store at the specified index. */ - void completeStore(int store_idx); - - /** Increments the given store index (circular queue). */ - inline void incrStIdx(int &store_idx); - /** Decrements the given store index (circular queue). */ - inline void decrStIdx(int &store_idx); - /** Increments the given load index (circular queue). */ - inline void incrLdIdx(int &load_idx); - /** Decrements the given load index (circular queue). */ - inline void decrLdIdx(int &load_idx); - - public: - /** Debugging function to dump instructions in the LSQ. */ - void dumpInsts(); - - private: - /** Pointer to the CPU. */ - FullCPU *cpu; - - /** Pointer to the IEW stage. */ - IEW *iewStage; - - /** Pointer to the D-cache. */ - MemInterface *dcacheInterface; - - /** Pointer to the page table. */ -// PageTable *pTable; - - public: - struct SQEntry { - /** Constructs an empty store queue entry. */ - SQEntry() - : inst(NULL), req(NULL), size(0), data(0), - canWB(0), committed(0), completed(0) - { } - - /** Constructs a store queue entry for a given instruction. */ - SQEntry(DynInstPtr &_inst) - : inst(_inst), req(NULL), size(0), data(0), - canWB(0), committed(0), completed(0) - { } - - /** The store instruction. */ - DynInstPtr inst; - /** The memory request for the store. */ - MemReqPtr req; - /** The size of the store. */ - int size; - /** The store data. */ - IntReg data; - /** Whether or not the store can writeback. */ - bool canWB; - /** Whether or not the store is committed. */ - bool committed; - /** Whether or not the store is completed. */ - bool completed; - }; - - private: - /** The LSQUnit thread id. */ - unsigned lsqID; - - /** The store queue. */ - std::vector<SQEntry> storeQueue; - - /** The load queue. */ - std::vector<DynInstPtr> loadQueue; - - /** The number of LQ entries, plus a sentinel entry (circular queue). - * @todo: Consider having var that records the true number of LQ entries. - */ - unsigned LQEntries; - /** The number of SQ entries, plus a sentinel entry (circular queue). - * @todo: Consider having var that records the true number of SQ entries. - */ - unsigned SQEntries; - - /** The number of load instructions in the LQ. */ - int loads; - /** The number of store instructions in the SQ. */ - int stores; - /** The number of store instructions in the SQ waiting to writeback. */ - int storesToWB; - - /** The index of the head instruction in the LQ. */ - int loadHead; - /** The index of the tail instruction in the LQ. */ - int loadTail; - - /** The index of the head instruction in the SQ. */ - int storeHead; - /** The index of the first instruction that may be ready to be - * written back, and has not yet been written back. - */ - int storeWBIdx; - /** The index of the tail instruction in the SQ. */ - int storeTail; - - /// @todo Consider moving to a more advanced model with write vs read ports - /** The number of cache ports available each cycle. */ - int cachePorts; - - /** The number of used cache ports in this cycle. */ - int usedPorts; - - bool switchedOut; - - //list<InstSeqNum> mshrSeqNums; - - /** Wire to read information from the issue stage time queue. */ - typename TimeBuffer<IssueStruct>::wire fromIssue; - - /** Whether or not the LSQ is stalled. */ - bool stalled; - /** The store that causes the stall due to partial store to load - * forwarding. - */ - InstSeqNum stallingStoreIsn; - /** The index of the above store. */ - int stallingLoadIdx; - - /** Whether or not a load is blocked due to the memory system. */ - bool isLoadBlocked; - - bool loadBlockedHandled; - - InstSeqNum blockedLoadSeqNum; - - /** The oldest load that caused a memory ordering violation. */ - DynInstPtr memDepViolator; - - // Will also need how many read/write ports the Dcache has. Or keep track - // of that in stage that is one level up, and only call executeLoad/Store - // the appropriate number of times. -/* - // total number of loads forwaded from LSQ stores - Stats::Vector<> lsq_forw_loads; - - // total number of loads ignored due to invalid addresses - Stats::Vector<> inv_addr_loads; - - // total number of software prefetches ignored due to invalid addresses - Stats::Vector<> inv_addr_swpfs; - - // total non-speculative bogus addresses seen (debug var) - Counter sim_invalid_addrs; - Stats::Vector<> fu_busy; //cumulative fu busy - - // ready loads blocked due to memory disambiguation - Stats::Vector<> lsq_blocked_loads; - - Stats::Scalar<> lsqInversion; -*/ - public: - /** Executes the load at the given index. */ - template <class T> - Fault read(MemReqPtr &req, T &data, int load_idx); - - /** Executes the store at the given index. */ - template <class T> - Fault write(MemReqPtr &req, T &data, int store_idx); - - /** Returns the index of the head load instruction. */ - int getLoadHead() { return loadHead; } - /** Returns the sequence number of the head load instruction. */ - InstSeqNum getLoadHeadSeqNum() - { - if (loadQueue[loadHead]) { - return loadQueue[loadHead]->seqNum; - } else { - return 0; - } - - } - - /** Returns the index of the head store instruction. */ - int getStoreHead() { return storeHead; } - /** Returns the sequence number of the head store instruction. */ - InstSeqNum getStoreHeadSeqNum() - { - if (storeQueue[storeHead].inst) { - return storeQueue[storeHead].inst->seqNum; - } else { - return 0; - } - - } - - /** Returns whether or not the LSQ unit is stalled. */ - bool isStalled() { return stalled; } -}; - -template <class Impl> -template <class T> -Fault -LSQUnit<Impl>::read(MemReqPtr &req, T &data, int load_idx) -{ - assert(loadQueue[load_idx]); - - assert(!loadQueue[load_idx]->isExecuted()); - - // Make sure this isn't an uncacheable access - // A bit of a hackish way to get uncached accesses to work only if they're - // at the head of the LSQ and are ready to commit (at the head of the ROB - // too). - if (req->flags & UNCACHEABLE && - (load_idx != loadHead || !loadQueue[load_idx]->reachedCommit)) { - iewStage->rescheduleMemInst(loadQueue[load_idx]); - return TheISA::genMachineCheckFault(); - } - - // Check the SQ for any previous stores that might lead to forwarding - int store_idx = loadQueue[load_idx]->sqIdx; - - int store_size = 0; - - DPRINTF(LSQUnit, "Read called, load idx: %i, store idx: %i, " - "storeHead: %i addr: %#x\n", - load_idx, store_idx, storeHead, req->paddr); - -#if 0 - if (req->flags & LOCKED) { - cpu->lockAddr = req->paddr; - cpu->lockFlag = true; - } -#endif - req->cmd = Read; - assert(!req->completionEvent); - req->completionEvent = NULL; - req->time = curTick; - - while (store_idx != -1) { - // End once we've reached the top of the LSQ - if (store_idx == storeWBIdx) { - break; - } - - // Move the index to one younger - if (--store_idx < 0) - store_idx += SQEntries; - - assert(storeQueue[store_idx].inst); - - store_size = storeQueue[store_idx].size; - - if (store_size == 0) - continue; - - // Check if the store data is within the lower and upper bounds of - // addresses that the request needs. - bool store_has_lower_limit = - req->vaddr >= storeQueue[store_idx].inst->effAddr; - bool store_has_upper_limit = - (req->vaddr + req->size) <= (storeQueue[store_idx].inst->effAddr + - store_size); - bool lower_load_has_store_part = - req->vaddr < (storeQueue[store_idx].inst->effAddr + - store_size); - bool upper_load_has_store_part = - (req->vaddr + req->size) > storeQueue[store_idx].inst->effAddr; - - // If the store's data has all of the data needed, we can forward. - if (store_has_lower_limit && store_has_upper_limit) { - // Get shift amount for offset into the store's data. - int shift_amt = req->vaddr & (store_size - 1); - // @todo: Magic number, assumes byte addressing - shift_amt = shift_amt << 3; - - // Cast this to type T? - data = storeQueue[store_idx].data >> shift_amt; - - assert(!req->data); - req->data = new uint8_t[64]; - - memcpy(req->data, &data, req->size); - - DPRINTF(LSQUnit, "Forwarding from store idx %i to load to " - "addr %#x, data %#x\n", - store_idx, req->vaddr, *(req->data)); - - typename IEW::LdWritebackEvent *wb = - new typename IEW::LdWritebackEvent(loadQueue[load_idx], - iewStage); - - // We'll say this has a 1 cycle load-store forwarding latency - // for now. - // @todo: Need to make this a parameter. - wb->schedule(curTick); - - // Should keep track of stat for forwarded data - return NoFault; - } else if ((store_has_lower_limit && lower_load_has_store_part) || - (store_has_upper_limit && upper_load_has_store_part) || - (lower_load_has_store_part && upper_load_has_store_part)) { - // This is the partial store-load forwarding case where a store - // has only part of the load's data. - - // If it's already been written back, then don't worry about - // stalling on it. - if (storeQueue[store_idx].completed) { - continue; - } - - // Must stall load and force it to retry, so long as it's the oldest - // load that needs to do so. - if (!stalled || - (stalled && - loadQueue[load_idx]->seqNum < - loadQueue[stallingLoadIdx]->seqNum)) { - stalled = true; - stallingStoreIsn = storeQueue[store_idx].inst->seqNum; - stallingLoadIdx = load_idx; - } - - // Tell IQ/mem dep unit that this instruction will need to be - // rescheduled eventually - iewStage->rescheduleMemInst(loadQueue[load_idx]); - - // Do not generate a writeback event as this instruction is not - // complete. - DPRINTF(LSQUnit, "Load-store forwarding mis-match. " - "Store idx %i to load addr %#x\n", - store_idx, req->vaddr); - - return NoFault; - } - } - - // If there's no forwarding case, then go access memory - DynInstPtr inst = loadQueue[load_idx]; - - DPRINTF(LSQUnit, "Doing functional access for inst [sn:%lli] PC %#x\n", - loadQueue[load_idx]->seqNum, loadQueue[load_idx]->readPC()); - - assert(!req->data); - req->data = new uint8_t[64]; - Fault fault = cpu->read(req, data); - memcpy(req->data, &data, sizeof(T)); - - ++usedPorts; - - // if we have a cache, do cache access too - if (fault == NoFault && dcacheInterface) { - if (dcacheInterface->isBlocked()) { - // There's an older load that's already going to squash. - if (isLoadBlocked && blockedLoadSeqNum < inst->seqNum) - return NoFault; - - // Record that the load was blocked due to memory. This - // load will squash all instructions after it, be - // refetched, and re-executed. - isLoadBlocked = true; - loadBlockedHandled = false; - blockedLoadSeqNum = inst->seqNum; - // No fault occurred, even though the interface is blocked. - return NoFault; - } - - DPRINTF(LSQUnit, "Doing timing access for inst PC %#x\n", - loadQueue[load_idx]->readPC()); - - assert(!req->completionEvent); - req->completionEvent = - new typename IEW::LdWritebackEvent(loadQueue[load_idx], iewStage); - MemAccessResult result = dcacheInterface->access(req); - - assert(dcacheInterface->doEvents()); - - if (result != MA_HIT) { - DPRINTF(LSQUnit, "LSQUnit: D-cache miss!\n"); - DPRINTF(Activity, "Activity: ld accessing mem miss [sn:%lli]\n", - inst->seqNum); - } else { - DPRINTF(LSQUnit, "LSQUnit: D-cache hit!\n"); - DPRINTF(Activity, "Activity: ld accessing mem hit [sn:%lli]\n", - inst->seqNum); - } - } - - return fault; -} - -template <class Impl> -template <class T> -Fault -LSQUnit<Impl>::write(MemReqPtr &req, T &data, int store_idx) -{ - assert(storeQueue[store_idx].inst); - - DPRINTF(LSQUnit, "Doing write to store idx %i, addr %#x data %#x" - " | storeHead:%i [sn:%i]\n", - store_idx, req->paddr, data, storeHead, - storeQueue[store_idx].inst->seqNum); - - storeQueue[store_idx].req = req; - storeQueue[store_idx].size = sizeof(T); - storeQueue[store_idx].data = data; - - // This function only writes the data to the store queue, so no fault - // can happen here. - return NoFault; -} - -#endif // __CPU_O3_LSQ_UNIT_HH__ diff --git a/cpu/o3/lsq_unit_impl.hh b/cpu/o3/lsq_unit_impl.hh deleted file mode 100644 index 7974ddaad..000000000 --- a/cpu/o3/lsq_unit_impl.hh +++ /dev/null @@ -1,873 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/checker/cpu.hh" -#include "cpu/o3/lsq_unit.hh" -#include "base/str.hh" - -template <class Impl> -LSQUnit<Impl>::StoreCompletionEvent::StoreCompletionEvent(int store_idx, - Event *wb_event, - LSQUnit<Impl> *lsq_ptr) - : Event(&mainEventQueue), - wbEvent(wb_event), - storeIdx(store_idx), - lsqPtr(lsq_ptr) -{ - this->setFlags(Event::AutoDelete); -} - -template <class Impl> -void -LSQUnit<Impl>::StoreCompletionEvent::process() -{ - DPRINTF(LSQ, "Cache miss complete for store idx:%i\n", storeIdx); - DPRINTF(Activity, "Activity: st writeback event idx:%i\n", storeIdx); - - //lsqPtr->removeMSHR(lsqPtr->storeQueue[storeIdx].inst->seqNum); - - if (lsqPtr->isSwitchedOut()) - return; - - lsqPtr->cpu->wakeCPU(); - if (wbEvent) - wbEvent->process(); - lsqPtr->completeStore(storeIdx); -} - -template <class Impl> -const char * -LSQUnit<Impl>::StoreCompletionEvent::description() -{ - return "LSQ store completion event"; -} - -template <class Impl> -LSQUnit<Impl>::LSQUnit() - : loads(0), stores(0), storesToWB(0), stalled(false), isLoadBlocked(false), - loadBlockedHandled(false) -{ -} - -template<class Impl> -void -LSQUnit<Impl>::init(Params *params, unsigned maxLQEntries, - unsigned maxSQEntries, unsigned id) - -{ - DPRINTF(LSQUnit, "Creating LSQUnit%i object.\n",id); - - switchedOut = false; - - lsqID = id; - - // Add 1 for the sentinel entry (they are circular queues). - LQEntries = maxLQEntries + 1; - SQEntries = maxSQEntries + 1; - - loadQueue.resize(LQEntries); - storeQueue.resize(SQEntries); - - loadHead = loadTail = 0; - - storeHead = storeWBIdx = storeTail = 0; - - usedPorts = 0; - cachePorts = params->cachePorts; - - dcacheInterface = params->dcacheInterface; - - memDepViolator = NULL; - - blockedLoadSeqNum = 0; -} - -template<class Impl> -std::string -LSQUnit<Impl>::name() const -{ - if (Impl::MaxThreads == 1) { - return iewStage->name() + ".lsq"; - } else { - return iewStage->name() + ".lsq.thread." + to_string(lsqID); - } -} - -template<class Impl> -void -LSQUnit<Impl>::clearLQ() -{ - loadQueue.clear(); -} - -template<class Impl> -void -LSQUnit<Impl>::clearSQ() -{ - storeQueue.clear(); -} - -#if 0 -template<class Impl> -void -LSQUnit<Impl>::setPageTable(PageTable *pt_ptr) -{ - DPRINTF(LSQUnit, "Setting the page table pointer.\n"); - pTable = pt_ptr; -} -#endif - -template<class Impl> -void -LSQUnit<Impl>::switchOut() -{ - switchedOut = true; - for (int i = 0; i < loadQueue.size(); ++i) - loadQueue[i] = NULL; - - assert(storesToWB == 0); - - while (storesToWB > 0 && - storeWBIdx != storeTail && - storeQueue[storeWBIdx].inst && - storeQueue[storeWBIdx].canWB) { - - if (storeQueue[storeWBIdx].size == 0 || - storeQueue[storeWBIdx].inst->isDataPrefetch() || - storeQueue[storeWBIdx].committed || - storeQueue[storeWBIdx].req->flags & LOCKED) { - incrStIdx(storeWBIdx); - - continue; - } - - assert(storeQueue[storeWBIdx].req); - assert(!storeQueue[storeWBIdx].committed); - - MemReqPtr req = storeQueue[storeWBIdx].req; - storeQueue[storeWBIdx].committed = true; - - req->cmd = Write; - req->completionEvent = NULL; - req->time = curTick; - assert(!req->data); - req->data = new uint8_t[64]; - memcpy(req->data, (uint8_t *)&storeQueue[storeWBIdx].data, req->size); - - DPRINTF(LSQUnit, "D-Cache: Writing back store idx:%i PC:%#x " - "to Addr:%#x, data:%#x [sn:%lli]\n", - storeWBIdx,storeQueue[storeWBIdx].inst->readPC(), - req->paddr, *(req->data), - storeQueue[storeWBIdx].inst->seqNum); - - switch(storeQueue[storeWBIdx].size) { - case 1: - cpu->write(req, (uint8_t &)storeQueue[storeWBIdx].data); - break; - case 2: - cpu->write(req, (uint16_t &)storeQueue[storeWBIdx].data); - break; - case 4: - cpu->write(req, (uint32_t &)storeQueue[storeWBIdx].data); - break; - case 8: - cpu->write(req, (uint64_t &)storeQueue[storeWBIdx].data); - break; - default: - panic("Unexpected store size!\n"); - } - incrStIdx(storeWBIdx); - } -} - -template<class Impl> -void -LSQUnit<Impl>::takeOverFrom() -{ - switchedOut = false; - loads = stores = storesToWB = 0; - - loadHead = loadTail = 0; - - storeHead = storeWBIdx = storeTail = 0; - - usedPorts = 0; - - memDepViolator = NULL; - - blockedLoadSeqNum = 0; - - stalled = false; - isLoadBlocked = false; - loadBlockedHandled = false; -} - -template<class Impl> -void -LSQUnit<Impl>::resizeLQ(unsigned size) -{ - unsigned size_plus_sentinel = size + 1; - assert(size_plus_sentinel >= LQEntries); - - if (size_plus_sentinel > LQEntries) { - while (size_plus_sentinel > loadQueue.size()) { - DynInstPtr dummy; - loadQueue.push_back(dummy); - LQEntries++; - } - } else { - LQEntries = size_plus_sentinel; - } - -} - -template<class Impl> -void -LSQUnit<Impl>::resizeSQ(unsigned size) -{ - unsigned size_plus_sentinel = size + 1; - if (size_plus_sentinel > SQEntries) { - while (size_plus_sentinel > storeQueue.size()) { - SQEntry dummy; - storeQueue.push_back(dummy); - SQEntries++; - } - } else { - SQEntries = size_plus_sentinel; - } -} - -template <class Impl> -void -LSQUnit<Impl>::insert(DynInstPtr &inst) -{ - assert(inst->isMemRef()); - - assert(inst->isLoad() || inst->isStore()); - - if (inst->isLoad()) { - insertLoad(inst); - } else { - insertStore(inst); - } - - inst->setInLSQ(); -} - -template <class Impl> -void -LSQUnit<Impl>::insertLoad(DynInstPtr &load_inst) -{ - assert((loadTail + 1) % LQEntries != loadHead); - assert(loads < LQEntries); - - DPRINTF(LSQUnit, "Inserting load PC %#x, idx:%i [sn:%lli]\n", - load_inst->readPC(), loadTail, load_inst->seqNum); - - load_inst->lqIdx = loadTail; - - if (stores == 0) { - load_inst->sqIdx = -1; - } else { - load_inst->sqIdx = storeTail; - } - - loadQueue[loadTail] = load_inst; - - incrLdIdx(loadTail); - - ++loads; -} - -template <class Impl> -void -LSQUnit<Impl>::insertStore(DynInstPtr &store_inst) -{ - // Make sure it is not full before inserting an instruction. - assert((storeTail + 1) % SQEntries != storeHead); - assert(stores < SQEntries); - - DPRINTF(LSQUnit, "Inserting store PC %#x, idx:%i [sn:%lli]\n", - store_inst->readPC(), storeTail, store_inst->seqNum); - - store_inst->sqIdx = storeTail; - store_inst->lqIdx = loadTail; - - storeQueue[storeTail] = SQEntry(store_inst); - - incrStIdx(storeTail); - - ++stores; -} - -template <class Impl> -typename Impl::DynInstPtr -LSQUnit<Impl>::getMemDepViolator() -{ - DynInstPtr temp = memDepViolator; - - memDepViolator = NULL; - - return temp; -} - -template <class Impl> -unsigned -LSQUnit<Impl>::numFreeEntries() -{ - unsigned free_lq_entries = LQEntries - loads; - unsigned free_sq_entries = SQEntries - stores; - - // Both the LQ and SQ entries have an extra dummy entry to differentiate - // empty/full conditions. Subtract 1 from the free entries. - if (free_lq_entries < free_sq_entries) { - return free_lq_entries - 1; - } else { - return free_sq_entries - 1; - } -} - -template <class Impl> -int -LSQUnit<Impl>::numLoadsReady() -{ - int load_idx = loadHead; - int retval = 0; - - while (load_idx != loadTail) { - assert(loadQueue[load_idx]); - - if (loadQueue[load_idx]->readyToIssue()) { - ++retval; - } - } - - return retval; -} - -template <class Impl> -Fault -LSQUnit<Impl>::executeLoad(DynInstPtr &inst) -{ - // Execute a specific load. - Fault load_fault = NoFault; - - DPRINTF(LSQUnit, "Executing load PC %#x, [sn:%lli]\n", - inst->readPC(),inst->seqNum); - -// load_fault = inst->initiateAcc(); - load_fault = inst->execute(); - - // If the instruction faulted, then we need to send it along to commit - // without the instruction completing. - if (load_fault != NoFault) { - // Send this instruction to commit, also make sure iew stage - // realizes there is activity. - iewStage->instToCommit(inst); - iewStage->activityThisCycle(); - } - - return load_fault; -} - -template <class Impl> -Fault -LSQUnit<Impl>::executeStore(DynInstPtr &store_inst) -{ - using namespace TheISA; - // Make sure that a store exists. - assert(stores != 0); - - int store_idx = store_inst->sqIdx; - - DPRINTF(LSQUnit, "Executing store PC %#x [sn:%lli]\n", - store_inst->readPC(), store_inst->seqNum); - - // Check the recently completed loads to see if any match this store's - // address. If so, then we have a memory ordering violation. - int load_idx = store_inst->lqIdx; - - Fault store_fault = store_inst->initiateAcc(); -// Fault store_fault = store_inst->execute(); - - if (storeQueue[store_idx].size == 0) { - DPRINTF(LSQUnit,"Fault on Store PC %#x, [sn:%lli],Size = 0\n", - store_inst->readPC(),store_inst->seqNum); - - return store_fault; - } - - assert(store_fault == NoFault); - - if (store_inst->isStoreConditional()) { - // Store conditionals need to set themselves as able to - // writeback if we haven't had a fault by here. - storeQueue[store_idx].canWB = true; - - ++storesToWB; - } - - if (!memDepViolator) { - while (load_idx != loadTail) { - // Really only need to check loads that have actually executed - // It's safe to check all loads because effAddr is set to - // InvalAddr when the dyn inst is created. - - // @todo: For now this is extra conservative, detecting a - // violation if the addresses match assuming all accesses - // are quad word accesses. - - // @todo: Fix this, magic number being used here - if ((loadQueue[load_idx]->effAddr >> 8) == - (store_inst->effAddr >> 8)) { - // A load incorrectly passed this store. Squash and refetch. - // For now return a fault to show that it was unsuccessful. - memDepViolator = loadQueue[load_idx]; - - return genMachineCheckFault(); - } - - incrLdIdx(load_idx); - } - - // If we've reached this point, there was no violation. - memDepViolator = NULL; - } - - return store_fault; -} - -template <class Impl> -void -LSQUnit<Impl>::commitLoad() -{ - assert(loadQueue[loadHead]); - - DPRINTF(LSQUnit, "Committing head load instruction, PC %#x\n", - loadQueue[loadHead]->readPC()); - - - loadQueue[loadHead] = NULL; - - incrLdIdx(loadHead); - - --loads; -} - -template <class Impl> -void -LSQUnit<Impl>::commitLoads(InstSeqNum &youngest_inst) -{ - assert(loads == 0 || loadQueue[loadHead]); - - while (loads != 0 && loadQueue[loadHead]->seqNum <= youngest_inst) { - commitLoad(); - } -} - -template <class Impl> -void -LSQUnit<Impl>::commitStores(InstSeqNum &youngest_inst) -{ - assert(stores == 0 || storeQueue[storeHead].inst); - - int store_idx = storeHead; - - while (store_idx != storeTail) { - assert(storeQueue[store_idx].inst); - // Mark any stores that are now committed and have not yet - // been marked as able to write back. - if (!storeQueue[store_idx].canWB) { - if (storeQueue[store_idx].inst->seqNum > youngest_inst) { - break; - } - DPRINTF(LSQUnit, "Marking store as able to write back, PC " - "%#x [sn:%lli]\n", - storeQueue[store_idx].inst->readPC(), - storeQueue[store_idx].inst->seqNum); - - storeQueue[store_idx].canWB = true; - - ++storesToWB; - } - - incrStIdx(store_idx); - } -} - -template <class Impl> -void -LSQUnit<Impl>::writebackStores() -{ - while (storesToWB > 0 && - storeWBIdx != storeTail && - storeQueue[storeWBIdx].inst && - storeQueue[storeWBIdx].canWB && - usedPorts < cachePorts) { - - // Store didn't write any data so no need to write it back to - // memory. - if (storeQueue[storeWBIdx].size == 0) { - completeStore(storeWBIdx); - - incrStIdx(storeWBIdx); - - continue; - } - - if (dcacheInterface && dcacheInterface->isBlocked()) { - DPRINTF(LSQUnit, "Unable to write back any more stores, cache" - " is blocked!\n"); - break; - } - - ++usedPorts; - - if (storeQueue[storeWBIdx].inst->isDataPrefetch()) { - incrStIdx(storeWBIdx); - - continue; - } - - assert(storeQueue[storeWBIdx].req); - assert(!storeQueue[storeWBIdx].committed); - - MemReqPtr req = storeQueue[storeWBIdx].req; - storeQueue[storeWBIdx].committed = true; - - req->cmd = Write; - req->completionEvent = NULL; - req->time = curTick; - assert(!req->data); - req->data = new uint8_t[64]; - memcpy(req->data, (uint8_t *)&storeQueue[storeWBIdx].data, req->size); - - DPRINTF(LSQUnit, "D-Cache: Writing back store idx:%i PC:%#x " - "to Addr:%#x, data:%#x [sn:%lli]\n", - storeWBIdx,storeQueue[storeWBIdx].inst->readPC(), - req->paddr, *(req->data), - storeQueue[storeWBIdx].inst->seqNum); - - switch(storeQueue[storeWBIdx].size) { - case 1: - cpu->write(req, (uint8_t &)storeQueue[storeWBIdx].data); - break; - case 2: - cpu->write(req, (uint16_t &)storeQueue[storeWBIdx].data); - break; - case 4: - cpu->write(req, (uint32_t &)storeQueue[storeWBIdx].data); - break; - case 8: - cpu->write(req, (uint64_t &)storeQueue[storeWBIdx].data); - break; - default: - panic("Unexpected store size!\n"); - } - - // Stores other than store conditionals are completed at this - // time. Mark them as completed and, if we have a checker, - // tell it that the instruction is completed. - // @todo: Figure out what time I can say stores are complete in - // the timing memory. - if (!(req->flags & LOCKED)) { - storeQueue[storeWBIdx].inst->setCompleted(); - if (cpu->checker) { - cpu->checker->tick(storeQueue[storeWBIdx].inst); - } - } - - if (dcacheInterface) { - assert(!req->completionEvent); - StoreCompletionEvent *store_event = new - StoreCompletionEvent(storeWBIdx, NULL, this); - req->completionEvent = store_event; - - MemAccessResult result = dcacheInterface->access(req); - - if (isStalled() && - storeQueue[storeWBIdx].inst->seqNum == stallingStoreIsn) { - DPRINTF(LSQUnit, "Unstalling, stalling store [sn:%lli] " - "load idx:%i\n", - stallingStoreIsn, stallingLoadIdx); - stalled = false; - stallingStoreIsn = 0; - iewStage->replayMemInst(loadQueue[stallingLoadIdx]); - } - - typename IEW::LdWritebackEvent *wb = NULL; - if (req->flags & LOCKED) { - // Stx_C should not generate a system port transaction - // if it misses in the cache, but that might be hard - // to accomplish without explicit cache support. - wb = new typename - IEW::LdWritebackEvent(storeQueue[storeWBIdx].inst, - iewStage); - store_event->wbEvent = wb; - } - - if (result != MA_HIT && dcacheInterface->doEvents()) { - DPRINTF(LSQUnit,"D-Cache Write Miss on idx:%i!\n", - storeWBIdx); - - DPRINTF(Activity, "Active st accessing mem miss [sn:%lli]\n", - storeQueue[storeWBIdx].inst->seqNum); - - //mshrSeqNums.push_back(storeQueue[storeWBIdx].inst->seqNum); - - //DPRINTF(LSQUnit, "Added MSHR. count = %i\n",mshrSeqNums.size()); - - // @todo: Increment stat here. - } else { - DPRINTF(LSQUnit,"D-Cache: Write Hit on idx:%i !\n", - storeWBIdx); - - DPRINTF(Activity, "Active st accessing mem hit [sn:%lli]\n", - storeQueue[storeWBIdx].inst->seqNum); - } - - incrStIdx(storeWBIdx); - } else { - panic("Must HAVE DCACHE!!!!!\n"); - } - } - - // Not sure this should set it to 0. - usedPorts = 0; - - assert(stores >= 0 && storesToWB >= 0); -} - -/*template <class Impl> -void -LSQUnit<Impl>::removeMSHR(InstSeqNum seqNum) -{ - list<InstSeqNum>::iterator mshr_it = find(mshrSeqNums.begin(), - mshrSeqNums.end(), - seqNum); - - if (mshr_it != mshrSeqNums.end()) { - mshrSeqNums.erase(mshr_it); - DPRINTF(LSQUnit, "Removing MSHR. count = %i\n",mshrSeqNums.size()); - } -}*/ - -template <class Impl> -void -LSQUnit<Impl>::squash(const InstSeqNum &squashed_num) -{ - DPRINTF(LSQUnit, "Squashing until [sn:%lli]!" - "(Loads:%i Stores:%i)\n", squashed_num, loads, stores); - - int load_idx = loadTail; - decrLdIdx(load_idx); - - while (loads != 0 && loadQueue[load_idx]->seqNum > squashed_num) { - DPRINTF(LSQUnit,"Load Instruction PC %#x squashed, " - "[sn:%lli]\n", - loadQueue[load_idx]->readPC(), - loadQueue[load_idx]->seqNum); - - if (isStalled() && load_idx == stallingLoadIdx) { - stalled = false; - stallingStoreIsn = 0; - stallingLoadIdx = 0; - } - - // Clear the smart pointer to make sure it is decremented. - loadQueue[load_idx]->squashed = true; - loadQueue[load_idx] = NULL; - --loads; - - // Inefficient! - loadTail = load_idx; - - decrLdIdx(load_idx); - } - - if (isLoadBlocked) { - if (squashed_num < blockedLoadSeqNum) { - isLoadBlocked = false; - loadBlockedHandled = false; - blockedLoadSeqNum = 0; - } - } - - int store_idx = storeTail; - decrStIdx(store_idx); - - while (stores != 0 && - storeQueue[store_idx].inst->seqNum > squashed_num) { - // Instructions marked as can WB are already committed. - if (storeQueue[store_idx].canWB) { - break; - } - - DPRINTF(LSQUnit,"Store Instruction PC %#x squashed, " - "idx:%i [sn:%lli]\n", - storeQueue[store_idx].inst->readPC(), - store_idx, storeQueue[store_idx].inst->seqNum); - - // I don't think this can happen. It should have been cleared - // by the stalling load. - if (isStalled() && - storeQueue[store_idx].inst->seqNum == stallingStoreIsn) { - panic("Is stalled should have been cleared by stalling load!\n"); - stalled = false; - stallingStoreIsn = 0; - } - - // Clear the smart pointer to make sure it is decremented. - storeQueue[store_idx].inst->squashed = true; - storeQueue[store_idx].inst = NULL; - storeQueue[store_idx].canWB = 0; - - if (storeQueue[store_idx].req) { - // There should not be a completion event if the store has - // not yet committed. - assert(!storeQueue[store_idx].req->completionEvent); - } - - storeQueue[store_idx].req = NULL; - --stores; - - // Inefficient! - storeTail = store_idx; - - decrStIdx(store_idx); - } -} - -template <class Impl> -void -LSQUnit<Impl>::completeStore(int store_idx) -{ - assert(storeQueue[store_idx].inst); - storeQueue[store_idx].completed = true; - --storesToWB; - // A bit conservative because a store completion may not free up entries, - // but hopefully avoids two store completions in one cycle from making - // the CPU tick twice. - cpu->activityThisCycle(); - - if (store_idx == storeHead) { - do { - incrStIdx(storeHead); - - --stores; - } while (storeQueue[storeHead].completed && - storeHead != storeTail); - - iewStage->updateLSQNextCycle = true; - } - - DPRINTF(LSQUnit, "Completing store [sn:%lli], idx:%i, store head " - "idx:%i\n", - storeQueue[store_idx].inst->seqNum, store_idx, storeHead); - - if (isStalled() && - storeQueue[store_idx].inst->seqNum == stallingStoreIsn) { - DPRINTF(LSQUnit, "Unstalling, stalling store [sn:%lli] " - "load idx:%i\n", - stallingStoreIsn, stallingLoadIdx); - stalled = false; - stallingStoreIsn = 0; - iewStage->replayMemInst(loadQueue[stallingLoadIdx]); - } - - storeQueue[store_idx].inst->setCompleted(); - - // Tell the checker we've completed this instruction. Some stores - // may get reported twice to the checker, but the checker can - // handle that case. - if (cpu->checker) { - cpu->checker->tick(storeQueue[store_idx].inst); - } -} - -template <class Impl> -inline void -LSQUnit<Impl>::incrStIdx(int &store_idx) -{ - if (++store_idx >= SQEntries) - store_idx = 0; -} - -template <class Impl> -inline void -LSQUnit<Impl>::decrStIdx(int &store_idx) -{ - if (--store_idx < 0) - store_idx += SQEntries; -} - -template <class Impl> -inline void -LSQUnit<Impl>::incrLdIdx(int &load_idx) -{ - if (++load_idx >= LQEntries) - load_idx = 0; -} - -template <class Impl> -inline void -LSQUnit<Impl>::decrLdIdx(int &load_idx) -{ - if (--load_idx < 0) - load_idx += LQEntries; -} - -template <class Impl> -void -LSQUnit<Impl>::dumpInsts() -{ - cprintf("Load store queue: Dumping instructions.\n"); - cprintf("Load queue size: %i\n", loads); - cprintf("Load queue: "); - - int load_idx = loadHead; - - while (load_idx != loadTail && loadQueue[load_idx]) { - cprintf("%#x ", loadQueue[load_idx]->readPC()); - - incrLdIdx(load_idx); - } - - cprintf("Store queue size: %i\n", stores); - cprintf("Store queue: "); - - int store_idx = storeHead; - - while (store_idx != storeTail && storeQueue[store_idx].inst) { - cprintf("%#x ", storeQueue[store_idx].inst->readPC()); - - incrStIdx(store_idx); - } - - cprintf("\n"); -} diff --git a/cpu/o3/mem_dep_unit.cc b/cpu/o3/mem_dep_unit.cc deleted file mode 100644 index ccdd1a515..000000000 --- a/cpu/o3/mem_dep_unit.cc +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/o3/alpha_dyn_inst.hh" -#include "cpu/o3/alpha_impl.hh" -#include "cpu/o3/store_set.hh" -#include "cpu/o3/mem_dep_unit_impl.hh" - -// Force instantation of memory dependency unit using store sets and -// AlphaSimpleImpl. -template class MemDepUnit<StoreSet, AlphaSimpleImpl>; - -template <> -int -MemDepUnit<StoreSet, AlphaSimpleImpl>::MemDepEntry::memdep_count = 0; -template <> -int -MemDepUnit<StoreSet, AlphaSimpleImpl>::MemDepEntry::memdep_insert = 0; -template <> -int -MemDepUnit<StoreSet, AlphaSimpleImpl>::MemDepEntry::memdep_erase = 0; diff --git a/cpu/o3/mem_dep_unit.hh b/cpu/o3/mem_dep_unit.hh deleted file mode 100644 index acbe08ec2..000000000 --- a/cpu/o3/mem_dep_unit.hh +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_MEM_DEP_UNIT_HH__ -#define __CPU_O3_MEM_DEP_UNIT_HH__ - -#include <list> -#include <set> - -#include "base/hashmap.hh" -#include "base/refcnt.hh" -#include "base/statistics.hh" -#include "cpu/inst_seq.hh" - -struct SNHash { - size_t operator() (const InstSeqNum &seq_num) const { - unsigned a = (unsigned)seq_num; - unsigned hash = (((a >> 14) ^ ((a >> 2) & 0xffff))) & 0x7FFFFFFF; - - return hash; - } -}; - -template <class Impl> -class InstructionQueue; - -/** - * Memory dependency unit class. This holds the memory dependence predictor. - * As memory operations are issued to the IQ, they are also issued to this - * unit, which then looks up the prediction as to what they are dependent - * upon. This unit must be checked prior to a memory operation being able - * to issue. Although this is templated, it's somewhat hard to make a generic - * memory dependence unit. This one is mostly for store sets; it will be - * quite limited in what other memory dependence predictions it can also - * utilize. Thus this class should be most likely be rewritten for other - * dependence prediction schemes. - */ -template <class MemDepPred, class Impl> -class MemDepUnit { - public: - typedef typename Impl::Params Params; - typedef typename Impl::DynInstPtr DynInstPtr; - - /** Empty constructor. Must call init() prior to using in this case. */ - MemDepUnit() {} - - /** Constructs a MemDepUnit with given parameters. */ - MemDepUnit(Params *params); - - /** Frees up any memory allocated. */ - ~MemDepUnit(); - - /** Returns the name of the memory dependence unit. */ - std::string name() const; - - /** Initializes the unit with parameters and a thread id. */ - void init(Params *params, int tid); - - /** Registers statistics. */ - void regStats(); - - void switchOut(); - - void takeOverFrom(); - - /** Sets the pointer to the IQ. */ - void setIQ(InstructionQueue<Impl> *iq_ptr); - - /** Inserts a memory instruction. */ - void insert(DynInstPtr &inst); - - /** Inserts a non-speculative memory instruction. */ - void insertNonSpec(DynInstPtr &inst); - - /** Inserts a barrier instruction. */ - void insertBarrier(DynInstPtr &barr_inst); - - /** Indicate that an instruction has its registers ready. */ - void regsReady(DynInstPtr &inst); - - /** Indicate that a non-speculative instruction is ready. */ - void nonSpecInstReady(DynInstPtr &inst); - - /** Reschedules an instruction to be re-executed. */ - void reschedule(DynInstPtr &inst); - - /** Replays all instructions that have been rescheduled by moving them to - * the ready list. - */ - void replay(DynInstPtr &inst); - - /** Completes a memory instruction. */ - void completed(DynInstPtr &inst); - - /** Completes a barrier instruction. */ - void completeBarrier(DynInstPtr &inst); - - /** Wakes any dependents of a memory instruction. */ - void wakeDependents(DynInstPtr &inst); - - /** Squashes all instructions up until a given sequence number for a - * specific thread. - */ - void squash(const InstSeqNum &squashed_num, unsigned tid); - - /** Indicates an ordering violation between a store and a younger load. */ - void violation(DynInstPtr &store_inst, DynInstPtr &violating_load); - - /** Issues the given instruction */ - void issue(DynInstPtr &inst); - - /** Debugging function to dump the lists of instructions. */ - void dumpLists(); - - private: - typedef typename std::list<DynInstPtr>::iterator ListIt; - - class MemDepEntry; - - typedef RefCountingPtr<MemDepEntry> MemDepEntryPtr; - - /** Memory dependence entries that track memory operations, marking - * when the instruction is ready to execute and what instructions depend - * upon it. - */ - class MemDepEntry : public RefCounted { - public: - /** Constructs a memory dependence entry. */ - MemDepEntry(DynInstPtr &new_inst) - : inst(new_inst), regsReady(false), memDepReady(false), - completed(false), squashed(false) - { - ++memdep_count; - - DPRINTF(MemDepUnit, "Memory dependency entry created. " - "memdep_count=%i\n", memdep_count); - } - - /** Frees any pointers. */ - ~MemDepEntry() - { - for (int i = 0; i < dependInsts.size(); ++i) { - dependInsts[i] = NULL; - } - - --memdep_count; - - DPRINTF(MemDepUnit, "Memory dependency entry deleted. " - "memdep_count=%i\n", memdep_count); - } - - /** Returns the name of the memory dependence entry. */ - std::string name() const { return "memdepentry"; } - - /** The instruction being tracked. */ - DynInstPtr inst; - - /** The iterator to the instruction's location inside the list. */ - ListIt listIt; - - /** A vector of any dependent instructions. */ - std::vector<MemDepEntryPtr> dependInsts; - - /** If the registers are ready or not. */ - bool regsReady; - /** If all memory dependencies have been satisfied. */ - bool memDepReady; - /** If the instruction is completed. */ - bool completed; - /** If the instruction is squashed. */ - bool squashed; - - /** For debugging. */ - static int memdep_count; - static int memdep_insert; - static int memdep_erase; - }; - - /** Finds the memory dependence entry in the hash map. */ - inline MemDepEntryPtr &findInHash(const DynInstPtr &inst); - - /** Moves an entry to the ready list. */ - inline void moveToReady(MemDepEntryPtr &ready_inst_entry); - - typedef m5::hash_map<InstSeqNum, MemDepEntryPtr, SNHash> MemDepHash; - - typedef typename MemDepHash::iterator MemDepHashIt; - - /** A hash map of all memory dependence entries. */ - MemDepHash memDepHash; - - /** A list of all instructions in the memory dependence unit. */ - std::list<DynInstPtr> instList[Impl::MaxThreads]; - - /** A list of all instructions that are going to be replayed. */ - std::list<DynInstPtr> instsToReplay; - - /** The memory dependence predictor. It is accessed upon new - * instructions being added to the IQ, and responds by telling - * this unit what instruction the newly added instruction is dependent - * upon. - */ - MemDepPred depPred; - - bool loadBarrier; - InstSeqNum loadBarrierSN; - bool storeBarrier; - InstSeqNum storeBarrierSN; - - /** Pointer to the IQ. */ - InstructionQueue<Impl> *iqPtr; - - /** The thread id of this memory dependence unit. */ - int id; - - /** Stat for number of inserted loads. */ - Stats::Scalar<> insertedLoads; - /** Stat for number of inserted stores. */ - Stats::Scalar<> insertedStores; - /** Stat for number of conflicting loads that had to wait for a store. */ - Stats::Scalar<> conflictingLoads; - /** Stat for number of conflicting stores that had to wait for a store. */ - Stats::Scalar<> conflictingStores; -}; - -#endif // __CPU_O3_MEM_DEP_UNIT_HH__ diff --git a/cpu/o3/mem_dep_unit_impl.hh b/cpu/o3/mem_dep_unit_impl.hh deleted file mode 100644 index 8b195baab..000000000 --- a/cpu/o3/mem_dep_unit_impl.hh +++ /dev/null @@ -1,551 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <map> - -#include "cpu/o3/inst_queue.hh" -#include "cpu/o3/mem_dep_unit.hh" - -template <class MemDepPred, class Impl> -MemDepUnit<MemDepPred, Impl>::MemDepUnit(Params *params) - : depPred(params->SSITSize, params->LFSTSize), loadBarrier(false), - loadBarrierSN(0), storeBarrier(false), storeBarrierSN(0), iqPtr(NULL) -{ - DPRINTF(MemDepUnit, "Creating MemDepUnit object.\n"); -} - -template <class MemDepPred, class Impl> -MemDepUnit<MemDepPred, Impl>::~MemDepUnit() -{ - for (int tid=0; tid < Impl::MaxThreads; tid++) { - - ListIt inst_list_it = instList[tid].begin(); - - MemDepHashIt hash_it; - - while (!instList[tid].empty()) { - hash_it = memDepHash.find((*inst_list_it)->seqNum); - - assert(hash_it != memDepHash.end()); - - memDepHash.erase(hash_it); - - instList[tid].erase(inst_list_it++); - } - } - - assert(MemDepEntry::memdep_count == 0); -} - -template <class MemDepPred, class Impl> -std::string -MemDepUnit<MemDepPred, Impl>::name() const -{ - return "memdepunit"; -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::init(Params *params, int tid) -{ - DPRINTF(MemDepUnit, "Creating MemDepUnit %i object.\n",tid); - - id = tid; - - depPred.init(params->SSITSize, params->LFSTSize); -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::regStats() -{ - insertedLoads - .name(name() + ".memDep.insertedLoads") - .desc("Number of loads inserted to the mem dependence unit."); - - insertedStores - .name(name() + ".memDep.insertedStores") - .desc("Number of stores inserted to the mem dependence unit."); - - conflictingLoads - .name(name() + ".memDep.conflictingLoads") - .desc("Number of conflicting loads."); - - conflictingStores - .name(name() + ".memDep.conflictingStores") - .desc("Number of conflicting stores."); -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::switchOut() -{ - for (int i = 0; i < Impl::MaxThreads; ++i) { - instList[i].clear(); - } - instsToReplay.clear(); - memDepHash.clear(); -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::takeOverFrom() -{ - loadBarrier = storeBarrier = false; - loadBarrierSN = storeBarrierSN = 0; - depPred.clear(); -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::setIQ(InstructionQueue<Impl> *iq_ptr) -{ - iqPtr = iq_ptr; -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::insert(DynInstPtr &inst) -{ - unsigned tid = inst->threadNumber; - - MemDepEntryPtr inst_entry = new MemDepEntry(inst); - - // Add the MemDepEntry to the hash. - memDepHash.insert( - std::pair<InstSeqNum, MemDepEntryPtr>(inst->seqNum, inst_entry)); - MemDepEntry::memdep_insert++; - - instList[tid].push_back(inst); - - inst_entry->listIt = --(instList[tid].end()); - - // Check any barriers and the dependence predictor for any - // producing stores. - InstSeqNum producing_store; - if (inst->isLoad() && loadBarrier) { - producing_store = loadBarrierSN; - } else if (inst->isStore() && storeBarrier) { - producing_store = storeBarrierSN; - } else { - producing_store = depPred.checkInst(inst->readPC()); - } - - MemDepEntryPtr store_entry = NULL; - - // If there is a producing store, try to find the entry. - if (producing_store != 0) { - MemDepHashIt hash_it = memDepHash.find(producing_store); - - if (hash_it != memDepHash.end()) { - store_entry = (*hash_it).second; - } - } - - // If no store entry, then instruction can issue as soon as the registers - // are ready. - if (!store_entry) { - DPRINTF(MemDepUnit, "No dependency for inst PC " - "%#x [sn:%lli].\n", inst->readPC(), inst->seqNum); - - inst_entry->memDepReady = true; - - if (inst->readyToIssue()) { - inst_entry->regsReady = true; - - moveToReady(inst_entry); - } - } else { - // Otherwise make the instruction dependent on the store/barrier. - DPRINTF(MemDepUnit, "Adding to dependency list; " - "inst PC %#x is dependent on [sn:%lli].\n", - inst->readPC(), producing_store); - - if (inst->readyToIssue()) { - inst_entry->regsReady = true; - } - - // Add this instruction to the list of dependents. - store_entry->dependInsts.push_back(inst_entry); - - if (inst->isLoad()) { - ++conflictingLoads; - } else { - ++conflictingStores; - } - } - - if (inst->isStore()) { - DPRINTF(MemDepUnit, "Inserting store PC %#x [sn:%lli].\n", - inst->readPC(), inst->seqNum); - - depPred.insertStore(inst->readPC(), inst->seqNum, inst->threadNumber); - - ++insertedStores; - } else if (inst->isLoad()) { - ++insertedLoads; - } else { - panic("Unknown type! (most likely a barrier)."); - } -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::insertNonSpec(DynInstPtr &inst) -{ - unsigned tid = inst->threadNumber; - - MemDepEntryPtr inst_entry = new MemDepEntry(inst); - - // Insert the MemDepEntry into the hash. - memDepHash.insert( - std::pair<InstSeqNum, MemDepEntryPtr>(inst->seqNum, inst_entry)); - MemDepEntry::memdep_insert++; - - // Add the instruction to the list. - instList[tid].push_back(inst); - - inst_entry->listIt = --(instList[tid].end()); - - // Might want to turn this part into an inline function or something. - // It's shared between both insert functions. - if (inst->isStore()) { - DPRINTF(MemDepUnit, "Inserting store PC %#x [sn:%lli].\n", - inst->readPC(), inst->seqNum); - - depPred.insertStore(inst->readPC(), inst->seqNum, inst->threadNumber); - - ++insertedStores; - } else if (inst->isLoad()) { - ++insertedLoads; - } else { - panic("Unknown type! (most likely a barrier)."); - } -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::insertBarrier(DynInstPtr &barr_inst) -{ - InstSeqNum barr_sn = barr_inst->seqNum; - if (barr_inst->isMemBarrier()) { - loadBarrier = true; - loadBarrierSN = barr_sn; - storeBarrier = true; - storeBarrierSN = barr_sn; - DPRINTF(MemDepUnit, "Inserted a memory barrier\n"); - } else if (barr_inst->isWriteBarrier()) { - storeBarrier = true; - storeBarrierSN = barr_sn; - DPRINTF(MemDepUnit, "Inserted a write barrier\n"); - } - - unsigned tid = barr_inst->threadNumber; - - MemDepEntryPtr inst_entry = new MemDepEntry(barr_inst); - - // Add the MemDepEntry to the hash. - memDepHash.insert( - std::pair<InstSeqNum, MemDepEntryPtr>(barr_sn, inst_entry)); - MemDepEntry::memdep_insert++; - - // Add the instruction to the instruction list. - instList[tid].push_back(barr_inst); - - inst_entry->listIt = --(instList[tid].end()); -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::regsReady(DynInstPtr &inst) -{ - DPRINTF(MemDepUnit, "Marking registers as ready for " - "instruction PC %#x [sn:%lli].\n", - inst->readPC(), inst->seqNum); - - MemDepEntryPtr inst_entry = findInHash(inst); - - inst_entry->regsReady = true; - - if (inst_entry->memDepReady) { - DPRINTF(MemDepUnit, "Instruction has its memory " - "dependencies resolved, adding it to the ready list.\n"); - - moveToReady(inst_entry); - } else { - DPRINTF(MemDepUnit, "Instruction still waiting on " - "memory dependency.\n"); - } -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::nonSpecInstReady(DynInstPtr &inst) -{ - DPRINTF(MemDepUnit, "Marking non speculative " - "instruction PC %#x as ready [sn:%lli].\n", - inst->readPC(), inst->seqNum); - - MemDepEntryPtr inst_entry = findInHash(inst); - - moveToReady(inst_entry); -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::reschedule(DynInstPtr &inst) -{ - instsToReplay.push_back(inst); -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::replay(DynInstPtr &inst) -{ - DynInstPtr temp_inst; - bool found_inst = false; - - while (!instsToReplay.empty()) { - temp_inst = instsToReplay.front(); - - MemDepEntryPtr inst_entry = findInHash(temp_inst); - - DPRINTF(MemDepUnit, "Replaying mem instruction PC %#x " - "[sn:%lli].\n", - temp_inst->readPC(), temp_inst->seqNum); - - moveToReady(inst_entry); - - if (temp_inst == inst) { - found_inst = true; - } - - instsToReplay.pop_front(); - } - - assert(found_inst); -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::completed(DynInstPtr &inst) -{ - DPRINTF(MemDepUnit, "Completed mem instruction PC %#x " - "[sn:%lli].\n", - inst->readPC(), inst->seqNum); - - unsigned tid = inst->threadNumber; - - // Remove the instruction from the hash and the list. - MemDepHashIt hash_it = memDepHash.find(inst->seqNum); - - assert(hash_it != memDepHash.end()); - - instList[tid].erase((*hash_it).second->listIt); - - (*hash_it).second = NULL; - - memDepHash.erase(hash_it); - MemDepEntry::memdep_erase++; -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::completeBarrier(DynInstPtr &inst) -{ - wakeDependents(inst); - completed(inst); - - InstSeqNum barr_sn = inst->seqNum; - - if (inst->isMemBarrier()) { - assert(loadBarrier && storeBarrier); - if (loadBarrierSN == barr_sn) - loadBarrier = false; - if (storeBarrierSN == barr_sn) - storeBarrier = false; - } else if (inst->isWriteBarrier()) { - assert(storeBarrier); - if (storeBarrierSN == barr_sn) - storeBarrier = false; - } -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::wakeDependents(DynInstPtr &inst) -{ - // Only stores and barriers have dependents. - if (!inst->isStore() && !inst->isMemBarrier() && !inst->isWriteBarrier()) { - return; - } - - MemDepEntryPtr inst_entry = findInHash(inst); - - for (int i = 0; i < inst_entry->dependInsts.size(); ++i ) { - MemDepEntryPtr woken_inst = inst_entry->dependInsts[i]; - - if (!woken_inst->inst) { - // Potentially removed mem dep entries could be on this list - continue; - } - - DPRINTF(MemDepUnit, "Waking up a dependent inst, " - "[sn:%lli].\n", - woken_inst->inst->seqNum); - - if (woken_inst->regsReady && !woken_inst->squashed) { - moveToReady(woken_inst); - } else { - woken_inst->memDepReady = true; - } - } - - inst_entry->dependInsts.clear(); -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::squash(const InstSeqNum &squashed_num, - unsigned tid) -{ - if (!instsToReplay.empty()) { - ListIt replay_it = instsToReplay.begin(); - while (replay_it != instsToReplay.end()) { - if ((*replay_it)->threadNumber == tid && - (*replay_it)->seqNum > squashed_num) { - instsToReplay.erase(replay_it++); - } else { - ++replay_it; - } - } - } - - ListIt squash_it = instList[tid].end(); - --squash_it; - - MemDepHashIt hash_it; - - while (!instList[tid].empty() && - (*squash_it)->seqNum > squashed_num) { - - DPRINTF(MemDepUnit, "Squashing inst [sn:%lli]\n", - (*squash_it)->seqNum); - - hash_it = memDepHash.find((*squash_it)->seqNum); - - assert(hash_it != memDepHash.end()); - - (*hash_it).second->squashed = true; - - (*hash_it).second = NULL; - - memDepHash.erase(hash_it); - MemDepEntry::memdep_erase++; - - instList[tid].erase(squash_it--); - } - - // Tell the dependency predictor to squash as well. - depPred.squash(squashed_num, tid); -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::violation(DynInstPtr &store_inst, - DynInstPtr &violating_load) -{ - DPRINTF(MemDepUnit, "Passing violating PCs to store sets," - " load: %#x, store: %#x\n", violating_load->readPC(), - store_inst->readPC()); - // Tell the memory dependence unit of the violation. - depPred.violation(violating_load->readPC(), store_inst->readPC()); -} - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::issue(DynInstPtr &inst) -{ - DPRINTF(MemDepUnit, "Issuing instruction PC %#x [sn:%lli].\n", - inst->readPC(), inst->seqNum); - - depPred.issued(inst->readPC(), inst->seqNum, inst->isStore()); -} - -template <class MemDepPred, class Impl> -inline typename MemDepUnit<MemDepPred,Impl>::MemDepEntryPtr & -MemDepUnit<MemDepPred, Impl>::findInHash(const DynInstPtr &inst) -{ - MemDepHashIt hash_it = memDepHash.find(inst->seqNum); - - assert(hash_it != memDepHash.end()); - - return (*hash_it).second; -} - -template <class MemDepPred, class Impl> -inline void -MemDepUnit<MemDepPred, Impl>::moveToReady(MemDepEntryPtr &woken_inst_entry) -{ - DPRINTF(MemDepUnit, "Adding instruction [sn:%lli] " - "to the ready list.\n", woken_inst_entry->inst->seqNum); - - assert(!woken_inst_entry->squashed); - - iqPtr->addReadyMemInst(woken_inst_entry->inst); -} - - -template <class MemDepPred, class Impl> -void -MemDepUnit<MemDepPred, Impl>::dumpLists() -{ - for (unsigned tid=0; tid < Impl::MaxThreads; tid++) { - cprintf("Instruction list %i size: %i\n", - tid, instList[tid].size()); - - ListIt inst_list_it = instList[tid].begin(); - int num = 0; - - while (inst_list_it != instList[tid].end()) { - cprintf("Instruction:%i\nPC:%#x\n[sn:%i]\n[tid:%i]\nIssued:%i\n" - "Squashed:%i\n\n", - num, (*inst_list_it)->readPC(), - (*inst_list_it)->seqNum, - (*inst_list_it)->threadNumber, - (*inst_list_it)->isIssued(), - (*inst_list_it)->isSquashed()); - inst_list_it++; - ++num; - } - } - - cprintf("Memory dependence hash size: %i\n", memDepHash.size()); - - cprintf("Memory dependence entries: %i\n", MemDepEntry::memdep_count); -} diff --git a/cpu/o3/ras.cc b/cpu/o3/ras.cc deleted file mode 100644 index 0b3ea4918..000000000 --- a/cpu/o3/ras.cc +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/o3/ras.hh" - -void -ReturnAddrStack::init(unsigned _numEntries) -{ - numEntries = _numEntries; - usedEntries = 0; - tos = 0; - - addrStack.resize(numEntries); - - for (int i = 0; i < numEntries; ++i) - addrStack[i] = 0; -} - -void -ReturnAddrStack::reset() -{ - usedEntries = 0; - tos = 0; - for (int i = 0; i < numEntries; ++i) - addrStack[i] = 0; -} - -void -ReturnAddrStack::push(const Addr &return_addr) -{ - incrTos(); - - addrStack[tos] = return_addr; - - if (usedEntries != numEntries) { - ++usedEntries; - } -} - -void -ReturnAddrStack::pop() -{ - if (usedEntries > 0) { - --usedEntries; - } - - decrTos(); -} - -void -ReturnAddrStack::restore(unsigned top_entry_idx, - const Addr &restored_target) -{ - tos = top_entry_idx; - - addrStack[tos] = restored_target; -} diff --git a/cpu/o3/ras.hh b/cpu/o3/ras.hh deleted file mode 100644 index 27e7c2df4..000000000 --- a/cpu/o3/ras.hh +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_RAS_HH__ -#define __CPU_O3_RAS_HH__ - -// For Addr type. -#include "arch/isa_traits.hh" -#include <vector> - -/** Return address stack class, implements a simple RAS. */ -class ReturnAddrStack -{ - public: - /** Creates a return address stack, but init() must be called prior to - * use. - */ - ReturnAddrStack() {} - - /** Initializes RAS with a specified number of entries. - * @param numEntries Number of entries in the RAS. - */ - void init(unsigned numEntries); - - void reset(); - - /** Returns the top address on the RAS. */ - Addr top() - { return addrStack[tos]; } - - /** Returns the index of the top of the RAS. */ - unsigned topIdx() - { return tos; } - - /** Pushes an address onto the RAS. */ - void push(const Addr &return_addr); - - /** Pops the top address from the RAS. */ - void pop(); - - /** Changes index to the top of the RAS, and replaces the top address with - * a new target. - * @param top_entry_idx The index of the RAS that will now be the top. - * @param restored_target The new target address of the new top of the RAS. - */ - void restore(unsigned top_entry_idx, const Addr &restored_target); - - private: - /** Increments the top of stack index. */ - inline void incrTos() - { if (++tos == numEntries) tos = 0; } - - /** Decrements the top of stack index. */ - inline void decrTos() - { tos = (tos == 0 ? numEntries - 1 : tos - 1); } - - /** The RAS itself. */ - std::vector<Addr> addrStack; - - /** The number of entries in the RAS. */ - unsigned numEntries; - - /** The number of used entries in the RAS. */ - unsigned usedEntries; - - /** The top of stack index. */ - unsigned tos; -}; - -#endif // __CPU_O3_RAS_HH__ diff --git a/cpu/o3/regfile.hh b/cpu/o3/regfile.hh deleted file mode 100644 index ed1238d36..000000000 --- a/cpu/o3/regfile.hh +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_REGFILE_HH__ -#define __CPU_O3_REGFILE_HH__ - -#include "arch/isa_traits.hh" -#include "arch/faults.hh" -#include "base/trace.hh" -#include "config/full_system.hh" -#include "cpu/o3/comm.hh" - -#if FULL_SYSTEM -#include "kern/kernel_stats.hh" - -#endif - -#include <vector> - -/** - * Simple physical register file class. - * This really only depends on the ISA, and not the Impl. Things that are - * in the ifdef FULL_SYSTEM are pretty dependent on the ISA, and probably - * should go in the AlphaFullCPU. - */ -template <class Impl> -class PhysRegFile -{ - protected: - typedef TheISA::IntReg IntReg; - typedef TheISA::FloatReg FloatReg; - typedef TheISA::MiscRegFile MiscRegFile; - typedef TheISA::MiscReg MiscReg; - // Note that most of the definitions of the IntReg, FloatReg, etc. exist - // within the Impl/ISA class and not within this PhysRegFile class. - - // Will make these registers public for now, but they probably should - // be private eventually with some accessor functions. - public: - typedef typename Impl::FullCPU FullCPU; - - /** - * Constructs a physical register file with the specified amount of - * integer and floating point registers. - */ - PhysRegFile(unsigned _numPhysicalIntRegs, - unsigned _numPhysicalFloatRegs); - - //Everything below should be pretty well identical to the normal - //register file that exists within AlphaISA class. - //The duplication is unfortunate but it's better than having - //different ways to access certain registers. - - //Add these in later when everything else is in place -// void serialize(std::ostream &os); -// void unserialize(Checkpoint *cp, const std::string §ion); - - /** Reads an integer register. */ - uint64_t readIntReg(PhysRegIndex reg_idx) - { - assert(reg_idx < numPhysicalIntRegs); - - DPRINTF(IEW, "RegFile: Access to int register %i, has data " - "%i\n", int(reg_idx), intRegFile[reg_idx]); - return intRegFile[reg_idx]; - } - - /** Reads a floating point register (single precision). */ - float readFloatRegSingle(PhysRegIndex reg_idx) - { - // Remove the base Float reg dependency. - reg_idx = reg_idx - numPhysicalIntRegs; - - assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); - - DPRINTF(IEW, "RegFile: Access to float register %i as single, has " - "data %8.8f\n", int(reg_idx), (float)floatRegFile[reg_idx].d); - - return (float)floatRegFile[reg_idx].d; - } - - /** Reads a floating point register (double precision). */ - double readFloatRegDouble(PhysRegIndex reg_idx) - { - // Remove the base Float reg dependency. - reg_idx = reg_idx - numPhysicalIntRegs; - - assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); - - DPRINTF(IEW, "RegFile: Access to float register %i as double, has " - " data %8.8f\n", int(reg_idx), floatRegFile[reg_idx].d); - - return floatRegFile[reg_idx].d; - } - - /** Reads a floating point register as an integer. */ - uint64_t readFloatRegInt(PhysRegIndex reg_idx) - { - // Remove the base Float reg dependency. - reg_idx = reg_idx - numPhysicalIntRegs; - - assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); - - DPRINTF(IEW, "RegFile: Access to float register %i as int, has data " - "%lli\n", int(reg_idx), floatRegFile[reg_idx].q); - - return floatRegFile[reg_idx].q; - } - - /** Sets an integer register to the given value. */ - void setIntReg(PhysRegIndex reg_idx, uint64_t val) - { - assert(reg_idx < numPhysicalIntRegs); - - DPRINTF(IEW, "RegFile: Setting int register %i to %lli\n", - int(reg_idx), val); - - if (reg_idx != TheISA::ZeroReg) - intRegFile[reg_idx] = val; - } - - /** Sets a single precision floating point register to the given value. */ - void setFloatRegSingle(PhysRegIndex reg_idx, float val) - { - // Remove the base Float reg dependency. - reg_idx = reg_idx - numPhysicalIntRegs; - - assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); - - DPRINTF(IEW, "RegFile: Setting float register %i to %8.8f\n", - int(reg_idx), val); - - if (reg_idx != TheISA::ZeroReg) - floatRegFile[reg_idx].d = (double)val; - } - - /** Sets a double precision floating point register to the given value. */ - void setFloatRegDouble(PhysRegIndex reg_idx, double val) - { - // Remove the base Float reg dependency. - reg_idx = reg_idx - numPhysicalIntRegs; - - assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); - - DPRINTF(IEW, "RegFile: Setting float register %i to %8.8f\n", - int(reg_idx), val); - - if (reg_idx != TheISA::ZeroReg) - floatRegFile[reg_idx].d = val; - } - - /** Sets a floating point register to the given integer value. */ - void setFloatRegInt(PhysRegIndex reg_idx, uint64_t val) - { - // Remove the base Float reg dependency. - reg_idx = reg_idx - numPhysicalIntRegs; - - assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); - - DPRINTF(IEW, "RegFile: Setting float register %i to %lli\n", - int(reg_idx), val); - - if (reg_idx != TheISA::ZeroReg) - floatRegFile[reg_idx].q = val; - } - - //Consider leaving this stuff and below in some implementation specific - //file as opposed to the general register file. Or have a derived class. - MiscReg readMiscReg(int misc_reg, unsigned thread_id) - { - return miscRegs[thread_id].readReg(misc_reg); - } - - MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault, - unsigned thread_id) - { - return miscRegs[thread_id].readRegWithEffect(misc_reg, fault, - cpu->xcBase(thread_id)); - } - - Fault setMiscReg(int misc_reg, const MiscReg &val, unsigned thread_id) - { - return miscRegs[thread_id].setReg(misc_reg, val); - } - - Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val, - unsigned thread_id) - { - return miscRegs[thread_id].setRegWithEffect(misc_reg, val, - cpu->xcBase(thread_id)); - } - -#if FULL_SYSTEM - int readIntrFlag() { return intrflag; } - /** Sets an interrupt flag. */ - void setIntrFlag(int val) { intrflag = val; } -#endif - - public: - /** (signed) integer register file. */ - std::vector<IntReg> intRegFile; - - /** Floating point register file. */ - std::vector<FloatReg> floatRegFile; - - /** Miscellaneous register file. */ - MiscRegFile miscRegs[Impl::MaxThreads]; - -#if FULL_SYSTEM - private: - int intrflag; // interrupt flag -#endif - - private: - /** CPU pointer. */ - FullCPU *cpu; - - public: - /** Sets the CPU pointer. */ - void setCPU(FullCPU *cpu_ptr) { cpu = cpu_ptr; } - - /** Number of physical integer registers. */ - unsigned numPhysicalIntRegs; - /** Number of physical floating point registers. */ - unsigned numPhysicalFloatRegs; -}; - -template <class Impl> -PhysRegFile<Impl>::PhysRegFile(unsigned _numPhysicalIntRegs, - unsigned _numPhysicalFloatRegs) - : numPhysicalIntRegs(_numPhysicalIntRegs), - numPhysicalFloatRegs(_numPhysicalFloatRegs) -{ - intRegFile.resize(numPhysicalIntRegs); - floatRegFile.resize(numPhysicalFloatRegs); - - //memset(intRegFile, 0, sizeof(*intRegFile)); - //memset(floatRegFile, 0, sizeof(*floatRegFile)); -} - -#endif diff --git a/cpu/o3/rename.cc b/cpu/o3/rename.cc deleted file mode 100644 index 4dc3bf6b2..000000000 --- a/cpu/o3/rename.cc +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/o3/alpha_dyn_inst.hh" -#include "cpu/o3/alpha_impl.hh" -#include "cpu/o3/rename_impl.hh" - -template class DefaultRename<AlphaSimpleImpl>; diff --git a/cpu/o3/rename.hh b/cpu/o3/rename.hh deleted file mode 100644 index 3f1a27bb5..000000000 --- a/cpu/o3/rename.hh +++ /dev/null @@ -1,462 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_RENAME_HH__ -#define __CPU_O3_RENAME_HH__ - -#include <list> - -#include "base/statistics.hh" -#include "base/timebuf.hh" - -/** - * DefaultRename handles both single threaded and SMT rename. Its - * width is specified by the parameters; each cycle it tries to rename - * that many instructions. It holds onto the rename history of all - * instructions with destination registers, storing the - * arch. register, the new physical register, and the old physical - * register, to allow for undoing of mappings if squashing happens, or - * freeing up registers upon commit. Rename handles blocking if the - * ROB, IQ, or LSQ is going to be full. Rename also handles barriers, - * and does so by stalling on the instruction until the ROB is empty - * and there are no instructions in flight to the ROB. - */ -template<class Impl> -class DefaultRename -{ - public: - // Typedefs from the Impl. - typedef typename Impl::CPUPol CPUPol; - typedef typename Impl::DynInstPtr DynInstPtr; - typedef typename Impl::FullCPU FullCPU; - typedef typename Impl::Params Params; - - // Typedefs from the CPUPol - typedef typename CPUPol::DecodeStruct DecodeStruct; - typedef typename CPUPol::RenameStruct RenameStruct; - typedef typename CPUPol::TimeStruct TimeStruct; - typedef typename CPUPol::FreeList FreeList; - typedef typename CPUPol::RenameMap RenameMap; - // These are used only for initialization. - typedef typename CPUPol::IEW IEW; - typedef typename CPUPol::Commit Commit; - - // Typedefs from the ISA. - typedef TheISA::RegIndex RegIndex; - - // A list is used to queue the instructions. Barrier insts must - // be added to the front of the list, which is the only reason for - // using a list instead of a queue. (Most other stages use a - // queue) - typedef std::list<DynInstPtr> InstQueue; - - public: - /** Overall rename status. Used to determine if the CPU can - * deschedule itself due to a lack of activity. - */ - enum RenameStatus { - Active, - Inactive - }; - - /** Individual thread status. */ - enum ThreadStatus { - Running, - Idle, - StartSquash, - Squashing, - Blocked, - Unblocking, - SerializeStall - }; - - private: - /** Rename status. */ - RenameStatus _status; - - /** Per-thread status. */ - ThreadStatus renameStatus[Impl::MaxThreads]; - - public: - /** DefaultRename constructor. */ - DefaultRename(Params *params); - - /** Returns the name of rename. */ - std::string name() const; - - /** Registers statistics. */ - void regStats(); - - /** Sets CPU pointer. */ - void setCPU(FullCPU *cpu_ptr); - - /** Sets the main backwards communication time buffer pointer. */ - void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr); - - /** Sets pointer to time buffer used to communicate to the next stage. */ - void setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr); - - /** Sets pointer to time buffer coming from decode. */ - void setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr); - - /** Sets pointer to IEW stage. Used only for initialization. */ - void setIEWStage(IEW *iew_stage) - { iew_ptr = iew_stage; } - - /** Sets pointer to commit stage. Used only for initialization. */ - void setCommitStage(Commit *commit_stage) - { commit_ptr = commit_stage; } - - private: - /** Pointer to IEW stage. Used only for initialization. */ - IEW *iew_ptr; - - /** Pointer to commit stage. Used only for initialization. */ - Commit *commit_ptr; - - public: - /** Initializes variables for the stage. */ - void initStage(); - - /** Sets pointer to list of active threads. */ - void setActiveThreads(std::list<unsigned> *at_ptr); - - /** Sets pointer to rename maps (per-thread structures). */ - void setRenameMap(RenameMap rm_ptr[Impl::MaxThreads]); - - /** Sets pointer to the free list. */ - void setFreeList(FreeList *fl_ptr); - - /** Sets pointer to the scoreboard. */ - void setScoreboard(Scoreboard *_scoreboard); - - void switchOut(); - - void doSwitchOut(); - - void takeOverFrom(); - - /** Squashes all instructions in a thread. */ - void squash(unsigned tid); - - /** Ticks rename, which processes all input signals and attempts to rename - * as many instructions as possible. - */ - void tick(); - - /** Debugging function used to dump history buffer of renamings. */ - void dumpHistory(); - - private: - /** Determines what to do based on rename's current status. - * @param status_change rename() sets this variable if there was a status - * change (ie switching from blocking to unblocking). - * @param tid Thread id to rename instructions from. - */ - void rename(bool &status_change, unsigned tid); - - /** Renames instructions for the given thread. Also handles serializing - * instructions. - */ - void renameInsts(unsigned tid); - - /** Inserts unused instructions from a given thread into the skid buffer, - * to be renamed once rename unblocks. - */ - void skidInsert(unsigned tid); - - /** Separates instructions from decode into individual lists of instructions - * sorted by thread. - */ - void sortInsts(); - - /** Returns if all of the skid buffers are empty. */ - bool skidsEmpty(); - - /** Updates overall rename status based on all of the threads' statuses. */ - void updateStatus(); - - /** Switches rename to blocking, and signals back that rename has become - * blocked. - * @return Returns true if there is a status change. - */ - bool block(unsigned tid); - - /** Switches rename to unblocking if the skid buffer is empty, and signals - * back that rename has unblocked. - * @return Returns true if there is a status change. - */ - bool unblock(unsigned tid); - - /** Executes actual squash, removing squashed instructions. */ - void doSquash(unsigned tid); - - /** Removes a committed instruction's rename history. */ - void removeFromHistory(InstSeqNum inst_seq_num, unsigned tid); - - /** Renames the source registers of an instruction. */ - inline void renameSrcRegs(DynInstPtr &inst, unsigned tid); - - /** Renames the destination registers of an instruction. */ - inline void renameDestRegs(DynInstPtr &inst, unsigned tid); - - /** Calculates the number of free ROB entries for a specific thread. */ - inline int calcFreeROBEntries(unsigned tid); - - /** Calculates the number of free IQ entries for a specific thread. */ - inline int calcFreeIQEntries(unsigned tid); - - /** Calculates the number of free LSQ entries for a specific thread. */ - inline int calcFreeLSQEntries(unsigned tid); - - /** Returns the number of valid instructions coming from decode. */ - unsigned validInsts(); - - /** Reads signals telling rename to block/unblock. */ - void readStallSignals(unsigned tid); - - /** Checks if any stages are telling rename to block. */ - bool checkStall(unsigned tid); - - void readFreeEntries(unsigned tid); - - bool checkSignalsAndUpdate(unsigned tid); - - /** Either serializes on the next instruction available in the InstQueue, - * or records that it must serialize on the next instruction to enter - * rename. - * @param inst_list The list of younger, unprocessed instructions for the - * thread that has the serializeAfter instruction. - * @param tid The thread id. - */ - void serializeAfter(InstQueue &inst_list, unsigned tid); - - /** Holds the information for each destination register rename. It holds - * the instruction's sequence number, the arch register, the old physical - * register for that arch. register, and the new physical register. - */ - struct RenameHistory { - RenameHistory(InstSeqNum _instSeqNum, RegIndex _archReg, - PhysRegIndex _newPhysReg, PhysRegIndex _prevPhysReg) - : instSeqNum(_instSeqNum), archReg(_archReg), - newPhysReg(_newPhysReg), prevPhysReg(_prevPhysReg) - { - } - - /** The sequence number of the instruction that renamed. */ - InstSeqNum instSeqNum; - /** The architectural register index that was renamed. */ - RegIndex archReg; - /** The new physical register that the arch. register is renamed to. */ - PhysRegIndex newPhysReg; - /** The old physical register that the arch. register was renamed to. */ - PhysRegIndex prevPhysReg; - }; - - /** A per-thread list of all destination register renames, used to either - * undo rename mappings or free old physical registers. - */ - std::list<RenameHistory> historyBuffer[Impl::MaxThreads]; - - /** Pointer to CPU. */ - FullCPU *cpu; - - /** Pointer to main time buffer used for backwards communication. */ - TimeBuffer<TimeStruct> *timeBuffer; - - /** Wire to get IEW's output from backwards time buffer. */ - typename TimeBuffer<TimeStruct>::wire fromIEW; - - /** Wire to get commit's output from backwards time buffer. */ - typename TimeBuffer<TimeStruct>::wire fromCommit; - - /** Wire to write infromation heading to previous stages. */ - typename TimeBuffer<TimeStruct>::wire toDecode; - - /** Rename instruction queue. */ - TimeBuffer<RenameStruct> *renameQueue; - - /** Wire to write any information heading to IEW. */ - typename TimeBuffer<RenameStruct>::wire toIEW; - - /** Decode instruction queue interface. */ - TimeBuffer<DecodeStruct> *decodeQueue; - - /** Wire to get decode's output from decode queue. */ - typename TimeBuffer<DecodeStruct>::wire fromDecode; - - /** Queue of all instructions coming from decode this cycle. */ - InstQueue insts[Impl::MaxThreads]; - - /** Skid buffer between rename and decode. */ - InstQueue skidBuffer[Impl::MaxThreads]; - - /** Rename map interface. */ - RenameMap *renameMap[Impl::MaxThreads]; - - /** Free list interface. */ - FreeList *freeList; - - /** Pointer to the list of active threads. */ - std::list<unsigned> *activeThreads; - - /** Pointer to the scoreboard. */ - Scoreboard *scoreboard; - - /** Count of instructions in progress that have been sent off to the IQ - * and ROB, but are not yet included in their occupancy counts. - */ - int instsInProgress[Impl::MaxThreads]; - - /** Variable that tracks if decode has written to the time buffer this - * cycle. Used to tell CPU if there is activity this cycle. - */ - bool wroteToTimeBuffer; - - /** Structures whose free entries impact the amount of instructions that - * can be renamed. - */ - struct FreeEntries { - unsigned iqEntries; - unsigned lsqEntries; - unsigned robEntries; - }; - - /** Per-thread tracking of the number of free entries of back-end - * structures. - */ - FreeEntries freeEntries[Impl::MaxThreads]; - - /** Records if the ROB is empty. In SMT mode the ROB may be dynamically - * partitioned between threads, so the ROB must tell rename when it is - * empty. - */ - bool emptyROB[Impl::MaxThreads]; - - /** Source of possible stalls. */ - struct Stalls { - bool iew; - bool commit; - }; - - /** Tracks which stages are telling decode to stall. */ - Stalls stalls[Impl::MaxThreads]; - - /** The serialize instruction that rename has stalled on. */ - DynInstPtr serializeInst[Impl::MaxThreads]; - - /** Records if rename needs to serialize on the next instruction for any - * thread. - */ - bool serializeOnNextInst[Impl::MaxThreads]; - - /** Delay between iew and rename, in ticks. */ - int iewToRenameDelay; - - /** Delay between decode and rename, in ticks. */ - int decodeToRenameDelay; - - /** Delay between commit and rename, in ticks. */ - unsigned commitToRenameDelay; - - /** Rename width, in instructions. */ - unsigned renameWidth; - - /** Commit width, in instructions. Used so rename knows how many - * instructions might have freed registers in the previous cycle. - */ - unsigned commitWidth; - - /** The index of the instruction in the time buffer to IEW that rename is - * currently using. - */ - unsigned toIEWIndex; - - /** Whether or not rename needs to block this cycle. */ - bool blockThisCycle; - - /** The number of threads active in rename. */ - unsigned numThreads; - - /** The maximum skid buffer size. */ - unsigned skidBufferMax; - - /** Enum to record the source of a structure full stall. Can come from - * either ROB, IQ, LSQ, and it is priortized in that order. - */ - enum FullSource { - ROB, - IQ, - LSQ, - NONE - }; - - /** Function used to increment the stat that corresponds to the source of - * the stall. - */ - inline void incrFullStat(const FullSource &source); - - /** Stat for total number of cycles spent squashing. */ - Stats::Scalar<> renameSquashCycles; - /** Stat for total number of cycles spent idle. */ - Stats::Scalar<> renameIdleCycles; - /** Stat for total number of cycles spent blocking. */ - Stats::Scalar<> renameBlockCycles; - /** Stat for total number of cycles spent stalling for a serializing inst. */ - Stats::Scalar<> renameSerializeStallCycles; - /** Stat for total number of cycles spent running normally. */ - Stats::Scalar<> renameRunCycles; - /** Stat for total number of cycles spent unblocking. */ - Stats::Scalar<> renameUnblockCycles; - /** Stat for total number of renamed instructions. */ - Stats::Scalar<> renameRenamedInsts; - /** Stat for total number of squashed instructions that rename discards. */ - Stats::Scalar<> renameSquashedInsts; - /** Stat for total number of times that the ROB starts a stall in rename. */ - Stats::Scalar<> renameROBFullEvents; - /** Stat for total number of times that the IQ starts a stall in rename. */ - Stats::Scalar<> renameIQFullEvents; - /** Stat for total number of times that the LSQ starts a stall in rename. */ - Stats::Scalar<> renameLSQFullEvents; - /** Stat for total number of times that rename runs out of free registers - * to use to rename. */ - Stats::Scalar<> renameFullRegistersEvents; - /** Stat for total number of renamed destination registers. */ - Stats::Scalar<> renameRenamedOperands; - /** Stat for total number of source register rename lookups. */ - Stats::Scalar<> renameRenameLookups; - /** Stat for total number of committed renaming mappings. */ - Stats::Scalar<> renameCommittedMaps; - /** Stat for total number of mappings that were undone due to a squash. */ - Stats::Scalar<> renameUndoneMaps; - Stats::Scalar<> renamedSerializing; - Stats::Scalar<> renamedTempSerializing; - Stats::Scalar<> renameSkidInsts; -}; - -#endif // __CPU_O3_RENAME_HH__ diff --git a/cpu/o3/rename_impl.hh b/cpu/o3/rename_impl.hh deleted file mode 100644 index b4f1077d1..000000000 --- a/cpu/o3/rename_impl.hh +++ /dev/null @@ -1,1279 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <list> - -#include "config/full_system.hh" -#include "cpu/o3/rename.hh" - -using namespace std; - -template <class Impl> -DefaultRename<Impl>::DefaultRename(Params *params) - : iewToRenameDelay(params->iewToRenameDelay), - decodeToRenameDelay(params->decodeToRenameDelay), - commitToRenameDelay(params->commitToRenameDelay), - renameWidth(params->renameWidth), - commitWidth(params->commitWidth), - numThreads(params->numberOfThreads) -{ - _status = Inactive; - - for (int i=0; i< numThreads; i++) { - renameStatus[i] = Idle; - - freeEntries[i].iqEntries = 0; - freeEntries[i].lsqEntries = 0; - freeEntries[i].robEntries = 0; - - stalls[i].iew = false; - stalls[i].commit = false; - serializeInst[i] = NULL; - - instsInProgress[i] = 0; - - emptyROB[i] = true; - - serializeOnNextInst[i] = false; - } - - // @todo: Make into a parameter. - skidBufferMax = (2 * (iewToRenameDelay * params->decodeWidth)) + renameWidth; -} - -template <class Impl> -std::string -DefaultRename<Impl>::name() const -{ - return cpu->name() + ".rename"; -} - -template <class Impl> -void -DefaultRename<Impl>::regStats() -{ - renameSquashCycles - .name(name() + ".RENAME:SquashCycles") - .desc("Number of cycles rename is squashing") - .prereq(renameSquashCycles); - renameIdleCycles - .name(name() + ".RENAME:IdleCycles") - .desc("Number of cycles rename is idle") - .prereq(renameIdleCycles); - renameBlockCycles - .name(name() + ".RENAME:BlockCycles") - .desc("Number of cycles rename is blocking") - .prereq(renameBlockCycles); - renameSerializeStallCycles - .name(name() + ".RENAME:serializeStallCycles") - .desc("count of cycles rename stalled for serializing inst") - .flags(Stats::total); - renameRunCycles - .name(name() + ".RENAME:RunCycles") - .desc("Number of cycles rename is running") - .prereq(renameIdleCycles); - renameUnblockCycles - .name(name() + ".RENAME:UnblockCycles") - .desc("Number of cycles rename is unblocking") - .prereq(renameUnblockCycles); - renameRenamedInsts - .name(name() + ".RENAME:RenamedInsts") - .desc("Number of instructions processed by rename") - .prereq(renameRenamedInsts); - renameSquashedInsts - .name(name() + ".RENAME:SquashedInsts") - .desc("Number of squashed instructions processed by rename") - .prereq(renameSquashedInsts); - renameROBFullEvents - .name(name() + ".RENAME:ROBFullEvents") - .desc("Number of times rename has blocked due to ROB full") - .prereq(renameROBFullEvents); - renameIQFullEvents - .name(name() + ".RENAME:IQFullEvents") - .desc("Number of times rename has blocked due to IQ full") - .prereq(renameIQFullEvents); - renameLSQFullEvents - .name(name() + ".RENAME:LSQFullEvents") - .desc("Number of times rename has blocked due to LSQ full") - .prereq(renameLSQFullEvents); - renameFullRegistersEvents - .name(name() + ".RENAME:FullRegisterEvents") - .desc("Number of times there has been no free registers") - .prereq(renameFullRegistersEvents); - renameRenamedOperands - .name(name() + ".RENAME:RenamedOperands") - .desc("Number of destination operands rename has renamed") - .prereq(renameRenamedOperands); - renameRenameLookups - .name(name() + ".RENAME:RenameLookups") - .desc("Number of register rename lookups that rename has made") - .prereq(renameRenameLookups); - renameCommittedMaps - .name(name() + ".RENAME:CommittedMaps") - .desc("Number of HB maps that are committed") - .prereq(renameCommittedMaps); - renameUndoneMaps - .name(name() + ".RENAME:UndoneMaps") - .desc("Number of HB maps that are undone due to squashing") - .prereq(renameUndoneMaps); - renamedSerializing - .name(name() + ".RENAME:serializingInsts") - .desc("count of serializing insts renamed") - .flags(Stats::total) - ; - renamedTempSerializing - .name(name() + ".RENAME:tempSerializingInsts") - .desc("count of temporary serializing insts renamed") - .flags(Stats::total) - ; - renameSkidInsts - .name(name() + ".RENAME:skidInsts") - .desc("count of insts added to the skid buffer") - .flags(Stats::total) - ; -} - -template <class Impl> -void -DefaultRename<Impl>::setCPU(FullCPU *cpu_ptr) -{ - DPRINTF(Rename, "Setting CPU pointer.\n"); - cpu = cpu_ptr; -} - -template <class Impl> -void -DefaultRename<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) -{ - DPRINTF(Rename, "Setting time buffer pointer.\n"); - timeBuffer = tb_ptr; - - // Setup wire to read information from time buffer, from IEW stage. - fromIEW = timeBuffer->getWire(-iewToRenameDelay); - - // Setup wire to read infromation from time buffer, from commit stage. - fromCommit = timeBuffer->getWire(-commitToRenameDelay); - - // Setup wire to write information to previous stages. - toDecode = timeBuffer->getWire(0); -} - -template <class Impl> -void -DefaultRename<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr) -{ - DPRINTF(Rename, "Setting rename queue pointer.\n"); - renameQueue = rq_ptr; - - // Setup wire to write information to future stages. - toIEW = renameQueue->getWire(0); -} - -template <class Impl> -void -DefaultRename<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr) -{ - DPRINTF(Rename, "Setting decode queue pointer.\n"); - decodeQueue = dq_ptr; - - // Setup wire to get information from decode. - fromDecode = decodeQueue->getWire(-decodeToRenameDelay); -} - -template <class Impl> -void -DefaultRename<Impl>::initStage() -{ - // Grab the number of free entries directly from the stages. - for (int tid=0; tid < numThreads; tid++) { - freeEntries[tid].iqEntries = iew_ptr->instQueue.numFreeEntries(tid); - freeEntries[tid].lsqEntries = iew_ptr->ldstQueue.numFreeEntries(tid); - freeEntries[tid].robEntries = commit_ptr->numROBFreeEntries(tid); - emptyROB[tid] = true; - } -} - -template<class Impl> -void -DefaultRename<Impl>::setActiveThreads(list<unsigned> *at_ptr) -{ - DPRINTF(Rename, "Setting active threads list pointer.\n"); - activeThreads = at_ptr; -} - - -template <class Impl> -void -DefaultRename<Impl>::setRenameMap(RenameMap rm_ptr[]) -{ - DPRINTF(Rename, "Setting rename map pointers.\n"); - - for (int i=0; i<numThreads; i++) { - renameMap[i] = &rm_ptr[i]; - } -} - -template <class Impl> -void -DefaultRename<Impl>::setFreeList(FreeList *fl_ptr) -{ - DPRINTF(Rename, "Setting free list pointer.\n"); - freeList = fl_ptr; -} - -template<class Impl> -void -DefaultRename<Impl>::setScoreboard(Scoreboard *_scoreboard) -{ - DPRINTF(Rename, "Setting scoreboard pointer.\n"); - scoreboard = _scoreboard; -} - -template <class Impl> -void -DefaultRename<Impl>::switchOut() -{ - cpu->signalSwitched(); -} - -template <class Impl> -void -DefaultRename<Impl>::doSwitchOut() -{ - for (int i = 0; i < numThreads; i++) { - typename list<RenameHistory>::iterator hb_it = historyBuffer[i].begin(); - - while (!historyBuffer[i].empty()) { - assert(hb_it != historyBuffer[i].end()); - - DPRINTF(Rename, "[tid:%u]: Removing history entry with sequence " - "number %i.\n", i, (*hb_it).instSeqNum); - - // Tell the rename map to set the architected register to the - // previous physical register that it was renamed to. - renameMap[i]->setEntry(hb_it->archReg, hb_it->prevPhysReg); - - // Put the renamed physical register back on the free list. - freeList->addReg(hb_it->newPhysReg); - - historyBuffer[i].erase(hb_it++); - } - insts[i].clear(); - skidBuffer[i].clear(); - } -} - -template <class Impl> -void -DefaultRename<Impl>::takeOverFrom() -{ - _status = Inactive; - initStage(); - - // Reset all state prior to taking over from the other CPU. - for (int i=0; i< numThreads; i++) { - renameStatus[i] = Idle; - - stalls[i].iew = false; - stalls[i].commit = false; - serializeInst[i] = NULL; - - instsInProgress[i] = 0; - - emptyROB[i] = true; - - serializeOnNextInst[i] = false; - } -} - -template <class Impl> -void -DefaultRename<Impl>::squash(unsigned tid) -{ - DPRINTF(Rename, "[tid:%u]: Squashing instructions.\n",tid); - - // Clear the stall signal if rename was blocked or unblocking before. - // If it still needs to block, the blocking should happen the next - // cycle and there should be space to hold everything due to the squash. - if (renameStatus[tid] == Blocked || - renameStatus[tid] == Unblocking || - renameStatus[tid] == SerializeStall) { -#if 0 - // In syscall emulation, we can have both a block and a squash due - // to a syscall in the same cycle. This would cause both signals to - // be high. This shouldn't happen in full system. - if (toDecode->renameBlock[tid]) { - toDecode->renameBlock[tid] = 0; - } else { - toDecode->renameUnblock[tid] = 1; - } -#else - toDecode->renameUnblock[tid] = 1; -#endif - serializeInst[tid] = NULL; - } - - // Set the status to Squashing. - renameStatus[tid] = Squashing; - - // Squash any instructions from decode. - unsigned squashCount = 0; - - for (int i=0; i<fromDecode->size; i++) { - if (fromDecode->insts[i]->threadNumber == tid) { - fromDecode->insts[i]->squashed = true; - wroteToTimeBuffer = true; - squashCount++; - } - } - - insts[tid].clear(); - - // Clear the skid buffer in case it has any data in it. - skidBuffer[tid].clear(); - - doSquash(tid); -} - -template <class Impl> -void -DefaultRename<Impl>::tick() -{ - wroteToTimeBuffer = false; - - blockThisCycle = false; - - bool status_change = false; - - toIEWIndex = 0; - - sortInsts(); - - list<unsigned>::iterator threads = (*activeThreads).begin(); - - // Check stall and squash signals. - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - DPRINTF(Rename, "Processing [tid:%i]\n", tid); - - status_change = checkSignalsAndUpdate(tid) || status_change; - - rename(status_change, tid); - } - - if (status_change) { - updateStatus(); - } - - if (wroteToTimeBuffer) { - DPRINTF(Activity, "Activity this cycle.\n"); - cpu->activityThisCycle(); - } - - threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - // If we committed this cycle then doneSeqNum will be > 0 - if (fromCommit->commitInfo[tid].doneSeqNum != 0 && - !fromCommit->commitInfo[tid].squash && - renameStatus[tid] != Squashing) { - - removeFromHistory(fromCommit->commitInfo[tid].doneSeqNum, - tid); - } - } - - // @todo: make into updateProgress function - for (int tid=0; tid < numThreads; tid++) { - instsInProgress[tid] -= fromIEW->iewInfo[tid].dispatched; - - assert(instsInProgress[tid] >=0); - } - -} - -template<class Impl> -void -DefaultRename<Impl>::rename(bool &status_change, unsigned tid) -{ - // If status is Running or idle, - // call renameInsts() - // If status is Unblocking, - // buffer any instructions coming from decode - // continue trying to empty skid buffer - // check if stall conditions have passed - - if (renameStatus[tid] == Blocked) { - ++renameBlockCycles; - } else if (renameStatus[tid] == Squashing) { - ++renameSquashCycles; - } else if (renameStatus[tid] == SerializeStall) { - ++renameSerializeStallCycles; - } - - if (renameStatus[tid] == Running || - renameStatus[tid] == Idle) { - DPRINTF(Rename, "[tid:%u]: Not blocked, so attempting to run " - "stage.\n", tid); - - renameInsts(tid); - } else if (renameStatus[tid] == Unblocking) { - renameInsts(tid); - - if (validInsts()) { - // Add the current inputs to the skid buffer so they can be - // reprocessed when this stage unblocks. - skidInsert(tid); - } - - // If we switched over to blocking, then there's a potential for - // an overall status change. - status_change = unblock(tid) || status_change || blockThisCycle; - } -} - -template <class Impl> -void -DefaultRename<Impl>::renameInsts(unsigned tid) -{ - // Instructions can be either in the skid buffer or the queue of - // instructions coming from decode, depending on the status. - int insts_available = renameStatus[tid] == Unblocking ? - skidBuffer[tid].size() : insts[tid].size(); - - // Check the decode queue to see if instructions are available. - // If there are no available instructions to rename, then do nothing. - if (insts_available == 0) { - DPRINTF(Rename, "[tid:%u]: Nothing to do, breaking out early.\n", - tid); - // Should I change status to idle? - ++renameIdleCycles; - return; - } else if (renameStatus[tid] == Unblocking) { - ++renameUnblockCycles; - } else if (renameStatus[tid] == Running) { - ++renameRunCycles; - } - - DynInstPtr inst; - - // Will have to do a different calculation for the number of free - // entries. - int free_rob_entries = calcFreeROBEntries(tid); - int free_iq_entries = calcFreeIQEntries(tid); - int free_lsq_entries = calcFreeLSQEntries(tid); - int min_free_entries = free_rob_entries; - - FullSource source = ROB; - - if (free_iq_entries < min_free_entries) { - min_free_entries = free_iq_entries; - source = IQ; - } - - if (free_lsq_entries < min_free_entries) { - min_free_entries = free_lsq_entries; - source = LSQ; - } - - // Check if there's any space left. - if (min_free_entries <= 0) { - DPRINTF(Rename, "[tid:%u]: Blocking due to no free ROB/IQ/LSQ " - "entries.\n" - "ROB has %i free entries.\n" - "IQ has %i free entries.\n" - "LSQ has %i free entries.\n", - tid, - free_rob_entries, - free_iq_entries, - free_lsq_entries); - - blockThisCycle = true; - - block(tid); - - incrFullStat(source); - - return; - } else if (min_free_entries < insts_available) { - DPRINTF(Rename, "[tid:%u]: Will have to block this cycle." - "%i insts available, but only %i insts can be " - "renamed due to ROB/IQ/LSQ limits.\n", - tid, insts_available, min_free_entries); - - insts_available = min_free_entries; - - blockThisCycle = true; - - incrFullStat(source); - } - - InstQueue &insts_to_rename = renameStatus[tid] == Unblocking ? - skidBuffer[tid] : insts[tid]; - - DPRINTF(Rename, "[tid:%u]: %i available instructions to " - "send iew.\n", tid, insts_available); - - DPRINTF(Rename, "[tid:%u]: %i insts pipelining from Rename | %i insts " - "dispatched to IQ last cycle.\n", - tid, instsInProgress[tid], fromIEW->iewInfo[tid].dispatched); - - // Handle serializing the next instruction if necessary. - if (serializeOnNextInst[tid]) { - if (emptyROB[tid] && instsInProgress[tid] == 0) { - // ROB already empty; no need to serialize. - serializeOnNextInst[tid] = false; - } else if (!insts_to_rename.empty()) { - insts_to_rename.front()->setSerializeBefore(); - } - } - - int renamed_insts = 0; - - while (insts_available > 0 && toIEWIndex < renameWidth) { - DPRINTF(Rename, "[tid:%u]: Sending instructions to IEW.\n", tid); - - assert(!insts_to_rename.empty()); - - inst = insts_to_rename.front(); - - insts_to_rename.pop_front(); - - if (renameStatus[tid] == Unblocking) { - DPRINTF(Rename,"[tid:%u]: Removing [sn:%lli] PC:%#x from rename " - "skidBuffer\n", - tid, inst->seqNum, inst->readPC()); - } - - if (inst->isSquashed()) { - DPRINTF(Rename, "[tid:%u]: instruction %i with PC %#x is " - "squashed, skipping.\n", - tid, inst->seqNum, inst->threadNumber,inst->readPC()); - - ++renameSquashedInsts; - - // Decrement how many instructions are available. - --insts_available; - - continue; - } - - DPRINTF(Rename, "[tid:%u]: Processing instruction [sn:%lli] with " - "PC %#x.\n", - tid, inst->seqNum, inst->readPC()); - - // Handle serializeAfter/serializeBefore instructions. - // serializeAfter marks the next instruction as serializeBefore. - // serializeBefore makes the instruction wait in rename until the ROB - // is empty. - - // In this model, IPR accesses are serialize before - // instructions, and store conditionals are serialize after - // instructions. This is mainly due to lack of support for - // out-of-order operations of either of those classes of - // instructions. - if ((inst->isIprAccess() || inst->isSerializeBefore()) && - !inst->isSerializeHandled()) { - DPRINTF(Rename, "Serialize before instruction encountered.\n"); - - if (!inst->isTempSerializeBefore()) { - renamedSerializing++; - inst->setSerializeHandled(); - } else { - renamedTempSerializing++; - } - - // Change status over to SerializeStall so that other stages know - // what this is blocked on. - renameStatus[tid] = SerializeStall; - - serializeInst[tid] = inst; - - blockThisCycle = true; - - break; - } else if ((inst->isStoreConditional() || inst->isSerializeAfter()) && - !inst->isSerializeHandled()) { - DPRINTF(Rename, "Serialize after instruction encountered.\n"); - - renamedSerializing++; - - inst->setSerializeHandled(); - - serializeAfter(insts_to_rename, tid); - } - - // Check here to make sure there are enough destination registers - // to rename to. Otherwise block. - if (renameMap[tid]->numFreeEntries() < inst->numDestRegs()) { - DPRINTF(Rename, "Blocking due to lack of free " - "physical registers to rename to.\n"); - blockThisCycle = true; - - ++renameFullRegistersEvents; - - break; - } - - renameSrcRegs(inst, inst->threadNumber); - - renameDestRegs(inst, inst->threadNumber); - - ++renamed_insts; - - // Put instruction in rename queue. - toIEW->insts[toIEWIndex] = inst; - ++(toIEW->size); - - // Increment which instruction we're on. - ++toIEWIndex; - - // Decrement how many instructions are available. - --insts_available; - } - - instsInProgress[tid] += renamed_insts; - renameRenamedInsts += renamed_insts; - - // If we wrote to the time buffer, record this. - if (toIEWIndex) { - wroteToTimeBuffer = true; - } - - // Check if there's any instructions left that haven't yet been renamed. - // If so then block. - if (insts_available) { - blockThisCycle = true; - } - - if (blockThisCycle) { - block(tid); - toDecode->renameUnblock[tid] = false; - } -} - -template<class Impl> -void -DefaultRename<Impl>::skidInsert(unsigned tid) -{ - DynInstPtr inst = NULL; - - while (!insts[tid].empty()) { - inst = insts[tid].front(); - - insts[tid].pop_front(); - - assert(tid == inst->threadNumber); - - DPRINTF(Rename, "[tid:%u]: Inserting [sn:%lli] PC:%#x into Rename " - "skidBuffer\n", tid, inst->seqNum, inst->readPC()); - - ++renameSkidInsts; - - skidBuffer[tid].push_back(inst); - } - - if (skidBuffer[tid].size() > skidBufferMax) - panic("Skidbuffer Exceeded Max Size"); -} - -template <class Impl> -void -DefaultRename<Impl>::sortInsts() -{ - int insts_from_decode = fromDecode->size; -#ifdef DEBUG - for (int i=0; i < numThreads; i++) - assert(insts[i].empty()); -#endif - for (int i = 0; i < insts_from_decode; ++i) { - DynInstPtr inst = fromDecode->insts[i]; - insts[inst->threadNumber].push_back(inst); - } -} - -template<class Impl> -bool -DefaultRename<Impl>::skidsEmpty() -{ - list<unsigned>::iterator threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - if (!skidBuffer[*threads++].empty()) - return false; - } - - return true; -} - -template<class Impl> -void -DefaultRename<Impl>::updateStatus() -{ - bool any_unblocking = false; - - list<unsigned>::iterator threads = (*activeThreads).begin(); - - threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - if (renameStatus[tid] == Unblocking) { - any_unblocking = true; - break; - } - } - - // Rename will have activity if it's unblocking. - if (any_unblocking) { - if (_status == Inactive) { - _status = Active; - - DPRINTF(Activity, "Activating stage.\n"); - - cpu->activateStage(FullCPU::RenameIdx); - } - } else { - // If it's not unblocking, then rename will not have any internal - // activity. Switch it to inactive. - if (_status == Active) { - _status = Inactive; - DPRINTF(Activity, "Deactivating stage.\n"); - - cpu->deactivateStage(FullCPU::RenameIdx); - } - } -} - -template <class Impl> -bool -DefaultRename<Impl>::block(unsigned tid) -{ - DPRINTF(Rename, "[tid:%u]: Blocking.\n", tid); - - // Add the current inputs onto the skid buffer, so they can be - // reprocessed when this stage unblocks. - skidInsert(tid); - - // Only signal backwards to block if the previous stages do not think - // rename is already blocked. - if (renameStatus[tid] != Blocked) { - if (renameStatus[tid] != Unblocking) { - toDecode->renameBlock[tid] = true; - toDecode->renameUnblock[tid] = false; - wroteToTimeBuffer = true; - } - - // Rename can not go from SerializeStall to Blocked, otherwise - // it would not know to complete the serialize stall. - if (renameStatus[tid] != SerializeStall) { - // Set status to Blocked. - renameStatus[tid] = Blocked; - return true; - } - } - - return false; -} - -template <class Impl> -bool -DefaultRename<Impl>::unblock(unsigned tid) -{ - DPRINTF(Rename, "[tid:%u]: Trying to unblock.\n", tid); - - // Rename is done unblocking if the skid buffer is empty. - if (skidBuffer[tid].empty() && renameStatus[tid] != SerializeStall) { - - DPRINTF(Rename, "[tid:%u]: Done unblocking.\n", tid); - - toDecode->renameUnblock[tid] = true; - wroteToTimeBuffer = true; - - renameStatus[tid] = Running; - return true; - } - - return false; -} - -template <class Impl> -void -DefaultRename<Impl>::doSquash(unsigned tid) -{ - typename list<RenameHistory>::iterator hb_it = historyBuffer[tid].begin(); - - InstSeqNum squashed_seq_num = fromCommit->commitInfo[tid].doneSeqNum; - - // After a syscall squashes everything, the history buffer may be empty - // but the ROB may still be squashing instructions. - if (historyBuffer[tid].empty()) { - return; - } - - // Go through the most recent instructions, undoing the mappings - // they did and freeing up the registers. - while (!historyBuffer[tid].empty() && - (*hb_it).instSeqNum > squashed_seq_num) { - assert(hb_it != historyBuffer[tid].end()); - - DPRINTF(Rename, "[tid:%u]: Removing history entry with sequence " - "number %i.\n", tid, (*hb_it).instSeqNum); - - // Tell the rename map to set the architected register to the - // previous physical register that it was renamed to. - renameMap[tid]->setEntry(hb_it->archReg, hb_it->prevPhysReg); - - // Put the renamed physical register back on the free list. - freeList->addReg(hb_it->newPhysReg); - - historyBuffer[tid].erase(hb_it++); - - ++renameUndoneMaps; - } -} - -template<class Impl> -void -DefaultRename<Impl>::removeFromHistory(InstSeqNum inst_seq_num, unsigned tid) -{ - DPRINTF(Rename, "[tid:%u]: Removing a committed instruction from the " - "history buffer %u (size=%i), until [sn:%lli].\n", - tid, tid, historyBuffer[tid].size(), inst_seq_num); - - typename list<RenameHistory>::iterator hb_it = historyBuffer[tid].end(); - - --hb_it; - - if (historyBuffer[tid].empty()) { - DPRINTF(Rename, "[tid:%u]: History buffer is empty.\n", tid); - return; - } else if (hb_it->instSeqNum > inst_seq_num) { - DPRINTF(Rename, "[tid:%u]: Old sequence number encountered. Ensure " - "that a syscall happened recently.\n", tid); - return; - } - - // Commit all the renames up until (and including) the committed sequence - // number. Some or even all of the committed instructions may not have - // rename histories if they did not have destination registers that were - // renamed. - while (!historyBuffer[tid].empty() && - hb_it != historyBuffer[tid].end() && - (*hb_it).instSeqNum <= inst_seq_num) { - - DPRINTF(Rename, "[tid:%u]: Freeing up older rename of reg %i, " - "[sn:%lli].\n", - tid, (*hb_it).prevPhysReg, (*hb_it).instSeqNum); - - freeList->addReg((*hb_it).prevPhysReg); - ++renameCommittedMaps; - - historyBuffer[tid].erase(hb_it--); - } -} - -template <class Impl> -inline void -DefaultRename<Impl>::renameSrcRegs(DynInstPtr &inst,unsigned tid) -{ - assert(renameMap[tid] != 0); - - unsigned num_src_regs = inst->numSrcRegs(); - - // Get the architectual register numbers from the source and - // destination operands, and redirect them to the right register. - // Will need to mark dependencies though. - for (int src_idx = 0; src_idx < num_src_regs; src_idx++) { - RegIndex src_reg = inst->srcRegIdx(src_idx); - - // Look up the source registers to get the phys. register they've - // been renamed to, and set the sources to those registers. - PhysRegIndex renamed_reg = renameMap[tid]->lookup(src_reg); - - DPRINTF(Rename, "[tid:%u]: Looking up arch reg %i, got " - "physical reg %i.\n", tid, (int)src_reg, - (int)renamed_reg); - - inst->renameSrcReg(src_idx, renamed_reg); - - // See if the register is ready or not. - if (scoreboard->getReg(renamed_reg) == true) { - DPRINTF(Rename, "[tid:%u]: Register is ready.\n", tid); - - inst->markSrcRegReady(src_idx); - } - - ++renameRenameLookups; - } -} - -template <class Impl> -inline void -DefaultRename<Impl>::renameDestRegs(DynInstPtr &inst,unsigned tid) -{ - typename RenameMap::RenameInfo rename_result; - - unsigned num_dest_regs = inst->numDestRegs(); - - // Rename the destination registers. - for (int dest_idx = 0; dest_idx < num_dest_regs; dest_idx++) { - RegIndex dest_reg = inst->destRegIdx(dest_idx); - - // Get the physical register that the destination will be - // renamed to. - rename_result = renameMap[tid]->rename(dest_reg); - - //Mark Scoreboard entry as not ready - scoreboard->unsetReg(rename_result.first); - - DPRINTF(Rename, "[tid:%u]: Renaming arch reg %i to physical " - "reg %i.\n", tid, (int)dest_reg, - (int)rename_result.first); - - // Record the rename information so that a history can be kept. - RenameHistory hb_entry(inst->seqNum, dest_reg, - rename_result.first, - rename_result.second); - - historyBuffer[tid].push_front(hb_entry); - - DPRINTF(Rename, "[tid:%u]: Adding instruction to history buffer, " - "[sn:%lli].\n",tid, - (*historyBuffer[tid].begin()).instSeqNum); - - // Tell the instruction to rename the appropriate destination - // register (dest_idx) to the new physical register - // (rename_result.first), and record the previous physical - // register that the same logical register was renamed to - // (rename_result.second). - inst->renameDestReg(dest_idx, - rename_result.first, - rename_result.second); - - ++renameRenamedOperands; - } -} - -template <class Impl> -inline int -DefaultRename<Impl>::calcFreeROBEntries(unsigned tid) -{ - int num_free = freeEntries[tid].robEntries - - (instsInProgress[tid] - fromIEW->iewInfo[tid].dispatched); - - //DPRINTF(Rename,"[tid:%i]: %i rob free\n",tid,num_free); - - return num_free; -} - -template <class Impl> -inline int -DefaultRename<Impl>::calcFreeIQEntries(unsigned tid) -{ - int num_free = freeEntries[tid].iqEntries - - (instsInProgress[tid] - fromIEW->iewInfo[tid].dispatched); - - //DPRINTF(Rename,"[tid:%i]: %i iq free\n",tid,num_free); - - return num_free; -} - -template <class Impl> -inline int -DefaultRename<Impl>::calcFreeLSQEntries(unsigned tid) -{ - int num_free = freeEntries[tid].lsqEntries - - (instsInProgress[tid] - fromIEW->iewInfo[tid].dispatchedToLSQ); - - //DPRINTF(Rename,"[tid:%i]: %i lsq free\n",tid,num_free); - - return num_free; -} - -template <class Impl> -unsigned -DefaultRename<Impl>::validInsts() -{ - unsigned inst_count = 0; - - for (int i=0; i<fromDecode->size; i++) { - if (!fromDecode->insts[i]->squashed) - inst_count++; - } - - return inst_count; -} - -template <class Impl> -void -DefaultRename<Impl>::readStallSignals(unsigned tid) -{ - if (fromIEW->iewBlock[tid]) { - stalls[tid].iew = true; - } - - if (fromIEW->iewUnblock[tid]) { - assert(stalls[tid].iew); - stalls[tid].iew = false; - } - - if (fromCommit->commitBlock[tid]) { - stalls[tid].commit = true; - } - - if (fromCommit->commitUnblock[tid]) { - assert(stalls[tid].commit); - stalls[tid].commit = false; - } -} - -template <class Impl> -bool -DefaultRename<Impl>::checkStall(unsigned tid) -{ - bool ret_val = false; - - if (stalls[tid].iew) { - DPRINTF(Rename,"[tid:%i]: Stall from IEW stage detected.\n", tid); - ret_val = true; - } else if (stalls[tid].commit) { - DPRINTF(Rename,"[tid:%i]: Stall from Commit stage detected.\n", tid); - ret_val = true; - } else if (calcFreeROBEntries(tid) <= 0) { - DPRINTF(Rename,"[tid:%i]: Stall: ROB has 0 free entries.\n", tid); - ret_val = true; - } else if (calcFreeIQEntries(tid) <= 0) { - DPRINTF(Rename,"[tid:%i]: Stall: IQ has 0 free entries.\n", tid); - ret_val = true; - } else if (calcFreeLSQEntries(tid) <= 0) { - DPRINTF(Rename,"[tid:%i]: Stall: LSQ has 0 free entries.\n", tid); - ret_val = true; - } else if (renameMap[tid]->numFreeEntries() <= 0) { - DPRINTF(Rename,"[tid:%i]: Stall: RenameMap has 0 free entries.\n", tid); - ret_val = true; - } else if (renameStatus[tid] == SerializeStall && - (!emptyROB[tid] || instsInProgress[tid])) { - DPRINTF(Rename,"[tid:%i]: Stall: Serialize stall and ROB is not " - "empty.\n", - tid); - ret_val = true; - } - - return ret_val; -} - -template <class Impl> -void -DefaultRename<Impl>::readFreeEntries(unsigned tid) -{ - bool updated = false; - if (fromIEW->iewInfo[tid].usedIQ) { - freeEntries[tid].iqEntries = - fromIEW->iewInfo[tid].freeIQEntries; - updated = true; - } - - if (fromIEW->iewInfo[tid].usedLSQ) { - freeEntries[tid].lsqEntries = - fromIEW->iewInfo[tid].freeLSQEntries; - updated = true; - } - - if (fromCommit->commitInfo[tid].usedROB) { - freeEntries[tid].robEntries = - fromCommit->commitInfo[tid].freeROBEntries; - emptyROB[tid] = fromCommit->commitInfo[tid].emptyROB; - updated = true; - } - - DPRINTF(Rename, "[tid:%i]: Free IQ: %i, Free ROB: %i, Free LSQ: %i\n", - tid, - freeEntries[tid].iqEntries, - freeEntries[tid].robEntries, - freeEntries[tid].lsqEntries); - - DPRINTF(Rename, "[tid:%i]: %i instructions not yet in ROB\n", - tid, instsInProgress[tid]); -} - -template <class Impl> -bool -DefaultRename<Impl>::checkSignalsAndUpdate(unsigned tid) -{ - // Check if there's a squash signal, squash if there is - // Check stall signals, block if necessary. - // If status was blocked - // check if stall conditions have passed - // if so then go to unblocking - // If status was Squashing - // check if squashing is not high. Switch to running this cycle. - // If status was serialize stall - // check if ROB is empty and no insts are in flight to the ROB - - readFreeEntries(tid); - readStallSignals(tid); - - if (fromCommit->commitInfo[tid].squash) { - DPRINTF(Rename, "[tid:%u]: Squashing instructions due to squash from " - "commit.\n", tid); - - squash(tid); - - return true; - } - - if (fromCommit->commitInfo[tid].robSquashing) { - DPRINTF(Rename, "[tid:%u]: ROB is still squashing.\n", tid); - - renameStatus[tid] = Squashing; - - return true; - } - - if (checkStall(tid)) { - return block(tid); - } - - if (renameStatus[tid] == Blocked) { - DPRINTF(Rename, "[tid:%u]: Done blocking, switching to unblocking.\n", - tid); - - renameStatus[tid] = Unblocking; - - unblock(tid); - - return true; - } - - if (renameStatus[tid] == Squashing) { - // Switch status to running if rename isn't being told to block or - // squash this cycle. - DPRINTF(Rename, "[tid:%u]: Done squashing, switching to running.\n", - tid); - - renameStatus[tid] = Running; - - return false; - } - - if (renameStatus[tid] == SerializeStall) { - // Stall ends once the ROB is free. - DPRINTF(Rename, "[tid:%u]: Done with serialize stall, switching to " - "unblocking.\n", tid); - - DynInstPtr serial_inst = serializeInst[tid]; - - renameStatus[tid] = Unblocking; - - unblock(tid); - - DPRINTF(Rename, "[tid:%u]: Processing instruction [%lli] with " - "PC %#x.\n", - tid, serial_inst->seqNum, serial_inst->readPC()); - - // Put instruction into queue here. - serial_inst->clearSerializeBefore(); - - if (!skidBuffer[tid].empty()) { - skidBuffer[tid].push_front(serial_inst); - } else { - insts[tid].push_front(serial_inst); - } - - DPRINTF(Rename, "[tid:%u]: Instruction must be processed by rename." - " Adding to front of list.", tid); - - serializeInst[tid] = NULL; - - return true; - } - - // If we've reached this point, we have not gotten any signals that - // cause rename to change its status. Rename remains the same as before. - return false; -} - -template<class Impl> -void -DefaultRename<Impl>::serializeAfter(InstQueue &inst_list, - unsigned tid) -{ - if (inst_list.empty()) { - // Mark a bit to say that I must serialize on the next instruction. - serializeOnNextInst[tid] = true; - return; - } - - // Set the next instruction as serializing. - inst_list.front()->setSerializeBefore(); -} - -template <class Impl> -inline void -DefaultRename<Impl>::incrFullStat(const FullSource &source) -{ - switch (source) { - case ROB: - ++renameROBFullEvents; - break; - case IQ: - ++renameIQFullEvents; - break; - case LSQ: - ++renameLSQFullEvents; - break; - default: - panic("Rename full stall stat should be incremented for a reason!"); - break; - } -} - -template <class Impl> -void -DefaultRename<Impl>::dumpHistory() -{ - typename list<RenameHistory>::iterator buf_it; - - for (int i = 0; i < numThreads; i++) { - - buf_it = historyBuffer[i].begin(); - - while (buf_it != historyBuffer[i].end()) { - cprintf("Seq num: %i\nArch reg: %i New phys reg: %i Old phys " - "reg: %i\n", (*buf_it).instSeqNum, (int)(*buf_it).archReg, - (int)(*buf_it).newPhysReg, (int)(*buf_it).prevPhysReg); - - buf_it++; - } - } -} diff --git a/cpu/o3/rename_map.cc b/cpu/o3/rename_map.cc deleted file mode 100644 index fc59058a1..000000000 --- a/cpu/o3/rename_map.cc +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <vector> - -#include "cpu/o3/rename_map.hh" - -using namespace std; - -// @todo: Consider making inline bool functions that determine if the -// register is a logical int, logical fp, physical int, physical fp, -// etc. - -SimpleRenameMap::~SimpleRenameMap() -{ -} - -void -SimpleRenameMap::init(unsigned _numLogicalIntRegs, - unsigned _numPhysicalIntRegs, - PhysRegIndex &ireg_idx, - - unsigned _numLogicalFloatRegs, - unsigned _numPhysicalFloatRegs, - PhysRegIndex &freg_idx, - - unsigned _numMiscRegs, - - RegIndex _intZeroReg, - RegIndex _floatZeroReg, - - int map_id, - bool bindRegs) -{ - id = map_id; - - numLogicalIntRegs = _numLogicalIntRegs; - - numLogicalFloatRegs = _numLogicalFloatRegs; - - numPhysicalIntRegs = _numPhysicalIntRegs; - - numPhysicalFloatRegs = _numPhysicalFloatRegs; - - numMiscRegs = _numMiscRegs; - - intZeroReg = _intZeroReg; - floatZeroReg = _floatZeroReg; - - DPRINTF(Rename, "Creating rename map %i. Phys: %i / %i, Float: " - "%i / %i.\n", id, numLogicalIntRegs, numPhysicalIntRegs, - numLogicalFloatRegs, numPhysicalFloatRegs); - - numLogicalRegs = numLogicalIntRegs + numLogicalFloatRegs; - - numPhysicalRegs = numPhysicalIntRegs + numPhysicalFloatRegs; - - //Create the rename maps - intRenameMap.resize(numLogicalIntRegs); - floatRenameMap.resize(numLogicalRegs); - - if (bindRegs) { - DPRINTF(Rename, "Binding registers into rename map %i",id); - - // Initialize the entries in the integer rename map to point to the - // physical registers of the same index - for (RegIndex index = 0; index < numLogicalIntRegs; ++index) - { - intRenameMap[index].physical_reg = ireg_idx++; - } - - // Initialize the entries in the floating point rename map to point to - // the physical registers of the same index - // Although the index refers purely to architected registers, because - // the floating reg indices come after the integer reg indices, they - // may exceed the size of a normal RegIndex (short). - for (PhysRegIndex index = numLogicalIntRegs; - index < numLogicalRegs; ++index) - { - floatRenameMap[index].physical_reg = freg_idx++; - } - } else { - DPRINTF(Rename, "Binding registers into rename map %i",id); - - PhysRegIndex temp_ireg = ireg_idx; - - for (RegIndex index = 0; index < numLogicalIntRegs; ++index) - { - intRenameMap[index].physical_reg = temp_ireg++; - } - - PhysRegIndex temp_freg = freg_idx; - - for (PhysRegIndex index = numLogicalIntRegs; - index < numLogicalRegs; ++index) - { - floatRenameMap[index].physical_reg = temp_freg++; - } - } -} - -void -SimpleRenameMap::setFreeList(SimpleFreeList *fl_ptr) -{ - freeList = fl_ptr; -} - - -SimpleRenameMap::RenameInfo -SimpleRenameMap::rename(RegIndex arch_reg) -{ - PhysRegIndex renamed_reg; - PhysRegIndex prev_reg; - - if (arch_reg < numLogicalIntRegs) { - - // Record the current physical register that is renamed to the - // requested architected register. - prev_reg = intRenameMap[arch_reg].physical_reg; - - // If it's not referencing the zero register, then rename the - // register. - if (arch_reg != intZeroReg) { - renamed_reg = freeList->getIntReg(); - - intRenameMap[arch_reg].physical_reg = renamed_reg; - - assert(renamed_reg >= 0 && renamed_reg < numPhysicalIntRegs); - - } else { - // Otherwise return the zero register so nothing bad happens. - renamed_reg = intZeroReg; - } - } else if (arch_reg < numLogicalRegs) { - // Record the current physical register that is renamed to the - // requested architected register. - prev_reg = floatRenameMap[arch_reg].physical_reg; - - // If it's not referencing the zero register, then rename the - // register. - if (arch_reg != floatZeroReg) { - renamed_reg = freeList->getFloatReg(); - - floatRenameMap[arch_reg].physical_reg = renamed_reg; - - assert(renamed_reg < numPhysicalRegs && - renamed_reg >= numPhysicalIntRegs); - } else { - // Otherwise return the zero register so nothing bad happens. - renamed_reg = floatZeroReg; - } - } else { - // Subtract off the base offset for miscellaneous registers. - arch_reg = arch_reg - numLogicalRegs; - - // No renaming happens to the misc. registers. They are - // simply the registers that come after all the physical - // registers; thus take the base architected register and add - // the physical registers to it. - renamed_reg = arch_reg + numPhysicalRegs; - - // Set the previous register to the same register; mainly it must be - // known that the prev reg was outside the range of normal registers - // so the free list can avoid adding it. - prev_reg = renamed_reg; - - assert(renamed_reg < numPhysicalRegs + numMiscRegs); - } - - return RenameInfo(renamed_reg, prev_reg); -} - -PhysRegIndex -SimpleRenameMap::lookup(RegIndex arch_reg) -{ - if (arch_reg < numLogicalIntRegs) { - return intRenameMap[arch_reg].physical_reg; - } else if (arch_reg < numLogicalRegs) { - return floatRenameMap[arch_reg].physical_reg; - } else { - // Subtract off the misc registers offset. - arch_reg = arch_reg - numLogicalRegs; - - // Misc. regs don't rename, so simply add the base arch reg to - // the number of physical registers. - return numPhysicalRegs + arch_reg; - } -} - -void -SimpleRenameMap::setEntry(RegIndex arch_reg, PhysRegIndex renamed_reg) -{ - // In this implementation the miscellaneous registers do not - // actually rename, so this function does not allow you to try to - // change their mappings. - if (arch_reg < numLogicalIntRegs) { - DPRINTF(Rename, "Rename Map: Integer register %i being set to %i.\n", - (int)arch_reg, renamed_reg); - - intRenameMap[arch_reg].physical_reg = renamed_reg; - } else if (arch_reg < numLogicalIntRegs + numLogicalFloatRegs) { - DPRINTF(Rename, "Rename Map: Float register %i being set to %i.\n", - (int)arch_reg - numLogicalIntRegs, renamed_reg); - - floatRenameMap[arch_reg].physical_reg = renamed_reg; - } -} - -int -SimpleRenameMap::numFreeEntries() -{ - int free_int_regs = freeList->numFreeIntRegs(); - int free_float_regs = freeList->numFreeFloatRegs(); - - if (free_int_regs < free_float_regs) { - return free_int_regs; - } else { - return free_float_regs; - } -} diff --git a/cpu/o3/rename_map.hh b/cpu/o3/rename_map.hh deleted file mode 100644 index d7e49ae83..000000000 --- a/cpu/o3/rename_map.hh +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// Todo: Create destructor. -// Have it so that there's a more meaningful name given to the variable -// that marks the beginning of the FP registers. - -#ifndef __CPU_O3_RENAME_MAP_HH__ -#define __CPU_O3_RENAME_MAP_HH__ - -#include <iostream> -#include <utility> -#include <vector> - -#include "cpu/o3/free_list.hh" -//For RegIndex -#include "arch/isa_traits.hh" - -class SimpleRenameMap -{ - protected: - typedef TheISA::RegIndex RegIndex; - public: - /** - * Pair of a logical register and a physical register. Tells the - * previous mapping of a logical register to a physical register. - * Used to roll back the rename map to a previous state. - */ - typedef std::pair<RegIndex, PhysRegIndex> UnmapInfo; - - /** - * Pair of a physical register and a physical register. Used to - * return the physical register that a logical register has been - * renamed to, and the previous physical register that the same - * logical register was previously mapped to. - */ - typedef std::pair<PhysRegIndex, PhysRegIndex> RenameInfo; - - public: - //Constructor - SimpleRenameMap() {}; - - /** Destructor. */ - ~SimpleRenameMap(); - - void init(unsigned _numLogicalIntRegs, - unsigned _numPhysicalIntRegs, - PhysRegIndex &_int_reg_start, - - unsigned _numLogicalFloatRegs, - unsigned _numPhysicalFloatRegs, - PhysRegIndex &_float_reg_start, - - unsigned _numMiscRegs, - - RegIndex _intZeroReg, - RegIndex _floatZeroReg, - - int id, - bool bindRegs); - - void setFreeList(SimpleFreeList *fl_ptr); - - //Tell rename map to get a free physical register for a given - //architected register. Not sure it should have a return value, - //but perhaps it should have some sort of fault in case there are - //no free registers. - RenameInfo rename(RegIndex arch_reg); - - PhysRegIndex lookup(RegIndex phys_reg); - - /** - * Marks the given register as ready, meaning that its value has been - * calculated and written to the register file. - * @param ready_reg The index of the physical register that is now ready. - */ - void setEntry(RegIndex arch_reg, PhysRegIndex renamed_reg); - - int numFreeEntries(); - - private: - /** Rename Map ID */ - int id; - - /** Number of logical integer registers. */ - int numLogicalIntRegs; - - /** Number of physical integer registers. */ - int numPhysicalIntRegs; - - /** Number of logical floating point registers. */ - int numLogicalFloatRegs; - - /** Number of physical floating point registers. */ - int numPhysicalFloatRegs; - - /** Number of miscellaneous registers. */ - int numMiscRegs; - - /** Number of logical integer + float registers. */ - int numLogicalRegs; - - /** Number of physical integer + float registers. */ - int numPhysicalRegs; - - /** The integer zero register. This implementation assumes it is always - * zero and never can be anything else. - */ - RegIndex intZeroReg; - - /** The floating point zero register. This implementation assumes it is - * always zero and never can be anything else. - */ - RegIndex floatZeroReg; - - class RenameEntry - { - public: - PhysRegIndex physical_reg; - bool valid; - - RenameEntry() - : physical_reg(0), valid(false) - { } - }; - - //Change this to private - private: - /** Integer rename map. */ - std::vector<RenameEntry> intRenameMap; - - /** Floating point rename map. */ - std::vector<RenameEntry> floatRenameMap; - - private: - /** Free list interface. */ - SimpleFreeList *freeList; -}; - -#endif //__CPU_O3_RENAME_MAP_HH__ diff --git a/cpu/o3/rob.cc b/cpu/o3/rob.cc deleted file mode 100644 index c10f782fd..000000000 --- a/cpu/o3/rob.cc +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/o3/alpha_dyn_inst.hh" -#include "cpu/o3/alpha_impl.hh" -#include "cpu/o3/rob_impl.hh" - -// Force instantiation of InstructionQueue. -template class ROB<AlphaSimpleImpl>; diff --git a/cpu/o3/rob.hh b/cpu/o3/rob.hh deleted file mode 100644 index e05eebe5a..000000000 --- a/cpu/o3/rob.hh +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_ROB_HH__ -#define __CPU_O3_ROB_HH__ - -#include <string> -#include <utility> -#include <vector> - -/** - * ROB class. The ROB is largely what drives squashing. - */ -template <class Impl> -class ROB -{ - protected: - typedef TheISA::RegIndex RegIndex; - public: - //Typedefs from the Impl. - typedef typename Impl::FullCPU FullCPU; - typedef typename Impl::DynInstPtr DynInstPtr; - - typedef std::pair<RegIndex, PhysRegIndex> UnmapInfo; - typedef typename std::list<DynInstPtr>::iterator InstIt; - - /** Possible ROB statuses. */ - enum Status { - Running, - Idle, - ROBSquashing - }; - - /** SMT ROB Sharing Policy */ - enum ROBPolicy{ - Dynamic, - Partitioned, - Threshold - }; - - private: - /** Per-thread ROB status. */ - Status robStatus[Impl::MaxThreads]; - - /** ROB resource sharing policy for SMT mode. */ - ROBPolicy robPolicy; - - public: - /** ROB constructor. - * @param _numEntries Number of entries in ROB. - * @param _squashWidth Number of instructions that can be squashed in a - * single cycle. - * @param _smtROBPolicy ROB Partitioning Scheme for SMT. - * @param _smtROBThreshold Max Resources(by %) a thread can have in the ROB. - * @param _numThreads The number of active threads. - */ - ROB(unsigned _numEntries, unsigned _squashWidth, std::string smtROBPolicy, - unsigned _smtROBThreshold, unsigned _numThreads); - - std::string name() const; - - /** Function to set the CPU pointer, necessary due to which object the ROB - * is created within. - * @param cpu_ptr Pointer to the implementation specific full CPU object. - */ - void setCPU(FullCPU *cpu_ptr); - - /** Sets pointer to the list of active threads. - * @param at_ptr Pointer to the list of active threads. - */ - void setActiveThreads(std::list<unsigned>* at_ptr); - - void switchOut(); - - void takeOverFrom(); - - /** Function to insert an instruction into the ROB. Note that whatever - * calls this function must ensure that there is enough space within the - * ROB for the new instruction. - * @param inst The instruction being inserted into the ROB. - */ - void insertInst(DynInstPtr &inst); - - /** Returns pointer to the head instruction within the ROB. There is - * no guarantee as to the return value if the ROB is empty. - * @retval Pointer to the DynInst that is at the head of the ROB. - */ -// DynInstPtr readHeadInst(); - - /** Returns a pointer to the head instruction of a specific thread within - * the ROB. - * @return Pointer to the DynInst that is at the head of the ROB. - */ - DynInstPtr readHeadInst(unsigned tid); - - /** Returns pointer to the tail instruction within the ROB. There is - * no guarantee as to the return value if the ROB is empty. - * @retval Pointer to the DynInst that is at the tail of the ROB. - */ -// DynInstPtr readTailInst(); - - /** Returns a pointer to the tail instruction of a specific thread within - * the ROB. - * @return Pointer to the DynInst that is at the tail of the ROB. - */ - DynInstPtr readTailInst(unsigned tid); - - /** Retires the head instruction, removing it from the ROB. */ -// void retireHead(); - - /** Retires the head instruction of a specific thread, removing it from the - * ROB. - */ - void retireHead(unsigned tid); - - /** Is the oldest instruction across all threads ready. */ -// bool isHeadReady(); - - /** Is the oldest instruction across a particular thread ready. */ - bool isHeadReady(unsigned tid); - - /** Is there any commitable head instruction across all threads ready. */ - bool canCommit(); - - /** Re-adjust ROB partitioning. */ - void resetEntries(); - - /** Number of entries needed For 'num_threads' amount of threads. */ - int entryAmount(int num_threads); - - /** Returns the number of total free entries in the ROB. */ - unsigned numFreeEntries(); - - /** Returns the number of free entries in a specific ROB paritition. */ - unsigned numFreeEntries(unsigned tid); - - /** Returns the maximum number of entries for a specific thread. */ - unsigned getMaxEntries(unsigned tid) - { return maxEntries[tid]; } - - /** Returns the number of entries being used by a specific thread. */ - unsigned getThreadEntries(unsigned tid) - { return threadEntries[tid]; } - - /** Returns if the ROB is full. */ - bool isFull() - { return numInstsInROB == numEntries; } - - /** Returns if a specific thread's partition is full. */ - bool isFull(unsigned tid) - { return threadEntries[tid] == numEntries; } - - /** Returns if the ROB is empty. */ - bool isEmpty() - { return numInstsInROB == 0; } - - /** Returns if a specific thread's partition is empty. */ - bool isEmpty(unsigned tid) - { return threadEntries[tid] == 0; } - - /** Executes the squash, marking squashed instructions. */ - void doSquash(unsigned tid); - - /** Squashes all instructions younger than the given sequence number for - * the specific thread. - */ - void squash(InstSeqNum squash_num, unsigned tid); - - /** Updates the head instruction with the new oldest instruction. */ - void updateHead(); - - /** Updates the tail instruction with the new youngest instruction. */ - void updateTail(); - - /** Reads the PC of the oldest head instruction. */ -// uint64_t readHeadPC(); - - /** Reads the PC of the head instruction of a specific thread. */ -// uint64_t readHeadPC(unsigned tid); - - /** Reads the next PC of the oldest head instruction. */ -// uint64_t readHeadNextPC(); - - /** Reads the next PC of the head instruction of a specific thread. */ -// uint64_t readHeadNextPC(unsigned tid); - - /** Reads the sequence number of the oldest head instruction. */ -// InstSeqNum readHeadSeqNum(); - - /** Reads the sequence number of the head instruction of a specific thread. - */ -// InstSeqNum readHeadSeqNum(unsigned tid); - - /** Reads the PC of the youngest tail instruction. */ -// uint64_t readTailPC(); - - /** Reads the PC of the tail instruction of a specific thread. */ -// uint64_t readTailPC(unsigned tid); - - /** Reads the sequence number of the youngest tail instruction. */ -// InstSeqNum readTailSeqNum(); - - /** Reads the sequence number of tail instruction of a specific thread. */ -// InstSeqNum readTailSeqNum(unsigned tid); - - /** Checks if the ROB is still in the process of squashing instructions. - * @retval Whether or not the ROB is done squashing. - */ - bool isDoneSquashing(unsigned tid) const - { return doneSquashing[tid]; } - - /** Checks if the ROB is still in the process of squashing instructions for - * any thread. - */ - bool isDoneSquashing(); - - /** This is more of a debugging function than anything. Use - * numInstsInROB to get the instructions in the ROB unless you are - * double checking that variable. - */ - int countInsts(); - - /** This is more of a debugging function than anything. Use - * threadEntries to get the instructions in the ROB unless you are - * double checking that variable. - */ - int countInsts(unsigned tid); - - private: - /** Pointer to the CPU. */ - FullCPU *cpu; - - /** Active Threads in CPU */ - std::list<unsigned>* activeThreads; - - /** Number of instructions in the ROB. */ - unsigned numEntries; - - /** Entries Per Thread */ - unsigned threadEntries[Impl::MaxThreads]; - - /** Max Insts a Thread Can Have in the ROB */ - unsigned maxEntries[Impl::MaxThreads]; - - /** ROB List of Instructions */ - std::list<DynInstPtr> instList[Impl::MaxThreads]; - - /** Number of instructions that can be squashed in a single cycle. */ - unsigned squashWidth; - - public: - /** Iterator pointing to the instruction which is the last instruction - * in the ROB. This may at times be invalid (ie when the ROB is empty), - * however it should never be incorrect. - */ - InstIt tail; - - /** Iterator pointing to the instruction which is the first instruction in - * in the ROB*/ - InstIt head; - - private: - /** Iterator used for walking through the list of instructions when - * squashing. Used so that there is persistent state between cycles; - * when squashing, the instructions are marked as squashed but not - * immediately removed, meaning the tail iterator remains the same before - * and after a squash. - * This will always be set to cpu->instList.end() if it is invalid. - */ - InstIt squashIt[Impl::MaxThreads]; - - public: - /** Number of instructions in the ROB. */ - int numInstsInROB; - - DynInstPtr dummyInst; - - private: - /** The sequence number of the squashed instruction. */ - InstSeqNum squashedSeqNum; - - /** Is the ROB done squashing. */ - bool doneSquashing[Impl::MaxThreads]; - - /** Number of active threads. */ - unsigned numThreads; -}; - -#endif //__CPU_O3_ROB_HH__ diff --git a/cpu/o3/rob_impl.hh b/cpu/o3/rob_impl.hh deleted file mode 100644 index 25e0c80fd..000000000 --- a/cpu/o3/rob_impl.hh +++ /dev/null @@ -1,691 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config/full_system.hh" -#include "cpu/o3/rob.hh" - -using namespace std; - -template <class Impl> -ROB<Impl>::ROB(unsigned _numEntries, unsigned _squashWidth, - string _smtROBPolicy, unsigned _smtROBThreshold, - unsigned _numThreads) - : numEntries(_numEntries), - squashWidth(_squashWidth), - numInstsInROB(0), - squashedSeqNum(0), - numThreads(_numThreads) -{ - for (int tid=0; tid < numThreads; tid++) { - doneSquashing[tid] = true; - threadEntries[tid] = 0; - } - - string policy = _smtROBPolicy; - - //Convert string to lowercase - std::transform(policy.begin(), policy.end(), policy.begin(), - (int(*)(int)) tolower); - - //Figure out rob policy - if (policy == "dynamic") { - robPolicy = Dynamic; - - //Set Max Entries to Total ROB Capacity - for (int i = 0; i < numThreads; i++) { - maxEntries[i]=numEntries; - } - - } else if (policy == "partitioned") { - robPolicy = Partitioned; - DPRINTF(Fetch, "ROB sharing policy set to Partitioned\n"); - - //@todo:make work if part_amt doesnt divide evenly. - int part_amt = numEntries / numThreads; - - //Divide ROB up evenly - for (int i = 0; i < numThreads; i++) { - maxEntries[i]=part_amt; - } - - } else if (policy == "threshold") { - robPolicy = Threshold; - DPRINTF(Fetch, "ROB sharing policy set to Threshold\n"); - - int threshold = _smtROBThreshold;; - - //Divide up by threshold amount - for (int i = 0; i < numThreads; i++) { - maxEntries[i]=threshold; - } - } else { - assert(0 && "Invalid ROB Sharing Policy.Options Are:{Dynamic," - "Partitioned, Threshold}"); - } -} - -template <class Impl> -std::string -ROB<Impl>::name() const -{ - return cpu->name() + ".rob"; -} - -template <class Impl> -void -ROB<Impl>::setCPU(FullCPU *cpu_ptr) -{ - cpu = cpu_ptr; - - // Set the per-thread iterators to the end of the instruction list. - for (int i=0; i < numThreads;i++) { - squashIt[i] = instList[i].end(); - } - - // Initialize the "universal" ROB head & tail point to invalid - // pointers - head = instList[0].end(); - tail = instList[0].end(); -} - -template <class Impl> -void -ROB<Impl>::setActiveThreads(list<unsigned> *at_ptr) -{ - DPRINTF(ROB, "Setting active threads list pointer.\n"); - activeThreads = at_ptr; -} - -template <class Impl> -void -ROB<Impl>::switchOut() -{ - for (int tid = 0; tid < numThreads; tid++) { - instList[tid].clear(); - } -} - -template <class Impl> -void -ROB<Impl>::takeOverFrom() -{ - for (int tid=0; tid < numThreads; tid++) { - doneSquashing[tid] = true; - threadEntries[tid] = 0; - squashIt[tid] = instList[tid].end(); - } - numInstsInROB = 0; - - // Initialize the "universal" ROB head & tail point to invalid - // pointers - head = instList[0].end(); - tail = instList[0].end(); -} - -template <class Impl> -void -ROB<Impl>::resetEntries() -{ - if (robPolicy != Dynamic || numThreads > 1) { - int active_threads = (*activeThreads).size(); - - list<unsigned>::iterator threads = (*activeThreads).begin(); - list<unsigned>::iterator list_end = (*activeThreads).end(); - - while (threads != list_end) { - if (robPolicy == Partitioned) { - maxEntries[*threads++] = numEntries / active_threads; - } else if (robPolicy == Threshold && active_threads == 1) { - maxEntries[*threads++] = numEntries; - } - } - } -} - -template <class Impl> -int -ROB<Impl>::entryAmount(int num_threads) -{ - if (robPolicy == Partitioned) { - return numEntries / num_threads; - } else { - return 0; - } -} - -template <class Impl> -int -ROB<Impl>::countInsts() -{ - int total=0; - - for (int i=0;i < numThreads;i++) - total += countInsts(i); - - return total; -} - -template <class Impl> -int -ROB<Impl>::countInsts(unsigned tid) -{ - return instList[tid].size(); -} - -template <class Impl> -void -ROB<Impl>::insertInst(DynInstPtr &inst) -{ - //assert(numInstsInROB == countInsts()); - assert(inst); - - DPRINTF(ROB, "Adding inst PC %#x to the ROB.\n", inst->readPC()); - - assert(numInstsInROB != numEntries); - - int tid = inst->threadNumber; - - instList[tid].push_back(inst); - - //Set Up head iterator if this is the 1st instruction in the ROB - if (numInstsInROB == 0) { - head = instList[tid].begin(); - assert((*head) == inst); - } - - //Must Decrement for iterator to actually be valid since __.end() - //actually points to 1 after the last inst - tail = instList[tid].end(); - tail--; - - inst->setInROB(); - - ++numInstsInROB; - ++threadEntries[tid]; - - assert((*tail) == inst); - - DPRINTF(ROB, "[tid:%i] Now has %d instructions.\n", tid, threadEntries[tid]); -} - -// Whatever calls this function needs to ensure that it properly frees up -// registers prior to this function. -/* -template <class Impl> -void -ROB<Impl>::retireHead() -{ - //assert(numInstsInROB == countInsts()); - assert(numInstsInROB > 0); - - int tid = (*head)->threadNumber; - - retireHead(tid); - - if (numInstsInROB == 0) { - tail = instList[tid].end(); - } -} -*/ - -template <class Impl> -void -ROB<Impl>::retireHead(unsigned tid) -{ - //assert(numInstsInROB == countInsts()); - assert(numInstsInROB > 0); - - // Get the head ROB instruction. - InstIt head_it = instList[tid].begin(); - - DynInstPtr head_inst = (*head_it); - - assert(head_inst->readyToCommit()); - - DPRINTF(ROB, "[tid:%u]: Retiring head instruction, " - "instruction PC %#x,[sn:%lli]\n", tid, head_inst->readPC(), - head_inst->seqNum); - - --numInstsInROB; - --threadEntries[tid]; - - head_inst->removeInROB(); - head_inst->setCommitted(); - - instList[tid].erase(head_it); - - //Update "Global" Head of ROB - updateHead(); - - // @todo: A special case is needed if the instruction being - // retired is the only instruction in the ROB; otherwise the tail - // iterator will become invalidated. - cpu->removeFrontInst(head_inst); -} -/* -template <class Impl> -bool -ROB<Impl>::isHeadReady() -{ - if (numInstsInROB != 0) { - return (*head)->readyToCommit(); - } - - return false; -} -*/ -template <class Impl> -bool -ROB<Impl>::isHeadReady(unsigned tid) -{ - if (threadEntries[tid] != 0) { - return instList[tid].front()->readyToCommit(); - } - - return false; -} - -template <class Impl> -bool -ROB<Impl>::canCommit() -{ - //@todo: set ActiveThreads through ROB or CPU - list<unsigned>::iterator threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - if (isHeadReady(tid)) { - return true; - } - } - - return false; -} - -template <class Impl> -unsigned -ROB<Impl>::numFreeEntries() -{ - //assert(numInstsInROB == countInsts()); - - return numEntries - numInstsInROB; -} - -template <class Impl> -unsigned -ROB<Impl>::numFreeEntries(unsigned tid) -{ - return maxEntries[tid] - threadEntries[tid]; -} - -template <class Impl> -void -ROB<Impl>::doSquash(unsigned tid) -{ - DPRINTF(ROB, "[tid:%u]: Squashing instructions until [sn:%i].\n", - tid, squashedSeqNum); - - assert(squashIt[tid] != instList[tid].end()); - - if ((*squashIt[tid])->seqNum < squashedSeqNum) { - DPRINTF(ROB, "[tid:%u]: Done squashing instructions.\n", - tid); - - squashIt[tid] = instList[tid].end(); - - doneSquashing[tid] = true; - return; - } - - bool robTailUpdate = false; - - for (int numSquashed = 0; - numSquashed < squashWidth && - squashIt[tid] != instList[tid].end() && - (*squashIt[tid])->seqNum > squashedSeqNum; - ++numSquashed) - { - DPRINTF(ROB, "[tid:%u]: Squashing instruction PC %#x, seq num %i.\n", - (*squashIt[tid])->threadNumber, - (*squashIt[tid])->readPC(), - (*squashIt[tid])->seqNum); - - // Mark the instruction as squashed, and ready to commit so that - // it can drain out of the pipeline. - (*squashIt[tid])->setSquashed(); - - (*squashIt[tid])->setCanCommit(); - - - if (squashIt[tid] == instList[tid].begin()) { - DPRINTF(ROB, "Reached head of instruction list while " - "squashing.\n"); - - squashIt[tid] = instList[tid].end(); - - doneSquashing[tid] = true; - - return; - } - - InstIt tail_thread = instList[tid].end(); - tail_thread--; - - if ((*squashIt[tid]) == (*tail_thread)) - robTailUpdate = true; - - squashIt[tid]--; - } - - - // Check if ROB is done squashing. - if ((*squashIt[tid])->seqNum <= squashedSeqNum) { - DPRINTF(ROB, "[tid:%u]: Done squashing instructions.\n", - tid); - - squashIt[tid] = instList[tid].end(); - - doneSquashing[tid] = true; - } - - if (robTailUpdate) { - updateTail(); - } -} - - -template <class Impl> -void -ROB<Impl>::updateHead() -{ - DynInstPtr head_inst; - InstSeqNum lowest_num = 0; - bool first_valid = true; - - // @todo: set ActiveThreads through ROB or CPU - list<unsigned>::iterator threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned thread_num = *threads++; - - if (instList[thread_num].empty()) - continue; - - if (first_valid) { - head = instList[thread_num].begin(); - lowest_num = (*head)->seqNum; - first_valid = false; - continue; - } - - InstIt head_thread = instList[thread_num].begin(); - - DynInstPtr head_inst = (*head_thread); - - assert(head_inst != 0); - - if (head_inst->seqNum < lowest_num) { - head = head_thread; - lowest_num = head_inst->seqNum; - } - } - - if (first_valid) { - head = instList[0].end(); - } - -} - -template <class Impl> -void -ROB<Impl>::updateTail() -{ - tail = instList[0].end(); - bool first_valid = true; - - list<unsigned>::iterator threads = (*activeThreads).begin(); - - while (threads != (*activeThreads).end()) { - unsigned tid = *threads++; - - if (instList[tid].empty()) { - continue; - } - - // If this is the first valid then assign w/out - // comparison - if (first_valid) { - tail = instList[tid].end(); - tail--; - first_valid = false; - continue; - } - - // Assign new tail if this thread's tail is younger - // than our current "tail high" - InstIt tail_thread = instList[tid].end(); - tail_thread--; - - if ((*tail_thread)->seqNum > (*tail)->seqNum) { - tail = tail_thread; - } - } -} - - -template <class Impl> -void -ROB<Impl>::squash(InstSeqNum squash_num,unsigned tid) -{ - if (isEmpty()) { - DPRINTF(ROB, "Does not need to squash due to being empty " - "[sn:%i]\n", - squash_num); - - return; - } - - DPRINTF(ROB, "Starting to squash within the ROB.\n"); - - robStatus[tid] = ROBSquashing; - - doneSquashing[tid] = false; - - squashedSeqNum = squash_num; - - if (!instList[tid].empty()) { - InstIt tail_thread = instList[tid].end(); - tail_thread--; - - squashIt[tid] = tail_thread; - - doSquash(tid); - } -} -/* -template <class Impl> -typename Impl::DynInstPtr -ROB<Impl>::readHeadInst() -{ - if (numInstsInROB != 0) { - assert((*head)->isInROB()==true); - return *head; - } else { - return dummyInst; - } -} -*/ -template <class Impl> -typename Impl::DynInstPtr -ROB<Impl>::readHeadInst(unsigned tid) -{ - if (threadEntries[tid] != 0) { - InstIt head_thread = instList[tid].begin(); - - assert((*head_thread)->isInROB()==true); - - return *head_thread; - } else { - return dummyInst; - } -} -/* -template <class Impl> -uint64_t -ROB<Impl>::readHeadPC() -{ - //assert(numInstsInROB == countInsts()); - - DynInstPtr head_inst = *head; - - return head_inst->readPC(); -} - -template <class Impl> -uint64_t -ROB<Impl>::readHeadPC(unsigned tid) -{ - //assert(numInstsInROB == countInsts()); - InstIt head_thread = instList[tid].begin(); - - return (*head_thread)->readPC(); -} - - -template <class Impl> -uint64_t -ROB<Impl>::readHeadNextPC() -{ - //assert(numInstsInROB == countInsts()); - - DynInstPtr head_inst = *head; - - return head_inst->readNextPC(); -} - -template <class Impl> -uint64_t -ROB<Impl>::readHeadNextPC(unsigned tid) -{ - //assert(numInstsInROB == countInsts()); - InstIt head_thread = instList[tid].begin(); - - return (*head_thread)->readNextPC(); -} - -template <class Impl> -InstSeqNum -ROB<Impl>::readHeadSeqNum() -{ - //assert(numInstsInROB == countInsts()); - DynInstPtr head_inst = *head; - - return head_inst->seqNum; -} - -template <class Impl> -InstSeqNum -ROB<Impl>::readHeadSeqNum(unsigned tid) -{ - InstIt head_thread = instList[tid].begin(); - - return ((*head_thread)->seqNum); -} - -template <class Impl> -typename Impl::DynInstPtr -ROB<Impl>::readTailInst() -{ - //assert(numInstsInROB == countInsts()); - //assert(tail != instList[0].end()); - - return (*tail); -} -*/ -template <class Impl> -typename Impl::DynInstPtr -ROB<Impl>::readTailInst(unsigned tid) -{ - //assert(tail_thread[tid] != instList[tid].end()); - - InstIt tail_thread = instList[tid].end(); - tail_thread--; - - return *tail_thread; -} - -/* -template <class Impl> -uint64_t -ROB<Impl>::readTailPC() -{ - //assert(numInstsInROB == countInsts()); - - //assert(tail != instList[0].end()); - - return (*tail)->readPC(); -} - -template <class Impl> -uint64_t -ROB<Impl>::readTailPC(unsigned tid) -{ - //assert(tail_thread[tid] != instList[tid].end()); - - InstIt tail_thread = instList[tid].end(); - tail_thread--; - - return (*tail_thread)->readPC(); -} - -template <class Impl> -InstSeqNum -ROB<Impl>::readTailSeqNum() -{ - // Return the last sequence number that has not been squashed. Other - // stages can use it to squash any instructions younger than the current - // tail. - return (*tail)->seqNum; -} - -template <class Impl> -InstSeqNum -ROB<Impl>::readTailSeqNum(unsigned tid) -{ - // Return the last sequence number that has not been squashed. Other - // stages can use it to squash any instructions younger than the current - // tail. - // assert(tail_thread[tid] != instList[tid].end()); - - InstIt tail_thread = instList[tid].end(); - tail_thread--; - - return (*tail_thread)->seqNum; -} -*/ diff --git a/cpu/o3/sat_counter.hh b/cpu/o3/sat_counter.hh deleted file mode 100644 index d01fd93ce..000000000 --- a/cpu/o3/sat_counter.hh +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2005-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. - */ - -#ifndef __CPU_O3_SAT_COUNTER_HH__ -#define __CPU_O3_SAT_COUNTER_HH__ - -#include "sim/host.hh" - -/** - * Private counter class for the internal saturating counters. - * Implements an n bit saturating counter and provides methods to - * increment, decrement, and read it. - * @todo Consider making this something that more closely mimics a - * built in class so you can use ++ or --. - */ -class SatCounter -{ - public: - /** - * Constructor for the counter. - */ - SatCounter() - : initialVal(0), counter(0) - { } - - /** - * Constructor for the counter. - * @param bits How many bits the counter will have. - */ - SatCounter(unsigned bits) - : initialVal(0), maxVal((1 << bits) - 1), counter(0) - { } - - /** - * Constructor for the counter. - * @param bits How many bits the counter will have. - * @param initial_val Starting value for each counter. - */ - SatCounter(unsigned bits, uint8_t initial_val) - : initialVal(initialVal), maxVal((1 << bits) - 1), counter(initial_val) - { - // Check to make sure initial value doesn't exceed the max - // counter value. - if (initial_val > maxVal) { - fatal("BP: Initial counter value exceeds max size."); - } - } - - /** - * Sets the number of bits. - */ - void setBits(unsigned bits) { maxVal = (1 << bits) - 1; } - - void reset() { counter = initialVal; } - - /** - * Increments the counter's current value. - */ - void increment() - { - if (counter < maxVal) { - ++counter; - } - } - - /** - * Decrements the counter's current value. - */ - void decrement() - { - if (counter > 0) { - --counter; - } - } - - /** - * Read the counter's value. - */ - const uint8_t read() const - { return counter; } - - private: - uint8_t initialVal; - uint8_t maxVal; - uint8_t counter; -}; - -#endif // __CPU_O3_SAT_COUNTER_HH__ diff --git a/cpu/o3/scoreboard.cc b/cpu/o3/scoreboard.cc deleted file mode 100644 index b0e433620..000000000 --- a/cpu/o3/scoreboard.cc +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/o3/scoreboard.hh" - -Scoreboard::Scoreboard(unsigned activeThreads, - unsigned _numLogicalIntRegs, - unsigned _numPhysicalIntRegs, - unsigned _numLogicalFloatRegs, - unsigned _numPhysicalFloatRegs, - unsigned _numMiscRegs, - unsigned _zeroRegIdx) - : numLogicalIntRegs(_numLogicalIntRegs), - numPhysicalIntRegs(_numPhysicalIntRegs), - numLogicalFloatRegs(_numLogicalFloatRegs), - numPhysicalFloatRegs(_numPhysicalFloatRegs), - numMiscRegs(_numMiscRegs), - zeroRegIdx(_zeroRegIdx) -{ - //Get Register Sizes - numLogicalRegs = numLogicalIntRegs + numLogicalFloatRegs; - numPhysicalRegs = numPhysicalIntRegs + numPhysicalFloatRegs; - - //Resize scoreboard appropriately - regScoreBoard.resize(numPhysicalRegs + (numMiscRegs * activeThreads)); - - //Initialize values - for (int i=0; i < numLogicalIntRegs * activeThreads; i++) { - regScoreBoard[i] = 1; - } - - for (int i= numPhysicalIntRegs; - i < numPhysicalIntRegs + (numLogicalFloatRegs * activeThreads); - i++) { - regScoreBoard[i] = 1; - } - - for (int i = numPhysicalRegs; - i < numPhysicalRegs + (numMiscRegs * activeThreads); - i++) { - regScoreBoard[i] = 1; - } -} - -std::string -Scoreboard::name() const -{ - return "cpu.scoreboard"; -} - -bool -Scoreboard::getReg(PhysRegIndex phys_reg) -{ - // Always ready if int or fp zero reg. - if (phys_reg == zeroRegIdx || - phys_reg == (zeroRegIdx + numPhysicalIntRegs)) { - return 1; - } - - return regScoreBoard[phys_reg]; -} - -void -Scoreboard::setReg(PhysRegIndex phys_reg) -{ - DPRINTF(Scoreboard, "Setting reg %i as ready\n", phys_reg); - - regScoreBoard[phys_reg] = 1; -} - -void -Scoreboard::unsetReg(PhysRegIndex ready_reg) -{ - if (ready_reg == zeroRegIdx || - ready_reg == (zeroRegIdx + numPhysicalIntRegs)) { - // Don't do anything if int or fp zero reg. - return; - } - - regScoreBoard[ready_reg] = 0; -} diff --git a/cpu/o3/scoreboard.hh b/cpu/o3/scoreboard.hh deleted file mode 100644 index 77f2cf157..000000000 --- a/cpu/o3/scoreboard.hh +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_SCOREBOARD_HH__ -#define __CPU_O3_SCOREBOARD_HH__ - -#include <iostream> -#include <utility> -#include <vector> -#include "arch/alpha/isa_traits.hh" -#include "base/trace.hh" -#include "base/traceflags.hh" -#include "cpu/o3/comm.hh" - -/** - * Implements a simple scoreboard to track which registers are ready. - * This class assumes that the fp registers start, index wise, right after - * the integer registers. The misc. registers start, index wise, right after - * the fp registers. - * @todo: Fix up handling of the zero register in case the decoder does not - * automatically make insts that write the zero register into nops. - */ -class Scoreboard -{ - public: - /** Constructs a scoreboard. - * @param activeThreads The number of active threads. - * @param _numLogicalIntRegs Number of logical integer registers. - * @param _numPhysicalIntRegs Number of physical integer registers. - * @param _numLogicalFloatRegs Number of logical fp registers. - * @param _numPhysicalFloatRegs Number of physical fp registers. - * @param _numMiscRegs Number of miscellaneous registers. - * @param _zeroRegIdx Index of the zero register. - */ - Scoreboard(unsigned activeThreads, - unsigned _numLogicalIntRegs, - unsigned _numPhysicalIntRegs, - unsigned _numLogicalFloatRegs, - unsigned _numPhysicalFloatRegs, - unsigned _numMiscRegs, - unsigned _zeroRegIdx); - - /** Destructor. */ - ~Scoreboard() {} - - /** Returns the name of the scoreboard. */ - std::string name() const; - - /** Checks if the register is ready. */ - bool getReg(PhysRegIndex ready_reg); - - /** Sets the register as ready. */ - void setReg(PhysRegIndex phys_reg); - - /** Sets the register as not ready. */ - void unsetReg(PhysRegIndex ready_reg); - - private: - /** Scoreboard of physical integer registers, saying whether or not they - * are ready. - */ - std::vector<bool> regScoreBoard; - - /** Number of logical integer registers. */ - int numLogicalIntRegs; - - /** Number of physical integer registers. */ - int numPhysicalIntRegs; - - /** Number of logical floating point registers. */ - int numLogicalFloatRegs; - - /** Number of physical floating point registers. */ - int numPhysicalFloatRegs; - - /** Number of miscellaneous registers. */ - int numMiscRegs; - - /** Number of logical integer + float registers. */ - int numLogicalRegs; - - /** Number of physical integer + float registers. */ - int numPhysicalRegs; - - /** The logical index of the zero register. */ - int zeroRegIdx; -}; - -#endif diff --git a/cpu/o3/store_set.cc b/cpu/o3/store_set.cc deleted file mode 100644 index 0c957c8c7..000000000 --- a/cpu/o3/store_set.cc +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "base/trace.hh" -#include "cpu/o3/store_set.hh" - -StoreSet::StoreSet(int _SSIT_size, int _LFST_size) - : SSITSize(_SSIT_size), LFSTSize(_LFST_size) -{ - DPRINTF(StoreSet, "StoreSet: Creating store set object.\n"); - DPRINTF(StoreSet, "StoreSet: SSIT size: %i, LFST size: %i.\n", - SSITSize, LFSTSize); - - SSIT.resize(SSITSize); - - validSSIT.resize(SSITSize); - - for (int i = 0; i < SSITSize; ++i) - validSSIT[i] = false; - - LFST.resize(LFSTSize); - - validLFST.resize(LFSTSize); - - for (int i = 0; i < LFSTSize; ++i) { - validLFST[i] = false; - LFST[i] = 0; - } - - indexMask = SSITSize - 1; - - offsetBits = 2; -} - -StoreSet::~StoreSet() -{ -} - -void -StoreSet::init(int _SSIT_size, int _LFST_size) -{ - SSITSize = _SSIT_size; - LFSTSize = _LFST_size; - - DPRINTF(StoreSet, "StoreSet: Creating store set object.\n"); - DPRINTF(StoreSet, "StoreSet: SSIT size: %i, LFST size: %i.\n", - SSITSize, LFSTSize); - - SSIT.resize(SSITSize); - - validSSIT.resize(SSITSize); - - for (int i = 0; i < SSITSize; ++i) - validSSIT[i] = false; - - LFST.resize(LFSTSize); - - validLFST.resize(LFSTSize); - - for (int i = 0; i < LFSTSize; ++i) { - validLFST[i] = false; - LFST[i] = 0; - } - - indexMask = SSITSize - 1; - - offsetBits = 2; -} - - -void -StoreSet::violation(Addr store_PC, Addr load_PC) -{ - int load_index = calcIndex(load_PC); - int store_index = calcIndex(store_PC); - - assert(load_index < SSITSize && store_index < SSITSize); - - bool valid_load_SSID = validSSIT[load_index]; - bool valid_store_SSID = validSSIT[store_index]; - - if (!valid_load_SSID && !valid_store_SSID) { - // Calculate a new SSID here. - SSID new_set = calcSSID(load_PC); - - validSSIT[load_index] = true; - - SSIT[load_index] = new_set; - - validSSIT[store_index] = true; - - SSIT[store_index] = new_set; - - assert(new_set < LFSTSize); - - DPRINTF(StoreSet, "StoreSet: Neither load nor store had a valid " - "storeset, creating a new one: %i for load %#x, store %#x\n", - new_set, load_PC, store_PC); - } else if (valid_load_SSID && !valid_store_SSID) { - SSID load_SSID = SSIT[load_index]; - - validSSIT[store_index] = true; - - SSIT[store_index] = load_SSID; - - assert(load_SSID < LFSTSize); - - DPRINTF(StoreSet, "StoreSet: Load had a valid store set. Adding " - "store to that set: %i for load %#x, store %#x\n", - load_SSID, load_PC, store_PC); - } else if (!valid_load_SSID && valid_store_SSID) { - SSID store_SSID = SSIT[store_index]; - - validSSIT[load_index] = true; - - SSIT[load_index] = store_SSID; - - DPRINTF(StoreSet, "StoreSet: Store had a valid store set: %i for " - "load %#x, store %#x\n", - store_SSID, load_PC, store_PC); - } else { - SSID load_SSID = SSIT[load_index]; - SSID store_SSID = SSIT[store_index]; - - assert(load_SSID < LFSTSize && store_SSID < LFSTSize); - - // The store set with the lower number wins - if (store_SSID > load_SSID) { - SSIT[store_index] = load_SSID; - - DPRINTF(StoreSet, "StoreSet: Load had smaller store set: %i; " - "for load %#x, store %#x\n", - load_SSID, load_PC, store_PC); - } else { - SSIT[load_index] = store_SSID; - - DPRINTF(StoreSet, "StoreSet: Store had smaller store set: %i; " - "for load %#x, store %#x\n", - store_SSID, load_PC, store_PC); - } - } -} - -void -StoreSet::insertLoad(Addr load_PC, InstSeqNum load_seq_num) -{ - // Does nothing. - return; -} - -void -StoreSet::insertStore(Addr store_PC, InstSeqNum store_seq_num, - unsigned tid) -{ - int index = calcIndex(store_PC); - - int store_SSID; - - assert(index < SSITSize); - - if (!validSSIT[index]) { - // Do nothing if there's no valid entry. - return; - } else { - store_SSID = SSIT[index]; - - assert(store_SSID < LFSTSize); - - // Update the last store that was fetched with the current one. - LFST[store_SSID] = store_seq_num; - - validLFST[store_SSID] = 1; - - storeList[store_seq_num] = store_SSID; - - DPRINTF(StoreSet, "Store %#x updated the LFST, SSID: %i\n", - store_PC, store_SSID); - } -} - -InstSeqNum -StoreSet::checkInst(Addr PC) -{ - int index = calcIndex(PC); - - int inst_SSID; - - assert(index < SSITSize); - - if (!validSSIT[index]) { - DPRINTF(StoreSet, "Inst %#x with index %i had no SSID\n", - PC, index); - - // Return 0 if there's no valid entry. - return 0; - } else { - inst_SSID = SSIT[index]; - - assert(inst_SSID < LFSTSize); - - if (!validLFST[inst_SSID]) { - - DPRINTF(StoreSet, "Inst %#x with index %i and SSID %i had no " - "dependency\n", PC, index, inst_SSID); - - return 0; - } else { - DPRINTF(StoreSet, "Inst %#x with index %i and SSID %i had LFST " - "inum of %i\n", PC, index, inst_SSID, LFST[inst_SSID]); - - return LFST[inst_SSID]; - } - } -} - -void -StoreSet::issued(Addr issued_PC, InstSeqNum issued_seq_num, bool is_store) -{ - // This only is updated upon a store being issued. - if (!is_store) { - return; - } - - int index = calcIndex(issued_PC); - - int store_SSID; - - assert(index < SSITSize); - - SeqNumMapIt store_list_it = storeList.find(issued_seq_num); - - if (store_list_it != storeList.end()) { - storeList.erase(store_list_it); - } - - // Make sure the SSIT still has a valid entry for the issued store. - if (!validSSIT[index]) { - return; - } - - store_SSID = SSIT[index]; - - assert(store_SSID < LFSTSize); - - // If the last fetched store in the store set refers to the store that - // was just issued, then invalidate the entry. - if (validLFST[store_SSID] && LFST[store_SSID] == issued_seq_num) { - DPRINTF(StoreSet, "StoreSet: store invalidated itself in LFST.\n"); - validLFST[store_SSID] = false; - } -} - -void -StoreSet::squash(InstSeqNum squashed_num, unsigned tid) -{ - DPRINTF(StoreSet, "StoreSet: Squashing until inum %i\n", - squashed_num); - - int idx; - SeqNumMapIt store_list_it = storeList.begin(); - - //@todo:Fix to only delete from correct thread - while (!storeList.empty()) { - idx = (*store_list_it).second; - - if ((*store_list_it).first <= squashed_num) { - break; - } - - bool younger = LFST[idx] > squashed_num; - - if (validLFST[idx] && younger) { - DPRINTF(StoreSet, "Squashed [sn:%lli]\n", LFST[idx]); - validLFST[idx] = false; - - storeList.erase(store_list_it++); - } else if (!validLFST[idx] && younger) { - storeList.erase(store_list_it++); - } - } -} - -void -StoreSet::clear() -{ - for (int i = 0; i < SSITSize; ++i) { - validSSIT[i] = false; - } - - for (int i = 0; i < LFSTSize; ++i) { - validLFST[i] = false; - } - - storeList.clear(); -} diff --git a/cpu/o3/store_set.hh b/cpu/o3/store_set.hh deleted file mode 100644 index 7189db3ab..000000000 --- a/cpu/o3/store_set.hh +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_STORE_SET_HH__ -#define __CPU_O3_STORE_SET_HH__ - -#include <list> -#include <map> -#include <utility> -#include <vector> - -#include "arch/isa_traits.hh" -#include "cpu/inst_seq.hh" - -struct ltseqnum { - bool operator()(const InstSeqNum &lhs, const InstSeqNum &rhs) const - { - return lhs > rhs; - } -}; - -class StoreSet -{ - public: - typedef unsigned SSID; - - public: - StoreSet() { }; - - StoreSet(int SSIT_size, int LFST_size); - - ~StoreSet(); - - void init(int SSIT_size, int LFST_size); - - void violation(Addr store_PC, Addr load_PC); - - void insertLoad(Addr load_PC, InstSeqNum load_seq_num); - - void insertStore(Addr store_PC, InstSeqNum store_seq_num, - unsigned tid); - - InstSeqNum checkInst(Addr PC); - - void issued(Addr issued_PC, InstSeqNum issued_seq_num, bool is_store); - - void squash(InstSeqNum squashed_num, unsigned tid); - - void clear(); - - private: - inline int calcIndex(Addr PC) - { return (PC >> offsetBits) & indexMask; } - - inline SSID calcSSID(Addr PC) - { return ((PC ^ (PC >> 10)) % LFSTSize); } - - std::vector<SSID> SSIT; - - std::vector<bool> validSSIT; - - std::vector<InstSeqNum> LFST; - - std::vector<bool> validLFST; - - std::map<InstSeqNum, int, ltseqnum> storeList; - - typedef std::map<InstSeqNum, int, ltseqnum>::iterator SeqNumMapIt; - - int SSITSize; - - int LFSTSize; - - int indexMask; - - // HACK: Hardcoded for now. - int offsetBits; -}; - -#endif // __CPU_O3_STORE_SET_HH__ diff --git a/cpu/o3/thread_state.hh b/cpu/o3/thread_state.hh deleted file mode 100644 index 2c9788e4b..000000000 --- a/cpu/o3/thread_state.hh +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (c) 2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_THREAD_STATE_HH__ -#define __CPU_O3_THREAD_STATE_HH__ - -#include "arch/faults.hh" -#include "arch/isa_traits.hh" -#include "cpu/exec_context.hh" -#include "cpu/thread_state.hh" - -class Event; -class Process; - -#if FULL_SYSTEM -class EndQuiesceEvent; -class FunctionProfile; -class ProfileNode; -#else -class FunctionalMemory; -class Process; -#endif - -/** - * 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 ExecContext - * proxy pointer, etc. It also handles anything related to a specific - * thread's process, such as syscalls and checking valid addresses. - */ -template <class Impl> -struct O3ThreadState : public ThreadState { - typedef ExecContext::Status Status; - typedef typename Impl::FullCPU FullCPU; - - Status _status; - - // Current instruction - TheISA::MachInst inst; - private: - FullCPU *cpu; - public: - - bool inSyscall; - - bool trapPending; - -#if FULL_SYSTEM - O3ThreadState(FullCPU *_cpu, int _thread_num, FunctionalMemory *_mem) - : ThreadState(-1, _thread_num, _mem), - inSyscall(0), trapPending(0) - { } -#else - O3ThreadState(FullCPU *_cpu, int _thread_num, Process *_process, int _asid) - : ThreadState(-1, _thread_num, _process->getMemory(), _process, _asid), - cpu(_cpu), inSyscall(0), trapPending(0) - { } - - O3ThreadState(FullCPU *_cpu, int _thread_num, FunctionalMemory *_mem, - int _asid) - : ThreadState(-1, _thread_num, _mem, NULL, _asid), - cpu(_cpu), inSyscall(0), trapPending(0) - { } -#endif - - ExecContext *xcProxy; - - ExecContext *getXCProxy() { return xcProxy; } - - Status status() const { return _status; } - - void setStatus(Status new_status) { _status = new_status; } - -#if !FULL_SYSTEM - bool validInstAddr(Addr addr) - { return process->validInstAddr(addr); } - - bool validDataAddr(Addr addr) - { return process->validDataAddr(addr); } -#endif - - bool misspeculating() { return false; } - - void setInst(TheISA::MachInst _inst) { inst = _inst; } - - Counter readFuncExeInst() { return funcExeInst; } - - void setFuncExeInst(Counter new_val) { funcExeInst = new_val; } - -#if !FULL_SYSTEM - void syscall() { process->syscall(xcProxy); } -#endif -}; - -#endif // __CPU_O3_THREAD_STATE_HH__ diff --git a/cpu/o3/tournament_pred.cc b/cpu/o3/tournament_pred.cc deleted file mode 100644 index 89da7b9f5..000000000 --- a/cpu/o3/tournament_pred.cc +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/o3/tournament_pred.hh" - -TournamentBP::TournamentBP(unsigned _localPredictorSize, - unsigned _localCtrBits, - unsigned _localHistoryTableSize, - unsigned _localHistoryBits, - unsigned _globalPredictorSize, - unsigned _globalCtrBits, - unsigned _globalHistoryBits, - unsigned _choicePredictorSize, - unsigned _choiceCtrBits, - unsigned _instShiftAmt) - : localPredictorSize(_localPredictorSize), - localCtrBits(_localCtrBits), - localHistoryTableSize(_localHistoryTableSize), - localHistoryBits(_localHistoryBits), - globalPredictorSize(_globalPredictorSize), - globalCtrBits(_globalCtrBits), - globalHistoryBits(_globalHistoryBits), - choicePredictorSize(_globalPredictorSize), - choiceCtrBits(_choiceCtrBits), - instShiftAmt(_instShiftAmt) -{ - //Should do checks here to make sure sizes are correct (powers of 2) - - //Setup the array of counters for the local predictor - localCtrs.resize(localPredictorSize); - - for (int i = 0; i < localPredictorSize; ++i) - localCtrs[i].setBits(localCtrBits); - - //Setup the history table for the local table - localHistoryTable.resize(localHistoryTableSize); - - for (int i = 0; i < localHistoryTableSize; ++i) - localHistoryTable[i] = 0; - - // Setup the local history mask - localHistoryMask = (1 << localHistoryBits) - 1; - - //Setup the array of counters for the global predictor - globalCtrs.resize(globalPredictorSize); - - for (int i = 0; i < globalPredictorSize; ++i) - globalCtrs[i].setBits(globalCtrBits); - - //Clear the global history - globalHistory = 0; - // Setup the global history mask - globalHistoryMask = (1 << globalHistoryBits) - 1; - - //Setup the array of counters for the choice predictor - choiceCtrs.resize(choicePredictorSize); - - for (int i = 0; i < choicePredictorSize; ++i) - choiceCtrs[i].setBits(choiceCtrBits); - - threshold = (1 << (localCtrBits - 1)) - 1; - threshold = threshold / 2; -} - -inline -unsigned -TournamentBP::calcLocHistIdx(Addr &branch_addr) -{ - return (branch_addr >> instShiftAmt) & (localHistoryTableSize - 1); -} - -inline -void -TournamentBP::updateHistoriesTaken(unsigned local_history_idx) -{ - globalHistory = (globalHistory << 1) | 1; - globalHistory = globalHistory & globalHistoryMask; - - localHistoryTable[local_history_idx] = - (localHistoryTable[local_history_idx] << 1) | 1; -} - -inline -void -TournamentBP::updateHistoriesNotTaken(unsigned local_history_idx) -{ - globalHistory = (globalHistory << 1); - globalHistory = globalHistory & globalHistoryMask; - - localHistoryTable[local_history_idx] = - (localHistoryTable[local_history_idx] << 1); -} - -bool -TournamentBP::lookup(Addr &branch_addr) -{ - uint8_t local_prediction; - unsigned local_history_idx; - unsigned local_predictor_idx; - - uint8_t global_prediction; - uint8_t choice_prediction; - - //Lookup in the local predictor to get its branch prediction - local_history_idx = calcLocHistIdx(branch_addr); - local_predictor_idx = localHistoryTable[local_history_idx] - & localHistoryMask; - local_prediction = localCtrs[local_predictor_idx].read(); - - //Lookup in the global predictor to get its branch prediction - global_prediction = globalCtrs[globalHistory].read(); - - //Lookup in the choice predictor to see which one to use - choice_prediction = choiceCtrs[globalHistory].read(); - - //@todo Put a threshold value in for the three predictors that can - // be set through the constructor (so this isn't hard coded). - //Also should put some of this code into functions. - if (choice_prediction > threshold) { - if (global_prediction > threshold) { - updateHistoriesTaken(local_history_idx); - - assert(globalHistory < globalPredictorSize && - local_history_idx < localPredictorSize); - - globalCtrs[globalHistory].increment(); - localCtrs[local_history_idx].increment(); - - return true; - } else { - updateHistoriesNotTaken(local_history_idx); - - assert(globalHistory < globalPredictorSize && - local_history_idx < localPredictorSize); - - globalCtrs[globalHistory].decrement(); - localCtrs[local_history_idx].decrement(); - - return false; - } - } else { - if (local_prediction > threshold) { - updateHistoriesTaken(local_history_idx); - - assert(globalHistory < globalPredictorSize && - local_history_idx < localPredictorSize); - - globalCtrs[globalHistory].increment(); - localCtrs[local_history_idx].increment(); - - return true; - } else { - updateHistoriesNotTaken(local_history_idx); - - assert(globalHistory < globalPredictorSize && - local_history_idx < localPredictorSize); - - globalCtrs[globalHistory].decrement(); - localCtrs[local_history_idx].decrement(); - - return false; - } - } -} - -// Update the branch predictor if it predicted a branch wrong. -void -TournamentBP::update(Addr &branch_addr, unsigned correct_gh, bool taken) -{ - - uint8_t local_prediction; - unsigned local_history_idx; - unsigned local_predictor_idx; - bool local_pred_taken; - - uint8_t global_prediction; - bool global_pred_taken; - - // Load the correct global history into the register. - globalHistory = correct_gh; - - // Get the local predictor's current prediction, remove the incorrect - // update, and update the local predictor - local_history_idx = calcLocHistIdx(branch_addr); - local_predictor_idx = localHistoryTable[local_history_idx]; - local_predictor_idx = (local_predictor_idx >> 1) & localHistoryMask; - - local_prediction = localCtrs[local_predictor_idx].read(); - local_pred_taken = local_prediction > threshold; - - //Get the global predictor's current prediction, and update the - //global predictor - global_prediction = globalCtrs[globalHistory].read(); - global_pred_taken = global_prediction > threshold; - - //Update the choice predictor to tell it which one was correct - if (local_pred_taken != global_pred_taken) { - //If the local prediction matches the actual outcome, decerement - //the counter. Otherwise increment the counter. - if (local_pred_taken == taken) { - choiceCtrs[globalHistory].decrement(); - } else { - choiceCtrs[globalHistory].increment(); - } - } - - if (taken) { - assert(globalHistory < globalPredictorSize && - local_predictor_idx < localPredictorSize); - - localCtrs[local_predictor_idx].increment(); - globalCtrs[globalHistory].increment(); - - globalHistory = (globalHistory << 1) | 1; - globalHistory = globalHistory & globalHistoryMask; - - localHistoryTable[local_history_idx] |= 1; - } else { - assert(globalHistory < globalPredictorSize && - local_predictor_idx < localPredictorSize); - - localCtrs[local_predictor_idx].decrement(); - globalCtrs[globalHistory].decrement(); - - globalHistory = (globalHistory << 1); - globalHistory = globalHistory & globalHistoryMask; - - localHistoryTable[local_history_idx] &= ~1; - } -} diff --git a/cpu/o3/tournament_pred.hh b/cpu/o3/tournament_pred.hh deleted file mode 100644 index 7b600aa53..000000000 --- a/cpu/o3/tournament_pred.hh +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_O3_TOURNAMENT_PRED_HH__ -#define __CPU_O3_TOURNAMENT_PRED_HH__ - -// For Addr type. -#include "arch/isa_traits.hh" -#include "cpu/o3/sat_counter.hh" -#include <vector> - -class TournamentBP -{ - public: - /** - * Default branch predictor constructor. - */ - TournamentBP(unsigned localPredictorSize, - unsigned localCtrBits, - unsigned localHistoryTableSize, - unsigned localHistoryBits, - unsigned globalPredictorSize, - unsigned globalHistoryBits, - unsigned globalCtrBits, - unsigned choicePredictorSize, - unsigned choiceCtrBits, - unsigned instShiftAmt); - - /** - * Looks up the given address in the branch predictor and returns - * a true/false value as to whether it is taken. - * @param branch_addr The address of the branch to look up. - * @return Whether or not the branch is taken. - */ - bool lookup(Addr &branch_addr); - - /** - * Updates the branch predictor with the actual result of a branch. - * @param branch_addr The address of the branch to update. - * @param taken Whether or not the branch was taken. - */ - void update(Addr &branch_addr, unsigned global_history, bool taken); - - inline unsigned readGlobalHist() { return globalHistory; } - - private: - - inline bool getPrediction(uint8_t &count); - - inline unsigned calcLocHistIdx(Addr &branch_addr); - - inline void updateHistoriesTaken(unsigned local_history_idx); - - inline void updateHistoriesNotTaken(unsigned local_history_idx); - - /** Local counters. */ - std::vector<SatCounter> localCtrs; - - /** Size of the local predictor. */ - unsigned localPredictorSize; - - /** Number of bits of the local predictor's counters. */ - unsigned localCtrBits; - - /** Array of local history table entries. */ - std::vector<unsigned> localHistoryTable; - - /** Size of the local history table. */ - unsigned localHistoryTableSize; - - /** Number of bits for each entry of the local history table. - * @todo Doesn't this come from the size of the local predictor? - */ - unsigned localHistoryBits; - - /** Mask to get the proper local history. */ - unsigned localHistoryMask; - - - /** Array of counters that make up the global predictor. */ - std::vector<SatCounter> globalCtrs; - - /** Size of the global predictor. */ - unsigned globalPredictorSize; - - /** Number of bits of the global predictor's counters. */ - unsigned globalCtrBits; - - /** Global history register. */ - unsigned globalHistory; - - /** Number of bits for the global history. */ - unsigned globalHistoryBits; - - /** Mask to get the proper global history. */ - unsigned globalHistoryMask; - - - /** Array of counters that make up the choice predictor. */ - std::vector<SatCounter> choiceCtrs; - - /** Size of the choice predictor (identical to the global predictor). */ - unsigned choicePredictorSize; - - /** Number of bits of the choice predictor's counters. */ - unsigned choiceCtrBits; - - /** Number of bits to shift the instruction over to get rid of the word - * offset. - */ - unsigned instShiftAmt; - - /** Threshold for the counter value; above the threshold is taken, - * equal to or below the threshold is not taken. - */ - unsigned threshold; -}; - -#endif // __CPU_O3_TOURNAMENT_PRED_HH__ diff --git a/cpu/ozone/back_end.cc b/cpu/ozone/back_end.cc deleted file mode 100644 index cb014e4cc..000000000 --- a/cpu/ozone/back_end.cc +++ /dev/null @@ -1,5 +0,0 @@ - -#include "cpu/ozone/back_end_impl.hh" -#include "cpu/ozone/ozone_impl.hh" - -//template class BackEnd<OzoneImpl>; diff --git a/cpu/ozone/back_end.hh b/cpu/ozone/back_end.hh deleted file mode 100644 index 14b011ab8..000000000 --- a/cpu/ozone/back_end.hh +++ /dev/null @@ -1,516 +0,0 @@ - -#ifndef __CPU_OZONE_BACK_END_HH__ -#define __CPU_OZONE_BACK_END_HH__ - -#include <list> -#include <queue> -#include <string> - -#include "arch/faults.hh" -#include "base/timebuf.hh" -#include "cpu/inst_seq.hh" -#include "cpu/ozone/rename_table.hh" -#include "cpu/ozone/thread_state.hh" -#include "mem/functional/functional.hh" -#include "mem/mem_interface.hh" -#include "mem/mem_req.hh" -#include "sim/eventq.hh" - -class ExecContext; - -template <class Impl> -class OzoneThreadState; - -template <class Impl> -class BackEnd -{ - public: - typedef OzoneThreadState<Impl> Thread; - - typedef typename Impl::Params Params; - typedef typename Impl::DynInst DynInst; - typedef typename Impl::DynInstPtr DynInstPtr; - typedef typename Impl::FullCPU FullCPU; - typedef typename Impl::FrontEnd FrontEnd; - typedef typename Impl::FullCPU::CommStruct CommStruct; - - struct SizeStruct { - int size; - }; - - typedef SizeStruct DispatchToIssue; - typedef SizeStruct IssueToExec; - typedef SizeStruct ExecToCommit; - typedef SizeStruct Writeback; - - TimeBuffer<DispatchToIssue> d2i; - typename TimeBuffer<DispatchToIssue>::wire instsToDispatch; - TimeBuffer<IssueToExec> i2e; - typename TimeBuffer<IssueToExec>::wire instsToExecute; - TimeBuffer<ExecToCommit> e2c; - TimeBuffer<Writeback> numInstsToWB; - - TimeBuffer<CommStruct> *comm; - typename TimeBuffer<CommStruct>::wire toIEW; - typename TimeBuffer<CommStruct>::wire fromCommit; - - class InstQueue { - enum queue { - NonSpec, - IQ, - ToBeScheduled, - ReadyList, - ReplayList - }; - struct pqCompare { - bool operator() (const DynInstPtr &lhs, const DynInstPtr &rhs) const - { - return lhs->seqNum > rhs->seqNum; - } - }; - public: - InstQueue(Params *params); - - std::string name() const; - - void regStats(); - - void setIssueExecQueue(TimeBuffer<IssueToExec> *i2e_queue); - - void setBE(BackEnd *_be) { be = _be; } - - void insert(DynInstPtr &inst); - - void scheduleReadyInsts(); - - void scheduleNonSpec(const InstSeqNum &sn); - - DynInstPtr getReadyInst(); - - void commit(const InstSeqNum &sn) {} - - void squash(const InstSeqNum &sn); - - int wakeDependents(DynInstPtr &inst); - - /** Tells memory dependence unit that a memory instruction needs to be - * rescheduled. It will re-execute once replayMemInst() is called. - */ - void rescheduleMemInst(DynInstPtr &inst); - - /** Re-executes all rescheduled memory instructions. */ - void replayMemInst(DynInstPtr &inst); - - /** Completes memory instruction. */ - void completeMemInst(DynInstPtr &inst); - - void violation(DynInstPtr &inst, DynInstPtr &violation) { } - - bool isFull() { return numInsts >= size; } - - void dumpInsts(); - - private: - bool find(queue q, typename std::list<DynInstPtr>::iterator it); - BackEnd *be; - TimeBuffer<IssueToExec> *i2e; - typename TimeBuffer<IssueToExec>::wire numIssued; - typedef typename std::list<DynInstPtr> InstList; - typedef typename std::list<DynInstPtr>::iterator InstListIt; - typedef typename std::priority_queue<DynInstPtr, std::vector<DynInstPtr>, pqCompare> ReadyInstQueue; - // Not sure I need the IQ list; it just needs to be a count. - InstList iq; - InstList toBeScheduled; - InstList readyList; - InstList nonSpec; - InstList replayList; - ReadyInstQueue readyQueue; - public: - int size; - int numInsts; - int width; - - Stats::VectorDistribution<> occ_dist; - - Stats::Vector<> inst_count; - Stats::Vector<> peak_inst_count; - Stats::Scalar<> empty_count; - Stats::Scalar<> current_count; - Stats::Scalar<> fullCount; - - Stats::Formula occ_rate; - Stats::Formula avg_residency; - Stats::Formula empty_rate; - Stats::Formula full_rate; - }; - - /** LdWriteback event for a load completion. */ - class LdWritebackEvent : public Event { - private: - /** Instruction that is writing back data to the register file. */ - DynInstPtr inst; - /** Pointer to IEW stage. */ - BackEnd *be; - - public: - /** Constructs a load writeback event. */ - LdWritebackEvent(DynInstPtr &_inst, BackEnd *be); - - /** Processes writeback event. */ - virtual void process(); - /** Returns the description of the writeback event. */ - virtual const char *description(); - }; - - BackEnd(Params *params); - - std::string name() const; - - void regStats(); - - void setCPU(FullCPU *cpu_ptr) - { cpu = cpu_ptr; } - - void setFrontEnd(FrontEnd *front_end_ptr) - { frontEnd = front_end_ptr; } - - void setXC(ExecContext *xc_ptr) - { xc = xc_ptr; } - - void setThreadState(Thread *thread_ptr) - { thread = thread_ptr; } - - void setCommBuffer(TimeBuffer<CommStruct> *_comm); - - void tick(); - void squash(); - void squashFromXC(); - bool xcSquash; - - template <class T> - Fault read(MemReqPtr &req, T &data, int load_idx); - - template <class T> - Fault write(MemReqPtr &req, T &data, int store_idx); - - Addr readCommitPC() { return commitPC; } - - Addr commitPC; - - bool robEmpty() { return instList.empty(); } - - bool isFull() { return numInsts >= numROBEntries; } - bool isBlocked() { return status == Blocked || dispatchStatus == Blocked; } - - /** Tells memory dependence unit that a memory instruction needs to be - * rescheduled. It will re-execute once replayMemInst() is called. - */ - void rescheduleMemInst(DynInstPtr &inst) - { IQ.rescheduleMemInst(inst); } - - /** Re-executes all rescheduled memory instructions. */ - void replayMemInst(DynInstPtr &inst) - { IQ.replayMemInst(inst); } - - /** Completes memory instruction. */ - void completeMemInst(DynInstPtr &inst) - { IQ.completeMemInst(inst); } - - void fetchFault(Fault &fault); - - private: - void updateStructures(); - void dispatchInsts(); - void dispatchStall(); - void checkDispatchStatus(); - void scheduleReadyInsts(); - void executeInsts(); - void commitInsts(); - void addToIQ(DynInstPtr &inst); - void addToLSQ(DynInstPtr &inst); - void instToCommit(DynInstPtr &inst); - void writebackInsts(); - bool commitInst(int inst_num); - void squash(const InstSeqNum &sn); - void squashDueToBranch(DynInstPtr &inst); - void squashDueToMemBlocked(DynInstPtr &inst); - void updateExeInstStats(DynInstPtr &inst); - void updateComInstStats(DynInstPtr &inst); - - public: - FullCPU *cpu; - - FrontEnd *frontEnd; - - ExecContext *xc; - - Thread *thread; - - enum Status { - Running, - Idle, - DcacheMissStall, - DcacheMissComplete, - Blocked - }; - - Status status; - - Status dispatchStatus; - - Counter funcExeInst; - - private: -// typedef typename Impl::InstQueue InstQueue; - - InstQueue IQ; - - typedef typename Impl::LdstQueue LdstQueue; - - LdstQueue LSQ; - public: - RenameTable<Impl> commitRenameTable; - - RenameTable<Impl> renameTable; - private: - class DCacheCompletionEvent : public Event - { - private: - BackEnd *be; - - public: - DCacheCompletionEvent(BackEnd *_be); - - virtual void process(); - virtual const char *description(); - }; - - friend class DCacheCompletionEvent; - - DCacheCompletionEvent cacheCompletionEvent; - - MemInterface *dcacheInterface; - - MemReqPtr memReq; - - // General back end width. Used if the more specific isn't given. - int width; - - // Dispatch width. - int dispatchWidth; - int numDispatchEntries; - int dispatchSize; - - int issueWidth; - - // Writeback width - int wbWidth; - - // Commit width - int commitWidth; - - /** Index into queue of instructions being written back. */ - unsigned wbNumInst; - - /** Cycle number within the queue of instructions being written - * back. Used in case there are too many instructions writing - * back at the current cycle and writesbacks need to be scheduled - * for the future. See comments in instToCommit(). - */ - unsigned wbCycle; - - int numROBEntries; - int numInsts; - - bool squashPending; - InstSeqNum squashSeqNum; - Addr squashNextPC; - - Fault faultFromFetch; - - private: - typedef typename std::list<DynInstPtr>::iterator InstListIt; - - std::list<DynInstPtr> instList; - std::list<DynInstPtr> dispatch; - std::list<DynInstPtr> writeback; - - int latency; - - int squashLatency; - - bool exactFullStall; - - bool fetchRedirect[Impl::MaxThreads]; - - // number of cycles stalled for D-cache misses -/* Stats::Scalar<> dcacheStallCycles; - Counter lastDcacheStall; -*/ - Stats::Vector<> rob_cap_events; - Stats::Vector<> rob_cap_inst_count; - Stats::Vector<> iq_cap_events; - Stats::Vector<> iq_cap_inst_count; - // total number of instructions executed - Stats::Vector<> exe_inst; - Stats::Vector<> exe_swp; - Stats::Vector<> exe_nop; - Stats::Vector<> exe_refs; - Stats::Vector<> exe_loads; - Stats::Vector<> exe_branches; - - Stats::Vector<> issued_ops; - - // total number of loads forwaded from LSQ stores - Stats::Vector<> lsq_forw_loads; - - // total number of loads ignored due to invalid addresses - Stats::Vector<> inv_addr_loads; - - // total number of software prefetches ignored due to invalid addresses - Stats::Vector<> inv_addr_swpfs; - // ready loads blocked due to memory disambiguation - Stats::Vector<> lsq_blocked_loads; - - Stats::Scalar<> lsqInversion; - - Stats::Vector<> n_issued_dist; - Stats::VectorDistribution<> issue_delay_dist; - - Stats::VectorDistribution<> queue_res_dist; -/* - Stats::Vector<> stat_fu_busy; - Stats::Vector2d<> stat_fuBusy; - Stats::Vector<> dist_unissued; - Stats::Vector2d<> stat_issued_inst_type; - - Stats::Formula misspec_cnt; - Stats::Formula misspec_ipc; - Stats::Formula issue_rate; - Stats::Formula issue_stores; - Stats::Formula issue_op_rate; - Stats::Formula fu_busy_rate; - Stats::Formula commit_stores; - Stats::Formula commit_ipc; - Stats::Formula commit_ipb; - Stats::Formula lsq_inv_rate; -*/ - Stats::Vector<> writeback_count; - Stats::Vector<> producer_inst; - Stats::Vector<> consumer_inst; - Stats::Vector<> wb_penalized; - - Stats::Formula wb_rate; - Stats::Formula wb_fanout; - Stats::Formula wb_penalized_rate; - - // total number of instructions committed - Stats::Vector<> stat_com_inst; - Stats::Vector<> stat_com_swp; - Stats::Vector<> stat_com_refs; - Stats::Vector<> stat_com_loads; - Stats::Vector<> stat_com_membars; - Stats::Vector<> stat_com_branches; - - Stats::Distribution<> n_committed_dist; - - Stats::Scalar<> commit_eligible_samples; - Stats::Vector<> commit_eligible; - - Stats::Scalar<> ROB_fcount; - Stats::Formula ROB_full_rate; - - Stats::Vector<> ROB_count; // cumulative ROB occupancy - Stats::Formula ROB_occ_rate; - Stats::VectorDistribution<> ROB_occ_dist; - public: - void dumpInsts(); -}; - -template <class Impl> -template <class T> -Fault -BackEnd<Impl>::read(MemReqPtr &req, T &data, int load_idx) -{ -/* memReq->reset(addr, sizeof(T), flags); - - // translate to physical address - Fault fault = cpu->translateDataReadReq(memReq); - - // if we have a cache, do cache access too - if (fault == NoFault && dcacheInterface) { - memReq->cmd = Read; - memReq->completionEvent = NULL; - memReq->time = curTick; - memReq->flags &= ~INST_READ; - MemAccessResult result = dcacheInterface->access(memReq); - - // Ugly hack to get an event scheduled *only* if the access is - // a miss. We really should add first-class support for this - // at some point. - if (result != MA_HIT && dcacheInterface->doEvents()) { - // Fix this hack for keeping funcExeInst correct with loads that - // are executed twice. - --funcExeInst; - - memReq->completionEvent = &cacheCompletionEvent; - lastDcacheStall = curTick; -// unscheduleTickEvent(); -// status = DcacheMissStall; - DPRINTF(OzoneCPU, "Dcache miss stall!\n"); - } else { - // do functional access - fault = thread->mem->read(memReq, data); - - } - } -*/ -/* - if (!dcacheInterface && (memReq->flags & UNCACHEABLE)) - recordEvent("Uncached Read"); -*/ - return LSQ.read(req, data, load_idx); -} - -template <class Impl> -template <class T> -Fault -BackEnd<Impl>::write(MemReqPtr &req, T &data, int store_idx) -{ -/* - memReq->reset(addr, sizeof(T), flags); - - // translate to physical address - Fault fault = cpu->translateDataWriteReq(memReq); - - if (fault == NoFault && dcacheInterface) { - memReq->cmd = Write; - memcpy(memReq->data,(uint8_t *)&data,memReq->size); - memReq->completionEvent = NULL; - memReq->time = curTick; - memReq->flags &= ~INST_READ; - MemAccessResult result = dcacheInterface->access(memReq); - - // Ugly hack to get an event scheduled *only* if the access is - // a miss. We really should add first-class support for this - // at some point. - if (result != MA_HIT && dcacheInterface->doEvents()) { - memReq->completionEvent = &cacheCompletionEvent; - lastDcacheStall = curTick; -// unscheduleTickEvent(); -// status = DcacheMissStall; - DPRINTF(OzoneCPU, "Dcache miss stall!\n"); - } - } - - if (res && (fault == NoFault)) - *res = memReq->result; - */ -/* - if (!dcacheInterface && (memReq->flags & UNCACHEABLE)) - recordEvent("Uncached Write"); -*/ - return LSQ.write(req, data, store_idx); -} - -#endif // __CPU_OZONE_BACK_END_HH__ diff --git a/cpu/ozone/back_end_impl.hh b/cpu/ozone/back_end_impl.hh deleted file mode 100644 index 36770d65c..000000000 --- a/cpu/ozone/back_end_impl.hh +++ /dev/null @@ -1,1904 +0,0 @@ - -#include "encumbered/cpu/full/op_class.hh" -#include "cpu/ozone/back_end.hh" - -template <class Impl> -BackEnd<Impl>::InstQueue::InstQueue(Params *params) - : size(params->numIQEntries), numInsts(0), width(params->issueWidth) -{ -} - -template <class Impl> -std::string -BackEnd<Impl>::InstQueue::name() const -{ - return be->name() + ".iq"; -} - -template <class Impl> -void -BackEnd<Impl>::InstQueue::regStats() -{ - using namespace Stats; - - occ_dist - .init(1, 0, size, 2) - .name(name() + "occ_dist") - .desc("IQ Occupancy per cycle") - .flags(total | cdf) - ; - - inst_count - .init(1) - .name(name() + "cum_num_insts") - .desc("Total occupancy") - .flags(total) - ; - - peak_inst_count - .init(1) - .name(name() + "peak_occupancy") - .desc("Peak IQ occupancy") - .flags(total) - ; - - current_count - .name(name() + "current_count") - .desc("Occupancy this cycle") - ; - - empty_count - .name(name() + "empty_count") - .desc("Number of empty cycles") - ; - - fullCount - .name(name() + "full_count") - .desc("Number of full cycles") - ; - - - occ_rate - .name(name() + "occ_rate") - .desc("Average occupancy") - .flags(total) - ; - occ_rate = inst_count / be->cpu->numCycles; - - avg_residency - .name(name() + "avg_residency") - .desc("Average IQ residency") - .flags(total) - ; - avg_residency = occ_rate / be->cpu->numCycles; - - empty_rate - .name(name() + "empty_rate") - .desc("Fraction of cycles empty") - ; - empty_rate = 100 * empty_count / be->cpu->numCycles; - - full_rate - .name(name() + "full_rate") - .desc("Fraction of cycles full") - ; - full_rate = 100 * fullCount / be->cpu->numCycles; -} - -template <class Impl> -void -BackEnd<Impl>::InstQueue::setIssueExecQueue(TimeBuffer<IssueToExec> *i2e_queue) -{ - i2e = i2e_queue; - numIssued = i2e->getWire(0); -} - -template <class Impl> -void -BackEnd<Impl>::InstQueue::insert(DynInstPtr &inst) -{ - numInsts++; - inst_count[0]++; - if (!inst->isNonSpeculative()) { - DPRINTF(BE, "Instruction [sn:%lli] added to IQ\n", inst->seqNum); - if (inst->readyToIssue()) { - toBeScheduled.push_front(inst); - inst->iqIt = toBeScheduled.begin(); - inst->iqItValid = true; - } else { - iq.push_front(inst); - inst->iqIt = iq.begin(); - inst->iqItValid = true; - } - } else { - DPRINTF(BE, "Nonspeculative instruction [sn:%lli] added to IQ\n", inst->seqNum); - nonSpec.push_front(inst); - inst->iqIt = nonSpec.begin(); - inst->iqItValid = true; - } -} - -template <class Impl> -void -BackEnd<Impl>::InstQueue::scheduleReadyInsts() -{ - int scheduled = numIssued->size; - InstListIt iq_it = --toBeScheduled.end(); - InstListIt iq_end_it = toBeScheduled.end(); - - while (iq_it != iq_end_it && scheduled < width) { -// if ((*iq_it)->readyToIssue()) { - DPRINTF(BE, "Instruction [sn:%lli] PC:%#x is ready\n", - (*iq_it)->seqNum, (*iq_it)->readPC()); - readyQueue.push(*iq_it); - readyList.push_front(*iq_it); - - (*iq_it)->iqIt = readyList.begin(); - - toBeScheduled.erase(iq_it--); - - ++scheduled; -// } else { -// iq_it++; -// } - } - - numIssued->size+= scheduled; -} - -template <class Impl> -void -BackEnd<Impl>::InstQueue::scheduleNonSpec(const InstSeqNum &sn) -{ -/* - InstListIt non_spec_it = nonSpec.begin(); - InstListIt non_spec_end_it = nonSpec.end(); - - while ((*non_spec_it)->seqNum != sn) { - non_spec_it++; - assert(non_spec_it != non_spec_end_it); - } -*/ - DynInstPtr inst = nonSpec.back(); - - DPRINTF(BE, "Nonspeculative instruction [sn:%lli] scheduled\n", inst->seqNum); - - assert(inst->seqNum == sn); - - assert(find(NonSpec, inst->iqIt)); - nonSpec.erase(inst->iqIt); - readyList.push_front(inst); - inst->iqIt = readyList.begin(); - readyQueue.push(inst); - numIssued->size++; -} - -template <class Impl> -typename Impl::DynInstPtr -BackEnd<Impl>::InstQueue::getReadyInst() -{ - assert(!readyList.empty()); - - DynInstPtr inst = readyQueue.top(); - readyQueue.pop(); - assert(find(ReadyList, inst->iqIt)); - readyList.erase(inst->iqIt); - inst->iqItValid = false; -// if (!inst->isMemRef()) - --numInsts; - return inst; -} - -template <class Impl> -void -BackEnd<Impl>::InstQueue::squash(const InstSeqNum &sn) -{ - InstListIt iq_it = iq.begin(); - InstListIt iq_end_it = iq.end(); - - while (iq_it != iq_end_it && (*iq_it)->seqNum > sn) { - DPRINTF(BE, "Instruction [sn:%lli] removed from IQ\n", (*iq_it)->seqNum); - (*iq_it)->iqItValid = false; - iq.erase(iq_it++); - --numInsts; - } - - iq_it = nonSpec.begin(); - iq_end_it = nonSpec.end(); - - while (iq_it != iq_end_it && (*iq_it)->seqNum > sn) { - DPRINTF(BE, "Instruction [sn:%lli] removed from IQ\n", (*iq_it)->seqNum); - (*iq_it)->iqItValid = false; - nonSpec.erase(iq_it++); - --numInsts; - } - - iq_it = replayList.begin(); - iq_end_it = replayList.end(); - - while (iq_it != iq_end_it) { - if ((*iq_it)->seqNum > sn) { - DPRINTF(BE, "Instruction [sn:%lli] removed from IQ\n", (*iq_it)->seqNum); - (*iq_it)->iqItValid = false; - replayList.erase(iq_it++); - --numInsts; - } else { - iq_it++; - } - } - - assert(numInsts >= 0); -/* - InstListIt ready_it = readyList.begin(); - InstListIt ready_end_it = readyList.end(); - - while (ready_it != ready_end_it) { - if ((*ready_it)->seqNum > sn) { - readyList.erase(ready_it++); - } else { - ready_it++; - } - } -*/ -} - -template <class Impl> -int -BackEnd<Impl>::InstQueue::wakeDependents(DynInstPtr &inst) -{ - assert(!inst->isSquashed()); - std::vector<DynInstPtr> &dependents = inst->getDependents(); - int num_outputs = dependents.size(); - - DPRINTF(BE, "Waking instruction [sn:%lli] dependents in IQ\n", inst->seqNum); - - for (int i = 0; i < num_outputs; i++) { - DynInstPtr dep_inst = dependents[i]; - dep_inst->markSrcRegReady(); - DPRINTF(BE, "Marking source reg ready [sn:%lli] in IQ\n", dep_inst->seqNum); - - if (dep_inst->readyToIssue() && dep_inst->iqItValid) { - if (dep_inst->isNonSpeculative()) { - assert(find(NonSpec, dep_inst->iqIt)); - nonSpec.erase(dep_inst->iqIt); - } else { - assert(find(IQ, dep_inst->iqIt)); - iq.erase(dep_inst->iqIt); - } - - toBeScheduled.push_front(dep_inst); - dep_inst->iqIt = toBeScheduled.begin(); - } - } - return num_outputs; -} - -template <class Impl> -void -BackEnd<Impl>::InstQueue::rescheduleMemInst(DynInstPtr &inst) -{ - DPRINTF(BE, "Rescheduling memory instruction [sn:%lli]\n", inst->seqNum); - assert(!inst->iqItValid); - replayList.push_front(inst); - inst->iqIt = replayList.begin(); - inst->iqItValid = true; - ++numInsts; -} - -template <class Impl> -void -BackEnd<Impl>::InstQueue::replayMemInst(DynInstPtr &inst) -{ - DPRINTF(BE, "Replaying memory instruction [sn:%lli]\n", inst->seqNum); - assert(find(ReplayList, inst->iqIt)); - InstListIt iq_it = --replayList.end(); - InstListIt iq_end_it = replayList.end(); - while (iq_it != iq_end_it) { - DynInstPtr rescheduled_inst = (*iq_it); - - DPRINTF(BE, "Memory instruction [sn:%lli] also replayed\n", inst->seqNum); - replayList.erase(iq_it--); - toBeScheduled.push_front(rescheduled_inst); - rescheduled_inst->iqIt = toBeScheduled.begin(); - } -} - -template <class Impl> -void -BackEnd<Impl>::InstQueue::completeMemInst(DynInstPtr &inst) -{ - panic("Not implemented."); -} - -template <class Impl> -bool -BackEnd<Impl>::InstQueue::find(queue q, InstListIt it) -{ - InstListIt iq_it, iq_end_it; - switch(q) { - case NonSpec: - iq_it = nonSpec.begin(); - iq_end_it = nonSpec.end(); - break; - case IQ: - iq_it = iq.begin(); - iq_end_it = iq.end(); - break; - case ToBeScheduled: - iq_it = toBeScheduled.begin(); - iq_end_it = toBeScheduled.end(); - break; - case ReadyList: - iq_it = readyList.begin(); - iq_end_it = readyList.end(); - break; - case ReplayList: - iq_it = replayList.begin(); - iq_end_it = replayList.end(); - } - - while (iq_it != it && iq_it != iq_end_it) { - iq_it++; - } - if (iq_it == it) { - return true; - } else { - return false; - } -} - -template <class Impl> -void -BackEnd<Impl>::InstQueue::dumpInsts() -{ - cprintf("IQ size: %i\n", iq.size()); - - InstListIt inst_list_it = --iq.end(); - - int num = 0; - int valid_num = 0; - while (inst_list_it != iq.end()) - { - cprintf("Instruction:%i\n", - num); - if (!(*inst_list_it)->isSquashed()) { - if (!(*inst_list_it)->isIssued()) { - ++valid_num; - cprintf("Count:%i\n", valid_num); - } else if ((*inst_list_it)->isMemRef() && - !(*inst_list_it)->memOpDone) { - // Loads that have not been marked as executed still count - // towards the total instructions. - ++valid_num; - cprintf("Count:%i\n", valid_num); - } - } - - cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" - "Issued:%i\nSquashed:%i\n", - (*inst_list_it)->readPC(), - (*inst_list_it)->seqNum, - (*inst_list_it)->threadNumber, - (*inst_list_it)->isIssued(), - (*inst_list_it)->isSquashed()); - - if ((*inst_list_it)->isMemRef()) { - cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone); - } - - cprintf("\n"); - - inst_list_it--; - ++num; - } - - cprintf("nonSpec size: %i\n", nonSpec.size()); - - inst_list_it = --nonSpec.end(); - - while (inst_list_it != nonSpec.end()) - { - cprintf("Instruction:%i\n", - num); - if (!(*inst_list_it)->isSquashed()) { - if (!(*inst_list_it)->isIssued()) { - ++valid_num; - cprintf("Count:%i\n", valid_num); - } else if ((*inst_list_it)->isMemRef() && - !(*inst_list_it)->memOpDone) { - // Loads that have not been marked as executed still count - // towards the total instructions. - ++valid_num; - cprintf("Count:%i\n", valid_num); - } - } - - cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" - "Issued:%i\nSquashed:%i\n", - (*inst_list_it)->readPC(), - (*inst_list_it)->seqNum, - (*inst_list_it)->threadNumber, - (*inst_list_it)->isIssued(), - (*inst_list_it)->isSquashed()); - - if ((*inst_list_it)->isMemRef()) { - cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone); - } - - cprintf("\n"); - - inst_list_it--; - ++num; - } - - cprintf("toBeScheduled size: %i\n", toBeScheduled.size()); - - inst_list_it = --toBeScheduled.end(); - - while (inst_list_it != toBeScheduled.end()) - { - cprintf("Instruction:%i\n", - num); - if (!(*inst_list_it)->isSquashed()) { - if (!(*inst_list_it)->isIssued()) { - ++valid_num; - cprintf("Count:%i\n", valid_num); - } else if ((*inst_list_it)->isMemRef() && - !(*inst_list_it)->memOpDone) { - // Loads that have not been marked as executed still count - // towards the total instructions. - ++valid_num; - cprintf("Count:%i\n", valid_num); - } - } - - cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" - "Issued:%i\nSquashed:%i\n", - (*inst_list_it)->readPC(), - (*inst_list_it)->seqNum, - (*inst_list_it)->threadNumber, - (*inst_list_it)->isIssued(), - (*inst_list_it)->isSquashed()); - - if ((*inst_list_it)->isMemRef()) { - cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone); - } - - cprintf("\n"); - - inst_list_it--; - ++num; - } - - cprintf("readyList size: %i\n", readyList.size()); - - inst_list_it = --readyList.end(); - - while (inst_list_it != readyList.end()) - { - cprintf("Instruction:%i\n", - num); - if (!(*inst_list_it)->isSquashed()) { - if (!(*inst_list_it)->isIssued()) { - ++valid_num; - cprintf("Count:%i\n", valid_num); - } else if ((*inst_list_it)->isMemRef() && - !(*inst_list_it)->memOpDone) { - // Loads that have not been marked as executed still count - // towards the total instructions. - ++valid_num; - cprintf("Count:%i\n", valid_num); - } - } - - cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" - "Issued:%i\nSquashed:%i\n", - (*inst_list_it)->readPC(), - (*inst_list_it)->seqNum, - (*inst_list_it)->threadNumber, - (*inst_list_it)->isIssued(), - (*inst_list_it)->isSquashed()); - - if ((*inst_list_it)->isMemRef()) { - cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone); - } - - cprintf("\n"); - - inst_list_it--; - ++num; - } -} - -template<class Impl> -BackEnd<Impl>::LdWritebackEvent::LdWritebackEvent(DynInstPtr &_inst, - BackEnd<Impl> *_be) - : Event(&mainEventQueue), inst(_inst), be(_be) -{ - this->setFlags(Event::AutoDelete); -} - -template<class Impl> -void -BackEnd<Impl>::LdWritebackEvent::process() -{ - DPRINTF(BE, "Load writeback event [sn:%lli]\n", inst->seqNum); -// DPRINTF(Activity, "Activity: Ld Writeback event [sn:%lli]\n", inst->seqNum); - - //iewStage->ldstQueue.removeMSHR(inst->threadNumber,inst->seqNum); - -// iewStage->wakeCPU(); - - if (inst->isSquashed()) { - inst = NULL; - return; - } - - if (!inst->isExecuted()) { - inst->setExecuted(); - - // Execute again to copy data to proper place. - inst->completeAcc(); - } - - // Need to insert instruction into queue to commit - be->instToCommit(inst); - - //wroteToTimeBuffer = true; -// iewStage->activityThisCycle(); - - inst = NULL; -} - -template<class Impl> -const char * -BackEnd<Impl>::LdWritebackEvent::description() -{ - return "Load writeback event"; -} - - -template <class Impl> -BackEnd<Impl>::DCacheCompletionEvent::DCacheCompletionEvent(BackEnd *_be) - : Event(&mainEventQueue, CPU_Tick_Pri), be(_be) -{ -} - -template <class Impl> -void -BackEnd<Impl>::DCacheCompletionEvent::process() -{ -} - -template <class Impl> -const char * -BackEnd<Impl>::DCacheCompletionEvent::description() -{ - return "Cache completion event"; -} - -template <class Impl> -BackEnd<Impl>::BackEnd(Params *params) - : d2i(5, 5), i2e(5, 5), e2c(5, 5), numInstsToWB(5, 5), - xcSquash(false), IQ(params), - cacheCompletionEvent(this), width(params->backEndWidth), - exactFullStall(true) -{ - numROBEntries = params->numROBEntries; - numInsts = 0; - numDispatchEntries = 32; - IQ.setBE(this); - LSQ.setBE(this); - - // Setup IQ and LSQ with their parameters here. - instsToDispatch = d2i.getWire(-1); - - instsToExecute = i2e.getWire(-1); - - IQ.setIssueExecQueue(&i2e); - - dispatchWidth = params->dispatchWidth ? params->dispatchWidth : width; - issueWidth = params->issueWidth ? params->issueWidth : width; - wbWidth = params->wbWidth ? params->wbWidth : width; - commitWidth = params->commitWidth ? params->commitWidth : width; - - LSQ.init(params, params->LQEntries, params->SQEntries, 0); - - dispatchStatus = Running; -} - -template <class Impl> -std::string -BackEnd<Impl>::name() const -{ - return cpu->name() + ".backend"; -} - -template <class Impl> -void -BackEnd<Impl>::regStats() -{ - using namespace Stats; - rob_cap_events - .init(cpu->number_of_threads) - .name(name() + ".ROB:cap_events") - .desc("number of cycles where ROB cap was active") - .flags(total) - ; - - rob_cap_inst_count - .init(cpu->number_of_threads) - .name(name() + ".ROB:cap_inst") - .desc("number of instructions held up by ROB cap") - .flags(total) - ; - - iq_cap_events - .init(cpu->number_of_threads) - .name(name() +".IQ:cap_events" ) - .desc("number of cycles where IQ cap was active") - .flags(total) - ; - - iq_cap_inst_count - .init(cpu->number_of_threads) - .name(name() + ".IQ:cap_inst") - .desc("number of instructions held up by IQ cap") - .flags(total) - ; - - - exe_inst - .init(cpu->number_of_threads) - .name(name() + ".ISSUE:count") - .desc("number of insts issued") - .flags(total) - ; - - exe_swp - .init(cpu->number_of_threads) - .name(name() + ".ISSUE:swp") - .desc("number of swp insts issued") - .flags(total) - ; - - exe_nop - .init(cpu->number_of_threads) - .name(name() + ".ISSUE:nop") - .desc("number of nop insts issued") - .flags(total) - ; - - exe_refs - .init(cpu->number_of_threads) - .name(name() + ".ISSUE:refs") - .desc("number of memory reference insts issued") - .flags(total) - ; - - exe_loads - .init(cpu->number_of_threads) - .name(name() + ".ISSUE:loads") - .desc("number of load insts issued") - .flags(total) - ; - - exe_branches - .init(cpu->number_of_threads) - .name(name() + ".ISSUE:branches") - .desc("Number of branches issued") - .flags(total) - ; - - issued_ops - .init(cpu->number_of_threads) - .name(name() + ".ISSUE:op_count") - .desc("number of insts issued") - .flags(total) - ; - -/* - for (int i=0; i<Num_OpClasses; ++i) { - stringstream subname; - subname << opClassStrings[i] << "_delay"; - issue_delay_dist.subname(i, subname.str()); - } -*/ - // - // Other stats - // - lsq_forw_loads - .init(cpu->number_of_threads) - .name(name() + ".LSQ:forw_loads") - .desc("number of loads forwarded via LSQ") - .flags(total) - ; - - inv_addr_loads - .init(cpu->number_of_threads) - .name(name() + ".ISSUE:addr_loads") - .desc("number of invalid-address loads") - .flags(total) - ; - - inv_addr_swpfs - .init(cpu->number_of_threads) - .name(name() + ".ISSUE:addr_swpfs") - .desc("number of invalid-address SW prefetches") - .flags(total) - ; - - lsq_blocked_loads - .init(cpu->number_of_threads) - .name(name() + ".LSQ:blocked_loads") - .desc("number of ready loads not issued due to memory disambiguation") - .flags(total) - ; - - lsqInversion - .name(name() + ".ISSUE:lsq_invert") - .desc("Number of times LSQ instruction issued early") - ; - - n_issued_dist - .init(issueWidth + 1) - .name(name() + ".ISSUE:issued_per_cycle") - .desc("Number of insts issued each cycle") - .flags(total | pdf | dist) - ; - issue_delay_dist - .init(Num_OpClasses,0,99,2) - .name(name() + ".ISSUE:") - .desc("cycles from operands ready to issue") - .flags(pdf | cdf) - ; - - queue_res_dist - .init(Num_OpClasses, 0, 99, 2) - .name(name() + ".IQ:residence:") - .desc("cycles from dispatch to issue") - .flags(total | pdf | cdf ) - ; - for (int i = 0; i < Num_OpClasses; ++i) { - queue_res_dist.subname(i, opClassStrings[i]); - } - - writeback_count - .init(cpu->number_of_threads) - .name(name() + ".WB:count") - .desc("cumulative count of insts written-back") - .flags(total) - ; - - producer_inst - .init(cpu->number_of_threads) - .name(name() + ".WB:producers") - .desc("num instructions producing a value") - .flags(total) - ; - - consumer_inst - .init(cpu->number_of_threads) - .name(name() + ".WB:consumers") - .desc("num instructions consuming a value") - .flags(total) - ; - - wb_penalized - .init(cpu->number_of_threads) - .name(name() + ".WB:penalized") - .desc("number of instrctions required to write to 'other' IQ") - .flags(total) - ; - - - wb_penalized_rate - .name(name() + ".WB:penalized_rate") - .desc ("fraction of instructions written-back that wrote to 'other' IQ") - .flags(total) - ; - - wb_penalized_rate = wb_penalized / writeback_count; - - wb_fanout - .name(name() + ".WB:fanout") - .desc("average fanout of values written-back") - .flags(total) - ; - - wb_fanout = producer_inst / consumer_inst; - - wb_rate - .name(name() + ".WB:rate") - .desc("insts written-back per cycle") - .flags(total) - ; - wb_rate = writeback_count / cpu->numCycles; - - stat_com_inst - .init(cpu->number_of_threads) - .name(name() + ".COM:count") - .desc("Number of instructions committed") - .flags(total) - ; - - stat_com_swp - .init(cpu->number_of_threads) - .name(name() + ".COM:swp_count") - .desc("Number of s/w prefetches committed") - .flags(total) - ; - - stat_com_refs - .init(cpu->number_of_threads) - .name(name() + ".COM:refs") - .desc("Number of memory references committed") - .flags(total) - ; - - stat_com_loads - .init(cpu->number_of_threads) - .name(name() + ".COM:loads") - .desc("Number of loads committed") - .flags(total) - ; - - stat_com_membars - .init(cpu->number_of_threads) - .name(name() + ".COM:membars") - .desc("Number of memory barriers committed") - .flags(total) - ; - - stat_com_branches - .init(cpu->number_of_threads) - .name(name() + ".COM:branches") - .desc("Number of branches committed") - .flags(total) - ; - n_committed_dist - .init(0,commitWidth,1) - .name(name() + ".COM:committed_per_cycle") - .desc("Number of insts commited each cycle") - .flags(pdf) - ; - - // - // Commit-Eligible instructions... - // - // -> The number of instructions eligible to commit in those - // cycles where we reached our commit BW limit (less the number - // actually committed) - // - // -> The average value is computed over ALL CYCLES... not just - // the BW limited cycles - // - // -> The standard deviation is computed only over cycles where - // we reached the BW limit - // - commit_eligible - .init(cpu->number_of_threads) - .name(name() + ".COM:bw_limited") - .desc("number of insts not committed due to BW limits") - .flags(total) - ; - - commit_eligible_samples - .name(name() + ".COM:bw_lim_events") - .desc("number cycles where commit BW limit reached") - ; - - ROB_fcount - .name(name() + ".ROB:full_count") - .desc("number of cycles where ROB was full") - ; - - ROB_count - .init(cpu->number_of_threads) - .name(name() + ".ROB:occupancy") - .desc(name() + ".ROB occupancy (cumulative)") - .flags(total) - ; - - ROB_full_rate - .name(name() + ".ROB:full_rate") - .desc("ROB full per cycle") - ; - ROB_full_rate = ROB_fcount / cpu->numCycles; - - ROB_occ_rate - .name(name() + ".ROB:occ_rate") - .desc("ROB occupancy rate") - .flags(total) - ; - ROB_occ_rate = ROB_count / cpu->numCycles; - - ROB_occ_dist - .init(cpu->number_of_threads,0,numROBEntries,2) - .name(name() + ".ROB:occ_dist") - .desc("ROB Occupancy per cycle") - .flags(total | cdf) - ; - - IQ.regStats(); -} - -template <class Impl> -void -BackEnd<Impl>::setCommBuffer(TimeBuffer<CommStruct> *_comm) -{ - comm = _comm; - toIEW = comm->getWire(0); - fromCommit = comm->getWire(-1); -} - -template <class Impl> -void -BackEnd<Impl>::tick() -{ - DPRINTF(BE, "Ticking back end\n"); - - ROB_count[0]+= numInsts; - - wbCycle = 0; - - if (xcSquash) { - squashFromXC(); - } - - // Read in any done instruction information and update the IQ or LSQ. - updateStructures(); - - if (dispatchStatus != Blocked) { - d2i.advance(); - dispatchInsts(); - } else { - checkDispatchStatus(); - } - - i2e.advance(); - scheduleReadyInsts(); - - e2c.advance(); - executeInsts(); - - numInstsToWB.advance(); - writebackInsts(); - - commitInsts(); - - DPRINTF(BE, "IQ entries in use: %i, ROB entries in use: %i, LSQ loads: %i, LSQ stores: %i\n", - IQ.numInsts, numInsts, LSQ.numLoads(), LSQ.numStores()); - - assert(numInsts == instList.size()); -} - -template <class Impl> -void -BackEnd<Impl>::updateStructures() -{ - if (fromCommit->doneSeqNum) { - IQ.commit(fromCommit->doneSeqNum); - LSQ.commitLoads(fromCommit->doneSeqNum); - LSQ.commitStores(fromCommit->doneSeqNum); - } - - if (fromCommit->nonSpecSeqNum) { - if (fromCommit->uncached) { - LSQ.executeLoad(fromCommit->lqIdx); - } else { - IQ.scheduleNonSpec( - fromCommit->nonSpecSeqNum); - } - } -} - -template <class Impl> -void -BackEnd<Impl>::addToIQ(DynInstPtr &inst) -{ - // Do anything IQ specific here? - IQ.insert(inst); -} - -template <class Impl> -void -BackEnd<Impl>::addToLSQ(DynInstPtr &inst) -{ - // Do anything LSQ specific here? - LSQ.insert(inst); -} - -template <class Impl> -void -BackEnd<Impl>::dispatchInsts() -{ - DPRINTF(BE, "Trying to dispatch instructions.\n"); - - // Pull instructions out of the front end. - int disp_width = dispatchWidth ? dispatchWidth : width; - - // Could model dispatching time, but in general 1 cycle is probably - // good enough. - - if (dispatchSize < numDispatchEntries) { - for (int i = 0; i < disp_width; i++) { - // Get instructions - DynInstPtr inst = frontEnd->getInst(); - - if (!inst) { - // No more instructions to get - break; - } - - DPRINTF(BE, "Processing instruction [sn:%lli] PC:%#x\n", - inst->seqNum, inst->readPC()); - - for (int i = 0; i < inst->numDestRegs(); ++i) - renameTable[inst->destRegIdx(i)] = inst; - - // Add to queue to be dispatched. - dispatch.push_back(inst); - - d2i[0].size++; - ++dispatchSize; - } - } - - assert(dispatch.size() < 64); - - for (int i = 0; i < instsToDispatch->size; ++i) { - assert(!dispatch.empty()); - // Get instruction from front of time buffer - DynInstPtr inst = dispatch.front(); - dispatch.pop_front(); - --dispatchSize; - - if (inst->isSquashed()) - continue; - - ++numInsts; - instList.push_back(inst); - - DPRINTF(BE, "Dispatching instruction [sn:%lli] PC:%#x\n", - inst->seqNum, inst->readPC()); - - addToIQ(inst); - - if (inst->isMemRef()) { - addToLSQ(inst); - } - - if (inst->isNonSpeculative()) { - inst->setCanCommit(); - } - - // Check if IQ or LSQ is full. If so we'll need to break and stop - // removing instructions. Also update the number of insts to remove - // from the queue. - if (exactFullStall) { - bool stall = false; - if (IQ.isFull()) { - DPRINTF(BE, "IQ is full!\n"); - stall = true; - } else if (LSQ.isFull()) { - DPRINTF(BE, "LSQ is full!\n"); - stall = true; - } else if (isFull()) { - DPRINTF(BE, "ROB is full!\n"); - stall = true; - ROB_fcount++; - } - if (stall) { - instsToDispatch->size-= i+1; - dispatchStall(); - return; - } - } - } - - // Check if IQ or LSQ is full. If so we'll need to break and stop - // removing instructions. Also update the number of insts to remove - // from the queue. Check here if we don't care about exact stall - // conditions. - - bool stall = false; - if (IQ.isFull()) { - DPRINTF(BE, "IQ is full!\n"); - stall = true; - } else if (LSQ.isFull()) { - DPRINTF(BE, "LSQ is full!\n"); - stall = true; - } else if (isFull()) { - DPRINTF(BE, "ROB is full!\n"); - stall = true; - ROB_fcount++; - } - if (stall) { - d2i.advance(); - dispatchStall(); - return; - } -} - -template <class Impl> -void -BackEnd<Impl>::dispatchStall() -{ - dispatchStatus = Blocked; - if (!cpu->decoupledFrontEnd) { - // Tell front end to stall here through a timebuffer, or just tell - // it directly. - } -} - -template <class Impl> -void -BackEnd<Impl>::checkDispatchStatus() -{ - DPRINTF(BE, "Checking dispatch status\n"); - assert(dispatchStatus == Blocked); - if (!IQ.isFull() && !LSQ.isFull() && !isFull()) { - DPRINTF(BE, "Dispatch no longer blocked\n"); - dispatchStatus = Running; - dispatchInsts(); - } -} - -template <class Impl> -void -BackEnd<Impl>::scheduleReadyInsts() -{ - // Tell IQ to put any ready instructions into the instruction list. - // Probably want to have a list of DynInstPtrs returned here. Then I - // can choose to either put them into a time buffer to simulate - // IQ scheduling time, or hand them directly off to the next stage. - // Do you ever want to directly hand it off to the next stage? - DPRINTF(BE, "Trying to schedule ready instructions\n"); - IQ.scheduleReadyInsts(); -} - -template <class Impl> -void -BackEnd<Impl>::executeInsts() -{ - int insts_to_execute = instsToExecute->size; - - issued_ops[0]+= insts_to_execute; - n_issued_dist[insts_to_execute]++; - - DPRINTF(BE, "Trying to execute %i instructions\n", insts_to_execute); - - fetchRedirect[0] = false; - - while (insts_to_execute > 0) { - // Get ready instruction from the IQ (or queue coming out of IQ) - // Execute the ready instruction. - // Wakeup any dependents if it's done. - DynInstPtr inst = IQ.getReadyInst(); - - DPRINTF(BE, "Executing inst [sn:%lli] PC: %#x\n", - inst->seqNum, inst->readPC()); - - ++funcExeInst; - - // Check if the instruction is squashed; if so then skip it - // and don't count it towards the FU usage. - if (inst->isSquashed()) { - DPRINTF(BE, "Execute: Instruction was squashed.\n"); - - // Not sure how to handle this plus the method of sending # of - // instructions to use. Probably will just have to count it - // towards the bandwidth usage, but not the FU usage. - --insts_to_execute; - - // Consider this instruction executed so that commit can go - // ahead and retire the instruction. - inst->setExecuted(); - - // Not sure if I should set this here or just let commit try to - // commit any squashed instructions. I like the latter a bit more. - inst->setCanCommit(); - -// ++iewExecSquashedInsts; - - continue; - } - - Fault fault = NoFault; - - // Execute instruction. - // Note that if the instruction faults, it will be handled - // at the commit stage. - if (inst->isMemRef() && - (!inst->isDataPrefetch() && !inst->isInstPrefetch())) { - DPRINTF(BE, "Execute: Initiating access for memory " - "reference.\n"); - - // Tell the LDSTQ to execute this instruction (if it is a load). - if (inst->isLoad()) { - // Loads will mark themselves as executed, and their writeback - // event adds the instruction to the queue to commit - fault = LSQ.executeLoad(inst); - -// ++iewExecLoadInsts; - } else if (inst->isStore()) { - LSQ.executeStore(inst); - -// ++iewExecStoreInsts; - - if (!(inst->req->flags & LOCKED)) { - inst->setExecuted(); - - instToCommit(inst); - } - // Store conditionals will mark themselves as executed, and - // their writeback event will add the instruction to the queue - // to commit. - } else { - panic("Unexpected memory type!\n"); - } - - } else { - inst->execute(); - -// ++iewExecutedInsts; - - inst->setExecuted(); - - instToCommit(inst); - } - - updateExeInstStats(inst); - - // Probably should have some sort of function for this. - // More general question of how to handle squashes? Have some sort of - // squash unit that controls it? Probably... - // Check if branch was correct. This check happens after the - // instruction is added to the queue because even if the branch - // is mispredicted, the branch instruction itself is still valid. - // Only handle this if there hasn't already been something that - // redirects fetch in this group of instructions. - - // This probably needs to prioritize the redirects if a different - // scheduler is used. Currently the scheduler schedules the oldest - // instruction first, so the branch resolution order will be correct. - unsigned tid = inst->threadNumber; - - if (!fetchRedirect[tid]) { - - if (inst->mispredicted()) { - fetchRedirect[tid] = true; - - DPRINTF(BE, "Execute: Branch mispredict detected.\n"); - DPRINTF(BE, "Execute: Redirecting fetch to PC: %#x.\n", - inst->nextPC); - - // If incorrect, then signal the ROB that it must be squashed. - squashDueToBranch(inst); - - if (inst->predTaken()) { -// predictedTakenIncorrect++; - } else { -// predictedNotTakenIncorrect++; - } - } else if (LSQ.violation()) { - fetchRedirect[tid] = true; - - // Get the DynInst that caused the violation. Note that this - // clears the violation signal. - DynInstPtr violator; - violator = LSQ.getMemDepViolator(); - - DPRINTF(BE, "LDSTQ detected a violation. Violator PC: " - "%#x, inst PC: %#x. Addr is: %#x.\n", - violator->readPC(), inst->readPC(), inst->physEffAddr); - - // Tell the instruction queue that a violation has occured. -// IQ.violation(inst, violator); - - // Squash. -// squashDueToMemOrder(inst,tid); - squashDueToBranch(inst); - -// ++memOrderViolationEvents; - } else if (LSQ.loadBlocked()) { - fetchRedirect[tid] = true; - - DPRINTF(BE, "Load operation couldn't execute because the " - "memory system is blocked. PC: %#x [sn:%lli]\n", - inst->readPC(), inst->seqNum); - - squashDueToMemBlocked(inst); - } - } - -// instList.pop_front(); - - --insts_to_execute; - - // keep an instruction count - thread->numInst++; - thread->numInsts++; - } - - assert(insts_to_execute >= 0); -} - -template<class Impl> -void -BackEnd<Impl>::instToCommit(DynInstPtr &inst) -{ - int wb_width = wbWidth; - // First check the time slot that this instruction will write - // to. If there are free write ports at the time, then go ahead - // and write the instruction to that time. If there are not, - // keep looking back to see where's the first time there's a - // free slot. What happens if you run out of free spaces? - // For now naively assume that all instructions take one cycle. - // Otherwise would have to look into the time buffer based on the - // latency of the instruction. - - DPRINTF(BE, "Sending instructions to commit [sn:%lli] PC %#x.\n", - inst->seqNum, inst->readPC()); - - while (numInstsToWB[wbCycle].size >= wb_width) { - ++wbCycle; - - assert(wbCycle < 5); - } - - // Add finished instruction to queue to commit. - writeback.push_back(inst); - numInstsToWB[wbCycle].size++; - - if (wbCycle) - wb_penalized[0]++; -} - -template <class Impl> -void -BackEnd<Impl>::writebackInsts() -{ - int wb_width = wbWidth; - // Using this method I'm not quite sure how to prevent an - // instruction from waking its own dependents multiple times, - // without the guarantee that commit always has enough bandwidth - // to accept all instructions being written back. This guarantee - // might not be too unrealistic. - InstListIt wb_inst_it = writeback.begin(); - InstListIt wb_end_it = writeback.end(); - int inst_num = 0; - int consumer_insts = 0; - - for (; inst_num < wb_width && - wb_inst_it != wb_end_it; inst_num++) { - DynInstPtr inst = (*wb_inst_it); - - // Some instructions will be sent to commit without having - // executed because they need commit to handle them. - // E.g. Uncached loads have not actually executed when they - // are first sent to commit. Instead commit must tell the LSQ - // when it's ready to execute the uncached load. - if (!inst->isSquashed()) { - DPRINTF(BE, "Writing back instruction [sn:%lli] PC %#x.\n", - inst->seqNum, inst->readPC()); - - inst->setCanCommit(); - inst->setResultReady(); - - if (inst->isExecuted()) { - int dependents = IQ.wakeDependents(inst); - if (dependents) { - producer_inst[0]++; - consumer_insts+= dependents; - } - } - } - - writeback.erase(wb_inst_it++); - } - LSQ.writebackStores(); - consumer_inst[0]+= consumer_insts; - writeback_count[0]+= inst_num; -} - -template <class Impl> -bool -BackEnd<Impl>::commitInst(int inst_num) -{ - // Read instruction from the head of the ROB - DynInstPtr inst = instList.front(); - - // Make sure instruction is valid - assert(inst); - - if (!inst->readyToCommit()) - return false; - - DPRINTF(BE, "Trying to commit instruction [sn:%lli] PC:%#x\n", - inst->seqNum, inst->readPC()); - - // If the instruction is not executed yet, then it is a non-speculative - // or store inst. Signal backwards that it should be executed. - if (!inst->isExecuted()) { - // Keep this number correct. We have not yet actually executed - // and committed this instruction. -// thread->funcExeInst--; - - if (inst->isNonSpeculative()) { -#if !FULL_SYSTEM - // Hack to make sure syscalls aren't executed until all stores - // write back their data. This direct communication shouldn't - // be used for anything other than this. - if (inst_num > 0 || LSQ.hasStoresToWB()) { - DPRINTF(BE, "Waiting for all stores to writeback.\n"); - return false; - } -#endif - - DPRINTF(BE, "Encountered a store or non-speculative " - "instruction at the head of the ROB, PC %#x.\n", - inst->readPC()); - - // Send back the non-speculative instruction's sequence number. - toIEW->nonSpecSeqNum = inst->seqNum; - - // Change the instruction so it won't try to commit again until - // it is executed. - inst->clearCanCommit(); - -// ++commitNonSpecStalls; - - return false; - } else if (inst->isLoad()) { - DPRINTF(BE, "[sn:%lli]: Uncached load, PC %#x.\n", - inst->seqNum, inst->readPC()); - - // Send back the non-speculative instruction's sequence - // number. Maybe just tell the lsq to re-execute the load. - toIEW->nonSpecSeqNum = inst->seqNum; - toIEW->uncached = true; - toIEW->lqIdx = inst->lqIdx; - - inst->clearCanCommit(); - - return false; - } else { - panic("Trying to commit un-executed instruction " - "of unknown type!\n"); - } - } - - // Now check if it's one of the special trap or barrier or - // serializing instructions. - if (inst->isThreadSync()) - { - // Not handled for now. - panic("Barrier instructions are not handled yet.\n"); - } - - // Check if the instruction caused a fault. If so, trap. - Fault inst_fault = inst->getFault(); - - if (inst_fault != NoFault) { - if (!inst->isNop()) { -#if FULL_SYSTEM - DPRINTF(BE, "Inst [sn:%lli] PC %#x has a fault\n", - inst->seqNum, inst->readPC()); - -// assert(!thread->inSyscall); - -// thread->inSyscall = true; - - // Consider holding onto the trap and waiting until the trap event - // happens for this to be executed. - inst_fault->invoke(thread->getXCProxy()); - - // Exit state update mode to avoid accidental updating. -// thread->inSyscall = false; - -// commitStatus = TrapPending; - - // Generate trap squash event. -// generateTrapEvent(); - - return false; -#else // !FULL_SYSTEM - panic("fault (%d) detected @ PC %08p", inst_fault, - inst->PC); -#endif // FULL_SYSTEM - } - } - - if (inst->isControl()) { -// ++commitCommittedBranches; - } - - int freed_regs = 0; - - for (int i = 0; i < inst->numDestRegs(); ++i) { - DPRINTF(BE, "Commit rename map setting register %i to [sn:%lli]\n", - (int)inst->destRegIdx(i), inst->seqNum); - thread->renameTable[inst->destRegIdx(i)] = inst; - ++freed_regs; - } - - if (inst->traceData) { - inst->traceData->finalize(); - inst->traceData = NULL; - } - - inst->clearDependents(); - - frontEnd->addFreeRegs(freed_regs); - - instList.pop_front(); - - --numInsts; - cpu->numInst++; - thread->numInsts++; - ++thread->funcExeInst; - thread->PC = inst->readNextPC(); - updateComInstStats(inst); - - // Write the done sequence number here. - toIEW->doneSeqNum = inst->seqNum; - -#if FULL_SYSTEM - int count = 0; - Addr oldpc; - do { - if (count == 0) - assert(!thread->inSyscall && !thread->trapPending); - oldpc = thread->readPC(); - cpu->system->pcEventQueue.service( - thread->getXCProxy()); - count++; - } while (oldpc != thread->readPC()); - if (count > 1) { - DPRINTF(BE, "PC skip function event, stopping commit\n"); -// completed_last_inst = false; -// squashPending = true; - return false; - } -#endif - return true; -} - -template <class Impl> -void -BackEnd<Impl>::commitInsts() -{ - int commit_width = commitWidth ? commitWidth : width; - - // Not sure this should be a loop or not. - int inst_num = 0; - while (!instList.empty() && inst_num < commit_width) { - if (instList.front()->isSquashed()) { - panic("No squashed insts should still be on the list!"); - instList.front()->clearDependents(); - instList.pop_front(); - continue; - } - - if (!commitInst(inst_num++)) { - break; - } - } - n_committed_dist.sample(inst_num); -} - -template <class Impl> -void -BackEnd<Impl>::squash(const InstSeqNum &sn) -{ - IQ.squash(sn); - LSQ.squash(sn); - - int freed_regs = 0; - InstListIt dispatch_end = dispatch.end(); - InstListIt insts_it = dispatch.end(); - insts_it--; - - while (insts_it != dispatch_end && (*insts_it)->seqNum > sn) - { - if ((*insts_it)->isSquashed()) { - --insts_it; - continue; - } - DPRINTF(BE, "Squashing instruction on dispatch list PC %#x, [sn:%lli].\n", - (*insts_it)->readPC(), - (*insts_it)->seqNum); - - // Mark the instruction as squashed, and ready to commit so that - // it can drain out of the pipeline. - (*insts_it)->setSquashed(); - - (*insts_it)->setCanCommit(); - - // Be careful with IPRs and such here - for (int i = 0; i < (*insts_it)->numDestRegs(); ++i) { - DynInstPtr prev_dest = (*insts_it)->getPrevDestInst(i); - DPRINTF(BE, "Commit rename map setting register %i to [sn:%lli]\n", - (int)(*insts_it)->destRegIdx(i), prev_dest); - renameTable[(*insts_it)->destRegIdx(i)] = prev_dest; - ++freed_regs; - } - - (*insts_it)->clearDependents(); - - --insts_it; - } - - insts_it = instList.end(); - insts_it--; - - while (!instList.empty() && (*insts_it)->seqNum > sn) - { - if ((*insts_it)->isSquashed()) { - --insts_it; - continue; - } - DPRINTF(BE, "Squashing instruction on inst list PC %#x, [sn:%lli].\n", - (*insts_it)->readPC(), - (*insts_it)->seqNum); - - // Mark the instruction as squashed, and ready to commit so that - // it can drain out of the pipeline. - (*insts_it)->setSquashed(); - - (*insts_it)->setCanCommit(); - - for (int i = 0; i < (*insts_it)->numDestRegs(); ++i) { - DynInstPtr prev_dest = (*insts_it)->getPrevDestInst(i); - DPRINTF(BE, "Commit rename map setting register %i to [sn:%lli]\n", - (int)(*insts_it)->destRegIdx(i), prev_dest); - renameTable[(*insts_it)->destRegIdx(i)] = prev_dest; - ++freed_regs; - } - - (*insts_it)->clearDependents(); - - instList.erase(insts_it--); - --numInsts; - } - - frontEnd->addFreeRegs(freed_regs); -} - -template <class Impl> -void -BackEnd<Impl>::squashFromXC() -{ - xcSquash = true; -} - -template <class Impl> -void -BackEnd<Impl>::squashDueToBranch(DynInstPtr &inst) -{ - // Update the branch predictor state I guess - squash(inst->seqNum); - frontEnd->squash(inst->seqNum, inst->readNextPC(), - true, inst->mispredicted()); -} - -template <class Impl> -void -BackEnd<Impl>::squashDueToMemBlocked(DynInstPtr &inst) -{ - DPRINTF(IEW, "Memory blocked, squashing load and younger insts, " - "PC: %#x [sn:%i].\n", inst->readPC(), inst->seqNum); - - squash(inst->seqNum - 1); - frontEnd->squash(inst->seqNum - 1, inst->readPC()); -} - -template <class Impl> -void -BackEnd<Impl>::fetchFault(Fault &fault) -{ - faultFromFetch = fault; -} - -template <class Impl> -void -BackEnd<Impl>::updateExeInstStats(DynInstPtr &inst) -{ - int thread_number = inst->threadNumber; - - // - // Pick off the software prefetches - // -#ifdef TARGET_ALPHA - if (inst->isDataPrefetch()) - exe_swp[thread_number]++; - else - exe_inst[thread_number]++; -#else - exe_inst[thread_number]++; -#endif - - // - // Control operations - // - if (inst->isControl()) - exe_branches[thread_number]++; - - // - // Memory operations - // - if (inst->isMemRef()) { - exe_refs[thread_number]++; - - if (inst->isLoad()) - exe_loads[thread_number]++; - } -} - -template <class Impl> -void -BackEnd<Impl>::updateComInstStats(DynInstPtr &inst) -{ - unsigned thread = inst->threadNumber; - - // - // Pick off the software prefetches - // -#ifdef TARGET_ALPHA - if (inst->isDataPrefetch()) { - stat_com_swp[thread]++; - } else { - stat_com_inst[thread]++; - } -#else - stat_com_inst[thread]++; -#endif - - // - // Control Instructions - // - if (inst->isControl()) - stat_com_branches[thread]++; - - // - // Memory references - // - if (inst->isMemRef()) { - stat_com_refs[thread]++; - - if (inst->isLoad()) { - stat_com_loads[thread]++; - } - } - - if (inst->isMemBarrier()) { - stat_com_membars[thread]++; - } -} - -template <class Impl> -void -BackEnd<Impl>::dumpInsts() -{ - int num = 0; - int valid_num = 0; - - InstListIt inst_list_it = instList.begin(); - - cprintf("Inst list size: %i\n", instList.size()); - - while (inst_list_it != instList.end()) - { - cprintf("Instruction:%i\n", - num); - if (!(*inst_list_it)->isSquashed()) { - if (!(*inst_list_it)->isIssued()) { - ++valid_num; - cprintf("Count:%i\n", valid_num); - } else if ((*inst_list_it)->isMemRef() && - !(*inst_list_it)->memOpDone) { - // Loads that have not been marked as executed still count - // towards the total instructions. - ++valid_num; - cprintf("Count:%i\n", valid_num); - } - } - - cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" - "Issued:%i\nSquashed:%i\n", - (*inst_list_it)->readPC(), - (*inst_list_it)->seqNum, - (*inst_list_it)->threadNumber, - (*inst_list_it)->isIssued(), - (*inst_list_it)->isSquashed()); - - if ((*inst_list_it)->isMemRef()) { - cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone); - } - - cprintf("\n"); - - inst_list_it++; - ++num; - } - - cprintf("Dispatch list size: %i\n", dispatch.size()); - - inst_list_it = dispatch.begin(); - - while (inst_list_it != dispatch.end()) - { - cprintf("Instruction:%i\n", - num); - if (!(*inst_list_it)->isSquashed()) { - if (!(*inst_list_it)->isIssued()) { - ++valid_num; - cprintf("Count:%i\n", valid_num); - } else if ((*inst_list_it)->isMemRef() && - !(*inst_list_it)->memOpDone) { - // Loads that have not been marked as executed still count - // towards the total instructions. - ++valid_num; - cprintf("Count:%i\n", valid_num); - } - } - - cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" - "Issued:%i\nSquashed:%i\n", - (*inst_list_it)->readPC(), - (*inst_list_it)->seqNum, - (*inst_list_it)->threadNumber, - (*inst_list_it)->isIssued(), - (*inst_list_it)->isSquashed()); - - if ((*inst_list_it)->isMemRef()) { - cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone); - } - - cprintf("\n"); - - inst_list_it++; - ++num; - } - - cprintf("Writeback list size: %i\n", writeback.size()); - - inst_list_it = writeback.begin(); - - while (inst_list_it != writeback.end()) - { - cprintf("Instruction:%i\n", - num); - if (!(*inst_list_it)->isSquashed()) { - if (!(*inst_list_it)->isIssued()) { - ++valid_num; - cprintf("Count:%i\n", valid_num); - } else if ((*inst_list_it)->isMemRef() && - !(*inst_list_it)->memOpDone) { - // Loads that have not been marked as executed still count - // towards the total instructions. - ++valid_num; - cprintf("Count:%i\n", valid_num); - } - } - - cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" - "Issued:%i\nSquashed:%i\n", - (*inst_list_it)->readPC(), - (*inst_list_it)->seqNum, - (*inst_list_it)->threadNumber, - (*inst_list_it)->isIssued(), - (*inst_list_it)->isSquashed()); - - if ((*inst_list_it)->isMemRef()) { - cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone); - } - - cprintf("\n"); - - inst_list_it++; - ++num; - } -} diff --git a/cpu/ozone/cpu.cc b/cpu/ozone/cpu.cc deleted file mode 100644 index d2ea0164c..000000000 --- a/cpu/ozone/cpu.cc +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include "cpu/ozone/cpu_impl.hh" -#include "cpu/ozone/ozone_impl.hh" -#include "cpu/ozone/simple_impl.hh" - -template class OzoneCPU<SimpleImpl>; -template class OzoneCPU<OzoneImpl>; diff --git a/cpu/ozone/cpu.hh b/cpu/ozone/cpu.hh deleted file mode 100644 index 5af2b02b2..000000000 --- a/cpu/ozone/cpu.hh +++ /dev/null @@ -1,629 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __CPU_OZONE_CPU_HH__ -#define __CPU_OZONE_CPU_HH__ - -#include <set> - -#include "base/statistics.hh" -#include "base/timebuf.hh" -#include "config/full_system.hh" -#include "cpu/base.hh" -#include "cpu/exec_context.hh" -#include "cpu/inst_seq.hh" -#include "cpu/ozone/rename_table.hh" -#include "cpu/ozone/thread_state.hh" -#include "cpu/pc_event.hh" -#include "cpu/static_inst.hh" -#include "mem/mem_interface.hh" -#include "sim/eventq.hh" - -// forward declarations -#if FULL_SYSTEM -#include "arch/alpha/tlb.hh" - -class AlphaITB; -class AlphaDTB; -class PhysicalMemory; -class MemoryController; - -class Sampler; -class RemoteGDB; -class GDBListener; - -namespace Kernel { - class Statistics; -}; - -#else - -class Process; - -#endif // FULL_SYSTEM - -class Checkpoint; -class EndQuiesceEvent; -class MemInterface; - -namespace Trace { - class InstRecord; -} - -template <class> -class Checker; - -/** - * Declaration of Out-of-Order CPU class. Basically it is a SimpleCPU with - * simple out-of-order capabilities added to it. It is still a 1 CPI machine - * (?), but is capable of handling cache misses. Basically it models having - * a ROB/IQ by only allowing a certain amount of instructions to execute while - * the cache miss is outstanding. - */ - -template <class Impl> -class OzoneCPU : public BaseCPU -{ - private: - typedef typename Impl::FrontEnd FrontEnd; - typedef typename Impl::BackEnd BackEnd; - typedef typename Impl::DynInst DynInst; - typedef typename Impl::DynInstPtr DynInstPtr; - - typedef TheISA::MiscReg MiscReg; - - public: - class OzoneXC : public ExecContext { - public: - OzoneCPU<Impl> *cpu; - - OzoneThreadState<Impl> *thread; - - BaseCPU *getCpuPtr(); - - void setCpuId(int id); - - int readCpuId() { return thread->cpuId; } - - FunctionalMemory *getMemPtr() { return thread->mem; } - -#if FULL_SYSTEM - System *getSystemPtr() { return cpu->system; } - - PhysicalMemory *getPhysMemPtr() { return cpu->physmem; } - - AlphaITB *getITBPtr() { return cpu->itb; } - - AlphaDTB * getDTBPtr() { return cpu->dtb; } - - Kernel::Statistics *getKernelStats() { return thread->kernelStats; } -#else - Process *getProcessPtr() { return thread->process; } -#endif - - Status status() const { return thread->_status; } - - void setStatus(Status 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(); - - /// Set the status to Unallocated. - void deallocate(); - - /// Set the status to Halted. - void halt(); - -#if FULL_SYSTEM - void dumpFuncProfile(); -#endif - - void takeOverFrom(ExecContext *old_context); - - void regStats(const std::string &name); - - void serialize(std::ostream &os); - void unserialize(Checkpoint *cp, const std::string §ion); - -#if FULL_SYSTEM - EndQuiesceEvent *getQuiesceEvent(); - - Tick readLastActivate(); - Tick readLastSuspend(); - - void profileClear(); - void profileSample(); -#endif - - int getThreadNum(); - - // Also somewhat obnoxious. Really only used for the TLB fault. - TheISA::MachInst getInst(); - - void copyArchRegs(ExecContext *xc); - - void clearArchRegs(); - - uint64_t readIntReg(int reg_idx); - - float readFloatRegSingle(int reg_idx); - - double readFloatRegDouble(int reg_idx); - - uint64_t readFloatRegInt(int reg_idx); - - void setIntReg(int reg_idx, uint64_t val); - - void setFloatRegSingle(int reg_idx, float val); - - void setFloatRegDouble(int reg_idx, double val); - - void setFloatRegInt(int reg_idx, uint64_t val); - - uint64_t readPC() { return thread->PC; } - void setPC(Addr val); - - uint64_t readNextPC() { return thread->nextPC; } - void setNextPC(Addr val); - - public: - // ISA stuff: - MiscReg readMiscReg(int misc_reg); - - MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault); - - Fault setMiscReg(int misc_reg, const MiscReg &val); - - Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val); - - unsigned readStCondFailures() - { return thread->storeCondFailures; } - - void setStCondFailures(unsigned sc_failures) - { thread->storeCondFailures = sc_failures; } - -#if FULL_SYSTEM - bool inPalMode() { return cpu->inPalMode(); } -#endif - - bool misspeculating() { return false; } - -#if !FULL_SYSTEM - TheISA::IntReg getSyscallArg(int i) - { return thread->renameTable[TheISA::ArgumentReg0 + i]->readIntResult(); } - - // used to shift args for indirect syscall - void setSyscallArg(int i, TheISA::IntReg val) - { thread->renameTable[TheISA::ArgumentReg0 + i]->setIntResult(i); } - - void setSyscallReturn(SyscallReturn return_value) - { cpu->setSyscallReturn(return_value, thread->tid); } - - Counter readFuncExeInst() { return thread->funcExeInst; } - - void setFuncExeInst(Counter new_val) - { thread->funcExeInst = new_val; } -#endif - }; - - // execution context proxy - OzoneXC ozoneXC; - ExecContext *xcProxy; - ExecContext *checkerXC; - - typedef OzoneThreadState<Impl> ImplState; - - private: - OzoneThreadState<Impl> thread; - - public: - // main simulation loop (one cycle) - void tick(); - - std::set<InstSeqNum> snList; - std::set<Addr> lockAddrList; - private: - struct TickEvent : public Event - { - OzoneCPU *cpu; - int width; - - TickEvent(OzoneCPU *c, int w); - void process(); - const char *description(); - }; - - TickEvent tickEvent; - - /// Schedule tick event, regardless of its current state. - void scheduleTickEvent(int delay) - { - if (tickEvent.squashed()) - tickEvent.reschedule(curTick + cycles(delay)); - else if (!tickEvent.scheduled()) - tickEvent.schedule(curTick + cycles(delay)); - } - - /// Unschedule tick event, regardless of its current state. - void unscheduleTickEvent() - { - if (tickEvent.scheduled()) - tickEvent.squash(); - } - - private: - Trace::InstRecord *traceData; - - template<typename T> - void trace_data(T data); - - public: - enum Status { - Running, - Idle, - SwitchedOut - }; - - Status _status; - - public: - bool checkInterrupts; - - void post_interrupt(int int_num, int index); - - void zero_fill_64(Addr addr) { - static int warned = 0; - if (!warned) { - warn ("WH64 is not implemented"); - warned = 1; - } - }; - - typedef typename Impl::Params Params; - - OzoneCPU(Params *params); - - virtual ~OzoneCPU(); - - void init(); - - public: - BaseCPU *getCpuPtr() { return this; } - - void setCpuId(int id) { cpuId = id; } - - int readCpuId() { return cpuId; } - - int cpuId; - - void switchOut(Sampler *sampler); - void signalSwitched(); - void takeOverFrom(BaseCPU *oldCPU); - - Sampler *sampler; - - int switchCount; - -#if FULL_SYSTEM - Addr dbg_vtophys(Addr addr); - - bool interval_stats; - - AlphaITB *itb; - AlphaDTB *dtb; - System *system; - - // the following two fields are redundant, since we can always - // look them up through the system pointer, but we'll leave them - // here for now for convenience - MemoryController *memctrl; - PhysicalMemory *physmem; -#endif - - // L1 instruction cache - MemInterface *icacheInterface; - - // L1 data cache - MemInterface *dcacheInterface; - - /** Pointer to memory. */ - FunctionalMemory *mem; - - FrontEnd *frontEnd; - - BackEnd *backEnd; - private: - Status status() const { return _status; } - void setStatus(Status new_status) { _status = new_status; } - - virtual void activateContext(int thread_num, int delay); - virtual void suspendContext(int thread_num); - virtual void deallocateContext(int thread_num); - virtual void haltContext(int thread_num); - - // statistics - virtual void regStats(); - virtual void resetStats(); - - // number of simulated instructions - public: - Counter numInst; - Counter startNumInst; - - virtual Counter totalInstructions() const - { - return numInst - startNumInst; - } - - private: - // number of simulated loads - Counter numLoad; - Counter startNumLoad; - - // number of idle cycles - Stats::Average<> notIdleFraction; - Stats::Formula idleFraction; - public: - - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); - - -#if FULL_SYSTEM - bool validInstAddr(Addr addr) { return true; } - bool validDataAddr(Addr addr) { return true; } - - Fault translateInstReq(MemReqPtr &req) - { - return itb->translate(req); - } - - Fault translateDataReadReq(MemReqPtr &req) - { - return dtb->translate(req, false); - } - - Fault translateDataWriteReq(MemReqPtr &req) - { - return dtb->translate(req, true); - } - -#else - bool validInstAddr(Addr addr) - { return true; } - - bool validDataAddr(Addr addr) - { return true; } - - int getInstAsid() { return thread.asid; } - int getDataAsid() { return thread.asid; } - - Fault dummyTranslation(MemReqPtr &req) - { -#if 0 - assert((req->vaddr >> 48 & 0xffff) == 0); -#endif - - // put the asid in the upper 16 bits of the paddr - req->paddr = req->vaddr & ~((Addr)0xffff << sizeof(Addr) * 8 - 16); - req->paddr = req->paddr | (Addr)req->asid << sizeof(Addr) * 8 - 16; - return NoFault; - } - - /** Translates instruction requestion in syscall emulation mode. */ - Fault translateInstReq(MemReqPtr &req) - { - return dummyTranslation(req); - } - - /** Translates data read request in syscall emulation mode. */ - Fault translateDataReadReq(MemReqPtr &req) - { - return dummyTranslation(req); - } - - /** Translates data write request in syscall emulation mode. */ - Fault translateDataWriteReq(MemReqPtr &req) - { - return dummyTranslation(req); - } -#endif - - /** Old CPU read from memory function. No longer used. */ - template <class T> - Fault read(MemReqPtr &req, T &data) - { -#if 0 -#if FULL_SYSTEM && defined(TARGET_ALPHA) - if (req->flags & LOCKED) { - req->xc->setMiscReg(TheISA::Lock_Addr_DepTag, req->paddr); - req->xc->setMiscReg(TheISA::Lock_Flag_DepTag, true); - } -#endif -#endif - Fault error; - if (req->flags & LOCKED) { - lockAddrList.insert(req->paddr); - lockFlag = true; - } - - error = this->mem->read(req, data); - data = gtoh(data); - return error; - } - - - /** CPU read function, forwards read to LSQ. */ - template <class T> - Fault read(MemReqPtr &req, T &data, int load_idx) - { - return backEnd->read(req, data, load_idx); - } - - /** Old CPU write to memory function. No longer used. */ - template <class T> - Fault write(MemReqPtr &req, T &data) - { -#if 0 -#if FULL_SYSTEM && defined(TARGET_ALPHA) - ExecContext *xc; - - // If this is a store conditional, act appropriately - if (req->flags & LOCKED) { - xc = req->xc; - - if (req->flags & UNCACHEABLE) { - // Don't update result register (see stq_c in isa_desc) - req->result = 2; - xc->setStCondFailures(0);//Needed? [RGD] - } else { - bool lock_flag = xc->readMiscReg(TheISA::Lock_Flag_DepTag); - Addr lock_addr = xc->readMiscReg(TheISA::Lock_Addr_DepTag); - req->result = lock_flag; - if (!lock_flag || - ((lock_addr & ~0xf) != (req->paddr & ~0xf))) { - xc->setMiscReg(TheISA::Lock_Flag_DepTag, false); - xc->setStCondFailures(xc->readStCondFailures() + 1); - if (((xc->readStCondFailures()) % 100000) == 0) { - std::cerr << "Warning: " - << xc->readStCondFailures() - << " consecutive store conditional failures " - << "on cpu " << req->xc->readCpuId() - << std::endl; - } - return NoFault; - } - else xc->setStCondFailures(0); - } - } - - // Need to clear any locked flags on other proccessors for - // this address. Only do this for succsful Store Conditionals - // and all other stores (WH64?). Unsuccessful Store - // Conditionals would have returned above, and wouldn't fall - // through. - for (int i = 0; i < this->system->execContexts.size(); i++){ - xc = this->system->execContexts[i]; - if ((xc->readMiscReg(TheISA::Lock_Addr_DepTag) & ~0xf) == - (req->paddr & ~0xf)) { - xc->setMiscReg(TheISA::Lock_Flag_DepTag, false); - } - } - -#endif -#endif - - if (req->flags & LOCKED) { - if (req->flags & UNCACHEABLE) { - req->result = 2; - } else { - if (this->lockFlag) { - if (lockAddrList.find(req->paddr) != - lockAddrList.end()) { - req->result = 1; - } else { - req->result = 0; - return NoFault; - } - } else { - req->result = 0; - return NoFault; - } - } - } - - return this->mem->write(req, (T)htog(data)); - } - - /** CPU write function, forwards write to LSQ. */ - template <class T> - Fault write(MemReqPtr &req, T &data, int store_idx) - { - return backEnd->write(req, data, store_idx); - } - - void prefetch(Addr addr, unsigned flags) - { - // need to do this... - } - - void writeHint(Addr addr, int size, unsigned flags) - { - // need to do this... - } - - Fault copySrcTranslate(Addr src); - - Fault copy(Addr dest); - - InstSeqNum globalSeqNum; - - public: - void squashFromXC(); - - // @todo: This can be a useful debug function. Implement it. - void dumpInsts() { frontEnd->dumpInsts(); } - -#if FULL_SYSTEM - Fault hwrei(); - int readIntrFlag() { return thread.regs.intrflag; } - void setIntrFlag(int val) { thread.regs.intrflag = val; } - bool inPalMode() { return AlphaISA::PcPAL(thread.PC); } - bool inPalMode(Addr pc) { return AlphaISA::PcPAL(pc); } - bool simPalCheck(int palFunc); - void processInterrupts(); -#else - void syscall(); - void setSyscallReturn(SyscallReturn return_value, int tid); -#endif - - ExecContext *xcBase() { return xcProxy; } - - bool decoupledFrontEnd; - struct CommStruct { - InstSeqNum doneSeqNum; - InstSeqNum nonSpecSeqNum; - bool uncached; - unsigned lqIdx; - - bool stall; - }; - TimeBuffer<CommStruct> comm; - - bool lockFlag; - - Stats::Scalar<> quiesceCycles; - - Checker<DynInstPtr> *checker; -}; - -#endif // __CPU_OZONE_CPU_HH__ diff --git a/cpu/ozone/cpu_builder.cc b/cpu/ozone/cpu_builder.cc deleted file mode 100644 index 64aa49c71..000000000 --- a/cpu/ozone/cpu_builder.cc +++ /dev/null @@ -1,830 +0,0 @@ - -#include <string> - -#include "cpu/checker/cpu.hh" -#include "cpu/inst_seq.hh" -#include "cpu/ozone/cpu.hh" -#include "cpu/ozone/ozone_impl.hh" -#include "cpu/ozone/simple_impl.hh" -#include "cpu/ozone/simple_params.hh" -#include "mem/cache/base_cache.hh" -#include "sim/builder.hh" -#include "sim/process.hh" -#include "sim/sim_object.hh" - -class DerivOzoneCPU : public OzoneCPU<OzoneImpl> -{ - public: - DerivOzoneCPU(SimpleParams *p) - : OzoneCPU<OzoneImpl>(p) - { } -}; - -class SimpleOzoneCPU : public OzoneCPU<SimpleImpl> -{ - public: - SimpleOzoneCPU(SimpleParams *p) - : OzoneCPU<SimpleImpl>(p) - { } -}; - - -//////////////////////////////////////////////////////////////////////// -// -// OzoneCPU Simulation Object -// - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(DerivOzoneCPU) - - Param<int> clock; - Param<int> numThreads; - -#if FULL_SYSTEM -SimObjectParam<System *> system; -Param<int> cpu_id; -SimObjectParam<AlphaITB *> itb; -SimObjectParam<AlphaDTB *> dtb; -#else -SimObjectVectorParam<Process *> workload; -//SimObjectParam<PageTable *> page_table; -#endif // FULL_SYSTEM - -SimObjectParam<FunctionalMemory *> mem; - -SimObjectParam<BaseCPU *> checker; - -Param<Counter> max_insts_any_thread; -Param<Counter> max_insts_all_threads; -Param<Counter> max_loads_any_thread; -Param<Counter> max_loads_all_threads; - -SimObjectParam<BaseCache *> icache; -SimObjectParam<BaseCache *> dcache; - -Param<unsigned> cachePorts; -Param<unsigned> width; -Param<unsigned> frontEndWidth; -Param<unsigned> backEndWidth; -Param<unsigned> backEndSquashLatency; -Param<unsigned> backEndLatency; -Param<unsigned> maxInstBufferSize; -Param<unsigned> numPhysicalRegs; -Param<unsigned> maxOutstandingMemOps; - -Param<unsigned> decodeToFetchDelay; -Param<unsigned> renameToFetchDelay; -Param<unsigned> iewToFetchDelay; -Param<unsigned> commitToFetchDelay; -Param<unsigned> fetchWidth; - -Param<unsigned> renameToDecodeDelay; -Param<unsigned> iewToDecodeDelay; -Param<unsigned> commitToDecodeDelay; -Param<unsigned> fetchToDecodeDelay; -Param<unsigned> decodeWidth; - -Param<unsigned> iewToRenameDelay; -Param<unsigned> commitToRenameDelay; -Param<unsigned> decodeToRenameDelay; -Param<unsigned> renameWidth; - -Param<unsigned> commitToIEWDelay; -Param<unsigned> renameToIEWDelay; -Param<unsigned> issueToExecuteDelay; -Param<unsigned> issueWidth; -Param<unsigned> executeWidth; -Param<unsigned> executeIntWidth; -Param<unsigned> executeFloatWidth; -Param<unsigned> executeBranchWidth; -Param<unsigned> executeMemoryWidth; - -Param<unsigned> iewToCommitDelay; -Param<unsigned> renameToROBDelay; -Param<unsigned> commitWidth; -Param<unsigned> squashWidth; - -Param<unsigned> localPredictorSize; -Param<unsigned> localCtrBits; -Param<unsigned> localHistoryTableSize; -Param<unsigned> localHistoryBits; -Param<unsigned> globalPredictorSize; -Param<unsigned> globalCtrBits; -Param<unsigned> globalHistoryBits; -Param<unsigned> choicePredictorSize; -Param<unsigned> choiceCtrBits; - -Param<unsigned> BTBEntries; -Param<unsigned> BTBTagSize; - -Param<unsigned> RASSize; - -Param<unsigned> LQEntries; -Param<unsigned> SQEntries; -Param<unsigned> LFSTSize; -Param<unsigned> SSITSize; - -Param<unsigned> numPhysIntRegs; -Param<unsigned> numPhysFloatRegs; -Param<unsigned> numIQEntries; -Param<unsigned> numROBEntries; - -Param<bool> decoupledFrontEnd; -Param<int> dispatchWidth; -Param<int> wbWidth; - -Param<unsigned> smtNumFetchingThreads; -Param<std::string> smtFetchPolicy; -Param<std::string> smtLSQPolicy; -Param<unsigned> smtLSQThreshold; -Param<std::string> smtIQPolicy; -Param<unsigned> smtIQThreshold; -Param<std::string> smtROBPolicy; -Param<unsigned> smtROBThreshold; -Param<std::string> smtCommitPolicy; - -Param<unsigned> instShiftAmt; - -Param<bool> defer_registration; - -Param<bool> function_trace; -Param<Tick> function_trace_start; - -END_DECLARE_SIM_OBJECT_PARAMS(DerivOzoneCPU) - -BEGIN_INIT_SIM_OBJECT_PARAMS(DerivOzoneCPU) - - INIT_PARAM(clock, "clock speed"), - INIT_PARAM(numThreads, "number of HW thread contexts"), - -#if FULL_SYSTEM - INIT_PARAM(system, "System object"), - INIT_PARAM(cpu_id, "processor ID"), - INIT_PARAM(itb, "Instruction translation buffer"), - INIT_PARAM(dtb, "Data translation buffer"), -#else - INIT_PARAM(workload, "Processes to run"), -// INIT_PARAM(page_table, "Page table"), -#endif // FULL_SYSTEM - - INIT_PARAM_DFLT(mem, "Memory", NULL), - - INIT_PARAM_DFLT(checker, "Checker CPU", NULL), - - INIT_PARAM_DFLT(max_insts_any_thread, - "Terminate when any thread reaches this inst count", - 0), - INIT_PARAM_DFLT(max_insts_all_threads, - "Terminate when all threads have reached" - "this inst count", - 0), - INIT_PARAM_DFLT(max_loads_any_thread, - "Terminate when any thread reaches this load count", - 0), - INIT_PARAM_DFLT(max_loads_all_threads, - "Terminate when all threads have reached this load" - "count", - 0), - - INIT_PARAM_DFLT(icache, "L1 instruction cache", NULL), - INIT_PARAM_DFLT(dcache, "L1 data cache", NULL), - - INIT_PARAM_DFLT(cachePorts, "Cache Ports", 200), - INIT_PARAM_DFLT(width, "Width", 1), - INIT_PARAM_DFLT(frontEndWidth, "Front end width", 1), - INIT_PARAM_DFLT(backEndWidth, "Back end width", 1), - INIT_PARAM_DFLT(backEndSquashLatency, "Back end squash latency", 1), - INIT_PARAM_DFLT(backEndLatency, "Back end latency", 1), - INIT_PARAM_DFLT(maxInstBufferSize, "Maximum instruction buffer size", 16), - INIT_PARAM(numPhysicalRegs, "Number of physical registers"), - INIT_PARAM_DFLT(maxOutstandingMemOps, "Maximum outstanding memory operations", 4), - - INIT_PARAM(decodeToFetchDelay, "Decode to fetch delay"), - INIT_PARAM(renameToFetchDelay, "Rename to fetch delay"), - INIT_PARAM(iewToFetchDelay, "Issue/Execute/Writeback to fetch" - "delay"), - INIT_PARAM(commitToFetchDelay, "Commit to fetch delay"), - INIT_PARAM(fetchWidth, "Fetch width"), - INIT_PARAM(renameToDecodeDelay, "Rename to decode delay"), - INIT_PARAM(iewToDecodeDelay, "Issue/Execute/Writeback to decode" - "delay"), - INIT_PARAM(commitToDecodeDelay, "Commit to decode delay"), - INIT_PARAM(fetchToDecodeDelay, "Fetch to decode delay"), - INIT_PARAM(decodeWidth, "Decode width"), - - INIT_PARAM(iewToRenameDelay, "Issue/Execute/Writeback to rename" - "delay"), - INIT_PARAM(commitToRenameDelay, "Commit to rename delay"), - INIT_PARAM(decodeToRenameDelay, "Decode to rename delay"), - INIT_PARAM(renameWidth, "Rename width"), - - INIT_PARAM(commitToIEWDelay, "Commit to " - "Issue/Execute/Writeback delay"), - INIT_PARAM(renameToIEWDelay, "Rename to " - "Issue/Execute/Writeback delay"), - INIT_PARAM(issueToExecuteDelay, "Issue to execute delay (internal" - "to the IEW stage)"), - INIT_PARAM(issueWidth, "Issue width"), - INIT_PARAM(executeWidth, "Execute width"), - INIT_PARAM(executeIntWidth, "Integer execute width"), - INIT_PARAM(executeFloatWidth, "Floating point execute width"), - INIT_PARAM(executeBranchWidth, "Branch execute width"), - INIT_PARAM(executeMemoryWidth, "Memory execute width"), - - INIT_PARAM(iewToCommitDelay, "Issue/Execute/Writeback to commit " - "delay"), - INIT_PARAM(renameToROBDelay, "Rename to reorder buffer delay"), - INIT_PARAM(commitWidth, "Commit width"), - INIT_PARAM(squashWidth, "Squash width"), - - INIT_PARAM(localPredictorSize, "Size of local predictor"), - INIT_PARAM(localCtrBits, "Bits per counter"), - INIT_PARAM(localHistoryTableSize, "Size of local history table"), - INIT_PARAM(localHistoryBits, "Bits for the local history"), - INIT_PARAM(globalPredictorSize, "Size of global predictor"), - INIT_PARAM(globalCtrBits, "Bits per counter"), - INIT_PARAM(globalHistoryBits, "Bits of history"), - INIT_PARAM(choicePredictorSize, "Size of choice predictor"), - INIT_PARAM(choiceCtrBits, "Bits of choice counters"), - - INIT_PARAM(BTBEntries, "Number of BTB entries"), - INIT_PARAM(BTBTagSize, "Size of the BTB tags, in bits"), - - INIT_PARAM(RASSize, "RAS size"), - - INIT_PARAM(LQEntries, "Number of load queue entries"), - INIT_PARAM(SQEntries, "Number of store queue entries"), - INIT_PARAM(LFSTSize, "Last fetched store table size"), - INIT_PARAM(SSITSize, "Store set ID table size"), - - INIT_PARAM(numPhysIntRegs, "Number of physical integer registers"), - INIT_PARAM(numPhysFloatRegs, "Number of physical floating point " - "registers"), - INIT_PARAM(numIQEntries, "Number of instruction queue entries"), - INIT_PARAM(numROBEntries, "Number of reorder buffer entries"), - - INIT_PARAM_DFLT(decoupledFrontEnd, "Decoupled front end", true), - INIT_PARAM_DFLT(dispatchWidth, "Dispatch width", 0), - INIT_PARAM_DFLT(wbWidth, "Writeback width", 0), - - INIT_PARAM_DFLT(smtNumFetchingThreads, "SMT Number of Fetching Threads", 1), - INIT_PARAM_DFLT(smtFetchPolicy, "SMT Fetch Policy", "SingleThread"), - INIT_PARAM_DFLT(smtLSQPolicy, "SMT LSQ Sharing Policy", "Partitioned"), - INIT_PARAM_DFLT(smtLSQThreshold,"SMT LSQ Threshold", 100), - INIT_PARAM_DFLT(smtIQPolicy, "SMT IQ Policy", "Partitioned"), - INIT_PARAM_DFLT(smtIQThreshold, "SMT IQ Threshold", 100), - INIT_PARAM_DFLT(smtROBPolicy, "SMT ROB Sharing Policy", "Partitioned"), - INIT_PARAM_DFLT(smtROBThreshold,"SMT ROB Threshold", 100), - INIT_PARAM_DFLT(smtCommitPolicy,"SMT Commit Fetch Policy", "RoundRobin"), - - INIT_PARAM(instShiftAmt, "Number of bits to shift instructions by"), - INIT_PARAM(defer_registration, "defer system registration (for sampling)"), - - INIT_PARAM(function_trace, "Enable function trace"), - INIT_PARAM(function_trace_start, "Cycle to start function trace") - -END_INIT_SIM_OBJECT_PARAMS(DerivOzoneCPU) - -CREATE_SIM_OBJECT(DerivOzoneCPU) -{ - DerivOzoneCPU *cpu; - -#if FULL_SYSTEM - // Full-system only supports a single thread for the moment. - int actual_num_threads = 1; -#else - // In non-full-system mode, we infer the number of threads from - // the workload if it's not explicitly specified. - int actual_num_threads = - numThreads.isValid() ? numThreads : workload.size(); - - if (workload.size() == 0) { - fatal("Must specify at least one workload!"); - } - -#endif - - SimpleParams *params = new SimpleParams; - - params->clock = clock; - - params->name = getInstanceName(); - params->numberOfThreads = actual_num_threads; - -#if FULL_SYSTEM - params->system = system; - params->cpu_id = cpu_id; - params->itb = itb; - params->dtb = dtb; -#else - params->workload = workload; -// params->pTable = page_table; -#endif // FULL_SYSTEM - - params->mem = mem; - params->checker = checker; - params->max_insts_any_thread = max_insts_any_thread; - params->max_insts_all_threads = max_insts_all_threads; - params->max_loads_any_thread = max_loads_any_thread; - params->max_loads_all_threads = max_loads_all_threads; - - // - // Caches - // - params->icacheInterface = icache ? icache->getInterface() : NULL; - params->dcacheInterface = dcache ? dcache->getInterface() : NULL; - params->cachePorts = cachePorts; - - params->width = width; - params->frontEndWidth = frontEndWidth; - params->backEndWidth = backEndWidth; - params->backEndSquashLatency = backEndSquashLatency; - params->backEndLatency = backEndLatency; - params->maxInstBufferSize = maxInstBufferSize; - params->numPhysicalRegs = numPhysIntRegs + numPhysFloatRegs; - params->maxOutstandingMemOps = maxOutstandingMemOps; - - params->decodeToFetchDelay = decodeToFetchDelay; - params->renameToFetchDelay = renameToFetchDelay; - params->iewToFetchDelay = iewToFetchDelay; - params->commitToFetchDelay = commitToFetchDelay; - params->fetchWidth = fetchWidth; - - params->renameToDecodeDelay = renameToDecodeDelay; - params->iewToDecodeDelay = iewToDecodeDelay; - params->commitToDecodeDelay = commitToDecodeDelay; - params->fetchToDecodeDelay = fetchToDecodeDelay; - params->decodeWidth = decodeWidth; - - params->iewToRenameDelay = iewToRenameDelay; - params->commitToRenameDelay = commitToRenameDelay; - params->decodeToRenameDelay = decodeToRenameDelay; - params->renameWidth = renameWidth; - - params->commitToIEWDelay = commitToIEWDelay; - params->renameToIEWDelay = renameToIEWDelay; - params->issueToExecuteDelay = issueToExecuteDelay; - params->issueWidth = issueWidth; - params->executeWidth = executeWidth; - params->executeIntWidth = executeIntWidth; - params->executeFloatWidth = executeFloatWidth; - params->executeBranchWidth = executeBranchWidth; - params->executeMemoryWidth = executeMemoryWidth; - - params->iewToCommitDelay = iewToCommitDelay; - params->renameToROBDelay = renameToROBDelay; - params->commitWidth = commitWidth; - params->squashWidth = squashWidth; - - - params->localPredictorSize = localPredictorSize; - params->localCtrBits = localCtrBits; - params->localHistoryTableSize = localHistoryTableSize; - params->localHistoryBits = localHistoryBits; - params->globalPredictorSize = globalPredictorSize; - params->globalCtrBits = globalCtrBits; - params->globalHistoryBits = globalHistoryBits; - params->choicePredictorSize = choicePredictorSize; - params->choiceCtrBits = choiceCtrBits; - - params->BTBEntries = BTBEntries; - params->BTBTagSize = BTBTagSize; - - params->RASSize = RASSize; - - params->LQEntries = LQEntries; - params->SQEntries = SQEntries; - - params->SSITSize = SSITSize; - params->LFSTSize = LFSTSize; - - params->numPhysIntRegs = numPhysIntRegs; - params->numPhysFloatRegs = numPhysFloatRegs; - params->numIQEntries = numIQEntries; - params->numROBEntries = numROBEntries; - - params->decoupledFrontEnd = decoupledFrontEnd; - params->dispatchWidth = dispatchWidth; - params->wbWidth = wbWidth; - - params->smtNumFetchingThreads = smtNumFetchingThreads; - params->smtFetchPolicy = smtFetchPolicy; - params->smtIQPolicy = smtIQPolicy; - params->smtLSQPolicy = smtLSQPolicy; - params->smtLSQThreshold = smtLSQThreshold; - params->smtROBPolicy = smtROBPolicy; - params->smtROBThreshold = smtROBThreshold; - params->smtCommitPolicy = smtCommitPolicy; - - params->instShiftAmt = 2; - - params->deferRegistration = defer_registration; - - params->functionTrace = function_trace; - params->functionTraceStart = function_trace_start; - - cpu = new DerivOzoneCPU(params); - - return cpu; -} - -REGISTER_SIM_OBJECT("DerivOzoneCPU", DerivOzoneCPU) - - - -//////////////////////////////////////////////////////////////////////// -// -// OzoneCPU Simulation Object -// - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleOzoneCPU) - - Param<int> clock; - Param<int> numThreads; - -#if FULL_SYSTEM -SimObjectParam<System *> system; -Param<int> cpu_id; -SimObjectParam<AlphaITB *> itb; -SimObjectParam<AlphaDTB *> dtb; -#else -SimObjectVectorParam<Process *> workload; -//SimObjectParam<PageTable *> page_table; -#endif // FULL_SYSTEM - -SimObjectParam<FunctionalMemory *> mem; - -SimObjectParam<BaseCPU *> checker; - -Param<Counter> max_insts_any_thread; -Param<Counter> max_insts_all_threads; -Param<Counter> max_loads_any_thread; -Param<Counter> max_loads_all_threads; - -SimObjectParam<BaseCache *> icache; -SimObjectParam<BaseCache *> dcache; - -Param<unsigned> cachePorts; -Param<unsigned> width; -Param<unsigned> frontEndWidth; -Param<unsigned> backEndWidth; -Param<unsigned> backEndSquashLatency; -Param<unsigned> backEndLatency; -Param<unsigned> maxInstBufferSize; -Param<unsigned> numPhysicalRegs; - -Param<unsigned> decodeToFetchDelay; -Param<unsigned> renameToFetchDelay; -Param<unsigned> iewToFetchDelay; -Param<unsigned> commitToFetchDelay; -Param<unsigned> fetchWidth; - -Param<unsigned> renameToDecodeDelay; -Param<unsigned> iewToDecodeDelay; -Param<unsigned> commitToDecodeDelay; -Param<unsigned> fetchToDecodeDelay; -Param<unsigned> decodeWidth; - -Param<unsigned> iewToRenameDelay; -Param<unsigned> commitToRenameDelay; -Param<unsigned> decodeToRenameDelay; -Param<unsigned> renameWidth; - -Param<unsigned> commitToIEWDelay; -Param<unsigned> renameToIEWDelay; -Param<unsigned> issueToExecuteDelay; -Param<unsigned> issueWidth; -Param<unsigned> executeWidth; -Param<unsigned> executeIntWidth; -Param<unsigned> executeFloatWidth; -Param<unsigned> executeBranchWidth; -Param<unsigned> executeMemoryWidth; - -Param<unsigned> iewToCommitDelay; -Param<unsigned> renameToROBDelay; -Param<unsigned> commitWidth; -Param<unsigned> squashWidth; - -Param<unsigned> localPredictorSize; -Param<unsigned> localCtrBits; -Param<unsigned> localHistoryTableSize; -Param<unsigned> localHistoryBits; -Param<unsigned> globalPredictorSize; -Param<unsigned> globalCtrBits; -Param<unsigned> globalHistoryBits; -Param<unsigned> choicePredictorSize; -Param<unsigned> choiceCtrBits; - -Param<unsigned> BTBEntries; -Param<unsigned> BTBTagSize; - -Param<unsigned> RASSize; - -Param<unsigned> LQEntries; -Param<unsigned> SQEntries; -Param<unsigned> LFSTSize; -Param<unsigned> SSITSize; - -Param<unsigned> numPhysIntRegs; -Param<unsigned> numPhysFloatRegs; -Param<unsigned> numIQEntries; -Param<unsigned> numROBEntries; - -Param<bool> decoupledFrontEnd; -Param<int> dispatchWidth; -Param<int> wbWidth; - -Param<unsigned> smtNumFetchingThreads; -Param<std::string> smtFetchPolicy; -Param<std::string> smtLSQPolicy; -Param<unsigned> smtLSQThreshold; -Param<std::string> smtIQPolicy; -Param<unsigned> smtIQThreshold; -Param<std::string> smtROBPolicy; -Param<unsigned> smtROBThreshold; -Param<std::string> smtCommitPolicy; - -Param<unsigned> instShiftAmt; - -Param<bool> defer_registration; - -Param<bool> function_trace; -Param<Tick> function_trace_start; - -END_DECLARE_SIM_OBJECT_PARAMS(SimpleOzoneCPU) - -BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleOzoneCPU) - - INIT_PARAM(clock, "clock speed"), - INIT_PARAM(numThreads, "number of HW thread contexts"), - -#if FULL_SYSTEM - INIT_PARAM(system, "System object"), - INIT_PARAM(cpu_id, "processor ID"), - INIT_PARAM(itb, "Instruction translation buffer"), - INIT_PARAM(dtb, "Data translation buffer"), -#else - INIT_PARAM(workload, "Processes to run"), -// INIT_PARAM(page_table, "Page table"), -#endif // FULL_SYSTEM - - INIT_PARAM_DFLT(mem, "Memory", NULL), - - INIT_PARAM_DFLT(checker, "Checker CPU", NULL), - - INIT_PARAM_DFLT(max_insts_any_thread, - "Terminate when any thread reaches this inst count", - 0), - INIT_PARAM_DFLT(max_insts_all_threads, - "Terminate when all threads have reached" - "this inst count", - 0), - INIT_PARAM_DFLT(max_loads_any_thread, - "Terminate when any thread reaches this load count", - 0), - INIT_PARAM_DFLT(max_loads_all_threads, - "Terminate when all threads have reached this load" - "count", - 0), - - INIT_PARAM_DFLT(icache, "L1 instruction cache", NULL), - INIT_PARAM_DFLT(dcache, "L1 data cache", NULL), - - INIT_PARAM_DFLT(cachePorts, "Cache Ports", 200), - INIT_PARAM_DFLT(width, "Width", 1), - INIT_PARAM_DFLT(frontEndWidth, "Front end width", 1), - INIT_PARAM_DFLT(backEndWidth, "Back end width", 1), - INIT_PARAM_DFLT(backEndSquashLatency, "Back end squash latency", 1), - INIT_PARAM_DFLT(backEndLatency, "Back end latency", 1), - INIT_PARAM_DFLT(maxInstBufferSize, "Maximum instruction buffer size", 16), - INIT_PARAM(numPhysicalRegs, "Number of physical registers"), - - INIT_PARAM(decodeToFetchDelay, "Decode to fetch delay"), - INIT_PARAM(renameToFetchDelay, "Rename to fetch delay"), - INIT_PARAM(iewToFetchDelay, "Issue/Execute/Writeback to fetch" - "delay"), - INIT_PARAM(commitToFetchDelay, "Commit to fetch delay"), - INIT_PARAM(fetchWidth, "Fetch width"), - INIT_PARAM(renameToDecodeDelay, "Rename to decode delay"), - INIT_PARAM(iewToDecodeDelay, "Issue/Execute/Writeback to decode" - "delay"), - INIT_PARAM(commitToDecodeDelay, "Commit to decode delay"), - INIT_PARAM(fetchToDecodeDelay, "Fetch to decode delay"), - INIT_PARAM(decodeWidth, "Decode width"), - - INIT_PARAM(iewToRenameDelay, "Issue/Execute/Writeback to rename" - "delay"), - INIT_PARAM(commitToRenameDelay, "Commit to rename delay"), - INIT_PARAM(decodeToRenameDelay, "Decode to rename delay"), - INIT_PARAM(renameWidth, "Rename width"), - - INIT_PARAM(commitToIEWDelay, "Commit to " - "Issue/Execute/Writeback delay"), - INIT_PARAM(renameToIEWDelay, "Rename to " - "Issue/Execute/Writeback delay"), - INIT_PARAM(issueToExecuteDelay, "Issue to execute delay (internal" - "to the IEW stage)"), - INIT_PARAM(issueWidth, "Issue width"), - INIT_PARAM(executeWidth, "Execute width"), - INIT_PARAM(executeIntWidth, "Integer execute width"), - INIT_PARAM(executeFloatWidth, "Floating point execute width"), - INIT_PARAM(executeBranchWidth, "Branch execute width"), - INIT_PARAM(executeMemoryWidth, "Memory execute width"), - - INIT_PARAM(iewToCommitDelay, "Issue/Execute/Writeback to commit " - "delay"), - INIT_PARAM(renameToROBDelay, "Rename to reorder buffer delay"), - INIT_PARAM(commitWidth, "Commit width"), - INIT_PARAM(squashWidth, "Squash width"), - - INIT_PARAM(localPredictorSize, "Size of local predictor"), - INIT_PARAM(localCtrBits, "Bits per counter"), - INIT_PARAM(localHistoryTableSize, "Size of local history table"), - INIT_PARAM(localHistoryBits, "Bits for the local history"), - INIT_PARAM(globalPredictorSize, "Size of global predictor"), - INIT_PARAM(globalCtrBits, "Bits per counter"), - INIT_PARAM(globalHistoryBits, "Bits of history"), - INIT_PARAM(choicePredictorSize, "Size of choice predictor"), - INIT_PARAM(choiceCtrBits, "Bits of choice counters"), - - INIT_PARAM(BTBEntries, "Number of BTB entries"), - INIT_PARAM(BTBTagSize, "Size of the BTB tags, in bits"), - - INIT_PARAM(RASSize, "RAS size"), - - INIT_PARAM(LQEntries, "Number of load queue entries"), - INIT_PARAM(SQEntries, "Number of store queue entries"), - INIT_PARAM(LFSTSize, "Last fetched store table size"), - INIT_PARAM(SSITSize, "Store set ID table size"), - - INIT_PARAM(numPhysIntRegs, "Number of physical integer registers"), - INIT_PARAM(numPhysFloatRegs, "Number of physical floating point " - "registers"), - INIT_PARAM(numIQEntries, "Number of instruction queue entries"), - INIT_PARAM(numROBEntries, "Number of reorder buffer entries"), - - INIT_PARAM_DFLT(decoupledFrontEnd, "Decoupled front end", true), - INIT_PARAM_DFLT(dispatchWidth, "Dispatch width", 0), - INIT_PARAM_DFLT(wbWidth, "Writeback width", 0), - - INIT_PARAM_DFLT(smtNumFetchingThreads, "SMT Number of Fetching Threads", 1), - INIT_PARAM_DFLT(smtFetchPolicy, "SMT Fetch Policy", "SingleThread"), - INIT_PARAM_DFLT(smtLSQPolicy, "SMT LSQ Sharing Policy", "Partitioned"), - INIT_PARAM_DFLT(smtLSQThreshold,"SMT LSQ Threshold", 100), - INIT_PARAM_DFLT(smtIQPolicy, "SMT IQ Policy", "Partitioned"), - INIT_PARAM_DFLT(smtIQThreshold, "SMT IQ Threshold", 100), - INIT_PARAM_DFLT(smtROBPolicy, "SMT ROB Sharing Policy", "Partitioned"), - INIT_PARAM_DFLT(smtROBThreshold,"SMT ROB Threshold", 100), - INIT_PARAM_DFLT(smtCommitPolicy,"SMT Commit Fetch Policy", "RoundRobin"), - - INIT_PARAM(instShiftAmt, "Number of bits to shift instructions by"), - INIT_PARAM(defer_registration, "defer system registration (for sampling)"), - - INIT_PARAM(function_trace, "Enable function trace"), - INIT_PARAM(function_trace_start, "Cycle to start function trace") - -END_INIT_SIM_OBJECT_PARAMS(SimpleOzoneCPU) - -CREATE_SIM_OBJECT(SimpleOzoneCPU) -{ - SimpleOzoneCPU *cpu; - -#if FULL_SYSTEM - // Full-system only supports a single thread for the moment. - int actual_num_threads = 1; -#else - // In non-full-system mode, we infer the number of threads from - // the workload if it's not explicitly specified. - int actual_num_threads = - numThreads.isValid() ? numThreads : workload.size(); - - if (workload.size() == 0) { - fatal("Must specify at least one workload!"); - } - -#endif - - SimpleParams *params = new SimpleParams; - - params->clock = clock; - - params->name = getInstanceName(); - params->numberOfThreads = actual_num_threads; - -#if FULL_SYSTEM - params->system = system; - params->cpu_id = cpu_id; - params->itb = itb; - params->dtb = dtb; -#else - params->workload = workload; -// params->pTable = page_table; -#endif // FULL_SYSTEM - - params->mem = mem; - params->checker = checker; - params->max_insts_any_thread = max_insts_any_thread; - params->max_insts_all_threads = max_insts_all_threads; - params->max_loads_any_thread = max_loads_any_thread; - params->max_loads_all_threads = max_loads_all_threads; - - // - // Caches - // - params->icacheInterface = icache ? icache->getInterface() : NULL; - params->dcacheInterface = dcache ? dcache->getInterface() : NULL; - params->cachePorts = cachePorts; - - params->width = width; - params->frontEndWidth = frontEndWidth; - params->backEndWidth = backEndWidth; - params->backEndSquashLatency = backEndSquashLatency; - params->backEndLatency = backEndLatency; - params->maxInstBufferSize = maxInstBufferSize; - params->numPhysicalRegs = numPhysIntRegs + numPhysFloatRegs; - - params->decodeToFetchDelay = decodeToFetchDelay; - params->renameToFetchDelay = renameToFetchDelay; - params->iewToFetchDelay = iewToFetchDelay; - params->commitToFetchDelay = commitToFetchDelay; - params->fetchWidth = fetchWidth; - - params->renameToDecodeDelay = renameToDecodeDelay; - params->iewToDecodeDelay = iewToDecodeDelay; - params->commitToDecodeDelay = commitToDecodeDelay; - params->fetchToDecodeDelay = fetchToDecodeDelay; - params->decodeWidth = decodeWidth; - - params->iewToRenameDelay = iewToRenameDelay; - params->commitToRenameDelay = commitToRenameDelay; - params->decodeToRenameDelay = decodeToRenameDelay; - params->renameWidth = renameWidth; - - params->commitToIEWDelay = commitToIEWDelay; - params->renameToIEWDelay = renameToIEWDelay; - params->issueToExecuteDelay = issueToExecuteDelay; - params->issueWidth = issueWidth; - params->executeWidth = executeWidth; - params->executeIntWidth = executeIntWidth; - params->executeFloatWidth = executeFloatWidth; - params->executeBranchWidth = executeBranchWidth; - params->executeMemoryWidth = executeMemoryWidth; - - params->iewToCommitDelay = iewToCommitDelay; - params->renameToROBDelay = renameToROBDelay; - params->commitWidth = commitWidth; - params->squashWidth = squashWidth; - - - params->localPredictorSize = localPredictorSize; - params->localCtrBits = localCtrBits; - params->localHistoryTableSize = localHistoryTableSize; - params->localHistoryBits = localHistoryBits; - params->globalPredictorSize = globalPredictorSize; - params->globalCtrBits = globalCtrBits; - params->globalHistoryBits = globalHistoryBits; - params->choicePredictorSize = choicePredictorSize; - params->choiceCtrBits = choiceCtrBits; - - params->BTBEntries = BTBEntries; - params->BTBTagSize = BTBTagSize; - - params->RASSize = RASSize; - - params->LQEntries = LQEntries; - params->SQEntries = SQEntries; - - params->SSITSize = SSITSize; - params->LFSTSize = LFSTSize; - - params->numPhysIntRegs = numPhysIntRegs; - params->numPhysFloatRegs = numPhysFloatRegs; - params->numIQEntries = numIQEntries; - params->numROBEntries = numROBEntries; - - params->decoupledFrontEnd = decoupledFrontEnd; - params->dispatchWidth = dispatchWidth; - params->wbWidth = wbWidth; - - params->smtNumFetchingThreads = smtNumFetchingThreads; - params->smtFetchPolicy = smtFetchPolicy; - params->smtIQPolicy = smtIQPolicy; - params->smtLSQPolicy = smtLSQPolicy; - params->smtLSQThreshold = smtLSQThreshold; - params->smtROBPolicy = smtROBPolicy; - params->smtROBThreshold = smtROBThreshold; - params->smtCommitPolicy = smtCommitPolicy; - - params->instShiftAmt = 2; - - params->deferRegistration = defer_registration; - - params->functionTrace = function_trace; - params->functionTraceStart = function_trace_start; - - cpu = new SimpleOzoneCPU(params); - - return cpu; -} - -REGISTER_SIM_OBJECT("SimpleOzoneCPU", SimpleOzoneCPU) - diff --git a/cpu/ozone/cpu_impl.hh b/cpu/ozone/cpu_impl.hh deleted file mode 100644 index 5675da3a8..000000000 --- a/cpu/ozone/cpu_impl.hh +++ /dev/null @@ -1,1049 +0,0 @@ -/* - * Copyright (c) 2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -//#include <cstdio> -//#include <cstdlib> - -#include "arch/isa_traits.hh" // For MachInst -#include "base/trace.hh" -#include "config/full_system.hh" -#include "cpu/base.hh" -#include "cpu/checker/exec_context.hh" -#include "cpu/exec_context.hh" -#include "cpu/exetrace.hh" -#include "cpu/ozone/cpu.hh" -#include "cpu/quiesce_event.hh" -#include "cpu/static_inst.hh" -//#include "mem/base_mem.hh" -#include "mem/mem_interface.hh" -#include "sim/sim_object.hh" -#include "sim/stats.hh" - -#if FULL_SYSTEM -#include "arch/faults.hh" -#include "arch/alpha/osfpal.hh" -#include "arch/alpha/tlb.hh" -#include "arch/vtophys.hh" -#include "base/callback.hh" -//#include "base/remote_gdb.hh" -#include "cpu/profile.hh" -#include "kern/kernel_stats.hh" -#include "mem/functional/memory_control.hh" -#include "mem/functional/physical.hh" -#include "sim/faults.hh" -#include "sim/sim_events.hh" -#include "sim/sim_exit.hh" -#include "sim/system.hh" -#else // !FULL_SYSTEM -#include "mem/functional/functional.hh" -#include "sim/process.hh" -#endif // FULL_SYSTEM - -using namespace TheISA; - -template <class Impl> -template<typename T> -void -OzoneCPU<Impl>::trace_data(T data) { - if (traceData) { - traceData->setData(data); - } -} - -template <class Impl> -OzoneCPU<Impl>::TickEvent::TickEvent(OzoneCPU *c, int w) - : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c), width(w) -{ -} - -template <class Impl> -void -OzoneCPU<Impl>::TickEvent::process() -{ - cpu->tick(); -} - -template <class Impl> -const char * -OzoneCPU<Impl>::TickEvent::description() -{ - return "OzoneCPU tick event"; -} - -template <class Impl> -OzoneCPU<Impl>::OzoneCPU(Params *p) -#if FULL_SYSTEM - : BaseCPU(p), thread(this, 0, p->mem), tickEvent(this, p->width), - mem(p->mem), -#else - : BaseCPU(p), thread(this, 0, p->workload[0], 0), tickEvent(this, p->width), - mem(p->workload[0]->getMemory()), -#endif - comm(5, 5) -{ - frontEnd = new FrontEnd(p); - backEnd = new BackEnd(p); - - _status = Idle; - - if (p->checker) { - BaseCPU *temp_checker = p->checker; - checker = dynamic_cast<Checker<DynInstPtr> *>(temp_checker); - checker->setMemory(mem); -#if FULL_SYSTEM - checker->setSystem(p->system); -#endif - checkerXC = new CheckerExecContext<OzoneXC>(&ozoneXC, checker); - thread.xcProxy = checkerXC; - xcProxy = checkerXC; - } else { - checker = NULL; - thread.xcProxy = &ozoneXC; - xcProxy = &ozoneXC; - } - - ozoneXC.cpu = this; - ozoneXC.thread = &thread; - - thread.inSyscall = false; - - thread.setStatus(ExecContext::Suspended); -#if FULL_SYSTEM - /***** All thread state stuff *****/ - thread.cpu = this; - thread.tid = 0; - thread.mem = p->mem; - - thread.quiesceEvent = new EndQuiesceEvent(xcProxy); - - system = p->system; - itb = p->itb; - dtb = p->dtb; - memctrl = p->system->memctrl; - physmem = p->system->physmem; - - if (p->profile) { - thread.profile = new FunctionProfile(p->system->kernelSymtab); - // @todo: This might be better as an ExecContext instead of OzoneXC - Callback *cb = - new MakeCallback<OzoneXC, - &OzoneXC::dumpFuncProfile>(&ozoneXC); - registerExitCallback(cb); - } - - // let's fill with a dummy node for now so we don't get a segfault - // on the first cycle when there's no node available. - static ProfileNode dummyNode; - thread.profileNode = &dummyNode; - thread.profilePC = 3; -#else - thread.cpu = this; - thread.tid = 0; - thread.process = p->workload[0]; - thread.asid = 0; -#endif // !FULL_SYSTEM - - numInst = 0; - startNumInst = 0; - - execContexts.push_back(xcProxy); - - frontEnd->setCPU(this); - backEnd->setCPU(this); - - frontEnd->setXC(xcProxy); - backEnd->setXC(xcProxy); - - frontEnd->setThreadState(&thread); - backEnd->setThreadState(&thread); - - frontEnd->setCommBuffer(&comm); - backEnd->setCommBuffer(&comm); - - frontEnd->setBackEnd(backEnd); - backEnd->setFrontEnd(frontEnd); - - decoupledFrontEnd = p->decoupledFrontEnd; - - globalSeqNum = 1; - - checkInterrupts = false; - - for (int i = 0; i < TheISA::TotalNumRegs; ++i) { - thread.renameTable[i] = new DynInst(this); - thread.renameTable[i]->setResultReady(); - } - - frontEnd->renameTable.copyFrom(thread.renameTable); - backEnd->renameTable.copyFrom(thread.renameTable); - -#if !FULL_SYSTEM -// pTable = p->pTable; -#endif - - lockFlag = 0; - - DPRINTF(OzoneCPU, "OzoneCPU: Created Ozone cpu object.\n"); -} - -template <class Impl> -OzoneCPU<Impl>::~OzoneCPU() -{ -} - -template <class Impl> -void -OzoneCPU<Impl>::switchOut(Sampler *_sampler) -{ - sampler = _sampler; - switchCount = 0; - // Front end needs state from back end, so switch out the back end first. - backEnd->switchOut(); - frontEnd->switchOut(); -} - -template <class Impl> -void -OzoneCPU<Impl>::signalSwitched() -{ - if (++switchCount == 2) { - backEnd->doSwitchOut(); - frontEnd->doSwitchOut(); - if (checker) - checker->switchOut(sampler); - _status = SwitchedOut; - if (tickEvent.scheduled()) - tickEvent.squash(); - sampler->signalSwitched(); - } - assert(switchCount <= 2); -} - -template <class Impl> -void -OzoneCPU<Impl>::takeOverFrom(BaseCPU *oldCPU) -{ - BaseCPU::takeOverFrom(oldCPU); - - backEnd->takeOverFrom(); - frontEnd->takeOverFrom(); - assert(!tickEvent.scheduled()); - - // @todo: Fix hardcoded number - // Clear out any old information in time buffer. - for (int i = 0; i < 6; ++i) { - comm.advance(); - } - - // if any of this CPU's ExecContexts are active, mark the CPU as - // running and schedule its tick event. - for (int i = 0; i < execContexts.size(); ++i) { - ExecContext *xc = execContexts[i]; - if (xc->status() == ExecContext::Active && - _status != Running) { - _status = Running; - tickEvent.schedule(curTick); - } - } - // Nothing running, change status to reflect that we're no longer - // switched out. - if (_status == SwitchedOut) { - _status = Idle; - } -} - -template <class Impl> -void -OzoneCPU<Impl>::activateContext(int thread_num, int delay) -{ - // Eventually change this in SMT. - assert(thread_num == 0); - - assert(_status == Idle); - notIdleFraction++; - scheduleTickEvent(delay); - _status = Running; - thread._status = ExecContext::Active; - frontEnd->wakeFromQuiesce(); -} - -template <class Impl> -void -OzoneCPU<Impl>::suspendContext(int thread_num) -{ - // Eventually change this in SMT. - assert(thread_num == 0); - // @todo: Figure out how to initially set the status properly so - // this is running. -// assert(_status == Running); - notIdleFraction--; - unscheduleTickEvent(); - _status = Idle; -} - -template <class Impl> -void -OzoneCPU<Impl>::deallocateContext(int thread_num) -{ - // for now, these are equivalent - suspendContext(thread_num); -} - -template <class Impl> -void -OzoneCPU<Impl>::haltContext(int thread_num) -{ - // for now, these are equivalent - suspendContext(thread_num); -} - -template <class Impl> -void -OzoneCPU<Impl>::regStats() -{ - using namespace Stats; - - BaseCPU::regStats(); - - thread.numInsts - .name(name() + ".num_insts") - .desc("Number of instructions executed") - ; - - thread.numMemRefs - .name(name() + ".num_refs") - .desc("Number of memory references") - ; - - notIdleFraction - .name(name() + ".not_idle_fraction") - .desc("Percentage of non-idle cycles") - ; - - idleFraction - .name(name() + ".idle_fraction") - .desc("Percentage of idle cycles") - ; - - quiesceCycles - .name(name() + ".quiesce_cycles") - .desc("Number of cycles spent in quiesce") - ; - - idleFraction = constant(1.0) - notIdleFraction; - - frontEnd->regStats(); - backEnd->regStats(); -} - -template <class Impl> -void -OzoneCPU<Impl>::resetStats() -{ - startNumInst = numInst; - notIdleFraction = (_status != Idle); -} - -template <class Impl> -void -OzoneCPU<Impl>::init() -{ - BaseCPU::init(); - - // Mark this as in syscall so it won't need to squash - thread.inSyscall = true; -#if FULL_SYSTEM - for (int i = 0; i < execContexts.size(); ++i) { - ExecContext *xc = execContexts[i]; - - // initialize CPU, including PC - TheISA::initCPU(xc, xc->readCpuId()); - } -#endif - frontEnd->renameTable.copyFrom(thread.renameTable); - backEnd->renameTable.copyFrom(thread.renameTable); - - thread.inSyscall = false; -} - -template <class Impl> -void -OzoneCPU<Impl>::serialize(std::ostream &os) -{ - BaseCPU::serialize(os); - SERIALIZE_ENUM(_status); - nameOut(os, csprintf("%s.xc", name())); - ozoneXC.serialize(os); - nameOut(os, csprintf("%s.tickEvent", name())); - tickEvent.serialize(os); -} - -template <class Impl> -void -OzoneCPU<Impl>::unserialize(Checkpoint *cp, const std::string §ion) -{ - BaseCPU::unserialize(cp, section); - UNSERIALIZE_ENUM(_status); - ozoneXC.unserialize(cp, csprintf("%s.xc", section)); - tickEvent.unserialize(cp, csprintf("%s.tickEvent", section)); -} - -template <class Impl> -Fault -OzoneCPU<Impl>::copySrcTranslate(Addr src) -{ - panic("Copy not implemented!\n"); - return NoFault; -#if 0 - static bool no_warn = true; - int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; - // Only support block sizes of 64 atm. - assert(blk_size == 64); - int offset = src & (blk_size - 1); - - // Make sure block doesn't span page - if (no_warn && - (src & TheISA::PageMask) != ((src + blk_size) & TheISA::PageMask) && - (src >> 40) != 0xfffffc) { - warn("Copied block source spans pages %x.", src); - no_warn = false; - } - - memReq->reset(src & ~(blk_size - 1), blk_size); - - // translate to physical address - Fault fault = xc->translateDataReadReq(memReq); - - assert(fault != Alignment_Fault); - - if (fault == NoFault) { - xc->copySrcAddr = src; - xc->copySrcPhysAddr = memReq->paddr + offset; - } else { - xc->copySrcAddr = 0; - xc->copySrcPhysAddr = 0; - } - return fault; -#endif -} - -template <class Impl> -Fault -OzoneCPU<Impl>::copy(Addr dest) -{ - panic("Copy not implemented!\n"); - return NoFault; -#if 0 - static bool no_warn = true; - int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; - // Only support block sizes of 64 atm. - assert(blk_size == 64); - uint8_t data[blk_size]; - //assert(xc->copySrcAddr); - int offset = dest & (blk_size - 1); - - // Make sure block doesn't span page - if (no_warn && - (dest & TheISA::PageMask) != ((dest + blk_size) & TheISA::PageMask) && - (dest >> 40) != 0xfffffc) { - no_warn = false; - warn("Copied block destination spans pages %x. ", dest); - } - - memReq->reset(dest & ~(blk_size -1), blk_size); - // translate to physical address - Fault fault = xc->translateDataWriteReq(memReq); - - assert(fault != Alignment_Fault); - - if (fault == NoFault) { - Addr dest_addr = memReq->paddr + offset; - // Need to read straight from memory since we have more than 8 bytes. - memReq->paddr = xc->copySrcPhysAddr; - xc->mem->read(memReq, data); - memReq->paddr = dest_addr; - xc->mem->write(memReq, data); - if (dcacheInterface) { - memReq->cmd = Copy; - memReq->completionEvent = NULL; - memReq->paddr = xc->copySrcPhysAddr; - memReq->dest = dest_addr; - memReq->size = 64; - memReq->time = curTick; - dcacheInterface->access(memReq); - } - } - return fault; -#endif -} - -#if FULL_SYSTEM -template <class Impl> -Addr -OzoneCPU<Impl>::dbg_vtophys(Addr addr) -{ - return vtophys(xcProxy, addr); -} -#endif // FULL_SYSTEM - -#if FULL_SYSTEM -template <class Impl> -void -OzoneCPU<Impl>::post_interrupt(int int_num, int index) -{ - BaseCPU::post_interrupt(int_num, index); - - if (_status == Idle) { - DPRINTF(IPI,"Suspended Processor awoke\n"); -// thread.activate(); - // Hack for now. Otherwise might have to go through the xcProxy, or - // I need to figure out what's the right thing to call. - activateContext(thread.tid, 1); - } -} -#endif // FULL_SYSTEM - -/* start simulation, program loaded, processor precise state initialized */ -template <class Impl> -void -OzoneCPU<Impl>::tick() -{ - DPRINTF(OzoneCPU, "\n\nOzoneCPU: Ticking cpu.\n"); - - _status = Running; - thread.renameTable[ZeroReg]->setIntResult(0); - thread.renameTable[ZeroReg+TheISA::FP_Base_DepTag]-> - setDoubleResult(0.0); - - comm.advance(); - frontEnd->tick(); - backEnd->tick(); - - // check for instruction-count-based events - comInstEventQueue[0]->serviceEvents(numInst); - - if (!tickEvent.scheduled() && _status == Running) - tickEvent.schedule(curTick + cycles(1)); -} - -template <class Impl> -void -OzoneCPU<Impl>::squashFromXC() -{ - thread.inSyscall = true; - backEnd->generateXCEvent(); -} - -#if !FULL_SYSTEM -template <class Impl> -void -OzoneCPU<Impl>::syscall() -{ - // Not sure this copy is needed, depending on how the XC proxy is made. - thread.renameTable.copyFrom(backEnd->renameTable); - - thread.inSyscall = true; - - thread.funcExeInst++; - - DPRINTF(OzoneCPU, "FuncExeInst: %i\n", thread.funcExeInst); - - thread.process->syscall(xcProxy); - - thread.funcExeInst--; - - thread.inSyscall = false; - - frontEnd->renameTable.copyFrom(thread.renameTable); - backEnd->renameTable.copyFrom(thread.renameTable); -} - -template <class Impl> -void -OzoneCPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid) -{ - // check for error condition. Alpha syscall convention is to - // indicate success/failure in reg a3 (r19) and put the - // return value itself in the standard return value reg (v0). - if (return_value.successful()) { - // no error - thread.renameTable[SyscallSuccessReg]->setIntResult(0); - thread.renameTable[ReturnValueReg]->setIntResult( - return_value.value()); - } else { - // got an error, return details - thread.renameTable[SyscallSuccessReg]->setIntResult((IntReg) -1); - thread.renameTable[ReturnValueReg]->setIntResult( - -return_value.value()); - } -} -#else -template <class Impl> -Fault -OzoneCPU<Impl>::hwrei() -{ - // Need to move this to ISA code - // May also need to make this per thread - - lockFlag = false; - lockAddrList.clear(); - thread.kernelStats->hwrei(); - - checkInterrupts = true; - - // FIXME: XXX check for interrupts? XXX - return NoFault; -} - -template <class Impl> -void -OzoneCPU<Impl>::processInterrupts() -{ - // Check for interrupts here. For now can copy the code that - // exists within isa_fullsys_traits.hh. Also assume that thread 0 - // is the one that handles the interrupts. - - // Check if there are any outstanding interrupts - //Handle the interrupts - int ipl = 0; - int summary = 0; - - checkInterrupts = false; - - if (thread.readMiscReg(IPR_ASTRR)) - panic("asynchronous traps not implemented\n"); - - if (thread.readMiscReg(IPR_SIRR)) { - for (int i = INTLEVEL_SOFTWARE_MIN; - i < INTLEVEL_SOFTWARE_MAX; i++) { - if (thread.readMiscReg(IPR_SIRR) & (ULL(1) << i)) { - // See table 4-19 of the 21164 hardware reference - ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1; - summary |= (ULL(1) << i); - } - } - } - - uint64_t interrupts = intr_status(); - - if (interrupts) { - for (int i = INTLEVEL_EXTERNAL_MIN; - i < INTLEVEL_EXTERNAL_MAX; i++) { - if (interrupts & (ULL(1) << i)) { - // See table 4-19 of the 21164 hardware reference - ipl = i; - summary |= (ULL(1) << i); - } - } - } - - if (ipl && ipl > thread.readMiscReg(IPR_IPLR)) { - thread.setMiscReg(IPR_ISR, summary); - thread.setMiscReg(IPR_INTID, ipl); - // @todo: Make this more transparent - if (checker) { - checker->cpuXCBase()->setMiscReg(IPR_ISR, summary); - checker->cpuXCBase()->setMiscReg(IPR_INTID, ipl); - } - Fault fault = new InterruptFault; - fault->invoke(thread.getXCProxy()); - DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", - thread.readMiscReg(IPR_IPLR), ipl, summary); - } -} - -template <class Impl> -bool -OzoneCPU<Impl>::simPalCheck(int palFunc) -{ - // Need to move this to ISA code - // May also need to make this per thread - thread.kernelStats->callpal(palFunc, xcProxy); - - switch (palFunc) { - case PAL::halt: - haltContext(thread.tid); - if (--System::numSystemsRunning == 0) - new SimExitEvent("all cpus halted"); - break; - - case PAL::bpt: - case PAL::bugchk: - if (system->breakpoint()) - return false; - break; - } - - return true; -} -#endif - -template <class Impl> -BaseCPU * -OzoneCPU<Impl>::OzoneXC::getCpuPtr() -{ - return cpu; -} - -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::setCpuId(int id) -{ - cpu->cpuId = id; - thread->cpuId = id; -} - -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::setStatus(Status new_status) -{ - thread->_status = new_status; -} - -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::activate(int delay) -{ - cpu->activateContext(thread->tid, delay); -} - -/// Set the status to Suspended. -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::suspend() -{ - cpu->suspendContext(thread->tid); -} - -/// Set the status to Unallocated. -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::deallocate() -{ - cpu->deallocateContext(thread->tid); -} - -/// Set the status to Halted. -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::halt() -{ - cpu->haltContext(thread->tid); -} - -#if FULL_SYSTEM -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::dumpFuncProfile() -{ } -#endif - -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::takeOverFrom(ExecContext *old_context) -{ - // some things should already be set up - assert(getMemPtr() == old_context->getMemPtr()); -#if FULL_SYSTEM - assert(getSystemPtr() == old_context->getSystemPtr()); -#else - assert(getProcessPtr() == old_context->getProcessPtr()); -#endif - - // copy over functional state - setStatus(old_context->status()); - copyArchRegs(old_context); - setCpuId(old_context->readCpuId()); - -#if !FULL_SYSTEM - setFuncExeInst(old_context->readFuncExeInst()); -#else - EndQuiesceEvent *other_quiesce = old_context->getQuiesceEvent(); - if (other_quiesce) { - // Point the quiesce event's XC at this XC so that it wakes up - // the proper CPU. - other_quiesce->xc = this; - } - if (thread->quiesceEvent) { - thread->quiesceEvent->xc = this; - } - - thread->kernelStats = old_context->getKernelStats(); -// storeCondFailures = 0; - cpu->lockFlag = false; -#endif - - old_context->setStatus(ExecContext::Unallocated); -} - -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::regStats(const std::string &name) -{ -#if FULL_SYSTEM - thread->kernelStats = new Kernel::Statistics(cpu->system); - thread->kernelStats->regStats(name + ".kern"); -#endif -} - -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::serialize(std::ostream &os) -{ } - -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::unserialize(Checkpoint *cp, const std::string §ion) -{ } - -#if FULL_SYSTEM -template <class Impl> -EndQuiesceEvent * -OzoneCPU<Impl>::OzoneXC::getQuiesceEvent() -{ - return thread->quiesceEvent; -} - -template <class Impl> -Tick -OzoneCPU<Impl>::OzoneXC::readLastActivate() -{ - return thread->lastActivate; -} - -template <class Impl> -Tick -OzoneCPU<Impl>::OzoneXC::readLastSuspend() -{ - return thread->lastSuspend; -} - -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::profileClear() -{ - if (thread->profile) - thread->profile->clear(); -} - -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::profileSample() -{ - if (thread->profile) - thread->profile->sample(thread->profileNode, thread->profilePC); -} -#endif - -template <class Impl> -int -OzoneCPU<Impl>::OzoneXC::getThreadNum() -{ - return thread->tid; -} - -// Also somewhat obnoxious. Really only used for the TLB fault. -template <class Impl> -TheISA::MachInst -OzoneCPU<Impl>::OzoneXC::getInst() -{ - return thread->inst; -} - -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::copyArchRegs(ExecContext *xc) -{ - thread->PC = xc->readPC(); - thread->nextPC = xc->readNextPC(); - - cpu->frontEnd->setPC(thread->PC); - cpu->frontEnd->setNextPC(thread->nextPC); - - for (int i = 0; i < TheISA::TotalNumRegs; ++i) { - if (i < TheISA::FP_Base_DepTag) { - thread->renameTable[i]->setIntResult(xc->readIntReg(i)); - } else if (i < (TheISA::FP_Base_DepTag + TheISA::NumFloatRegs)) { - int fp_idx = i - TheISA::FP_Base_DepTag; - thread->renameTable[i]->setDoubleResult( - xc->readFloatRegDouble(fp_idx)); - } - } - -#if !FULL_SYSTEM - thread->funcExeInst = xc->readFuncExeInst(); -#endif - - // Need to copy the XC values into the current rename table, - // copy the misc regs. - thread->regs.miscRegs.copyMiscRegs(xc); -} - -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::clearArchRegs() -{ - panic("Unimplemented!"); -} - -template <class Impl> -uint64_t -OzoneCPU<Impl>::OzoneXC::readIntReg(int reg_idx) -{ - return thread->renameTable[reg_idx]->readIntResult(); -} - -template <class Impl> -float -OzoneCPU<Impl>::OzoneXC::readFloatRegSingle(int reg_idx) -{ - int idx = reg_idx + TheISA::FP_Base_DepTag; - return thread->renameTable[idx]->readFloatResult(); -} - -template <class Impl> -double -OzoneCPU<Impl>::OzoneXC::readFloatRegDouble(int reg_idx) -{ - int idx = reg_idx + TheISA::FP_Base_DepTag; - return thread->renameTable[idx]->readDoubleResult(); -} - -template <class Impl> -uint64_t -OzoneCPU<Impl>::OzoneXC::readFloatRegInt(int reg_idx) -{ - int idx = reg_idx + TheISA::FP_Base_DepTag; - return thread->renameTable[idx]->readIntResult(); -} - -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::setIntReg(int reg_idx, uint64_t val) -{ - thread->renameTable[reg_idx]->setIntResult(val); - - if (!thread->inSyscall) { - cpu->squashFromXC(); - } -} - -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::setFloatRegSingle(int reg_idx, float val) -{ - panic("Unimplemented!"); -} - -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::setFloatRegDouble(int reg_idx, double val) -{ - int idx = reg_idx + TheISA::FP_Base_DepTag; - - thread->renameTable[idx]->setDoubleResult(val); - - if (!thread->inSyscall) { - cpu->squashFromXC(); - } -} - -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::setFloatRegInt(int reg_idx, uint64_t val) -{ - panic("Unimplemented!"); -} - -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::setPC(Addr val) -{ - thread->PC = val; - cpu->frontEnd->setPC(val); - - if (!thread->inSyscall) { - cpu->squashFromXC(); - } -} - -template <class Impl> -void -OzoneCPU<Impl>::OzoneXC::setNextPC(Addr val) -{ - thread->nextPC = val; - cpu->frontEnd->setNextPC(val); - - if (!thread->inSyscall) { - cpu->squashFromXC(); - } -} - -template <class Impl> -TheISA::MiscReg -OzoneCPU<Impl>::OzoneXC::readMiscReg(int misc_reg) -{ - return thread->regs.miscRegs.readReg(misc_reg); -} - -template <class Impl> -TheISA::MiscReg -OzoneCPU<Impl>::OzoneXC::readMiscRegWithEffect(int misc_reg, Fault &fault) -{ - return thread->regs.miscRegs.readRegWithEffect(misc_reg, - fault, this); -} - -template <class Impl> -Fault -OzoneCPU<Impl>::OzoneXC::setMiscReg(int misc_reg, const MiscReg &val) -{ - // Needs to setup a squash event unless we're in syscall mode - Fault ret_fault = thread->regs.miscRegs.setReg(misc_reg, val); - - if (!thread->inSyscall) { - cpu->squashFromXC(); - } - - return ret_fault; -} - -template <class Impl> -Fault -OzoneCPU<Impl>::OzoneXC::setMiscRegWithEffect(int misc_reg, const MiscReg &val) -{ - // Needs to setup a squash event unless we're in syscall mode - Fault ret_fault = thread->regs.miscRegs.setRegWithEffect(misc_reg, val, - this); - - if (!thread->inSyscall) { - cpu->squashFromXC(); - } - - return ret_fault; -} diff --git a/cpu/ozone/dyn_inst.cc b/cpu/ozone/dyn_inst.cc deleted file mode 100644 index 3bf8b03ca..000000000 --- a/cpu/ozone/dyn_inst.cc +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include "cpu/ozone/dyn_inst_impl.hh" -#include "cpu/ozone/ozone_impl.hh" -#include "cpu/ozone/simple_impl.hh" - -template class OzoneDynInst<OzoneImpl>; -template class OzoneDynInst<SimpleImpl>; - diff --git a/cpu/ozone/dyn_inst.hh b/cpu/ozone/dyn_inst.hh deleted file mode 100644 index 5d48bb361..000000000 --- a/cpu/ozone/dyn_inst.hh +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright (c) 2005-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. - */ - -#ifndef __CPU_OZONE_DYN_INST_HH__ -#define __CPU_OZONE_DYN_INST_HH__ - -#include "arch/isa_traits.hh" -#include "config/full_system.hh" -#include "cpu/base_dyn_inst.hh" -#include "cpu/ozone/cpu.hh" // MUST include this -#include "cpu/inst_seq.hh" -#include "cpu/ozone/simple_impl.hh" // Would be nice to not have to include this -#include "cpu/ozone/ozone_impl.hh" - -#include <list> -#include <vector> - -template <class Impl> -class OzoneDynInst : public BaseDynInst<Impl> -{ - public: - // Typedefs - typedef typename Impl::FullCPU FullCPU; - - typedef typename FullCPU::ImplState ImplState; - - // Typedef for DynInstPtr. This is really just a RefCountingPtr<OoODynInst>. - typedef typename Impl::DynInstPtr DynInstPtr; - - typedef TheISA::ExtMachInst ExtMachInst; - typedef TheISA::MachInst MachInst; - typedef TheISA::MiscReg MiscReg; - typedef typename std::list<DynInstPtr>::iterator ListIt; - - // Note that this is duplicated from the BaseDynInst class; I'm - // simply not sure the enum would carry through so I could use it - // in array declarations in this class. - enum { - MaxInstSrcRegs = TheISA::MaxInstSrcRegs, - MaxInstDestRegs = TheISA::MaxInstDestRegs - }; - - OzoneDynInst(FullCPU *cpu); - - OzoneDynInst(ExtMachInst inst, Addr PC, Addr Pred_PC, - InstSeqNum seq_num, FullCPU *cpu); - - OzoneDynInst(StaticInstPtr inst); - - ~OzoneDynInst(); - - void setSrcInst(DynInstPtr &newSrcInst, int regIdx) - { srcInsts[regIdx] = newSrcInst; } - - bool srcInstReady(int regIdx); - - void setPrevDestInst(DynInstPtr &oldDestInst, int regIdx) - { prevDestInst[regIdx] = oldDestInst; } - - DynInstPtr &getPrevDestInst(int regIdx) - { return prevDestInst[regIdx]; } - - void addDependent(DynInstPtr &dependent_inst); - - std::vector<DynInstPtr> &getDependents() { return dependents; } - std::vector<DynInstPtr> &getMemDeps() { return memDependents; } - std::list<DynInstPtr> &getMemSrcs() { return srcMemInsts; } - - void wakeDependents(); - - void wakeMemDependents(); - - void addMemDependent(DynInstPtr &inst) { memDependents.push_back(inst); } - - void addSrcMemInst(DynInstPtr &inst) { srcMemInsts.push_back(inst); } - - void markMemInstReady(OzoneDynInst<Impl> *inst); - - // For now I will remove instructions from the list when they wake - // up. In the future, you only really need a counter. - bool memDepReady() { return srcMemInsts.empty(); } - - private: - void initInstPtrs(); - - std::vector<DynInstPtr> dependents; - - std::vector<DynInstPtr> memDependents; - - std::list<DynInstPtr> srcMemInsts; - - /** The instruction that produces the value of the source - * registers. These may be NULL if the value has already been - * read from the source instruction. - */ - DynInstPtr srcInsts[MaxInstSrcRegs]; - - /** - * Previous rename instruction for this destination. - */ - DynInstPtr prevDestInst[MaxInstSrcRegs]; - - public: - - Fault initiateAcc(); - - Fault completeAcc(); - - // 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 readIntReg(const StaticInst *si, int idx) - { - return srcInsts[idx]->readIntResult(); - } - - float readFloatRegSingle(const StaticInst *si, int idx) - { - return srcInsts[idx]->readFloatResult(); - } - - double readFloatRegDouble(const StaticInst *si, int idx) - { - return srcInsts[idx]->readDoubleResult(); - } - - uint64_t readFloatRegInt(const StaticInst *si, int idx) - { - return srcInsts[idx]->readIntResult(); - } - - /** @todo: Make results into arrays so they can handle multiple dest - * registers. - */ - void setIntReg(const StaticInst *si, int idx, uint64_t val) - { - BaseDynInst<Impl>::setIntReg(si, idx, val); - } - - void setFloatRegSingle(const StaticInst *si, int idx, float val) - { - BaseDynInst<Impl>::setFloatRegSingle(si, idx, val); - } - - void setFloatRegDouble(const StaticInst *si, int idx, double val) - { - BaseDynInst<Impl>::setFloatRegDouble(si, idx, val); - } - - void setFloatRegInt(const StaticInst *si, int idx, uint64_t val) - { - BaseDynInst<Impl>::setFloatRegInt(si, idx, val); - } - - void setIntResult(uint64_t result) { this->instResult.integer = result; } - void setDoubleResult(double result) { this->instResult.dbl = result; } - - bool srcsReady(); - bool eaSrcsReady(); - - Fault execute(); - - Fault executeEAComp() - { return NoFault; } - - Fault executeMemAcc() - { return this->staticInst->memAccInst()->execute(this, this->traceData); } - - void clearDependents(); - - void clearMemDependents(); - - public: - // ISA stuff - MiscReg readMiscReg(int misc_reg); - - MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault); - - Fault setMiscReg(int misc_reg, const MiscReg &val); - - Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val); - -#if FULL_SYSTEM - Fault hwrei(); - int readIntrFlag(); - void setIntrFlag(int val); - bool inPalMode(); - void trap(Fault fault); - bool simPalCheck(int palFunc); -#else - void syscall(); -#endif - - ListIt iqIt; - bool iqItValid; -}; - -#endif // __CPU_OZONE_DYN_INST_HH__ diff --git a/cpu/ozone/dyn_inst_impl.hh b/cpu/ozone/dyn_inst_impl.hh deleted file mode 100644 index f891ec515..000000000 --- a/cpu/ozone/dyn_inst_impl.hh +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright (c) 2005-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. - */ - -#include "arch/faults.hh" -#include "arch/isa_traits.hh" -#include "config/full_system.hh" -#include "cpu/ozone/dyn_inst.hh" -#include "kern/kernel_stats.hh" - -using namespace TheISA; - -template <class Impl> -OzoneDynInst<Impl>::OzoneDynInst(FullCPU *cpu) - : BaseDynInst<Impl>(0, 0, 0, 0, cpu) -{ - this->setResultReady(); - - initInstPtrs(); -} - -template <class Impl> -OzoneDynInst<Impl>::OzoneDynInst(ExtMachInst inst, Addr PC, Addr Pred_PC, - InstSeqNum seq_num, FullCPU *cpu) - : BaseDynInst<Impl>(inst, PC, Pred_PC, seq_num, cpu) -{ - initInstPtrs(); -} - -template <class Impl> -OzoneDynInst<Impl>::OzoneDynInst(StaticInstPtr _staticInst) - : BaseDynInst<Impl>(_staticInst) -{ - initInstPtrs(); -} - -template <class Impl> -OzoneDynInst<Impl>::~OzoneDynInst() -{ - DPRINTF(BE, "[sn:%lli] destructor called\n", this->seqNum); - for (int i = 0; i < this->numSrcRegs(); ++i) { - srcInsts[i] = NULL; - } - - for (int i = 0; i < this->numDestRegs(); ++i) { - prevDestInst[i] = NULL; - } - - dependents.clear(); -} - -template <class Impl> -Fault -OzoneDynInst<Impl>::execute() -{ - // @todo: Pretty convoluted way to avoid squashing from happening when using - // the XC during an instruction's execution (specifically for instructions - // that have sideeffects that use the XC). Fix this. - bool in_syscall = this->thread->inSyscall; - this->thread->inSyscall = true; - - this->fault = this->staticInst->execute(this, this->traceData); - - this->thread->inSyscall = in_syscall; - - return this->fault; -} - -template <class Impl> -Fault -OzoneDynInst<Impl>::initiateAcc() -{ - // @todo: Pretty convoluted way to avoid squashing from happening when using - // the XC during an instruction's execution (specifically for instructions - // that have sideeffects that use the XC). Fix this. - bool in_syscall = this->thread->inSyscall; - this->thread->inSyscall = true; - - this->fault = this->staticInst->initiateAcc(this, this->traceData); - - this->thread->inSyscall = in_syscall; - - return this->fault; -} - -template <class Impl> -Fault -OzoneDynInst<Impl>::completeAcc() -{ - if (this->isLoad()) { - this->fault = this->staticInst->completeAcc(this->req->data, - this, - this->traceData); - } else if (this->isStore()) { - this->fault = this->staticInst->completeAcc((uint8_t*)&this->req->result, - this, - this->traceData); - } else { - panic("Unknown type!"); - } - - return this->fault; -} - -template <class Impl> -bool -OzoneDynInst<Impl>::srcInstReady(int regIdx) -{ - return srcInsts[regIdx]->isResultReady(); -} - -template <class Impl> -void -OzoneDynInst<Impl>::addDependent(DynInstPtr &dependent_inst) -{ - dependents.push_back(dependent_inst); -} - -template <class Impl> -void -OzoneDynInst<Impl>::wakeDependents() -{ - for (int i = 0; i < dependents.size(); ++i) { - dependents[i]->markSrcRegReady(); - } -} - -template <class Impl> -void -OzoneDynInst<Impl>::wakeMemDependents() -{ - for (int i = 0; i < memDependents.size(); ++i) { - memDependents[i]->markMemInstReady(this); - } -} - -template <class Impl> -void -OzoneDynInst<Impl>::markMemInstReady(OzoneDynInst<Impl> *inst) -{ - ListIt mem_it = srcMemInsts.begin(); - while ((*mem_it) != inst && mem_it != srcMemInsts.end()) { - mem_it++; - } - assert(mem_it != srcMemInsts.end()); - - srcMemInsts.erase(mem_it); -} - -template <class Impl> -void -OzoneDynInst<Impl>::initInstPtrs() -{ - for (int i = 0; i < MaxInstSrcRegs; ++i) { - srcInsts[i] = NULL; - } - iqItValid = false; -} - -template <class Impl> -bool -OzoneDynInst<Impl>::srcsReady() -{ - for (int i = 0; i < this->numSrcRegs(); ++i) { - if (!srcInsts[i]->isResultReady()) - return false; - } - - return true; -} - -template <class Impl> -bool -OzoneDynInst<Impl>::eaSrcsReady() -{ - for (int i = 1; i < this->numSrcRegs(); ++i) { - if (!srcInsts[i]->isResultReady()) - return false; - } - - return true; -} - -template <class Impl> -void -OzoneDynInst<Impl>::clearDependents() -{ - dependents.clear(); - for (int i = 0; i < this->numSrcRegs(); ++i) { - srcInsts[i] = NULL; - } - for (int i = 0; i < this->numDestRegs(); ++i) { - prevDestInst[i] = NULL; - } -} - -template <class Impl> -void -OzoneDynInst<Impl>::clearMemDependents() -{ - memDependents.clear(); -} - -template <class Impl> -MiscReg -OzoneDynInst<Impl>::readMiscReg(int misc_reg) -{ - return this->thread->readMiscReg(misc_reg); -} - -template <class Impl> -MiscReg -OzoneDynInst<Impl>::readMiscRegWithEffect(int misc_reg, Fault &fault) -{ - return this->thread->readMiscRegWithEffect(misc_reg, fault); -} - -template <class Impl> -Fault -OzoneDynInst<Impl>::setMiscReg(int misc_reg, const MiscReg &val) -{ - this->setIntResult(val); - return this->thread->setMiscReg(misc_reg, val); -} - -template <class Impl> -Fault -OzoneDynInst<Impl>::setMiscRegWithEffect(int misc_reg, const MiscReg &val) -{ - return this->thread->setMiscRegWithEffect(misc_reg, val); -} - -#if FULL_SYSTEM - -template <class Impl> -Fault -OzoneDynInst<Impl>::hwrei() -{ - if (!this->cpu->inPalMode(this->readPC())) - return new AlphaISA::UnimplementedOpcodeFault; - - this->setNextPC(this->thread->readMiscReg(AlphaISA::IPR_EXC_ADDR)); - - this->cpu->hwrei(); - - // FIXME: XXX check for interrupts? XXX - return NoFault; -} - -template <class Impl> -int -OzoneDynInst<Impl>::readIntrFlag() -{ -return this->cpu->readIntrFlag(); -} - -template <class Impl> -void -OzoneDynInst<Impl>::setIntrFlag(int val) -{ - this->cpu->setIntrFlag(val); -} - -template <class Impl> -bool -OzoneDynInst<Impl>::inPalMode() -{ - return this->cpu->inPalMode(); -} - -template <class Impl> -void -OzoneDynInst<Impl>::trap(Fault fault) -{ - fault->invoke(this->thread->getXCProxy()); -} - -template <class Impl> -bool -OzoneDynInst<Impl>::simPalCheck(int palFunc) -{ - return this->cpu->simPalCheck(palFunc); -} -#else -template <class Impl> -void -OzoneDynInst<Impl>::syscall() -{ - this->cpu->syscall(); -} -#endif diff --git a/cpu/ozone/ea_list.cc b/cpu/ozone/ea_list.cc deleted file mode 100644 index 6114a0ca1..000000000 --- a/cpu/ozone/ea_list.cc +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include "arch/isa_traits.hh" -#include "cpu/inst_seq.hh" -#include "cpu/ooo_cpu/ea_list.hh" - -void -EAList::addAddr(const InstSeqNum &new_sn, const Addr &new_ea) -{ - instEA newEA(new_sn, new_ea); - - eaList.push_back(newEA); -} - -void -EAList::clearAddr(const InstSeqNum &sn_to_clear, const Addr &ea_to_clear) -{ - eaListIt list_it = eaList.begin(); - - while (list_it != eaList.end() && (*list_it).first != sn_to_clear) { - assert((*list_it).second == ea_to_clear); - } -} - -bool -EAList::checkConflict(const InstSeqNum &check_sn, const Addr &check_ea) const -{ - const constEAListIt list_it = eaList.begin(); - - while (list_it != eaList.end() && (*list_it).first < check_sn) { - if ((*list_it).second == check_ea) { - return true; - } - } - - return false; -} - -void -EAList::clear() -{ - eaList.clear(); -} - -void -EAList::commit(const InstSeqNum &commit_sn) -{ - while (!eaList.empty() && eaList.front().first <= commit_sn) { - eaList.pop_front(); - } -} diff --git a/cpu/ozone/ea_list.hh b/cpu/ozone/ea_list.hh deleted file mode 100644 index c0eee4bb8..000000000 --- a/cpu/ozone/ea_list.hh +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __CPU_EA_LIST_HH__ -#define __CPU_EA_LIST_HH__ - -#include <list> -#include <utility> - -#include "arch/isa_traits.hh" -#include "cpu/inst_seq.hh" - -/** - * Simple class to hold onto a list of pairs, each pair having a memory - * instruction's sequence number and effective addr. This list can be used - * for memory disambiguation. However, if I ever want to forward results, I - * may have to use a list that holds DynInstPtrs. Hence this may change in - * the future. - */ -class EAList { - private: - typedef std::pair<InstSeqNum, Addr> instEA; - typedef std::list<instEA>::iterator eaListIt; - typedef std::list<instEA>::const_iterator constEAListIt; - - std::list<instEA> eaList; - - public: - EAList() { } - ~EAList() { } - - void addAddr(const InstSeqNum &new_sn, const Addr &new_ea); - - void clearAddr(const InstSeqNum &sn_to_clear, const Addr &ea_to_clear); - - /** Checks if any instructions older than check_sn have a conflicting - * address with check_ea. Note that this function does not handle the - * sequence number rolling over. - */ - bool checkConflict(const InstSeqNum &check_sn, const Addr &check_ea) const; - - void clear(); - - void commit(const InstSeqNum &commit_sn); -}; - -#endif // __CPU_EA_LIST_HH__ diff --git a/cpu/ozone/front_end.cc b/cpu/ozone/front_end.cc deleted file mode 100644 index a974d43cb..000000000 --- a/cpu/ozone/front_end.cc +++ /dev/null @@ -1,7 +0,0 @@ - -#include "cpu/ozone/front_end_impl.hh" -#include "cpu/ozone/ozone_impl.hh" -#include "cpu/ozone/simple_impl.hh" - -template class FrontEnd<OzoneImpl>; -template class FrontEnd<SimpleImpl>; diff --git a/cpu/ozone/front_end.hh b/cpu/ozone/front_end.hh deleted file mode 100644 index dd382491f..000000000 --- a/cpu/ozone/front_end.hh +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Copyright (c) 2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_OZONE_FRONT_END_HH__ -#define __CPU_OZONE_FRONT_END_HH__ - -#include <deque> - -#include "cpu/inst_seq.hh" -#include "cpu/o3/bpred_unit.hh" -#include "cpu/ozone/rename_table.hh" -#include "mem/mem_req.hh" -#include "sim/eventq.hh" -#include "sim/stats.hh" - -class ExecContext; -class MemInterface; -template <class> -class OzoneThreadState; -class PageTable; -template <class> -class TimeBuffer; - -template <class Impl> -class FrontEnd -{ - public: - typedef typename Impl::Params Params; - typedef typename Impl::DynInst DynInst; - typedef typename Impl::DynInstPtr DynInstPtr; - typedef typename Impl::FullCPU FullCPU; - typedef typename Impl::BackEnd BackEnd; - - typedef typename Impl::FullCPU::OzoneXC OzoneXC; - typedef typename Impl::FullCPU::CommStruct CommStruct; - - FrontEnd(Params *params); - - std::string name() const; - - void setCPU(FullCPU *cpu_ptr) - { cpu = cpu_ptr; } - - void setBackEnd(BackEnd *back_end_ptr) - { backEnd = back_end_ptr; } - - void setCommBuffer(TimeBuffer<CommStruct> *_comm); - - void setXC(ExecContext *xc_ptr); - - void setThreadState(OzoneThreadState<Impl> *thread_ptr) - { thread = thread_ptr; } - - void regStats(); - - void tick(); - Fault fetchCacheLine(); - void processInst(DynInstPtr &inst); - void squash(const InstSeqNum &squash_num, const Addr &next_PC, - const bool is_branch = false, const bool branch_taken = false); - DynInstPtr getInst(); - - void processCacheCompletion(MemReqPtr &req); - - void addFreeRegs(int num_freed); - - bool isEmpty() { return instBuffer.empty(); } - - void switchOut(); - - void doSwitchOut(); - - void takeOverFrom(ExecContext *old_xc = NULL); - - bool isSwitchedOut() { return switchedOut; } - - bool switchedOut; - - private: - bool updateStatus(); - - void checkBE(); - DynInstPtr getInstFromCacheline(); - void renameInst(DynInstPtr &inst); - // Returns true if we need to stop the front end this cycle - bool processBarriers(DynInstPtr &inst); - - void handleFault(Fault &fault); - public: - Fault getFault() { return fetchFault; } - private: - Fault fetchFault; - - // Align an address (typically a PC) to the start of an I-cache block. - // We fold in the PISA 64- to 32-bit conversion here as well. - Addr icacheBlockAlignPC(Addr addr) - { - addr = TheISA::realPCToFetchPC(addr); - return (addr & ~(cacheBlkMask)); - } - - InstSeqNum getAndIncrementInstSeq() - { return cpu->globalSeqNum++; } - - public: - FullCPU *cpu; - - BackEnd *backEnd; - - ExecContext *xc; - - OzoneThreadState<Impl> *thread; - - enum Status { - Running, - Idle, - IcacheMissStall, - IcacheMissComplete, - SerializeBlocked, - SerializeComplete, - RenameBlocked, - QuiescePending, - TrapPending, - BEBlocked - }; - - Status status; - - private: - TimeBuffer<CommStruct> *comm; - typename TimeBuffer<CommStruct>::wire fromCommit; - - typedef typename Impl::BranchPred BranchPred; - - BranchPred branchPred; - - class ICacheCompletionEvent : public Event - { - private: - MemReqPtr req; - FrontEnd *frontEnd; - - public: - ICacheCompletionEvent(MemReqPtr &_req, FrontEnd *_fe); - - virtual void process(); - virtual const char *description(); - }; - - MemInterface *icacheInterface; - -#if !FULL_SYSTEM - PageTable *pTable; -#endif - - MemReqPtr memReq; - - /** Mask to get a cache block's address. */ - Addr cacheBlkMask; - - unsigned cacheBlkSize; - - Addr cacheBlkPC; - - /** The cache line being fetched. */ - uint8_t *cacheData; - - bool fetchCacheLineNextCycle; - - bool cacheBlkValid; - - public: - RenameTable<Impl> renameTable; - - private: - Addr PC; - Addr nextPC; - - public: - void setPC(Addr val) { PC = val; } - void setNextPC(Addr val) { nextPC = val; } - - void wakeFromQuiesce(); - - void dumpInsts(); - - private: - typedef typename std::deque<DynInstPtr> InstBuff; - typedef typename InstBuff::iterator InstBuffIt; - - InstBuff instBuffer; - - int instBufferSize; - - int maxInstBufferSize; - - int width; - - int freeRegs; - - int numPhysRegs; - - bool serializeNext; - - DynInstPtr barrierInst; - - public: - bool interruptPending; - private: - // number of idle cycles -/* - Stats::Average<> notIdleFraction; - Stats::Formula idleFraction; -*/ - // @todo: Consider making these vectors and tracking on a per thread basis. - /** Stat for total number of cycles stalled due to an icache miss. */ - Stats::Scalar<> icacheStallCycles; - /** Stat for total number of fetched instructions. */ - Stats::Scalar<> fetchedInsts; - Stats::Scalar<> fetchedBranches; - /** Stat for total number of predicted branches. */ - Stats::Scalar<> predictedBranches; - /** Stat for total number of cycles spent fetching. */ - Stats::Scalar<> fetchCycles; - - Stats::Scalar<> fetchIdleCycles; - /** Stat for total number of cycles spent squashing. */ - Stats::Scalar<> fetchSquashCycles; - /** Stat for total number of cycles spent blocked due to other stages in - * the pipeline. - */ - Stats::Scalar<> fetchBlockedCycles; - /** Stat for total number of fetched cache lines. */ - Stats::Scalar<> fetchedCacheLines; - - Stats::Scalar<> fetchIcacheSquashes; - /** Distribution of number of instructions fetched each cycle. */ - Stats::Distribution<> fetchNisnDist; -// Stats::Vector<> qfull_iq_occupancy; -// Stats::VectorDistribution<> qfull_iq_occ_dist_; - Stats::Formula idleRate; - Stats::Formula branchRate; - Stats::Formula fetchRate; - Stats::Scalar<> IFQCount; // cumulative IFQ occupancy - Stats::Formula IFQOccupancy; - Stats::Formula IFQLatency; - Stats::Scalar<> IFQFcount; // cumulative IFQ full count - Stats::Formula IFQFullRate; - - Stats::Scalar<> dispatchCountStat; - Stats::Scalar<> dispatchedSerializing; - Stats::Scalar<> dispatchedTempSerializing; - Stats::Scalar<> dispatchSerializeStallCycles; - Stats::Formula dispatchRate; - Stats::Formula regIntFull; - Stats::Formula regFpFull; -}; - -#endif // __CPU_OZONE_FRONT_END_HH__ diff --git a/cpu/ozone/front_end_impl.hh b/cpu/ozone/front_end_impl.hh deleted file mode 100644 index ffbcf3340..000000000 --- a/cpu/ozone/front_end_impl.hh +++ /dev/null @@ -1,920 +0,0 @@ -/* - * Copyright (c) 2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "arch/faults.hh" -#include "arch/isa_traits.hh" -#include "base/statistics.hh" -#include "cpu/exec_context.hh" -#include "cpu/exetrace.hh" -#include "cpu/ozone/front_end.hh" -#include "mem/mem_interface.hh" -#include "sim/byte_swap.hh" - -using namespace TheISA; - -template <class Impl> -FrontEnd<Impl>::FrontEnd(Params *params) - : branchPred(params), - icacheInterface(params->icacheInterface), - instBufferSize(0), - maxInstBufferSize(params->maxInstBufferSize), - width(params->frontEndWidth), - freeRegs(params->numPhysicalRegs), - numPhysRegs(params->numPhysicalRegs), - serializeNext(false), - interruptPending(false) -{ - switchedOut = false; - - status = Idle; - - memReq = NULL; - // Size of cache block. - cacheBlkSize = icacheInterface ? icacheInterface->getBlockSize() : 64; - - assert(isPowerOf2(cacheBlkSize)); - - // Create mask to get rid of offset bits. - cacheBlkMask = (cacheBlkSize - 1); - - // Create space to store a cache line. - cacheData = new uint8_t[cacheBlkSize]; - - fetchCacheLineNextCycle = true; - - cacheBlkValid = false; - -#if !FULL_SYSTEM -// pTable = params->pTable; -#endif - fetchFault = NoFault; -} - -template <class Impl> -std::string -FrontEnd<Impl>::name() const -{ - return cpu->name() + ".frontend"; -} - -template <class Impl> -void -FrontEnd<Impl>::setCommBuffer(TimeBuffer<CommStruct> *_comm) -{ - comm = _comm; - // @todo: Hardcoded for now. Allow this to be set by a latency. - fromCommit = comm->getWire(-1); -} - -template <class Impl> -void -FrontEnd<Impl>::setXC(ExecContext *xc_ptr) -{ - xc = xc_ptr; -} - -template <class Impl> -void -FrontEnd<Impl>::regStats() -{ - icacheStallCycles - .name(name() + ".icacheStallCycles") - .desc("Number of cycles fetch is stalled on an Icache miss") - .prereq(icacheStallCycles); - - fetchedInsts - .name(name() + ".fetchedInsts") - .desc("Number of instructions fetch has processed") - .prereq(fetchedInsts); - - fetchedBranches - .name(name() + ".fetchedBranches") - .desc("Number of fetched branches") - .prereq(fetchedBranches); - - predictedBranches - .name(name() + ".predictedBranches") - .desc("Number of branches that fetch has predicted taken") - .prereq(predictedBranches); - - fetchCycles - .name(name() + ".fetchCycles") - .desc("Number of cycles fetch has run and was not squashing or" - " blocked") - .prereq(fetchCycles); - - fetchIdleCycles - .name(name() + ".fetchIdleCycles") - .desc("Number of cycles fetch was idle") - .prereq(fetchIdleCycles); - - fetchSquashCycles - .name(name() + ".fetchSquashCycles") - .desc("Number of cycles fetch has spent squashing") - .prereq(fetchSquashCycles); - - fetchBlockedCycles - .name(name() + ".fetchBlockedCycles") - .desc("Number of cycles fetch has spent blocked") - .prereq(fetchBlockedCycles); - - fetchedCacheLines - .name(name() + ".fetchedCacheLines") - .desc("Number of cache lines fetched") - .prereq(fetchedCacheLines); - - fetchIcacheSquashes - .name(name() + ".fetchIcacheSquashes") - .desc("Number of outstanding Icache misses that were squashed") - .prereq(fetchIcacheSquashes); - - fetchNisnDist - .init(/* base value */ 0, - /* last value */ width, - /* bucket size */ 1) - .name(name() + ".rateDist") - .desc("Number of instructions fetched each cycle (Total)") - .flags(Stats::pdf); - - idleRate - .name(name() + ".idleRate") - .desc("Percent of cycles fetch was idle") - .prereq(idleRate); - idleRate = fetchIdleCycles * 100 / cpu->numCycles; - - branchRate - .name(name() + ".branchRate") - .desc("Number of branch fetches per cycle") - .flags(Stats::total); - branchRate = fetchedBranches / cpu->numCycles; - - fetchRate - .name(name() + ".rate") - .desc("Number of inst fetches per cycle") - .flags(Stats::total); - fetchRate = fetchedInsts / cpu->numCycles; - - IFQCount - .name(name() + ".IFQ:count") - .desc("cumulative IFQ occupancy") - ; - - IFQFcount - .name(name() + ".IFQ:fullCount") - .desc("cumulative IFQ full count") - .flags(Stats::total) - ; - - IFQOccupancy - .name(name() + ".IFQ:occupancy") - .desc("avg IFQ occupancy (inst's)") - ; - IFQOccupancy = IFQCount / cpu->numCycles; - - IFQLatency - .name(name() + ".IFQ:latency") - .desc("avg IFQ occupant latency (cycle's)") - .flags(Stats::total) - ; - - IFQFullRate - .name(name() + ".IFQ:fullRate") - .desc("fraction of time (cycles) IFQ was full") - .flags(Stats::total); - ; - IFQFullRate = IFQFcount * Stats::constant(100) / cpu->numCycles; - - dispatchCountStat - .name(name() + ".DIS:count") - .desc("cumulative count of dispatched insts") - .flags(Stats::total) - ; - - dispatchedSerializing - .name(name() + ".DIS:serializingInsts") - .desc("count of serializing insts dispatched") - .flags(Stats::total) - ; - - dispatchedTempSerializing - .name(name() + ".DIS:tempSerializingInsts") - .desc("count of temporary serializing insts dispatched") - .flags(Stats::total) - ; - - dispatchSerializeStallCycles - .name(name() + ".DIS:serializeStallCycles") - .desc("count of cycles dispatch stalled for serializing inst") - .flags(Stats::total) - ; - - dispatchRate - .name(name() + ".DIS:rate") - .desc("dispatched insts per cycle") - .flags(Stats::total) - ; - dispatchRate = dispatchCountStat / cpu->numCycles; - - regIntFull - .name(name() + ".REG:int:full") - .desc("number of cycles where there were no INT registers") - ; - - regFpFull - .name(name() + ".REG:fp:full") - .desc("number of cycles where there were no FP registers") - ; - IFQLatency = IFQOccupancy / dispatchRate; - - branchPred.regStats(); -} - -template <class Impl> -void -FrontEnd<Impl>::tick() -{ - if (switchedOut) - return; - - // @todo: Maybe I want to just have direct communication... - if (fromCommit->doneSeqNum) { - branchPred.update(fromCommit->doneSeqNum, 0); - } - - IFQCount += instBufferSize; - IFQFcount += instBufferSize == maxInstBufferSize; - - // Fetch cache line - if (status == IcacheMissComplete) { - cacheBlkValid = true; - - status = Running; - if (barrierInst) - status = SerializeBlocked; - if (freeRegs <= 0) - status = RenameBlocked; - checkBE(); - } else if (status == IcacheMissStall) { - DPRINTF(FE, "Still in Icache miss stall.\n"); - icacheStallCycles++; - return; - } - - if (status == RenameBlocked || status == SerializeBlocked || - status == TrapPending || status == BEBlocked) { - // Will cause a one cycle bubble between changing state and - // restarting. - DPRINTF(FE, "In blocked status.\n"); - - fetchBlockedCycles++; - - if (status == SerializeBlocked) { - dispatchSerializeStallCycles++; - } - updateStatus(); - return; - } else if (status == QuiescePending) { - DPRINTF(FE, "Waiting for quiesce to execute or get squashed.\n"); - return; - } else if (status != IcacheMissComplete) { - if (fetchCacheLineNextCycle) { - Fault fault = fetchCacheLine(); - if (fault != NoFault) { - handleFault(fault); - fetchFault = fault; - return; - } - fetchCacheLineNextCycle = false; - } - // If miss, stall until it returns. - if (status == IcacheMissStall) { - // Tell CPU to not tick me for now. - return; - } - } - - fetchCycles++; - - int num_inst = 0; - - // Otherwise loop and process instructions. - // One way to hack infinite width is to set width and maxInstBufferSize - // both really high. Inelegant, but probably will work. - while (num_inst < width && - instBufferSize < maxInstBufferSize) { - // Get instruction from cache line. - DynInstPtr inst = getInstFromCacheline(); - - if (!inst) { - // PC is no longer in the cache line, end fetch. - // Might want to check this at the end of the cycle so that - // there's no cycle lost to checking for a new cache line. - DPRINTF(FE, "Need to get new cache line\n"); - fetchCacheLineNextCycle = true; - break; - } - - processInst(inst); - - if (status == SerializeBlocked) { - break; - } - - // Possibly push into a time buffer that estimates the front end - // latency - instBuffer.push_back(inst); - ++instBufferSize; - ++num_inst; - -#if FULL_SYSTEM - if (inst->isQuiesce()) { - warn("%lli: Quiesce instruction encountered, halting fetch!", curTick); - status = QuiescePending; - break; - } -#endif - - if (inst->predTaken()) { - // Start over with tick? - break; - } else if (freeRegs <= 0) { - DPRINTF(FE, "Ran out of free registers to rename to!\n"); - status = RenameBlocked; - break; - } else if (serializeNext) { - break; - } - } - - fetchNisnDist.sample(num_inst); - checkBE(); - - DPRINTF(FE, "Num insts processed: %i, Inst Buffer size: %i, Free " - "Regs %i\n", num_inst, instBufferSize, freeRegs); -} - -template <class Impl> -Fault -FrontEnd<Impl>::fetchCacheLine() -{ - // Read a cache line, based on the current PC. -#if FULL_SYSTEM - // Flag to say whether or not address is physical addr. - unsigned flags = cpu->inPalMode(PC) ? PHYSICAL : 0; -#else - unsigned flags = 0; -#endif // FULL_SYSTEM - Fault fault = NoFault; - - if (interruptPending && flags == 0) { - return fault; - } - - // Align the fetch PC so it's at the start of a cache block. - Addr fetch_PC = icacheBlockAlignPC(PC); - - DPRINTF(FE, "Fetching cache line starting at %#x.\n", fetch_PC); - - // Setup the memReq to do a read of the first isntruction's address. - // Set the appropriate read size and flags as well. - memReq = new MemReq(); - - memReq->asid = 0; - memReq->thread_num = 0; - memReq->data = new uint8_t[64]; - memReq->xc = xc; - memReq->cmd = Read; - memReq->reset(fetch_PC, cacheBlkSize, flags); - - // Translate the instruction request. - fault = cpu->translateInstReq(memReq); - - // Now do the timing access to see whether or not the instruction - // exists within the cache. - if (icacheInterface && fault == NoFault) { -#if FULL_SYSTEM - if (cpu->system->memctrl->badaddr(memReq->paddr) || - memReq->flags & UNCACHEABLE) { - DPRINTF(FE, "Fetch: Bad address %#x (hopefully on a " - "misspeculating path!", - memReq->paddr); - return TheISA::genMachineCheckFault(); - } -#endif - - memReq->completionEvent = NULL; - - memReq->time = curTick; - fault = cpu->mem->read(memReq, cacheData); - - MemAccessResult res = icacheInterface->access(memReq); - - // If the cache missed then schedule an event to wake - // up this stage once the cache miss completes. - if (icacheInterface->doEvents() && res != MA_HIT) { - memReq->completionEvent = new ICacheCompletionEvent(memReq, this); - - status = IcacheMissStall; - - cacheBlkValid = false; - - DPRINTF(FE, "Cache miss.\n"); - } else { - DPRINTF(FE, "Cache hit.\n"); - - cacheBlkValid = true; - -// memcpy(cacheData, memReq->data, memReq->size); - } - } - - // Note that this will set the cache block PC a bit earlier than it should - // be set. - cacheBlkPC = fetch_PC; - - ++fetchedCacheLines; - - DPRINTF(FE, "Done fetching cache line.\n"); - - return fault; -} - -template <class Impl> -void -FrontEnd<Impl>::processInst(DynInstPtr &inst) -{ - if (processBarriers(inst)) { - return; - } - - Addr inst_PC = inst->readPC(); - - if (!inst->isControl()) { - inst->setPredTarg(inst->readNextPC()); - } else { - fetchedBranches++; - if (branchPred.predict(inst, inst_PC, inst->threadNumber)) { - predictedBranches++; - } - } - - Addr next_PC = inst->readPredTarg(); - - DPRINTF(FE, "[sn:%lli] Predicted and processed inst PC %#x, next PC " - "%#x\n", inst->seqNum, inst_PC, next_PC); - -// inst->setNextPC(next_PC); - - // Not sure where I should set this - PC = next_PC; - - renameInst(inst); -} - -template <class Impl> -bool -FrontEnd<Impl>::processBarriers(DynInstPtr &inst) -{ - if (serializeNext) { - inst->setSerializeBefore(); - serializeNext = false; - } else if (!inst->isSerializing() && - !inst->isIprAccess() && - !inst->isStoreConditional()) { - return false; - } - - if ((inst->isIprAccess() || inst->isSerializeBefore()) && - !inst->isSerializeHandled()) { - DPRINTF(FE, "Serialize before instruction encountered.\n"); - - if (!inst->isTempSerializeBefore()) { - dispatchedSerializing++; - inst->setSerializeHandled(); - } else { - dispatchedTempSerializing++; - } - - // Change status over to SerializeBlocked so that other stages know - // what this is blocked on. - status = SerializeBlocked; - - barrierInst = inst; - return true; - } else if ((inst->isStoreConditional() || inst->isSerializeAfter()) - && !inst->isSerializeHandled()) { - DPRINTF(FE, "Serialize after instruction encountered.\n"); - - inst->setSerializeHandled(); - - dispatchedSerializing++; - - serializeNext = true; - return false; - } - return false; -} - -template <class Impl> -void -FrontEnd<Impl>::handleFault(Fault &fault) -{ - DPRINTF(FE, "Fault at fetch, telling commit\n"); - - // We're blocked on the back end until it handles this fault. - status = TrapPending; - - // Get a sequence number. - InstSeqNum inst_seq = getAndIncrementInstSeq(); - // We will use a nop in order to carry the fault. - ExtMachInst ext_inst = TheISA::NoopMachInst; - - // Create a new DynInst from the dummy nop. - DynInstPtr instruction = new DynInst(ext_inst, PC, - PC+sizeof(MachInst), - inst_seq, cpu); - instruction->setPredTarg(instruction->readNextPC()); -// instruction->setThread(tid); - -// instruction->setASID(tid); - - instruction->setState(thread); - - instruction->traceData = NULL; - - instruction->fault = fault; - instruction->setCanIssue(); - instBuffer.push_back(instruction); - ++instBufferSize; -} - -template <class Impl> -void -FrontEnd<Impl>::squash(const InstSeqNum &squash_num, const Addr &next_PC, - const bool is_branch, const bool branch_taken) -{ - DPRINTF(FE, "Squashing from [sn:%lli], setting PC to %#x\n", - squash_num, next_PC); - - if (fetchFault != NoFault) - fetchFault = NoFault; - - while (!instBuffer.empty() && - instBuffer.back()->seqNum > squash_num) { - DynInstPtr inst = instBuffer.back(); - - DPRINTF(FE, "Squashing instruction [sn:%lli] PC %#x\n", - inst->seqNum, inst->readPC()); - - inst->clearDependents(); - - instBuffer.pop_back(); - --instBufferSize; - - freeRegs+= inst->numDestRegs(); - } - - // Copy over rename table from the back end. - renameTable.copyFrom(backEnd->renameTable); - - PC = next_PC; - - // Update BP with proper information. - if (is_branch) { - branchPred.squash(squash_num, next_PC, branch_taken, 0); - } else { - branchPred.squash(squash_num, 0); - } - - // Clear the icache miss if it's outstanding. - if (status == IcacheMissStall && icacheInterface) { - DPRINTF(FE, "Squashing outstanding Icache miss.\n"); - memReq = NULL; - } - - if (status == SerializeBlocked) { - assert(barrierInst->seqNum > squash_num); - barrierInst = NULL; - } - - // Unless this squash originated from the front end, we're probably - // in running mode now. - // Actually might want to make this latency dependent. - status = Running; - fetchCacheLineNextCycle = true; -} - -template <class Impl> -typename Impl::DynInstPtr -FrontEnd<Impl>::getInst() -{ - if (instBufferSize == 0) { - return NULL; - } - - DynInstPtr inst = instBuffer.front(); - - instBuffer.pop_front(); - - --instBufferSize; - - dispatchCountStat++; - - return inst; -} - -template <class Impl> -void -FrontEnd<Impl>::processCacheCompletion(MemReqPtr &req) -{ - DPRINTF(FE, "Processing cache completion\n"); - - // Do something here. - if (status != IcacheMissStall || - req != memReq || - switchedOut) { - DPRINTF(FE, "Previous fetch was squashed.\n"); - fetchIcacheSquashes++; - return; - } - - status = IcacheMissComplete; - -/* if (checkStall(tid)) { - fetchStatus[tid] = Blocked; - } else { - fetchStatus[tid] = IcacheMissComplete; - } -*/ -// memcpy(cacheData, memReq->data, memReq->size); - - // Reset the completion event to NULL. -// memReq->completionEvent = NULL; - memReq = NULL; -} - -template <class Impl> -void -FrontEnd<Impl>::addFreeRegs(int num_freed) -{ - if (status == RenameBlocked && freeRegs + num_freed > 0) { - status = Running; - } - - DPRINTF(FE, "Adding %i freed registers\n", num_freed); - - freeRegs+= num_freed; - -// assert(freeRegs <= numPhysRegs); - if (freeRegs > numPhysRegs) - freeRegs = numPhysRegs; -} - -template <class Impl> -bool -FrontEnd<Impl>::updateStatus() -{ - bool serialize_block = !backEnd->robEmpty() || instBufferSize; - bool be_block = cpu->decoupledFrontEnd ? false : backEnd->isBlocked(); - bool ret_val = false; - - if (status == SerializeBlocked && !serialize_block) { - status = SerializeComplete; - ret_val = true; - } - - if (status == BEBlocked && !be_block) { - if (barrierInst) { - status = SerializeBlocked; - } else { - status = Running; - } - ret_val = true; - } - return ret_val; -} - -template <class Impl> -void -FrontEnd<Impl>::checkBE() -{ - bool be_block = cpu->decoupledFrontEnd ? false : backEnd->isBlocked(); - if (be_block) { - if (status == Running || status == Idle) { - status = BEBlocked; - } - } -} - -template <class Impl> -typename Impl::DynInstPtr -FrontEnd<Impl>::getInstFromCacheline() -{ - if (status == SerializeComplete) { - DynInstPtr inst = barrierInst; - status = Running; - barrierInst = NULL; - inst->clearSerializeBefore(); - return inst; - } - - InstSeqNum inst_seq; - MachInst inst; - // @todo: Fix this magic number used here to handle word offset (and - // getting rid of PAL bit) - unsigned offset = (PC & cacheBlkMask) & ~3; - - // PC of inst is not in this cache block - if (PC >= (cacheBlkPC + cacheBlkSize) || PC < cacheBlkPC || !cacheBlkValid) { - return NULL; - } - - ////////////////////////// - // Fetch one instruction - ////////////////////////// - - // Get a sequence number. - inst_seq = getAndIncrementInstSeq(); - - // Make sure this is a valid index. - assert(offset <= cacheBlkSize - sizeof(MachInst)); - - // Get the instruction from the array of the cache line. - inst = htog(*reinterpret_cast<MachInst *>(&cacheData[offset])); - - ExtMachInst decode_inst = TheISA::makeExtMI(inst, PC); - - // Create a new DynInst from the instruction fetched. - DynInstPtr instruction = new DynInst(decode_inst, PC, PC+sizeof(MachInst), - inst_seq, cpu); - - instruction->setState(thread); - - DPRINTF(FE, "Instruction [sn:%lli] created, with PC %#x\n%s\n", - inst_seq, instruction->readPC(), - instruction->staticInst->disassemble(PC)); - - instruction->traceData = - Trace::getInstRecord(curTick, xc, cpu, - instruction->staticInst, - instruction->readPC(), 0); - - // Increment stat of fetched instructions. - ++fetchedInsts; - - return instruction; -} - -template <class Impl> -void -FrontEnd<Impl>::renameInst(DynInstPtr &inst) -{ - DynInstPtr src_inst = NULL; - int num_src_regs = inst->numSrcRegs(); - if (num_src_regs == 0) { - inst->setCanIssue(); - } else { - for (int i = 0; i < num_src_regs; ++i) { - src_inst = renameTable[inst->srcRegIdx(i)]; - - inst->setSrcInst(src_inst, i); - - DPRINTF(FE, "[sn:%lli]: Src reg %i is inst [sn:%lli]\n", - inst->seqNum, (int)inst->srcRegIdx(i), src_inst->seqNum); - - if (src_inst->isResultReady()) { - DPRINTF(FE, "Reg ready.\n"); - inst->markSrcRegReady(i); - } else { - DPRINTF(FE, "Adding to dependent list.\n"); - src_inst->addDependent(inst); - } - } - } - - for (int i = 0; i < inst->numDestRegs(); ++i) { - RegIndex idx = inst->destRegIdx(i); - - DPRINTF(FE, "Dest reg %i is now inst [sn:%lli], was previously " - "[sn:%lli]\n", - (int)inst->destRegIdx(i), inst->seqNum, - renameTable[idx]->seqNum); - - inst->setPrevDestInst(renameTable[idx], i); - - renameTable[idx] = inst; - --freeRegs; - } -} - -template <class Impl> -void -FrontEnd<Impl>::wakeFromQuiesce() -{ - DPRINTF(FE, "Waking up from quiesce\n"); - // Hopefully this is safe - status = Running; -} - -template <class Impl> -void -FrontEnd<Impl>::switchOut() -{ - switchedOut = true; - cpu->signalSwitched(); -} - -template <class Impl> -void -FrontEnd<Impl>::doSwitchOut() -{ - memReq = NULL; - squash(0, 0); - instBuffer.clear(); - instBufferSize = 0; - status = Idle; -} - -template <class Impl> -void -FrontEnd<Impl>::takeOverFrom(ExecContext *old_xc) -{ - assert(freeRegs == numPhysRegs); - fetchCacheLineNextCycle = true; - - cacheBlkValid = false; - -#if !FULL_SYSTEM -// pTable = params->pTable; -#endif - fetchFault = NoFault; - serializeNext = false; - barrierInst = NULL; - status = Running; - switchedOut = false; - interruptPending = false; -} - -template <class Impl> -void -FrontEnd<Impl>::dumpInsts() -{ - cprintf("instBuffer size: %i\n", instBuffer.size()); - - InstBuffIt buff_it = instBuffer.begin(); - - for (int num = 0; buff_it != instBuffer.end(); num++) { - cprintf("Instruction:%i\nPC:%#x\n[tid:%i]\n[sn:%lli]\nIssued:%i\n" - "Squashed:%i\n\n", - num, (*buff_it)->readPC(), (*buff_it)->threadNumber, - (*buff_it)->seqNum, (*buff_it)->isIssued(), - (*buff_it)->isSquashed()); - buff_it++; - } -} - -template <class Impl> -FrontEnd<Impl>::ICacheCompletionEvent::ICacheCompletionEvent(MemReqPtr &_req, FrontEnd *fe) - : Event(&mainEventQueue, Delayed_Writeback_Pri), req(_req), frontEnd(fe) -{ - this->setFlags(Event::AutoDelete); -} - -template <class Impl> -void -FrontEnd<Impl>::ICacheCompletionEvent::process() -{ - frontEnd->processCacheCompletion(req); -} - -template <class Impl> -const char * -FrontEnd<Impl>::ICacheCompletionEvent::description() -{ - return "ICache completion event"; -} diff --git a/cpu/ozone/inorder_back_end.cc b/cpu/ozone/inorder_back_end.cc deleted file mode 100644 index 14db610d2..000000000 --- a/cpu/ozone/inorder_back_end.cc +++ /dev/null @@ -1,5 +0,0 @@ - -#include "cpu/ozone/inorder_back_end_impl.hh" -#include "cpu/ozone/simple_impl.hh" - -template class InorderBackEnd<SimpleImpl>; diff --git a/cpu/ozone/inorder_back_end.hh b/cpu/ozone/inorder_back_end.hh deleted file mode 100644 index 4039d8384..000000000 --- a/cpu/ozone/inorder_back_end.hh +++ /dev/null @@ -1,450 +0,0 @@ - -#ifndef __CPU_OZONE_INORDER_BACK_END_HH__ -#define __CPU_OZONE_INORDER_BACK_END_HH__ - -#include <list> - -#include "arch/faults.hh" -#include "base/timebuf.hh" -#include "cpu/exec_context.hh" -#include "cpu/inst_seq.hh" -#include "cpu/ozone/rename_table.hh" -#include "cpu/ozone/thread_state.hh" -#include "mem/mem_interface.hh" -#include "mem/mem_req.hh" -#include "sim/eventq.hh" - -template <class Impl> -class InorderBackEnd -{ - public: - typedef typename Impl::Params Params; - typedef typename Impl::DynInstPtr DynInstPtr; - typedef typename Impl::FullCPU FullCPU; - typedef typename Impl::FrontEnd FrontEnd; - - typedef typename FullCPU::OzoneXC OzoneXC; - typedef typename Impl::FullCPU::CommStruct CommStruct; - - InorderBackEnd(Params *params); - - std::string name() const; - - void setCPU(FullCPU *cpu_ptr) - { cpu = cpu_ptr; } - - void setFrontEnd(FrontEnd *front_end_ptr) - { frontEnd = front_end_ptr; } - - void setCommBuffer(TimeBuffer<CommStruct> *_comm) - { comm = _comm; } - - void setXC(ExecContext *xc_ptr); - - void setThreadState(OzoneThreadState<Impl> *thread_ptr); - - void regStats() { } - -#if FULL_SYSTEM - void checkInterrupts(); -#endif - - void tick(); - void executeInsts(); - void squash(const InstSeqNum &squash_num, const Addr &next_PC); - - void squashFromXC(); - void generateXCEvent() { } - - bool robEmpty() { return instList.empty(); } - - bool isFull() { return false; } - bool isBlocked() { return status == DcacheMissStoreStall || - status == DcacheMissLoadStall || - interruptBlocked; } - - void fetchFault(Fault &fault); - - void dumpInsts(); - - private: - void handleFault(); - - void setSquashInfoFromXC(); - - bool squashPending; - InstSeqNum squashSeqNum; - Addr squashNextPC; - - Fault faultFromFetch; - - bool interruptBlocked; - - public: - template <class T> - Fault read(Addr addr, T &data, unsigned flags); - - template <class T> - Fault read(MemReqPtr &req, T &data, int load_idx); - - template <class T> - Fault write(T data, Addr addr, unsigned flags, uint64_t *res); - - template <class T> - Fault write(MemReqPtr &req, T &data, int store_idx); - - Addr readCommitPC() { return commitPC; } - - Addr commitPC; - - void switchOut() { panic("Not implemented!"); } - void doSwitchOut() { panic("Not implemented!"); } - void takeOverFrom(ExecContext *old_xc = NULL) { panic("Not implemented!"); } - - public: - FullCPU *cpu; - - FrontEnd *frontEnd; - - ExecContext *xc; - - OzoneThreadState<Impl> *thread; - - RenameTable<Impl> renameTable; - - protected: - enum Status { - Running, - Idle, - DcacheMissLoadStall, - DcacheMissStoreStall, - DcacheMissComplete, - Blocked - }; - - Status status; - - class DCacheCompletionEvent : public Event - { - private: - InorderBackEnd *be; - - public: - DCacheCompletionEvent(InorderBackEnd *_be); - - virtual void process(); - virtual const char *description(); - - DynInstPtr inst; - }; - - friend class DCacheCompletionEvent; - - DCacheCompletionEvent cacheCompletionEvent; - - MemInterface *dcacheInterface; - - MemReqPtr memReq; - - private: - typedef typename std::list<DynInstPtr>::iterator InstListIt; - - std::list<DynInstPtr> instList; - - // General back end width. Used if the more specific isn't given. - int width; - - int latency; - - int squashLatency; - - TimeBuffer<int> numInstsToWB; - TimeBuffer<int>::wire instsAdded; - TimeBuffer<int>::wire instsToExecute; - - TimeBuffer<CommStruct> *comm; - // number of cycles stalled for D-cache misses - Stats::Scalar<> dcacheStallCycles; - Counter lastDcacheStall; -}; - -template <class Impl> -template <class T> -Fault -InorderBackEnd<Impl>::read(Addr addr, T &data, unsigned flags) -{ - memReq->reset(addr, sizeof(T), flags); - - // translate to physical address - Fault fault = cpu->translateDataReadReq(memReq); - - // if we have a cache, do cache access too - if (fault == NoFault && dcacheInterface) { - memReq->cmd = Read; - memReq->completionEvent = NULL; - memReq->time = curTick; - memReq->flags &= ~INST_READ; - MemAccessResult result = dcacheInterface->access(memReq); - - // Ugly hack to get an event scheduled *only* if the access is - // a miss. We really should add first-class support for this - // at some point. - if (result != MA_HIT) { - // Fix this hack for keeping funcExeInst correct with loads that - // are executed twice. - memReq->completionEvent = &cacheCompletionEvent; - lastDcacheStall = curTick; -// unscheduleTickEvent(); - status = DcacheMissLoadStall; - DPRINTF(IBE, "Dcache miss stall!\n"); - } else { - // do functional access - DPRINTF(IBE, "Dcache hit!\n"); - } - } -/* - if (!dcacheInterface && (memReq->flags & UNCACHEABLE)) - recordEvent("Uncached Read"); -*/ - return fault; -} -#if 0 -template <class Impl> -template <class T> -Fault -InorderBackEnd<Impl>::read(MemReqPtr &req, T &data) -{ -#if FULL_SYSTEM && defined(TARGET_ALPHA) - if (req->flags & LOCKED) { - req->xc->setMiscReg(TheISA::Lock_Addr_DepTag, req->paddr); - req->xc->setMiscReg(TheISA::Lock_Flag_DepTag, true); - } -#endif - - Fault error; - error = thread->mem->read(req, data); - data = LittleEndianGuest::gtoh(data); - return error; -} -#endif - -template <class Impl> -template <class T> -Fault -InorderBackEnd<Impl>::write(T data, Addr addr, unsigned flags, uint64_t *res) -{ - memReq->reset(addr, sizeof(T), flags); - - // translate to physical address - Fault fault = cpu->translateDataWriteReq(memReq); - - if (fault == NoFault && dcacheInterface) { - memReq->cmd = Write; -// memcpy(memReq->data,(uint8_t *)&data,memReq->size); - memReq->completionEvent = NULL; - memReq->time = curTick; - memReq->flags &= ~INST_READ; - MemAccessResult result = dcacheInterface->access(memReq); - - // Ugly hack to get an event scheduled *only* if the access is - // a miss. We really should add first-class support for this - // at some point. - if (result != MA_HIT) { - memReq->completionEvent = &cacheCompletionEvent; - lastDcacheStall = curTick; -// unscheduleTickEvent(); - status = DcacheMissStoreStall; - DPRINTF(IBE, "Dcache miss stall!\n"); - } else { - DPRINTF(IBE, "Dcache hit!\n"); - } - } - - if (res && (fault == NoFault)) - *res = memReq->result; -/* - if (!dcacheInterface && (memReq->flags & UNCACHEABLE)) - recordEvent("Uncached Write"); -*/ - return fault; -} -#if 0 -template <class Impl> -template <class T> -Fault -InorderBackEnd<Impl>::write(MemReqPtr &req, T &data) -{ -#if FULL_SYSTEM && defined(TARGET_ALPHA) - ExecContext *xc; - - // If this is a store conditional, act appropriately - if (req->flags & LOCKED) { - xc = req->xc; - - if (req->flags & UNCACHEABLE) { - // Don't update result register (see stq_c in isa_desc) - req->result = 2; - xc->setStCondFailures(0);//Needed? [RGD] - } else { - bool lock_flag = xc->readMiscReg(TheISA::Lock_Flag_DepTag); - Addr lock_addr = xc->readMiscReg(TheISA::Lock_Addr_DepTag); - req->result = lock_flag; - if (!lock_flag || - ((lock_addr & ~0xf) != (req->paddr & ~0xf))) { - xc->setMiscReg(TheISA::Lock_Flag_DepTag, false); - xc->setStCondFailures(xc->readStCondFailures() + 1); - if (((xc->readStCondFailures()) % 100000) == 0) { - std::cerr << "Warning: " - << xc->readStCondFailures() - << " consecutive store conditional failures " - << "on cpu " << req->xc->readCpuId() - << std::endl; - } - return NoFault; - } - else xc->setStCondFailures(0); - } - } - - // Need to clear any locked flags on other proccessors for - // this address. Only do this for succsful Store Conditionals - // and all other stores (WH64?). Unsuccessful Store - // Conditionals would have returned above, and wouldn't fall - // through. - for (int i = 0; i < cpu->system->execContexts.size(); i++){ - xc = cpu->system->execContexts[i]; - if ((xc->readMiscReg(TheISA::Lock_Addr_DepTag) & ~0xf) == - (req->paddr & ~0xf)) { - xc->setMiscReg(TheISA::Lock_Flag_DepTag, false); - } - } - -#endif - return thread->mem->write(req, (T)LittleEndianGuest::htog(data)); -} -#endif - -template <class Impl> -template <class T> -Fault -InorderBackEnd<Impl>::read(MemReqPtr &req, T &data, int load_idx) -{ -// panic("Unimplemented!"); -// memReq->reset(addr, sizeof(T), flags); - - // translate to physical address -// Fault fault = cpu->translateDataReadReq(req); - req->cmd = Read; - req->completionEvent = NULL; - req->time = curTick; - assert(!req->data); - req->data = new uint8_t[64]; - req->flags &= ~INST_READ; - Fault fault = cpu->read(req, data); - memcpy(req->data, &data, sizeof(T)); - - // if we have a cache, do cache access too - if (dcacheInterface) { - MemAccessResult result = dcacheInterface->access(req); - - // Ugly hack to get an event scheduled *only* if the access is - // a miss. We really should add first-class support for this - // at some point. - if (result != MA_HIT) { - req->completionEvent = &cacheCompletionEvent; - lastDcacheStall = curTick; -// unscheduleTickEvent(); - status = DcacheMissLoadStall; - DPRINTF(IBE, "Dcache miss load stall!\n"); - } else { - DPRINTF(IBE, "Dcache hit!\n"); - - } - } - -/* - if (!dcacheInterface && (req->flags & UNCACHEABLE)) - recordEvent("Uncached Read"); -*/ - return NoFault; -} - -template <class Impl> -template <class T> -Fault -InorderBackEnd<Impl>::write(MemReqPtr &req, T &data, int store_idx) -{ -// req->reset(addr, sizeof(T), flags); - - // translate to physical address -// Fault fault = cpu->translateDataWriteReq(req); - - req->cmd = Write; - req->completionEvent = NULL; - req->time = curTick; - assert(!req->data); - req->data = new uint8_t[64]; - memcpy(req->data, (uint8_t *)&data, req->size); - - switch(req->size) { - case 1: - cpu->write(req, (uint8_t &)data); - break; - case 2: - cpu->write(req, (uint16_t &)data); - break; - case 4: - cpu->write(req, (uint32_t &)data); - break; - case 8: - cpu->write(req, (uint64_t &)data); - break; - default: - panic("Unexpected store size!\n"); - } - - if (dcacheInterface) { - req->cmd = Write; - req->data = new uint8_t[64]; - memcpy(req->data,(uint8_t *)&data,req->size); - req->completionEvent = NULL; - req->time = curTick; - req->flags &= ~INST_READ; - MemAccessResult result = dcacheInterface->access(req); - - // Ugly hack to get an event scheduled *only* if the access is - // a miss. We really should add first-class support for this - // at some point. - if (result != MA_HIT) { - req->completionEvent = &cacheCompletionEvent; - lastDcacheStall = curTick; -// unscheduleTickEvent(); - status = DcacheMissStoreStall; - DPRINTF(IBE, "Dcache miss store stall!\n"); - } else { - DPRINTF(IBE, "Dcache hit!\n"); - - } - } -/* - if (req->flags & LOCKED) { - if (req->flags & UNCACHEABLE) { - // Don't update result register (see stq_c in isa_desc) - req->result = 2; - } else { - req->result = 1; - } - } -*/ -/* - if (res && (fault == NoFault)) - *res = req->result; - */ -/* - if (!dcacheInterface && (req->flags & UNCACHEABLE)) - recordEvent("Uncached Write"); -*/ - return NoFault; -} - -#endif // __CPU_OZONE_INORDER_BACK_END_HH__ diff --git a/cpu/ozone/inorder_back_end_impl.hh b/cpu/ozone/inorder_back_end_impl.hh deleted file mode 100644 index 5a378ec76..000000000 --- a/cpu/ozone/inorder_back_end_impl.hh +++ /dev/null @@ -1,519 +0,0 @@ - -#include "arch/faults.hh" -#include "arch/isa_traits.hh" -#include "cpu/ozone/inorder_back_end.hh" -#include "cpu/ozone/thread_state.hh" - -using namespace TheISA; - -template <class Impl> -InorderBackEnd<Impl>::InorderBackEnd(Params *params) - : squashPending(false), - squashSeqNum(0), - squashNextPC(0), - faultFromFetch(NoFault), - interruptBlocked(false), - cacheCompletionEvent(this), - dcacheInterface(params->dcacheInterface), - width(params->backEndWidth), - latency(params->backEndLatency), - squashLatency(params->backEndSquashLatency), - numInstsToWB(0, latency + 1) -{ - instsAdded = numInstsToWB.getWire(latency); - instsToExecute = numInstsToWB.getWire(0); - - memReq = new MemReq; - memReq->data = new uint8_t[64]; - status = Running; -} - -template <class Impl> -std::string -InorderBackEnd<Impl>::name() const -{ - return cpu->name() + ".inorderbackend"; -} - -template <class Impl> -void -InorderBackEnd<Impl>::setXC(ExecContext *xc_ptr) -{ - xc = xc_ptr; - memReq->xc = xc; -} - -template <class Impl> -void -InorderBackEnd<Impl>::setThreadState(OzoneThreadState<Impl> *thread_ptr) -{ - thread = thread_ptr; - thread->setFuncExeInst(0); -} - -#if FULL_SYSTEM -template <class Impl> -void -InorderBackEnd<Impl>::checkInterrupts() -{ - //Check if there are any outstanding interrupts - //Handle the interrupts - int ipl = 0; - int summary = 0; - - cpu->checkInterrupts = false; - - if (thread->readMiscReg(IPR_ASTRR)) - panic("asynchronous traps not implemented\n"); - - if (thread->readMiscReg(IPR_SIRR)) { - for (int i = INTLEVEL_SOFTWARE_MIN; - i < INTLEVEL_SOFTWARE_MAX; i++) { - if (thread->readMiscReg(IPR_SIRR) & (ULL(1) << i)) { - // See table 4-19 of the 21164 hardware reference - ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1; - summary |= (ULL(1) << i); - } - } - } - - uint64_t interrupts = cpu->intr_status(); - - if (interrupts) { - for (int i = INTLEVEL_EXTERNAL_MIN; - i < INTLEVEL_EXTERNAL_MAX; i++) { - if (interrupts & (ULL(1) << i)) { - // See table 4-19 of the 21164 hardware reference - ipl = i; - summary |= (ULL(1) << i); - } - } - } - - if (ipl && ipl > thread->readMiscReg(IPR_IPLR)) { - thread->inSyscall = true; - - thread->setMiscReg(IPR_ISR, summary); - thread->setMiscReg(IPR_INTID, ipl); - Fault(new InterruptFault)->invoke(xc); - DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", - thread->readMiscReg(IPR_IPLR), ipl, summary); - - // May need to go 1 inst prior - squashPending = true; - - thread->inSyscall = false; - - setSquashInfoFromXC(); - } -} -#endif - -template <class Impl> -void -InorderBackEnd<Impl>::tick() -{ - // Squash due to an external source - // Not sure if this or an interrupt has higher priority - if (squashPending) { - squash(squashSeqNum, squashNextPC); - return; - } - - // if (interrupt) then set thread PC, stall front end, record that - // I'm waiting for it to drain. (for now just squash) -#if FULL_SYSTEM - if (interruptBlocked || - (cpu->checkInterrupts && - cpu->check_interrupts() && - !cpu->inPalMode())) { - if (!robEmpty()) { - interruptBlocked = true; - } else if (robEmpty() && cpu->inPalMode()) { - // Will need to let the front end continue a bit until - // we're out of pal mode. Hopefully we never get into an - // infinite loop... - interruptBlocked = false; - } else { - interruptBlocked = false; - checkInterrupts(); - return; - } - } -#endif - - if (status != DcacheMissLoadStall && - status != DcacheMissStoreStall) { - for (int i = 0; i < width && (*instsAdded) < width; ++i) { - DynInstPtr inst = frontEnd->getInst(); - - if (!inst) - break; - - instList.push_back(inst); - - (*instsAdded)++; - } - -#if FULL_SYSTEM - if (faultFromFetch && robEmpty() && frontEnd->isEmpty()) { - handleFault(); - } else { - executeInsts(); - } -#else - executeInsts(); -#endif - } -} - -template <class Impl> -void -InorderBackEnd<Impl>::executeInsts() -{ - bool completed_last_inst = true; - int insts_to_execute = *instsToExecute; - int freed_regs = 0; - - while (insts_to_execute > 0) { - assert(!instList.empty()); - DynInstPtr inst = instList.front(); - - commitPC = inst->readPC(); - - thread->setPC(commitPC); - thread->setNextPC(inst->readNextPC()); - -#if FULL_SYSTEM - int count = 0; - Addr oldpc; - do { - if (count == 0) - assert(!thread->inSyscall && !thread->trapPending); - oldpc = thread->readPC(); - cpu->system->pcEventQueue.service( - thread->getXCProxy()); - count++; - } while (oldpc != thread->readPC()); - if (count > 1) { - DPRINTF(IBE, "PC skip function event, stopping commit\n"); - completed_last_inst = false; - squashPending = true; - break; - } -#endif - - Fault inst_fault = NoFault; - - if (status == DcacheMissComplete) { - DPRINTF(IBE, "Completing inst [sn:%lli]\n", inst->seqNum); - status = Running; - } else if (inst->isMemRef() && status != DcacheMissComplete && - (!inst->isDataPrefetch() && !inst->isInstPrefetch())) { - DPRINTF(IBE, "Initiating mem op inst [sn:%lli] PC: %#x\n", - inst->seqNum, inst->readPC()); - - cacheCompletionEvent.inst = inst; - inst_fault = inst->initiateAcc(); - if (inst_fault == NoFault && - status != DcacheMissLoadStall && - status != DcacheMissStoreStall) { - inst_fault = inst->completeAcc(); - } - ++thread->funcExeInst; - } else { - DPRINTF(IBE, "Executing inst [sn:%lli] PC: %#x\n", - inst->seqNum, inst->readPC()); - inst_fault = inst->execute(); - ++thread->funcExeInst; - } - - // Will need to be able to break this loop in case the load - // misses. Split access/complete ops would be useful here - // with writeback events. - if (status == DcacheMissLoadStall) { - *instsToExecute = insts_to_execute; - - completed_last_inst = false; - break; - } else if (status == DcacheMissStoreStall) { - // Figure out how to fix this hack. Probably have DcacheMissLoad - // vs DcacheMissStore. - *instsToExecute = insts_to_execute; - completed_last_inst = false; -/* - instList.pop_front(); - --insts_to_execute; - if (inst->traceData) { - inst->traceData->finalize(); - } -*/ - - // Don't really need to stop for a store stall as long as - // the memory system is able to handle store forwarding - // and such. Breaking out might help avoid the cache - // interface becoming blocked. - break; - } - - inst->setExecuted(); - inst->setCompleted(); - inst->setCanCommit(); - - instList.pop_front(); - - --insts_to_execute; - --(*instsToExecute); - - if (inst->traceData) { - inst->traceData->finalize(); - inst->traceData = NULL; - } - - if (inst_fault != NoFault) { -#if FULL_SYSTEM - DPRINTF(IBE, "Inst [sn:%lli] PC %#x has a fault\n", - inst->seqNum, inst->readPC()); - - assert(!thread->inSyscall); - - thread->inSyscall = true; - - // Hack for now; DTB will sometimes need the machine instruction - // for when faults happen. So we will set it here, prior to the - // DTB possibly needing it for this translation. - thread->setInst( - static_cast<TheISA::MachInst>(inst->staticInst->machInst)); - - // Consider holding onto the trap and waiting until the trap event - // happens for this to be executed. - inst_fault->invoke(xc); - - // Exit state update mode to avoid accidental updating. - thread->inSyscall = false; - - squashPending = true; - - // Generate trap squash event. -// generateTrapEvent(tid); - completed_last_inst = false; - break; -#else // !FULL_SYSTEM - panic("fault (%d) detected @ PC %08p", inst_fault, - inst->PC); -#endif // FULL_SYSTEM - } - - for (int i = 0; i < inst->numDestRegs(); ++i) { - renameTable[inst->destRegIdx(i)] = inst; - thread->renameTable[inst->destRegIdx(i)] = inst; - ++freed_regs; - } - - inst->clearDependents(); - - comm->access(0)->doneSeqNum = inst->seqNum; - - if (inst->mispredicted()) { - squash(inst->seqNum, inst->readNextPC()); - - thread->setNextPC(inst->readNextPC()); - - break; - } else if (squashPending) { - // Something external happened that caused the CPU to squash. - // Break out of commit and handle the squash next cycle. - break; - } - // If it didn't mispredict, then it executed fine. Send back its - // registers and BP info? What about insts that may still have - // latency, like loads? Probably can send back the information after - // it is completed. - - // keep an instruction count - cpu->numInst++; - thread->numInsts++; - } - - frontEnd->addFreeRegs(freed_regs); - - assert(insts_to_execute >= 0); - - // Should only advance this if I have executed all instructions. - if (insts_to_execute == 0) { - numInstsToWB.advance(); - } - - // Should I set the PC to the next PC here? What do I set next PC to? - if (completed_last_inst) { - thread->setPC(thread->readNextPC()); - thread->setNextPC(thread->readPC() + sizeof(MachInst)); - } - - if (squashPending) { - setSquashInfoFromXC(); - } -} - -template <class Impl> -void -InorderBackEnd<Impl>::handleFault() -{ - DPRINTF(Commit, "Handling fault from fetch\n"); - - assert(!thread->inSyscall); - - thread->inSyscall = true; - - // Consider holding onto the trap and waiting until the trap event - // happens for this to be executed. - faultFromFetch->invoke(xc); - - // Exit state update mode to avoid accidental updating. - thread->inSyscall = false; - - squashPending = true; - - setSquashInfoFromXC(); -} - -template <class Impl> -void -InorderBackEnd<Impl>::squash(const InstSeqNum &squash_num, const Addr &next_PC) -{ - DPRINTF(IBE, "Squashing from [sn:%lli], setting PC to %#x\n", - squash_num, next_PC); - - InstListIt squash_it = --(instList.end()); - - int freed_regs = 0; - - while (!instList.empty() && (*squash_it)->seqNum > squash_num) { - DynInstPtr inst = *squash_it; - - DPRINTF(IBE, "Squashing instruction PC %#x, [sn:%lli].\n", - inst->readPC(), - inst->seqNum); - - // May cause problems with misc regs - freed_regs+= inst->numDestRegs(); - inst->clearDependents(); - squash_it--; - instList.pop_back(); - } - - frontEnd->addFreeRegs(freed_regs); - - for (int i = 0; i < latency+1; ++i) { - numInstsToWB.advance(); - } - - squashPending = false; - - // Probably want to make sure that this squash is the one that set the - // thread into inSyscall mode. - thread->inSyscall = false; - - // Tell front end to squash, reset PC to new one. - frontEnd->squash(squash_num, next_PC); - - faultFromFetch = NULL; -} - -template <class Impl> -void -InorderBackEnd<Impl>::squashFromXC() -{ - // Record that I need to squash - squashPending = true; - - thread->inSyscall = true; -} - -template <class Impl> -void -InorderBackEnd<Impl>::setSquashInfoFromXC() -{ - // Need to handle the case of the instList being empty. In that case - // probably any number works, except maybe with stores in the store buffer. - squashSeqNum = instList.empty() ? 0 : instList.front()->seqNum - 1; - - squashNextPC = thread->PC; -} - -template <class Impl> -void -InorderBackEnd<Impl>::fetchFault(Fault &fault) -{ - faultFromFetch = fault; -} - -template <class Impl> -void -InorderBackEnd<Impl>::dumpInsts() -{ - int num = 0; - int valid_num = 0; - - InstListIt inst_list_it = instList.begin(); - - cprintf("Inst list size: %i\n", instList.size()); - - while (inst_list_it != instList.end()) - { - cprintf("Instruction:%i\n", - num); - if (!(*inst_list_it)->isSquashed()) { - if (!(*inst_list_it)->isIssued()) { - ++valid_num; - cprintf("Count:%i\n", valid_num); - } else if ((*inst_list_it)->isMemRef() && - !(*inst_list_it)->memOpDone) { - // Loads that have not been marked as executed still count - // towards the total instructions. - ++valid_num; - cprintf("Count:%i\n", valid_num); - } - } - - cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" - "Issued:%i\nSquashed:%i\n", - (*inst_list_it)->readPC(), - (*inst_list_it)->seqNum, - (*inst_list_it)->threadNumber, - (*inst_list_it)->isIssued(), - (*inst_list_it)->isSquashed()); - - if ((*inst_list_it)->isMemRef()) { - cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone); - } - - cprintf("\n"); - - inst_list_it++; - ++num; - } -} - -template <class Impl> -InorderBackEnd<Impl>::DCacheCompletionEvent::DCacheCompletionEvent( - InorderBackEnd *_be) - : Event(&mainEventQueue, CPU_Tick_Pri), be(_be) -{ -// this->setFlags(Event::AutoDelete); -} - -template <class Impl> -void -InorderBackEnd<Impl>::DCacheCompletionEvent::process() -{ - inst->completeAcc(); - be->status = DcacheMissComplete; -} - -template <class Impl> -const char * -InorderBackEnd<Impl>::DCacheCompletionEvent::description() -{ - return "DCache completion event"; -} diff --git a/cpu/ozone/inst_queue.cc b/cpu/ozone/inst_queue.cc deleted file mode 100644 index 9c61602d9..000000000 --- a/cpu/ozone/inst_queue.cc +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/ozone/dyn_inst.hh" -#include "cpu/ozone/ozone_impl.hh" -#include "cpu/ozone/simple_impl.hh" -#include "cpu/ozone/inst_queue_impl.hh" - -// Force instantiation of InstructionQueue. -template class InstQueue<SimpleImpl>; -template class InstQueue<OzoneImpl>; diff --git a/cpu/ozone/inst_queue.hh b/cpu/ozone/inst_queue.hh deleted file mode 100644 index 2cbbb7987..000000000 --- a/cpu/ozone/inst_queue.hh +++ /dev/null @@ -1,506 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_OZONE_INST_QUEUE_HH__ -#define __CPU_OZONE_INST_QUEUE_HH__ - -#include <list> -#include <map> -#include <queue> -#include <vector> - -#include "base/statistics.hh" -#include "base/timebuf.hh" -#include "cpu/inst_seq.hh" -#include "sim/host.hh" - -class FUPool; -class MemInterface; - -/** - * A standard instruction queue class. It holds ready instructions, in - * order, in seperate priority queues to facilitate the scheduling of - * instructions. The IQ uses a separate linked list to track dependencies. - * Similar to the rename map and the free list, it expects that - * floating point registers have their indices start after the integer - * registers (ie with 96 int and 96 fp registers, regs 0-95 are integer - * and 96-191 are fp). This remains true even for both logical and - * physical register indices. The IQ depends on the memory dependence unit to - * track when memory operations are ready in terms of ordering; register - * dependencies are tracked normally. Right now the IQ also handles the - * execution timing; this is mainly to allow back-to-back scheduling without - * requiring IEW to be able to peek into the IQ. At the end of the execution - * latency, the instruction is put into the queue to execute, where it will - * have the execute() function called on it. - * @todo: Make IQ able to handle multiple FU pools. - */ -template <class Impl> -class InstQueue -{ - public: - //Typedefs from the Impl. - typedef typename Impl::FullCPU FullCPU; - typedef typename Impl::DynInstPtr DynInstPtr; - typedef typename Impl::Params Params; - typedef typename Impl::IssueStruct IssueStruct; -/* - typedef typename Impl::CPUPol::IEW IEW; - typedef typename Impl::CPUPol::MemDepUnit MemDepUnit; - typedef typename Impl::CPUPol::IssueStruct IssueStruct; - typedef typename Impl::CPUPol::TimeStruct TimeStruct; -*/ - // Typedef of iterator through the list of instructions. - typedef typename std::list<DynInstPtr>::iterator ListIt; - - friend class Impl::FullCPU; -#if 0 - /** FU completion event class. */ - class FUCompletion : public Event { - private: - /** Executing instruction. */ - DynInstPtr inst; - - /** Index of the FU used for executing. */ - int fuIdx; - - /** Pointer back to the instruction queue. */ - InstQueue<Impl> *iqPtr; - - public: - /** Construct a FU completion event. */ - FUCompletion(DynInstPtr &_inst, int fu_idx, - InstQueue<Impl> *iq_ptr); - - virtual void process(); - virtual const char *description(); - }; -#endif - /** Constructs an IQ. */ - InstQueue(Params *params); - - /** Destructs the IQ. */ - ~InstQueue(); - - /** Returns the name of the IQ. */ - std::string name() const; - - /** Registers statistics. */ - void regStats(); - - /** Sets CPU pointer. */ - void setCPU(FullCPU *_cpu) { cpu = _cpu; } -#if 0 - /** Sets active threads list. */ - void setActiveThreads(list<unsigned> *at_ptr); - - /** Sets the IEW pointer. */ - void setIEW(IEW *iew_ptr) { iewStage = iew_ptr; } -#endif - /** Sets the timer buffer between issue and execute. */ - void setIssueToExecuteQueue(TimeBuffer<IssueStruct> *i2eQueue); -#if 0 - /** Sets the global time buffer. */ - void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr); - - /** Number of entries needed for given amount of threads. */ - int entryAmount(int num_threads); - - /** Resets max entries for all threads. */ - void resetEntries(); -#endif - /** Returns total number of free entries. */ - unsigned numFreeEntries(); - - /** Returns number of free entries for a thread. */ - unsigned numFreeEntries(unsigned tid); - - /** Returns whether or not the IQ is full. */ - bool isFull(); - - /** Returns whether or not the IQ is full for a specific thread. */ - bool isFull(unsigned tid); - - /** Returns if there are any ready instructions in the IQ. */ - bool hasReadyInsts(); - - /** Inserts a new instruction into the IQ. */ - void insert(DynInstPtr &new_inst); - - /** Inserts a new, non-speculative instruction into the IQ. */ - void insertNonSpec(DynInstPtr &new_inst); -#if 0 - /** - * Advances the tail of the IQ, used if an instruction is not added to the - * IQ for scheduling. - * @todo: Rename this function. - */ - void advanceTail(DynInstPtr &inst); - - /** Process FU completion event. */ - void processFUCompletion(DynInstPtr &inst, int fu_idx); -#endif - /** - * Schedules ready instructions, adding the ready ones (oldest first) to - * the queue to execute. - */ - void scheduleReadyInsts(); - - /** Schedules a single specific non-speculative instruction. */ - void scheduleNonSpec(const InstSeqNum &inst); - - /** - * Commits all instructions up to and including the given sequence number, - * for a specific thread. - */ - void commit(const InstSeqNum &inst, unsigned tid = 0); - - /** Wakes all dependents of a completed instruction. */ - void wakeDependents(DynInstPtr &completed_inst); - - /** Adds a ready memory instruction to the ready list. */ - void addReadyMemInst(DynInstPtr &ready_inst); -#if 0 - /** - * Reschedules a memory instruction. It will be ready to issue once - * replayMemInst() is called. - */ - void rescheduleMemInst(DynInstPtr &resched_inst); - - /** Replays a memory instruction. It must be rescheduled first. */ - void replayMemInst(DynInstPtr &replay_inst); -#endif - /** Completes a memory operation. */ - void completeMemInst(DynInstPtr &completed_inst); -#if 0 - /** Indicates an ordering violation between a store and a load. */ - void violation(DynInstPtr &store, DynInstPtr &faulting_load); -#endif - /** - * Squashes instructions for a thread. Squashing information is obtained - * from the time buffer. - */ - void squash(unsigned tid); // Probably want the ISN - - /** Returns the number of used entries for a thread. */ - unsigned getCount(unsigned tid) { return count[tid]; }; - - /** Updates the number of free entries. */ - void updateFreeEntries(int num) { freeEntries += num; } - - /** Debug function to print all instructions. */ - void printInsts(); - - private: - /** Does the actual squashing. */ - void doSquash(unsigned tid); - - ///////////////////////// - // Various pointers - ///////////////////////// - - /** Pointer to the CPU. */ - FullCPU *cpu; - - /** Cache interface. */ - MemInterface *dcacheInterface; -#if 0 - /** Pointer to IEW stage. */ - IEW *iewStage; - - /** The memory dependence unit, which tracks/predicts memory dependences - * between instructions. - */ - MemDepUnit memDepUnit[Impl::MaxThreads]; -#endif - /** The queue to the execute stage. Issued instructions will be written - * into it. - */ - TimeBuffer<IssueStruct> *issueToExecuteQueue; -#if 0 - /** The backwards time buffer. */ - TimeBuffer<TimeStruct> *timeBuffer; - - /** Wire to read information from timebuffer. */ - typename TimeBuffer<TimeStruct>::wire fromCommit; - - /** Function unit pool. */ - FUPool *fuPool; -#endif - ////////////////////////////////////// - // Instruction lists, ready queues, and ordering - ////////////////////////////////////// - - /** List of all the instructions in the IQ (some of which may be issued). */ - std::list<DynInstPtr> instList[Impl::MaxThreads]; - - /** - * Struct for comparing entries to be added to the priority queue. This - * gives reverse ordering to the instructions in terms of sequence - * numbers: the instructions with smaller sequence numbers (and hence - * are older) will be at the top of the priority queue. - */ - struct pqCompare { - bool operator() (const DynInstPtr &lhs, const DynInstPtr &rhs) const - { - return lhs->seqNum > rhs->seqNum; - } - }; - - /** - * Struct for an IQ entry. It includes the instruction and an iterator - * to the instruction's spot in the IQ. - */ - struct IQEntry { - DynInstPtr inst; - ListIt iqIt; - }; - - typedef std::priority_queue<DynInstPtr, std::vector<DynInstPtr>, pqCompare> - ReadyInstQueue; - - typedef std::map<DynInstPtr, pqCompare> ReadyInstMap; - typedef typename std::map<DynInstPtr, pqCompare>::iterator ReadyMapIt; - - /** List of ready instructions. - */ - ReadyInstQueue readyInsts; - - /** List of non-speculative instructions that will be scheduled - * once the IQ gets a signal from commit. While it's redundant to - * have the key be a part of the value (the sequence number is stored - * inside of DynInst), when these instructions are woken up only - * the sequence number will be available. Thus it is most efficient to be - * able to search by the sequence number alone. - */ - std::map<InstSeqNum, DynInstPtr> nonSpecInsts; - - typedef typename std::map<InstSeqNum, DynInstPtr>::iterator NonSpecMapIt; -#if 0 - /** Entry for the list age ordering by op class. */ - struct ListOrderEntry { - OpClass queueType; - InstSeqNum oldestInst; - }; - - /** List that contains the age order of the oldest instruction of each - * ready queue. Used to select the oldest instruction available - * among op classes. - */ - std::list<ListOrderEntry> listOrder; - - typedef typename std::list<ListOrderEntry>::iterator ListOrderIt; - - /** Tracks if each ready queue is on the age order list. */ - bool queueOnList[Num_OpClasses]; - - /** Iterators of each ready queue. Points to their spot in the age order - * list. - */ - ListOrderIt readyIt[Num_OpClasses]; - - /** Add an op class to the age order list. */ - void addToOrderList(OpClass op_class); - - /** - * Called when the oldest instruction has been removed from a ready queue; - * this places that ready queue into the proper spot in the age order list. - */ - void moveToYoungerInst(ListOrderIt age_order_it); -#endif - ////////////////////////////////////// - // Various parameters - ////////////////////////////////////// -#if 0 - /** IQ Resource Sharing Policy */ - enum IQPolicy { - Dynamic, - Partitioned, - Threshold - }; - - /** IQ sharing policy for SMT. */ - IQPolicy iqPolicy; -#endif - /** Number of Total Threads*/ - unsigned numThreads; -#if 0 - /** Pointer to list of active threads. */ - list<unsigned> *activeThreads; -#endif - /** Per Thread IQ count */ - unsigned count[Impl::MaxThreads]; - - /** Max IQ Entries Per Thread */ - unsigned maxEntries[Impl::MaxThreads]; - - /** Number of free IQ entries left. */ - unsigned freeEntries; - - /** The number of entries in the instruction queue. */ - unsigned numEntries; - - /** The total number of instructions that can be issued in one cycle. */ - unsigned totalWidth; -#if 0 - /** The number of physical registers in the CPU. */ - unsigned numPhysRegs; - - /** The number of physical integer registers in the CPU. */ - unsigned numPhysIntRegs; - - /** The number of floating point registers in the CPU. */ - unsigned numPhysFloatRegs; -#endif - /** Delay between commit stage and the IQ. - * @todo: Make there be a distinction between the delays within IEW. - */ - unsigned commitToIEWDelay; - - ////////////////////////////////// - // Variables needed for squashing - ////////////////////////////////// - - /** The sequence number of the squashed instruction. */ - InstSeqNum squashedSeqNum[Impl::MaxThreads]; - - /** Iterator that points to the last instruction that has been squashed. - * This will not be valid unless the IQ is in the process of squashing. - */ - ListIt squashIt[Impl::MaxThreads]; -#if 0 - /////////////////////////////////// - // Dependency graph stuff - /////////////////////////////////// - - class DependencyEntry - { - public: - DependencyEntry() - : inst(NULL), next(NULL) - { } - - DynInstPtr inst; - //Might want to include data about what arch. register the - //dependence is waiting on. - DependencyEntry *next; - - //This function, and perhaps this whole class, stand out a little - //bit as they don't fit a classification well. I want access - //to the underlying structure of the linked list, yet at - //the same time it feels like this should be something abstracted - //away. So for now it will sit here, within the IQ, until - //a better implementation is decided upon. - // This function probably shouldn't be within the entry... - void insert(DynInstPtr &new_inst); - - void remove(DynInstPtr &inst_to_remove); - - // Debug variable, remove when done testing. - static unsigned mem_alloc_counter; - }; - - /** Array of linked lists. Each linked list is a list of all the - * instructions that depend upon a given register. The actual - * register's index is used to index into the graph; ie all - * instructions in flight that are dependent upon r34 will be - * in the linked list of dependGraph[34]. - */ - DependencyEntry *dependGraph; - - /** A cache of the recently woken registers. It is 1 if the register - * has been woken up recently, and 0 if the register has been added - * to the dependency graph and has not yet received its value. It - * is basically a secondary scoreboard, and should pretty much mirror - * the scoreboard that exists in the rename map. - */ - vector<bool> regScoreboard; - - /** Adds an instruction to the dependency graph, as a producer. */ - bool addToDependents(DynInstPtr &new_inst); - - /** Adds an instruction to the dependency graph, as a consumer. */ - void createDependency(DynInstPtr &new_inst); -#endif - /** Moves an instruction to the ready queue if it is ready. */ - void addIfReady(DynInstPtr &inst); - - /** Debugging function to count how many entries are in the IQ. It does - * a linear walk through the instructions, so do not call this function - * during normal execution. - */ - int countInsts(); -#if 0 - /** Debugging function to dump out the dependency graph. - */ - void dumpDependGraph(); -#endif - /** Debugging function to dump all the list sizes, as well as print - * out the list of nonspeculative instructions. Should not be used - * in any other capacity, but it has no harmful sideaffects. - */ - void dumpLists(); - - /** Debugging function to dump out all instructions that are in the - * IQ. - */ - void dumpInsts(); - - /** Stat for number of instructions added. */ - Stats::Scalar<> iqInstsAdded; - /** Stat for number of non-speculative instructions added. */ - Stats::Scalar<> iqNonSpecInstsAdded; -// Stats::Scalar<> iqIntInstsAdded; - /** Stat for number of integer instructions issued. */ - Stats::Scalar<> iqIntInstsIssued; -// Stats::Scalar<> iqFloatInstsAdded; - /** Stat for number of floating point instructions issued. */ - Stats::Scalar<> iqFloatInstsIssued; -// Stats::Scalar<> iqBranchInstsAdded; - /** Stat for number of branch instructions issued. */ - Stats::Scalar<> iqBranchInstsIssued; -// Stats::Scalar<> iqMemInstsAdded; - /** Stat for number of memory instructions issued. */ - Stats::Scalar<> iqMemInstsIssued; -// Stats::Scalar<> iqMiscInstsAdded; - /** Stat for number of miscellaneous instructions issued. */ - Stats::Scalar<> iqMiscInstsIssued; - /** Stat for number of squashed instructions that were ready to issue. */ - Stats::Scalar<> iqSquashedInstsIssued; - /** Stat for number of squashed instructions examined when squashing. */ - Stats::Scalar<> iqSquashedInstsExamined; - /** Stat for number of squashed instruction operands examined when - * squashing. - */ - Stats::Scalar<> iqSquashedOperandsExamined; - /** Stat for number of non-speculative instructions removed due to a squash. - */ - Stats::Scalar<> iqSquashedNonSpecRemoved; - -}; - -#endif //__CPU_OZONE_INST_QUEUE_HH__ diff --git a/cpu/ozone/inst_queue_impl.hh b/cpu/ozone/inst_queue_impl.hh deleted file mode 100644 index 0523c68d6..000000000 --- a/cpu/ozone/inst_queue_impl.hh +++ /dev/null @@ -1,1341 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// Todo: -// Current ordering allows for 0 cycle added-to-scheduled. Could maybe fake -// it; either do in reverse order, or have added instructions put into a -// different ready queue that, in scheduleRreadyInsts(), gets put onto the -// normal ready queue. This would however give only a one cycle delay, -// but probably is more flexible to actually add in a delay parameter than -// just running it backwards. - -#include <vector> - -#include "sim/root.hh" - -#include "cpu/ozone/inst_queue.hh" -#if 0 -template <class Impl> -InstQueue<Impl>::FUCompletion::FUCompletion(DynInstPtr &_inst, - int fu_idx, - InstQueue<Impl> *iq_ptr) - : Event(&mainEventQueue, Stat_Event_Pri), - inst(_inst), fuIdx(fu_idx), iqPtr(iq_ptr) -{ - this->setFlags(Event::AutoDelete); -} - -template <class Impl> -void -InstQueue<Impl>::FUCompletion::process() -{ - iqPtr->processFUCompletion(inst, fuIdx); -} - - -template <class Impl> -const char * -InstQueue<Impl>::FUCompletion::description() -{ - return "Functional unit completion event"; -} -#endif -template <class Impl> -InstQueue<Impl>::InstQueue(Params *params) - : dcacheInterface(params->dcacheInterface), -// fuPool(params->fuPool), - numEntries(params->numIQEntries), - totalWidth(params->issueWidth), -// numPhysIntRegs(params->numPhysIntRegs), -// numPhysFloatRegs(params->numPhysFloatRegs), - commitToIEWDelay(params->commitToIEWDelay) -{ -// assert(fuPool); - -// numThreads = params->numberOfThreads; - numThreads = 1; - - //Initialize thread IQ counts - for (int i = 0; i <numThreads; i++) { - count[i] = 0; - } - - // Initialize the number of free IQ entries. - freeEntries = numEntries; - - // Set the number of physical registers as the number of int + float -// numPhysRegs = numPhysIntRegs + numPhysFloatRegs; - -// DPRINTF(IQ, "There are %i physical registers.\n", numPhysRegs); - - //Create an entry for each physical register within the - //dependency graph. -// dependGraph = new DependencyEntry[numPhysRegs]; - - // Resize the register scoreboard. -// regScoreboard.resize(numPhysRegs); -/* - //Initialize Mem Dependence Units - for (int i = 0; i < numThreads; i++) { - memDepUnit[i].init(params,i); - memDepUnit[i].setIQ(this); - } - - // Initialize all the head pointers to point to NULL, and all the - // entries as unready. - // Note that in actuality, the registers corresponding to the logical - // registers start off as ready. However this doesn't matter for the - // IQ as the instruction should have been correctly told if those - // registers are ready in rename. Thus it can all be initialized as - // unready. - for (int i = 0; i < numPhysRegs; ++i) { - dependGraph[i].next = NULL; - dependGraph[i].inst = NULL; - regScoreboard[i] = false; - } -*/ - for (int i = 0; i < numThreads; ++i) { - squashedSeqNum[i] = 0; - } -/* - for (int i = 0; i < Num_OpClasses; ++i) { - queueOnList[i] = false; - readyIt[i] = listOrder.end(); - } - - string policy = params->smtIQPolicy; - - //Convert string to lowercase - std::transform(policy.begin(), policy.end(), policy.begin(), - (int(*)(int)) tolower); - - //Figure out resource sharing policy - if (policy == "dynamic") { - iqPolicy = Dynamic; - - //Set Max Entries to Total ROB Capacity - for (int i = 0; i < numThreads; i++) { - maxEntries[i] = numEntries; - } - - } else if (policy == "partitioned") { - iqPolicy = Partitioned; - - //@todo:make work if part_amt doesnt divide evenly. - int part_amt = numEntries / numThreads; - - //Divide ROB up evenly - for (int i = 0; i < numThreads; i++) { - maxEntries[i] = part_amt; - } - - DPRINTF(Fetch, "IQ sharing policy set to Partitioned:" - "%i entries per thread.\n",part_amt); - - } else if (policy == "threshold") { - iqPolicy = Threshold; - - double threshold = (double)params->smtIQThreshold / 100; - - int thresholdIQ = (int)((double)threshold * numEntries); - - //Divide up by threshold amount - for (int i = 0; i < numThreads; i++) { - maxEntries[i] = thresholdIQ; - } - - DPRINTF(Fetch, "IQ sharing policy set to Threshold:" - "%i entries per thread.\n",thresholdIQ); - } else { - assert(0 && "Invalid IQ Sharing Policy.Options Are:{Dynamic," - "Partitioned, Threshold}"); - } -*/ -} - -template <class Impl> -InstQueue<Impl>::~InstQueue() -{ - // Clear the dependency graph -/* - DependencyEntry *curr; - DependencyEntry *prev; - - for (int i = 0; i < numPhysRegs; ++i) { - curr = dependGraph[i].next; - - while (curr) { - DependencyEntry::mem_alloc_counter--; - - prev = curr; - curr = prev->next; - prev->inst = NULL; - - delete prev; - } - - if (dependGraph[i].inst) { - dependGraph[i].inst = NULL; - } - - dependGraph[i].next = NULL; - } - - assert(DependencyEntry::mem_alloc_counter == 0); - - delete [] dependGraph; -*/ -} - -template <class Impl> -std::string -InstQueue<Impl>::name() const -{ - return cpu->name() + ".iq"; -} - -template <class Impl> -void -InstQueue<Impl>::regStats() -{ - iqInstsAdded - .name(name() + ".iqInstsAdded") - .desc("Number of instructions added to the IQ (excludes non-spec)") - .prereq(iqInstsAdded); - - iqNonSpecInstsAdded - .name(name() + ".iqNonSpecInstsAdded") - .desc("Number of non-speculative instructions added to the IQ") - .prereq(iqNonSpecInstsAdded); - -// iqIntInstsAdded; - - iqIntInstsIssued - .name(name() + ".iqIntInstsIssued") - .desc("Number of integer instructions issued") - .prereq(iqIntInstsIssued); - -// iqFloatInstsAdded; - - iqFloatInstsIssued - .name(name() + ".iqFloatInstsIssued") - .desc("Number of float instructions issued") - .prereq(iqFloatInstsIssued); - -// iqBranchInstsAdded; - - iqBranchInstsIssued - .name(name() + ".iqBranchInstsIssued") - .desc("Number of branch instructions issued") - .prereq(iqBranchInstsIssued); - -// iqMemInstsAdded; - - iqMemInstsIssued - .name(name() + ".iqMemInstsIssued") - .desc("Number of memory instructions issued") - .prereq(iqMemInstsIssued); - -// iqMiscInstsAdded; - - iqMiscInstsIssued - .name(name() + ".iqMiscInstsIssued") - .desc("Number of miscellaneous instructions issued") - .prereq(iqMiscInstsIssued); - - iqSquashedInstsIssued - .name(name() + ".iqSquashedInstsIssued") - .desc("Number of squashed instructions issued") - .prereq(iqSquashedInstsIssued); - - iqSquashedInstsExamined - .name(name() + ".iqSquashedInstsExamined") - .desc("Number of squashed instructions iterated over during squash;" - " mainly for profiling") - .prereq(iqSquashedInstsExamined); - - iqSquashedOperandsExamined - .name(name() + ".iqSquashedOperandsExamined") - .desc("Number of squashed operands that are examined and possibly " - "removed from graph") - .prereq(iqSquashedOperandsExamined); - - iqSquashedNonSpecRemoved - .name(name() + ".iqSquashedNonSpecRemoved") - .desc("Number of squashed non-spec instructions that were removed") - .prereq(iqSquashedNonSpecRemoved); -/* - for ( int i=0; i < numThreads; i++) { - // Tell mem dependence unit to reg stats as well. - memDepUnit[i].regStats(); - } -*/ -} -/* -template <class Impl> -void -InstQueue<Impl>::setActiveThreads(list<unsigned> *at_ptr) -{ - DPRINTF(IQ, "Setting active threads list pointer.\n"); - activeThreads = at_ptr; -} -*/ -template <class Impl> -void -InstQueue<Impl>::setIssueToExecuteQueue(TimeBuffer<IssueStruct> *i2e_ptr) -{ - DPRINTF(IQ, "Set the issue to execute queue.\n"); - issueToExecuteQueue = i2e_ptr; -} -/* -template <class Impl> -void -InstQueue<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) -{ - DPRINTF(IQ, "Set the time buffer.\n"); - timeBuffer = tb_ptr; - - fromCommit = timeBuffer->getWire(-commitToIEWDelay); -} - -template <class Impl> -int -InstQueue<Impl>::entryAmount(int num_threads) -{ - if (iqPolicy == Partitioned) { - return numEntries / num_threads; - } else { - return 0; - } -} - - -template <class Impl> -void -InstQueue<Impl>::resetEntries() -{ - if (iqPolicy != Dynamic || numThreads > 1) { - int active_threads = (*activeThreads).size(); - - list<unsigned>::iterator threads = (*activeThreads).begin(); - list<unsigned>::iterator list_end = (*activeThreads).end(); - - while (threads != list_end) { - if (iqPolicy == Partitioned) { - maxEntries[*threads++] = numEntries / active_threads; - } else if(iqPolicy == Threshold && active_threads == 1) { - maxEntries[*threads++] = numEntries; - } - } - } -} -*/ -template <class Impl> -unsigned -InstQueue<Impl>::numFreeEntries() -{ - return freeEntries; -} - -template <class Impl> -unsigned -InstQueue<Impl>::numFreeEntries(unsigned tid) -{ - return maxEntries[tid] - count[tid]; -} - -// Might want to do something more complex if it knows how many instructions -// will be issued this cycle. -template <class Impl> -bool -InstQueue<Impl>::isFull() -{ - if (freeEntries == 0) { - return(true); - } else { - return(false); - } -} - -template <class Impl> -bool -InstQueue<Impl>::isFull(unsigned tid) -{ - if (numFreeEntries(tid) == 0) { - return(true); - } else { - return(false); - } -} - -template <class Impl> -bool -InstQueue<Impl>::hasReadyInsts() -{ -/* - if (!listOrder.empty()) { - return true; - } - - for (int i = 0; i < Num_OpClasses; ++i) { - if (!readyInsts[i].empty()) { - return true; - } - } - - return false; -*/ - return readyInsts.empty(); -} - -template <class Impl> -void -InstQueue<Impl>::insert(DynInstPtr &new_inst) -{ - // Make sure the instruction is valid - assert(new_inst); - - DPRINTF(IQ, "Adding instruction PC %#x to the IQ.\n", - new_inst->readPC()); - - // Check if there are any free entries. Panic if there are none. - // Might want to have this return a fault in the future instead of - // panicing. - assert(freeEntries != 0); - - instList[new_inst->threadNumber].push_back(new_inst); - - // Decrease the number of free entries. - --freeEntries; - - //Mark Instruction as in IQ -// new_inst->setInIQ(); -/* - // Look through its source registers (physical regs), and mark any - // dependencies. - addToDependents(new_inst); - - // Have this instruction set itself as the producer of its destination - // register(s). - createDependency(new_inst); -*/ - // If it's a memory instruction, add it to the memory dependency - // unit. -// if (new_inst->isMemRef()) { -// memDepUnit[new_inst->threadNumber].insert(new_inst); -// } else { - // If the instruction is ready then add it to the ready list. - addIfReady(new_inst); -// } - - ++iqInstsAdded; - - - //Update Thread IQ Count - count[new_inst->threadNumber]++; - - assert(freeEntries == (numEntries - countInsts())); -} - -template <class Impl> -void -InstQueue<Impl>::insertNonSpec(DynInstPtr &new_inst) -{ - nonSpecInsts[new_inst->seqNum] = new_inst; - - // @todo: Clean up this code; can do it by setting inst as unable - // to issue, then calling normal insert on the inst. - - // Make sure the instruction is valid - assert(new_inst); - - DPRINTF(IQ, "Adding instruction PC %#x to the IQ.\n", - new_inst->readPC()); - - // Check if there are any free entries. Panic if there are none. - // Might want to have this return a fault in the future instead of - // panicing. - assert(freeEntries != 0); - - instList[new_inst->threadNumber].push_back(new_inst); - - // Decrease the number of free entries. - --freeEntries; - - //Mark Instruction as in IQ -// new_inst->setInIQ(); -/* - // Have this instruction set itself as the producer of its destination - // register(s). - createDependency(new_inst); - - // If it's a memory instruction, add it to the memory dependency - // unit. - if (new_inst->isMemRef()) { - memDepUnit[new_inst->threadNumber].insertNonSpec(new_inst); - } -*/ - ++iqNonSpecInstsAdded; - - //Update Thread IQ Count - count[new_inst->threadNumber]++; - - assert(freeEntries == (numEntries - countInsts())); -} -/* -template <class Impl> -void -InstQueue<Impl>::advanceTail(DynInstPtr &inst) -{ - // Have this instruction set itself as the producer of its destination - // register(s). - createDependency(inst); -} - -template <class Impl> -void -InstQueue<Impl>::addToOrderList(OpClass op_class) -{ - assert(!readyInsts[op_class].empty()); - - ListOrderEntry queue_entry; - - queue_entry.queueType = op_class; - - queue_entry.oldestInst = readyInsts[op_class].top()->seqNum; - - ListOrderIt list_it = listOrder.begin(); - ListOrderIt list_end_it = listOrder.end(); - - while (list_it != list_end_it) { - if ((*list_it).oldestInst > queue_entry.oldestInst) { - break; - } - - list_it++; - } - - readyIt[op_class] = listOrder.insert(list_it, queue_entry); - queueOnList[op_class] = true; -} - -template <class Impl> -void -InstQueue<Impl>::moveToYoungerInst(ListOrderIt list_order_it) -{ - // Get iterator of next item on the list - // Delete the original iterator - // Determine if the next item is either the end of the list or younger - // than the new instruction. If so, then add in a new iterator right here. - // If not, then move along. - ListOrderEntry queue_entry; - OpClass op_class = (*list_order_it).queueType; - ListOrderIt next_it = list_order_it; - - ++next_it; - - queue_entry.queueType = op_class; - queue_entry.oldestInst = readyInsts[op_class].top()->seqNum; - - while (next_it != listOrder.end() && - (*next_it).oldestInst < queue_entry.oldestInst) { - ++next_it; - } - - readyIt[op_class] = listOrder.insert(next_it, queue_entry); -} - -template <class Impl> -void -InstQueue<Impl>::processFUCompletion(DynInstPtr &inst, int fu_idx) -{ - // The CPU could have been sleeping until this op completed (*extremely* - // long latency op). Wake it if it was. This may be overkill. - iewStage->wakeCPU(); - - fuPool->freeUnit(fu_idx); - - int &size = issueToExecuteQueue->access(0)->size; - - issueToExecuteQueue->access(0)->insts[size++] = inst; -} -*/ -// @todo: Figure out a better way to remove the squashed items from the -// lists. Checking the top item of each list to see if it's squashed -// wastes time and forces jumps. -template <class Impl> -void -InstQueue<Impl>::scheduleReadyInsts() -{ - DPRINTF(IQ, "Attempting to schedule ready instructions from " - "the IQ.\n"); - -// IssueStruct *i2e_info = issueToExecuteQueue->access(0); -/* - // Will need to reorder the list if either a queue is not on the list, - // or it has an older instruction than last time. - for (int i = 0; i < Num_OpClasses; ++i) { - if (!readyInsts[i].empty()) { - if (!queueOnList[i]) { - addToOrderList(OpClass(i)); - } else if (readyInsts[i].top()->seqNum < - (*readyIt[i]).oldestInst) { - listOrder.erase(readyIt[i]); - addToOrderList(OpClass(i)); - } - } - } - - // Have iterator to head of the list - // While I haven't exceeded bandwidth or reached the end of the list, - // Try to get a FU that can do what this op needs. - // If successful, change the oldestInst to the new top of the list, put - // the queue in the proper place in the list. - // Increment the iterator. - // This will avoid trying to schedule a certain op class if there are no - // FUs that handle it. - ListOrderIt order_it = listOrder.begin(); - ListOrderIt order_end_it = listOrder.end(); - int total_issued = 0; - int exec_queue_slot = i2e_info->size; - - while (exec_queue_slot < totalWidth && order_it != order_end_it) { - OpClass op_class = (*order_it).queueType; - - assert(!readyInsts[op_class].empty()); - - DynInstPtr issuing_inst = readyInsts[op_class].top(); - - assert(issuing_inst->seqNum == (*order_it).oldestInst); - - if (issuing_inst->isSquashed()) { - readyInsts[op_class].pop(); - - if (!readyInsts[op_class].empty()) { - moveToYoungerInst(order_it); - } else { - readyIt[op_class] = listOrder.end(); - queueOnList[op_class] = false; - } - - listOrder.erase(order_it++); - - ++iqSquashedInstsIssued; - - continue; - } - - int idx = fuPool->getUnit(op_class); - - if (idx != -1) { - int op_latency = fuPool->getOpLatency(op_class); - - if (op_latency == 1) { - i2e_info->insts[exec_queue_slot++] = issuing_inst; - i2e_info->size++; - - // Add the FU onto the list of FU's to be freed next cycle. - fuPool->freeUnit(idx); - } else { - int issue_latency = fuPool->getIssueLatency(op_class); - - if (issue_latency > 1) { - // Generate completion event for the FU - FUCompletion *execution = new FUCompletion(issuing_inst, - idx, this); - - execution->schedule(curTick + issue_latency - 1); - } else { - i2e_info->insts[exec_queue_slot++] = issuing_inst; - i2e_info->size++; - - // Add the FU onto the list of FU's to be freed next cycle. - fuPool->freeUnit(idx); - } - } - - DPRINTF(IQ, "Thread %i: Issuing instruction PC %#x " - "[sn:%lli]\n", - issuing_inst->threadNumber, issuing_inst->readPC(), - issuing_inst->seqNum); - - readyInsts[op_class].pop(); - - if (!readyInsts[op_class].empty()) { - moveToYoungerInst(order_it); - } else { - readyIt[op_class] = listOrder.end(); - queueOnList[op_class] = false; - } - - issuing_inst->setIssued(); - ++total_issued; - - if (!issuing_inst->isMemRef()) { - // Memory instructions can not be freed from the IQ until they - // complete. - ++freeEntries; - count[issuing_inst->threadNumber]--; - issuing_inst->removeInIQ(); - } else { - memDepUnit[issuing_inst->threadNumber].issue(issuing_inst); - } - - listOrder.erase(order_it++); - } else { - ++order_it; - } - } - - if (total_issued) { - cpu->activityThisCycle(); - } else { - DPRINTF(IQ, "Not able to schedule any instructions.\n"); - } -*/ -} - -template <class Impl> -void -InstQueue<Impl>::scheduleNonSpec(const InstSeqNum &inst) -{ - DPRINTF(IQ, "Marking nonspeculative instruction with sequence " - "number %i as ready to execute.\n", inst); - - NonSpecMapIt inst_it = nonSpecInsts.find(inst); - - assert(inst_it != nonSpecInsts.end()); - -// unsigned tid = (*inst_it).second->threadNumber; - - // Mark this instruction as ready to issue. - (*inst_it).second->setCanIssue(); - - // Now schedule the instruction. -// if (!(*inst_it).second->isMemRef()) { - addIfReady((*inst_it).second); -// } else { -// memDepUnit[tid].nonSpecInstReady((*inst_it).second); -// } - - nonSpecInsts.erase(inst_it); -} - -template <class Impl> -void -InstQueue<Impl>::commit(const InstSeqNum &inst, unsigned tid) -{ - /*Need to go through each thread??*/ - DPRINTF(IQ, "[tid:%i]: Committing instructions older than [sn:%i]\n", - tid,inst); - - ListIt iq_it = instList[tid].begin(); - - while (iq_it != instList[tid].end() && - (*iq_it)->seqNum <= inst) { - ++iq_it; - instList[tid].pop_front(); - } - - assert(freeEntries == (numEntries - countInsts())); -} - -template <class Impl> -void -InstQueue<Impl>::wakeDependents(DynInstPtr &completed_inst) -{ - DPRINTF(IQ, "Waking dependents of completed instruction.\n"); - // Look at the physical destination register of the DynInst - // and look it up on the dependency graph. Then mark as ready - // any instructions within the instruction queue. -/* - DependencyEntry *curr; - DependencyEntry *prev; -*/ - // Tell the memory dependence unit to wake any dependents on this - // instruction if it is a memory instruction. Also complete the memory - // instruction at this point since we know it executed fine. - // @todo: Might want to rename "completeMemInst" to - // something that indicates that it won't need to be replayed, and call - // this earlier. Might not be a big deal. - if (completed_inst->isMemRef()) { -// memDepUnit[completed_inst->threadNumber].wakeDependents(completed_inst); - completeMemInst(completed_inst); - } - completed_inst->wakeDependents(); -/* - for (int dest_reg_idx = 0; - dest_reg_idx < completed_inst->numDestRegs(); - dest_reg_idx++) - { - PhysRegIndex dest_reg = - completed_inst->renamedDestRegIdx(dest_reg_idx); - - // Special case of uniq or control registers. They are not - // handled by the IQ and thus have no dependency graph entry. - // @todo Figure out a cleaner way to handle this. - if (dest_reg >= numPhysRegs) { - continue; - } - - DPRINTF(IQ, "Waking any dependents on register %i.\n", - (int) dest_reg); - - //Maybe abstract this part into a function. - //Go through the dependency chain, marking the registers as ready - //within the waiting instructions. - - curr = dependGraph[dest_reg].next; - - while (curr) { - DPRINTF(IQ, "Waking up a dependent instruction, PC%#x.\n", - curr->inst->readPC()); - - // Might want to give more information to the instruction - // so that it knows which of its source registers is ready. - // However that would mean that the dependency graph entries - // would need to hold the src_reg_idx. - curr->inst->markSrcRegReady(); - - addIfReady(curr->inst); - - DependencyEntry::mem_alloc_counter--; - - prev = curr; - curr = prev->next; - prev->inst = NULL; - - delete prev; - } - - // Reset the head node now that all of its dependents have been woken - // up. - dependGraph[dest_reg].next = NULL; - dependGraph[dest_reg].inst = NULL; - - // Mark the scoreboard as having that register ready. - regScoreboard[dest_reg] = true; - } -*/ -} - -template <class Impl> -void -InstQueue<Impl>::addReadyMemInst(DynInstPtr &ready_inst) -{ - OpClass op_class = ready_inst->opClass(); - - readyInsts.push(ready_inst); - - DPRINTF(IQ, "Instruction is ready to issue, putting it onto " - "the ready list, PC %#x opclass:%i [sn:%lli].\n", - ready_inst->readPC(), op_class, ready_inst->seqNum); -} -/* -template <class Impl> -void -InstQueue<Impl>::rescheduleMemInst(DynInstPtr &resched_inst) -{ - memDepUnit[resched_inst->threadNumber].reschedule(resched_inst); -} - -template <class Impl> -void -InstQueue<Impl>::replayMemInst(DynInstPtr &replay_inst) -{ - memDepUnit[replay_inst->threadNumber].replay(replay_inst); -} -*/ -template <class Impl> -void -InstQueue<Impl>::completeMemInst(DynInstPtr &completed_inst) -{ - int tid = completed_inst->threadNumber; - - DPRINTF(IQ, "Completing mem instruction PC:%#x [sn:%lli]\n", - completed_inst->readPC(), completed_inst->seqNum); - - ++freeEntries; - -// completed_inst->memOpDone = true; - -// memDepUnit[tid].completed(completed_inst); - - count[tid]--; -} -/* -template <class Impl> -void -InstQueue<Impl>::violation(DynInstPtr &store, - DynInstPtr &faulting_load) -{ - memDepUnit[store->threadNumber].violation(store, faulting_load); -} -*/ -template <class Impl> -void -InstQueue<Impl>::squash(unsigned tid) -{ - DPRINTF(IQ, "[tid:%i]: Starting to squash instructions in " - "the IQ.\n", tid); - - // Read instruction sequence number of last instruction out of the - // time buffer. -// squashedSeqNum[tid] = fromCommit->commitInfo[tid].doneSeqNum; - - // Setup the squash iterator to point to the tail. - squashIt[tid] = instList[tid].end(); - --squashIt[tid]; - - // Call doSquash if there are insts in the IQ - if (count[tid] > 0) { - doSquash(tid); - } - - // Also tell the memory dependence unit to squash. -// memDepUnit[tid].squash(squashedSeqNum[tid], tid); -} - -template <class Impl> -void -InstQueue<Impl>::doSquash(unsigned tid) -{ - // Make sure the squashed sequence number is valid. - assert(squashedSeqNum[tid] != 0); - - DPRINTF(IQ, "[tid:%i]: Squashing until sequence number %i!\n", - tid, squashedSeqNum[tid]); - - // Squash any instructions younger than the squashed sequence number - // given. - while (squashIt[tid] != instList[tid].end() && - (*squashIt[tid])->seqNum > squashedSeqNum[tid]) { - - DynInstPtr squashed_inst = (*squashIt[tid]); - - // Only handle the instruction if it actually is in the IQ and - // hasn't already been squashed in the IQ. - if (squashed_inst->threadNumber != tid || - squashed_inst->isSquashedInIQ()) { - --squashIt[tid]; - continue; - } - - if (!squashed_inst->isIssued() || - (squashed_inst->isMemRef()/* && - !squashed_inst->memOpDone*/)) { - - // Remove the instruction from the dependency list. - if (!squashed_inst->isNonSpeculative()) { -/* - for (int src_reg_idx = 0; - src_reg_idx < squashed_inst->numSrcRegs(); - src_reg_idx++) - { - PhysRegIndex src_reg = - squashed_inst->renamedSrcRegIdx(src_reg_idx); - - // Only remove it from the dependency graph if it was - // placed there in the first place. - // HACK: This assumes that instructions woken up from the - // dependency chain aren't informed that a specific src - // register has become ready. This may not always be true - // in the future. - // Instead of doing a linked list traversal, we can just - // remove these squashed instructions either at issue time, - // or when the register is overwritten. The only downside - // to this is it leaves more room for error. - - if (!squashed_inst->isReadySrcRegIdx(src_reg_idx) && - src_reg < numPhysRegs) { - dependGraph[src_reg].remove(squashed_inst); - } - - - ++iqSquashedOperandsExamined; - } -*/ - // Might want to remove producers as well. - } else { - nonSpecInsts[squashed_inst->seqNum] = NULL; - - nonSpecInsts.erase(squashed_inst->seqNum); - - ++iqSquashedNonSpecRemoved; - } - - // Might want to also clear out the head of the dependency graph. - - // Mark it as squashed within the IQ. - squashed_inst->setSquashedInIQ(); - - // @todo: Remove this hack where several statuses are set so the - // inst will flow through the rest of the pipeline. - squashed_inst->setIssued(); - squashed_inst->setCanCommit(); -// squashed_inst->removeInIQ(); - - //Update Thread IQ Count - count[squashed_inst->threadNumber]--; - - ++freeEntries; - - if (numThreads > 1) { - DPRINTF(IQ, "[tid:%i]: Instruction PC %#x squashed.\n", - tid, squashed_inst->readPC()); - } else { - DPRINTF(IQ, "Instruction PC %#x squashed.\n", - squashed_inst->readPC()); - } - } - - --squashIt[tid]; - ++iqSquashedInstsExamined; - } -} -/* -template <class Impl> -void -InstQueue<Impl>::DependencyEntry::insert(DynInstPtr &new_inst) -{ - //Add this new, dependent instruction at the head of the dependency - //chain. - - // First create the entry that will be added to the head of the - // dependency chain. - DependencyEntry *new_entry = new DependencyEntry; - new_entry->next = this->next; - new_entry->inst = new_inst; - - // Then actually add it to the chain. - this->next = new_entry; - - ++mem_alloc_counter; -} - -template <class Impl> -void -InstQueue<Impl>::DependencyEntry::remove(DynInstPtr &inst_to_remove) -{ - DependencyEntry *prev = this; - DependencyEntry *curr = this->next; - - // Make sure curr isn't NULL. Because this instruction is being - // removed from a dependency list, it must have been placed there at - // an earlier time. The dependency chain should not be empty, - // unless the instruction dependent upon it is already ready. - if (curr == NULL) { - return; - } - - // Find the instruction to remove within the dependency linked list. - while (curr->inst != inst_to_remove) { - prev = curr; - curr = curr->next; - - assert(curr != NULL); - } - - // Now remove this instruction from the list. - prev->next = curr->next; - - --mem_alloc_counter; - - // Could push this off to the destructor of DependencyEntry - curr->inst = NULL; - - delete curr; -} - -template <class Impl> -bool -InstQueue<Impl>::addToDependents(DynInstPtr &new_inst) -{ - // Loop through the instruction's source registers, adding - // them to the dependency list if they are not ready. - int8_t total_src_regs = new_inst->numSrcRegs(); - bool return_val = false; - - for (int src_reg_idx = 0; - src_reg_idx < total_src_regs; - src_reg_idx++) - { - // Only add it to the dependency graph if it's not ready. - if (!new_inst->isReadySrcRegIdx(src_reg_idx)) { - PhysRegIndex src_reg = new_inst->renamedSrcRegIdx(src_reg_idx); - - // Check the IQ's scoreboard to make sure the register - // hasn't become ready while the instruction was in flight - // between stages. Only if it really isn't ready should - // it be added to the dependency graph. - if (src_reg >= numPhysRegs) { - continue; - } else if (regScoreboard[src_reg] == false) { - DPRINTF(IQ, "Instruction PC %#x has src reg %i that " - "is being added to the dependency chain.\n", - new_inst->readPC(), src_reg); - - dependGraph[src_reg].insert(new_inst); - - // Change the return value to indicate that something - // was added to the dependency graph. - return_val = true; - } else { - DPRINTF(IQ, "Instruction PC %#x has src reg %i that " - "became ready before it reached the IQ.\n", - new_inst->readPC(), src_reg); - // Mark a register ready within the instruction. - new_inst->markSrcRegReady(); - } - } - } - - return return_val; -} - -template <class Impl> -void -InstQueue<Impl>::createDependency(DynInstPtr &new_inst) -{ - //Actually nothing really needs to be marked when an - //instruction becomes the producer of a register's value, - //but for convenience a ptr to the producing instruction will - //be placed in the head node of the dependency links. - int8_t total_dest_regs = new_inst->numDestRegs(); - - for (int dest_reg_idx = 0; - dest_reg_idx < total_dest_regs; - dest_reg_idx++) - { - PhysRegIndex dest_reg = new_inst->renamedDestRegIdx(dest_reg_idx); - - // Instructions that use the misc regs will have a reg number - // higher than the normal physical registers. In this case these - // registers are not renamed, and there is no need to track - // dependencies as these instructions must be executed at commit. - if (dest_reg >= numPhysRegs) { - continue; - } - - if (dependGraph[dest_reg].next) { - dumpDependGraph(); - panic("Dependency graph %i not empty!", dest_reg); - } - - dependGraph[dest_reg].inst = new_inst; - - // Mark the scoreboard to say it's not yet ready. - regScoreboard[dest_reg] = false; - } -} -*/ -template <class Impl> -void -InstQueue<Impl>::addIfReady(DynInstPtr &inst) -{ - //If the instruction now has all of its source registers - // available, then add it to the list of ready instructions. - if (inst->readyToIssue()) { - - //Add the instruction to the proper ready list. - if (inst->isMemRef()) { - - DPRINTF(IQ, "Checking if memory instruction can issue.\n"); - - // Message to the mem dependence unit that this instruction has - // its registers ready. - -// memDepUnit[inst->threadNumber].regsReady(inst); - - return; - } - - OpClass op_class = inst->opClass(); - - DPRINTF(IQ, "Instruction is ready to issue, putting it onto " - "the ready list, PC %#x opclass:%i [sn:%lli].\n", - inst->readPC(), op_class, inst->seqNum); - - readyInsts.push(inst); - } -} - -template <class Impl> -int -InstQueue<Impl>::countInsts() -{ - //ksewell:This works but definitely could use a cleaner write - //with a more intuitive way of counting. Right now it's - //just brute force .... - -#if 0 - int total_insts = 0; - - for (int i = 0; i < numThreads; ++i) { - ListIt count_it = instList[i].begin(); - - while (count_it != instList[i].end()) { - if (!(*count_it)->isSquashed() && !(*count_it)->isSquashedInIQ()) { - if (!(*count_it)->isIssued()) { - ++total_insts; - } else if ((*count_it)->isMemRef() && - !(*count_it)->memOpDone) { - // Loads that have not been marked as executed still count - // towards the total instructions. - ++total_insts; - } - } - - ++count_it; - } - } - - return total_insts; -#else - return numEntries - freeEntries; -#endif -} -/* -template <class Impl> -void -InstQueue<Impl>::dumpDependGraph() -{ - DependencyEntry *curr; - - for (int i = 0; i < numPhysRegs; ++i) - { - curr = &dependGraph[i]; - - if (curr->inst) { - cprintf("dependGraph[%i]: producer: %#x [sn:%lli] consumer: ", - i, curr->inst->readPC(), curr->inst->seqNum); - } else { - cprintf("dependGraph[%i]: No producer. consumer: ", i); - } - - while (curr->next != NULL) { - curr = curr->next; - - cprintf("%#x [sn:%lli] ", - curr->inst->readPC(), curr->inst->seqNum); - } - - cprintf("\n"); - } -} -*/ -template <class Impl> -void -InstQueue<Impl>::dumpLists() -{ - for (int i = 0; i < Num_OpClasses; ++i) { - cprintf("Ready list %i size: %i\n", i, readyInsts.size()); - - cprintf("\n"); - } - - cprintf("Non speculative list size: %i\n", nonSpecInsts.size()); - - NonSpecMapIt non_spec_it = nonSpecInsts.begin(); - NonSpecMapIt non_spec_end_it = nonSpecInsts.end(); - - cprintf("Non speculative list: "); - - while (non_spec_it != non_spec_end_it) { - cprintf("%#x [sn:%lli]", (*non_spec_it).second->readPC(), - (*non_spec_it).second->seqNum); - ++non_spec_it; - } - - cprintf("\n"); -/* - ListOrderIt list_order_it = listOrder.begin(); - ListOrderIt list_order_end_it = listOrder.end(); - int i = 1; - - cprintf("List order: "); - - while (list_order_it != list_order_end_it) { - cprintf("%i OpClass:%i [sn:%lli] ", i, (*list_order_it).queueType, - (*list_order_it).oldestInst); - - ++list_order_it; - ++i; - } -*/ - cprintf("\n"); -} - - -template <class Impl> -void -InstQueue<Impl>::dumpInsts() -{ - for (int i = 0; i < numThreads; ++i) { -// int num = 0; -// int valid_num = 0; -/* - ListIt inst_list_it = instList[i].begin(); - - while (inst_list_it != instList[i].end()) - { - cprintf("Instruction:%i\n", - num); - if (!(*inst_list_it)->isSquashed()) { - if (!(*inst_list_it)->isIssued()) { - ++valid_num; - cprintf("Count:%i\n", valid_num); - } else if ((*inst_list_it)->isMemRef() && - !(*inst_list_it)->memOpDone) { - // Loads that have not been marked as executed still count - // towards the total instructions. - ++valid_num; - cprintf("Count:%i\n", valid_num); - } - } - - cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" - "Issued:%i\nSquashed:%i\n", - (*inst_list_it)->readPC(), - (*inst_list_it)->seqNum, - (*inst_list_it)->threadNumber, - (*inst_list_it)->isIssued(), - (*inst_list_it)->isSquashed()); - - if ((*inst_list_it)->isMemRef()) { - cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone); - } - - cprintf("\n"); - - inst_list_it++; - ++num; - } -*/ - } -} diff --git a/cpu/ozone/lsq_unit.cc b/cpu/ozone/lsq_unit.cc deleted file mode 100644 index 3ac51b87d..000000000 --- a/cpu/ozone/lsq_unit.cc +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/ozone/ozone_impl.hh" -#include "cpu/ozone/lsq_unit_impl.hh" - -// Force the instantiation of LDSTQ for all the implementations we care about. -template class OzoneLSQ<OzoneImpl>; - diff --git a/cpu/ozone/lsq_unit.hh b/cpu/ozone/lsq_unit.hh deleted file mode 100644 index 4b600af67..000000000 --- a/cpu/ozone/lsq_unit.hh +++ /dev/null @@ -1,637 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_OZONE_LSQ_UNIT_HH__ -#define __CPU_OZONE_LSQ_UNIT_HH__ - -#include <map> -#include <queue> -#include <algorithm> - -#include "arch/faults.hh" -#include "arch/isa_traits.hh" -#include "config/full_system.hh" -#include "base/hashmap.hh" -#include "cpu/inst_seq.hh" -#include "mem/mem_interface.hh" -//#include "mem/page_table.hh" -#include "sim/sim_object.hh" - -class PageTable; - -/** - * Class that implements the actual LQ and SQ for each specific thread. - * Both are circular queues; load entries are freed upon committing, while - * store entries are freed once they writeback. The LSQUnit tracks if there - * are memory ordering violations, and also detects partial load to store - * forwarding cases (a store only has part of a load's data) that requires - * the load to wait until the store writes back. In the former case it - * holds onto the instruction until the dependence unit looks at it, and - * in the latter it stalls the LSQ until the store writes back. At that - * point the load is replayed. - */ -template <class Impl> -class OzoneLSQ { - public: - typedef typename Impl::Params Params; - typedef typename Impl::FullCPU FullCPU; - typedef typename Impl::BackEnd BackEnd; - typedef typename Impl::DynInstPtr DynInstPtr; - typedef typename Impl::IssueStruct IssueStruct; - - typedef TheISA::IntReg IntReg; - - typedef typename std::map<InstSeqNum, DynInstPtr>::iterator LdMapIt; - - private: - class StoreCompletionEvent : public Event { - public: - /** Constructs a store completion event. */ - StoreCompletionEvent(int store_idx, Event *wb_event, OzoneLSQ *lsq_ptr); - - /** Processes the store completion event. */ - void process(); - - /** Returns the description of this event. */ - const char *description(); - - private: - /** The store index of the store being written back. */ - int storeIdx; - /** The writeback event for the store. Needed for store - * conditionals. - */ - Event *wbEvent; - /** The pointer to the LSQ unit that issued the store. */ - OzoneLSQ<Impl> *lsqPtr; - }; - - friend class StoreCompletionEvent; - - public: - /** Constructs an LSQ unit. init() must be called prior to use. */ - OzoneLSQ(); - - /** Initializes the LSQ unit with the specified number of entries. */ - void init(Params *params, unsigned maxLQEntries, - unsigned maxSQEntries, unsigned id); - - /** Returns the name of the LSQ unit. */ - std::string name() const; - - /** Sets the CPU pointer. */ - void setCPU(FullCPU *cpu_ptr) - { cpu = cpu_ptr; } - - /** Sets the back-end stage pointer. */ - void setBE(BackEnd *be_ptr) - { be = be_ptr; } - - /** Sets the page table pointer. */ - void setPageTable(PageTable *pt_ptr); - - /** Ticks the LSQ unit, which in this case only resets the number of - * used cache ports. - * @todo: Move the number of used ports up to the LSQ level so it can - * be shared by all LSQ units. - */ - void tick() { usedPorts = 0; } - - /** Inserts an instruction. */ - void insert(DynInstPtr &inst); - /** Inserts a load instruction. */ - void insertLoad(DynInstPtr &load_inst); - /** Inserts a store instruction. */ - void insertStore(DynInstPtr &store_inst); - - /** Executes a load instruction. */ - Fault executeLoad(DynInstPtr &inst); - - Fault executeLoad(int lq_idx); - /** Executes a store instruction. */ - Fault executeStore(DynInstPtr &inst); - - /** Commits the head load. */ - void commitLoad(); - /** Commits a specific load, given by the sequence number. */ - void commitLoad(InstSeqNum &inst); - /** Commits loads older than a specific sequence number. */ - void commitLoads(InstSeqNum &youngest_inst); - - /** Commits stores older than a specific sequence number. */ - void commitStores(InstSeqNum &youngest_inst); - - /** Writes back stores. */ - void writebackStores(); - - // @todo: Include stats in the LSQ unit. - //void regStats(); - - /** Clears all the entries in the LQ. */ - void clearLQ(); - - /** Clears all the entries in the SQ. */ - void clearSQ(); - - /** Resizes the LQ to a given size. */ - void resizeLQ(unsigned size); - - /** Resizes the SQ to a given size. */ - void resizeSQ(unsigned size); - - /** Squashes all instructions younger than a specific sequence number. */ - void squash(const InstSeqNum &squashed_num); - - /** Returns if there is a memory ordering violation. Value is reset upon - * call to getMemDepViolator(). - */ - bool violation() { return memDepViolator; } - - /** Returns the memory ordering violator. */ - DynInstPtr getMemDepViolator(); - - /** Returns if a load became blocked due to the memory system. It clears - * the bool's value upon this being called. - */ - inline bool loadBlocked(); - - /** Returns the number of free entries (min of free LQ and SQ entries). */ - unsigned numFreeEntries(); - - /** Returns the number of loads ready to execute. */ - int numLoadsReady(); - - /** Returns the number of loads in the LQ. */ - int numLoads() { return loads; } - - /** Returns the number of stores in the SQ. */ - int numStores() { return stores; } - - /** Returns if either the LQ or SQ is full. */ - bool isFull() { return lqFull() || sqFull(); } - - /** Returns if the LQ is full. */ - bool lqFull() { return loads >= (LQEntries - 1); } - - /** Returns if the SQ is full. */ - bool sqFull() { return stores >= (SQEntries - 1); } - - /** Debugging function to dump instructions in the LSQ. */ - void dumpInsts(); - - /** Returns the number of instructions in the LSQ. */ - unsigned getCount() { return loads + stores; } - - /** Returns if there are any stores to writeback. */ - bool hasStoresToWB() { return storesToWB; } - - /** Returns the number of stores to writeback. */ - int numStoresToWB() { return storesToWB; } - - /** Returns if the LSQ unit will writeback on this cycle. */ - bool willWB() { return storeQueue[storeWBIdx].canWB && - !storeQueue[storeWBIdx].completed && - !dcacheInterface->isBlocked(); } - - private: - /** Completes the store at the specified index. */ - void completeStore(int store_idx); - - /** Increments the given store index (circular queue). */ - inline void incrStIdx(int &store_idx); - /** Decrements the given store index (circular queue). */ - inline void decrStIdx(int &store_idx); - /** Increments the given load index (circular queue). */ - inline void incrLdIdx(int &load_idx); - /** Decrements the given load index (circular queue). */ - inline void decrLdIdx(int &load_idx); - - private: - /** Pointer to the CPU. */ - FullCPU *cpu; - - /** Pointer to the back-end stage. */ - BackEnd *be; - - /** Pointer to the D-cache. */ - MemInterface *dcacheInterface; - - /** Pointer to the page table. */ - PageTable *pTable; - - public: - struct SQEntry { - /** Constructs an empty store queue entry. */ - SQEntry() - : inst(NULL), req(NULL), size(0), data(0), - canWB(0), committed(0), completed(0) - { } - - /** Constructs a store queue entry for a given instruction. */ - SQEntry(DynInstPtr &_inst) - : inst(_inst), req(NULL), size(0), data(0), - canWB(0), committed(0), completed(0) - { } - - /** The store instruction. */ - DynInstPtr inst; - /** The memory request for the store. */ - MemReqPtr req; - /** The size of the store. */ - int size; - /** The store data. */ - IntReg data; - /** Whether or not the store can writeback. */ - bool canWB; - /** Whether or not the store is committed. */ - bool committed; - /** Whether or not the store is completed. */ - bool completed; - }; - - enum Status { - Running, - Idle, - DcacheMissStall, - DcacheMissSwitch - }; - - private: - /** The OzoneLSQ thread id. */ - unsigned lsqID; - - /** The status of the LSQ unit. */ - Status _status; - - /** The store queue. */ - std::vector<SQEntry> storeQueue; - - /** The load queue. */ - std::vector<DynInstPtr> loadQueue; - - // Consider making these 16 bits - /** The number of LQ entries. */ - unsigned LQEntries; - /** The number of SQ entries. */ - unsigned SQEntries; - - /** The number of load instructions in the LQ. */ - int loads; - /** The number of store instructions in the SQ (excludes those waiting to - * writeback). - */ - int stores; - /** The number of store instructions in the SQ waiting to writeback. */ - int storesToWB; - - /** The index of the head instruction in the LQ. */ - int loadHead; - /** The index of the tail instruction in the LQ. */ - int loadTail; - - /** The index of the head instruction in the SQ. */ - int storeHead; - /** The index of the first instruction that is ready to be written back, - * and has not yet been written back. - */ - int storeWBIdx; - /** The index of the tail instruction in the SQ. */ - int storeTail; - - /// @todo Consider moving to a more advanced model with write vs read ports - /** The number of cache ports available each cycle. */ - int cachePorts; - - /** The number of used cache ports in this cycle. */ - int usedPorts; - - //list<InstSeqNum> mshrSeqNums; - - //Stats::Scalar<> dcacheStallCycles; - Counter lastDcacheStall; - - /** Wire to read information from the issue stage time queue. */ - typename TimeBuffer<IssueStruct>::wire fromIssue; - - // Make these per thread? - /** Whether or not the LSQ is stalled. */ - bool stalled; - /** The store that causes the stall due to partial store to load - * forwarding. - */ - InstSeqNum stallingStoreIsn; - /** The index of the above store. */ - int stallingLoadIdx; - - /** Whether or not a load is blocked due to the memory system. It is - * cleared when this value is checked via loadBlocked(). - */ - bool isLoadBlocked; - - /** The oldest faulting load instruction. */ - DynInstPtr loadFaultInst; - /** The oldest faulting store instruction. */ - DynInstPtr storeFaultInst; - - /** The oldest load that caused a memory ordering violation. */ - DynInstPtr memDepViolator; - - // Will also need how many read/write ports the Dcache has. Or keep track - // of that in stage that is one level up, and only call executeLoad/Store - // the appropriate number of times. - - public: - /** Executes the load at the given index. */ - template <class T> - Fault read(MemReqPtr &req, T &data, int load_idx); - - /** Executes the store at the given index. */ - template <class T> - Fault write(MemReqPtr &req, T &data, int store_idx); - - /** Returns the index of the head load instruction. */ - int getLoadHead() { return loadHead; } - /** Returns the sequence number of the head load instruction. */ - InstSeqNum getLoadHeadSeqNum() - { - if (loadQueue[loadHead]) { - return loadQueue[loadHead]->seqNum; - } else { - return 0; - } - - } - - /** Returns the index of the head store instruction. */ - int getStoreHead() { return storeHead; } - /** Returns the sequence number of the head store instruction. */ - InstSeqNum getStoreHeadSeqNum() - { - if (storeQueue[storeHead].inst) { - return storeQueue[storeHead].inst->seqNum; - } else { - return 0; - } - - } - - /** Returns whether or not the LSQ unit is stalled. */ - bool isStalled() { return stalled; } -}; - -template <class Impl> -template <class T> -Fault -OzoneLSQ<Impl>::read(MemReqPtr &req, T &data, int load_idx) -{ - //Depending on issue2execute delay a squashed load could - //execute if it is found to be squashed in the same - //cycle it is scheduled to execute - assert(loadQueue[load_idx]); - - if (loadQueue[load_idx]->isExecuted()) { - panic("Should not reach this point with split ops!"); - - memcpy(&data,req->data,req->size); - - return NoFault; - } - - // Make sure this isn't an uncacheable access - // A bit of a hackish way to get uncached accesses to work only if they're - // at the head of the LSQ and are ready to commit (at the head of the ROB - // too). - // @todo: Fix uncached accesses. - if (req->flags & UNCACHEABLE && - (load_idx != loadHead || !loadQueue[load_idx]->readyToCommit())) { - - return TheISA::genMachineCheckFault(); - } - - // Check the SQ for any previous stores that might lead to forwarding - int store_idx = loadQueue[load_idx]->sqIdx; - - int store_size = 0; - - DPRINTF(OzoneLSQ, "Read called, load idx: %i, store idx: %i, " - "storeHead: %i addr: %#x\n", - load_idx, store_idx, storeHead, req->paddr); - - while (store_idx != -1) { - // End once we've reached the top of the LSQ - if (store_idx == storeWBIdx) { - break; - } - - // Move the index to one younger - if (--store_idx < 0) - store_idx += SQEntries; - - assert(storeQueue[store_idx].inst); - - store_size = storeQueue[store_idx].size; - - if (store_size == 0) - continue; - - // Check if the store data is within the lower and upper bounds of - // addresses that the request needs. - bool store_has_lower_limit = - req->vaddr >= storeQueue[store_idx].inst->effAddr; - bool store_has_upper_limit = - (req->vaddr + req->size) <= (storeQueue[store_idx].inst->effAddr + - store_size); - bool lower_load_has_store_part = - req->vaddr < (storeQueue[store_idx].inst->effAddr + - store_size); - bool upper_load_has_store_part = - (req->vaddr + req->size) > storeQueue[store_idx].inst->effAddr; - - // If the store's data has all of the data needed, we can forward. - if (store_has_lower_limit && store_has_upper_limit) { - - int shift_amt = req->vaddr & (store_size - 1); - // Assumes byte addressing - shift_amt = shift_amt << 3; - - // Cast this to type T? - data = storeQueue[store_idx].data >> shift_amt; - - req->cmd = Read; - assert(!req->completionEvent); - req->completionEvent = NULL; - req->time = curTick; - assert(!req->data); - req->data = new uint8_t[64]; - - memcpy(req->data, &data, req->size); - - DPRINTF(OzoneLSQ, "Forwarding from store idx %i to load to " - "addr %#x, data %#x\n", - store_idx, req->vaddr, *(req->data)); - - typename BackEnd::LdWritebackEvent *wb = - new typename BackEnd::LdWritebackEvent(loadQueue[load_idx], - be); - - // We'll say this has a 1 cycle load-store forwarding latency - // for now. - // FIXME - Need to make this a parameter. - wb->schedule(curTick); - - // Should keep track of stat for forwarded data - return NoFault; - } else if ((store_has_lower_limit && lower_load_has_store_part) || - (store_has_upper_limit && upper_load_has_store_part) || - (lower_load_has_store_part && upper_load_has_store_part)) { - // This is the partial store-load forwarding case where a store - // has only part of the load's data. - - // If it's already been written back, then don't worry about - // stalling on it. - if (storeQueue[store_idx].completed) { - continue; - } - - // Must stall load and force it to retry, so long as it's the oldest - // load that needs to do so. - if (!stalled || - (stalled && - loadQueue[load_idx]->seqNum < - loadQueue[stallingLoadIdx]->seqNum)) { - stalled = true; - stallingStoreIsn = storeQueue[store_idx].inst->seqNum; - stallingLoadIdx = load_idx; - } - - // Tell IQ/mem dep unit that this instruction will need to be - // rescheduled eventually - be->rescheduleMemInst(loadQueue[load_idx]); - - DPRINTF(OzoneLSQ, "Load-store forwarding mis-match. " - "Store idx %i to load addr %#x\n", - store_idx, req->vaddr); - - return NoFault; - } - } - - - // If there's no forwarding case, then go access memory - DynInstPtr inst = loadQueue[load_idx]; - - ++usedPorts; - - // if we have a cache, do cache access too - if (dcacheInterface) { - if (dcacheInterface->isBlocked()) { - isLoadBlocked = true; - // No fault occurred, even though the interface is blocked. - return NoFault; - } - - DPRINTF(OzoneLSQ, "D-cache: PC:%#x reading from paddr:%#x " - "vaddr:%#x flags:%i\n", - inst->readPC(), req->paddr, req->vaddr, req->flags); - - // Setup MemReq pointer - req->cmd = Read; - req->completionEvent = NULL; - req->time = curTick; - assert(!req->data); - req->data = new uint8_t[64]; - - assert(!req->completionEvent); - typedef typename BackEnd::LdWritebackEvent LdWritebackEvent; - - LdWritebackEvent *wb = new LdWritebackEvent(loadQueue[load_idx], be); - - req->completionEvent = wb; - - // Do Cache Access - MemAccessResult result = dcacheInterface->access(req); - - // Ugly hack to get an event scheduled *only* if the access is - // a miss. We really should add first-class support for this - // at some point. - // @todo: Probably should support having no events - if (result != MA_HIT) { - DPRINTF(OzoneLSQ, "D-cache miss!\n"); - DPRINTF(Activity, "Activity: ld accessing mem miss [sn:%lli]\n", - inst->seqNum); - - lastDcacheStall = curTick; - - _status = DcacheMissStall; - - wb->setDcacheMiss(); - - } else { -// DPRINTF(Activity, "Activity: ld accessing mem hit [sn:%lli]\n", -// inst->seqNum); - - DPRINTF(OzoneLSQ, "D-cache hit!\n"); - } - } else { - fatal("Must use D-cache with new memory system"); - } - - return NoFault; -} - -template <class Impl> -template <class T> -Fault -OzoneLSQ<Impl>::write(MemReqPtr &req, T &data, int store_idx) -{ - assert(storeQueue[store_idx].inst); - - DPRINTF(OzoneLSQ, "Doing write to store idx %i, addr %#x data %#x" - " | storeHead:%i [sn:%i]\n", - store_idx, req->paddr, data, storeHead, - storeQueue[store_idx].inst->seqNum); - - storeQueue[store_idx].req = req; - storeQueue[store_idx].size = sizeof(T); - storeQueue[store_idx].data = data; - - // This function only writes the data to the store queue, so no fault - // can happen here. - return NoFault; -} - -template <class Impl> -inline bool -OzoneLSQ<Impl>::loadBlocked() -{ - bool ret_val = isLoadBlocked; - isLoadBlocked = false; - return ret_val; -} - -#endif // __CPU_OZONE_LSQ_UNIT_HH__ diff --git a/cpu/ozone/lsq_unit_impl.hh b/cpu/ozone/lsq_unit_impl.hh deleted file mode 100644 index 726348d76..000000000 --- a/cpu/ozone/lsq_unit_impl.hh +++ /dev/null @@ -1,846 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "arch/isa_traits.hh" -#include "base/str.hh" -#include "cpu/ozone/lsq_unit.hh" - -template <class Impl> -OzoneLSQ<Impl>::StoreCompletionEvent::StoreCompletionEvent(int store_idx, - Event *wb_event, - OzoneLSQ<Impl> *lsq_ptr) - : Event(&mainEventQueue), - storeIdx(store_idx), - wbEvent(wb_event), - lsqPtr(lsq_ptr) -{ - this->setFlags(Event::AutoDelete); -} - -template <class Impl> -void -OzoneLSQ<Impl>::StoreCompletionEvent::process() -{ - DPRINTF(OzoneLSQ, "Cache miss complete for store idx:%i\n", storeIdx); - - //lsqPtr->removeMSHR(lsqPtr->storeQueue[storeIdx].inst->seqNum); - -// lsqPtr->cpu->wakeCPU(); - if (wbEvent) - wbEvent->process(); - lsqPtr->completeStore(storeIdx); -} - -template <class Impl> -const char * -OzoneLSQ<Impl>::StoreCompletionEvent::description() -{ - return "LSQ store completion event"; -} - -template <class Impl> -OzoneLSQ<Impl>::OzoneLSQ() - : loads(0), stores(0), storesToWB(0), stalled(false), isLoadBlocked(false) -{ -} - -template<class Impl> -void -OzoneLSQ<Impl>::init(Params *params, unsigned maxLQEntries, - unsigned maxSQEntries, unsigned id) - -{ - DPRINTF(OzoneLSQ, "Creating OzoneLSQ%i object.\n",id); - - lsqID = id; - - LQEntries = maxLQEntries; - SQEntries = maxSQEntries; - - loadQueue.resize(LQEntries); - storeQueue.resize(SQEntries); - - - // May want to initialize these entries to NULL - - loadHead = loadTail = 0; - - storeHead = storeWBIdx = storeTail = 0; - - usedPorts = 0; - cachePorts = params->cachePorts; - - dcacheInterface = params->dcacheInterface; - - loadFaultInst = storeFaultInst = memDepViolator = NULL; -} - -template<class Impl> -std::string -OzoneLSQ<Impl>::name() const -{ - return "lsqunit"; -} - -template<class Impl> -void -OzoneLSQ<Impl>::clearLQ() -{ - loadQueue.clear(); -} - -template<class Impl> -void -OzoneLSQ<Impl>::clearSQ() -{ - storeQueue.clear(); -} - -template<class Impl> -void -OzoneLSQ<Impl>::setPageTable(PageTable *pt_ptr) -{ - DPRINTF(OzoneLSQ, "Setting the page table pointer.\n"); - pTable = pt_ptr; -} - -template<class Impl> -void -OzoneLSQ<Impl>::resizeLQ(unsigned size) -{ - assert( size >= LQEntries); - - if (size > LQEntries) { - while (size > loadQueue.size()) { - DynInstPtr dummy; - loadQueue.push_back(dummy); - LQEntries++; - } - } else { - LQEntries = size; - } - -} - -template<class Impl> -void -OzoneLSQ<Impl>::resizeSQ(unsigned size) -{ - if (size > SQEntries) { - while (size > storeQueue.size()) { - SQEntry dummy; - storeQueue.push_back(dummy); - SQEntries++; - } - } else { - SQEntries = size; - } -} - -template <class Impl> -void -OzoneLSQ<Impl>::insert(DynInstPtr &inst) -{ - // Make sure we really have a memory reference. - assert(inst->isMemRef()); - - // Make sure it's one of the two classes of memory references. - assert(inst->isLoad() || inst->isStore()); - - if (inst->isLoad()) { - insertLoad(inst); - } else { - insertStore(inst); - } - -// inst->setInLSQ(); -} - -template <class Impl> -void -OzoneLSQ<Impl>::insertLoad(DynInstPtr &load_inst) -{ - assert((loadTail + 1) % LQEntries != loadHead && loads < LQEntries); - - DPRINTF(OzoneLSQ, "Inserting load PC %#x, idx:%i [sn:%lli]\n", - load_inst->readPC(), loadTail, load_inst->seqNum); - - load_inst->lqIdx = loadTail; - - if (stores == 0) { - load_inst->sqIdx = -1; - } else { - load_inst->sqIdx = storeTail; - } - - loadQueue[loadTail] = load_inst; - - incrLdIdx(loadTail); - - ++loads; -} - -template <class Impl> -void -OzoneLSQ<Impl>::insertStore(DynInstPtr &store_inst) -{ - // Make sure it is not full before inserting an instruction. - assert((storeTail + 1) % SQEntries != storeHead); - assert(stores < SQEntries); - - DPRINTF(OzoneLSQ, "Inserting store PC %#x, idx:%i [sn:%lli]\n", - store_inst->readPC(), storeTail, store_inst->seqNum); - - store_inst->sqIdx = storeTail; - store_inst->lqIdx = loadTail; - - storeQueue[storeTail] = SQEntry(store_inst); - - incrStIdx(storeTail); - - ++stores; - -} - -template <class Impl> -typename Impl::DynInstPtr -OzoneLSQ<Impl>::getMemDepViolator() -{ - DynInstPtr temp = memDepViolator; - - memDepViolator = NULL; - - return temp; -} - -template <class Impl> -unsigned -OzoneLSQ<Impl>::numFreeEntries() -{ - unsigned free_lq_entries = LQEntries - loads; - unsigned free_sq_entries = SQEntries - stores; - - // Both the LQ and SQ entries have an extra dummy entry to differentiate - // empty/full conditions. Subtract 1 from the free entries. - if (free_lq_entries < free_sq_entries) { - return free_lq_entries - 1; - } else { - return free_sq_entries - 1; - } -} - -template <class Impl> -int -OzoneLSQ<Impl>::numLoadsReady() -{ - int load_idx = loadHead; - int retval = 0; - - while (load_idx != loadTail) { - assert(loadQueue[load_idx]); - - if (loadQueue[load_idx]->readyToIssue()) { - ++retval; - } - } - - return retval; -} - -#if 0 -template <class Impl> -Fault -OzoneLSQ<Impl>::executeLoad() -{ - Fault load_fault = NoFault; - DynInstPtr load_inst; - - assert(readyLoads.size() != 0); - - // Execute a ready load. - LdMapIt ready_it = readyLoads.begin(); - - load_inst = (*ready_it).second; - - // Execute the instruction, which is held in the data portion of the - // iterator. - load_fault = load_inst->execute(); - - // If it executed successfully, then switch it over to the executed - // loads list. - if (load_fault == NoFault) { - executedLoads[load_inst->seqNum] = load_inst; - - readyLoads.erase(ready_it); - } else { - loadFaultInst = load_inst; - } - - return load_fault; -} -#endif - -template <class Impl> -Fault -OzoneLSQ<Impl>::executeLoad(DynInstPtr &inst) -{ - // Execute a specific load. - Fault load_fault = NoFault; - - DPRINTF(OzoneLSQ, "Executing load PC %#x, [sn:%lli]\n", - inst->readPC(),inst->seqNum); - - // Make sure it's really in the list. - // Normally it should always be in the list. However, - /* due to a syscall it may not be the list. -#ifdef DEBUG - int i = loadHead; - while (1) { - if (i == loadTail && !find(inst)) { - assert(0 && "Load not in the queue!"); - } else if (loadQueue[i] == inst) { - break; - } - - i = i + 1; - if (i >= LQEntries) { - i = 0; - } - } -#endif // DEBUG*/ - - load_fault = inst->initiateAcc(); - - // Might want to make sure that I'm not overwriting a previously faulting - // instruction that hasn't been checked yet. - // Actually probably want the oldest faulting load - if (load_fault != NoFault) { - // Maybe just set it as can commit here, although that might cause - // some other problems with sending traps to the ROB too quickly. -// iewStage->instToCommit(inst); -// iewStage->activityThisCycle(); - } - - return load_fault; -} - -template <class Impl> -Fault -OzoneLSQ<Impl>::executeLoad(int lq_idx) -{ - // Very hackish. Not sure the best way to check that this - // instruction is at the head of the ROB. I should have some sort - // of extra information here so that I'm not overloading the - // canCommit signal for 15 different things. - loadQueue[lq_idx]->setCanCommit(); - Fault ret_fault = executeLoad(loadQueue[lq_idx]); - loadQueue[lq_idx]->clearCanCommit(); - return ret_fault; -} - -template <class Impl> -Fault -OzoneLSQ<Impl>::executeStore(DynInstPtr &store_inst) -{ - // Make sure that a store exists. - assert(stores != 0); - - int store_idx = store_inst->sqIdx; - - DPRINTF(OzoneLSQ, "Executing store PC %#x [sn:%lli]\n", - store_inst->readPC(), store_inst->seqNum); - - // Check the recently completed loads to see if any match this store's - // address. If so, then we have a memory ordering violation. - int load_idx = store_inst->lqIdx; - - Fault store_fault = store_inst->initiateAcc(); - - // Store size should now be available. Use it to get proper offset for - // addr comparisons. - int size = storeQueue[store_idx].size; - - if (size == 0) { - DPRINTF(OzoneLSQ,"Fault on Store PC %#x, [sn:%lli],Size = 0\n", - store_inst->readPC(),store_inst->seqNum); - - return store_fault; - } - - assert(store_fault == NoFault); - - if (!storeFaultInst) { - if (store_fault != NoFault) { - panic("Fault in a store instruction!"); - storeFaultInst = store_inst; - } else if (store_inst->isNonSpeculative()) { - // Nonspeculative accesses (namely store conditionals) - // need to set themselves as able to writeback if we - // haven't had a fault by here. - storeQueue[store_idx].canWB = true; - - ++storesToWB; - } - } - - if (!memDepViolator) { - while (load_idx != loadTail) { - // Actually should only check loads that have actually executed - // Might be safe because effAddr is set to InvalAddr when the - // dyn inst is created. - - // Must actually check all addrs in the proper size range - // Which is more correct than needs to be. What if for now we just - // assume all loads are quad-word loads, and do the addr based - // on that. - // @todo: Fix this, magic number being used here - if ((loadQueue[load_idx]->effAddr >> 8) == - (store_inst->effAddr >> 8)) { - // A load incorrectly passed this store. Squash and refetch. - // For now return a fault to show that it was unsuccessful. - memDepViolator = loadQueue[load_idx]; - - return TheISA::genMachineCheckFault(); - } - - incrLdIdx(load_idx); - } - - // If we've reached this point, there was no violation. - memDepViolator = NULL; - } - - return store_fault; -} - -template <class Impl> -void -OzoneLSQ<Impl>::commitLoad() -{ - assert(loadQueue[loadHead]); - - DPRINTF(OzoneLSQ, "[sn:%lli] Committing head load instruction, PC %#x\n", - loadQueue[loadHead]->seqNum, loadQueue[loadHead]->readPC()); - - - loadQueue[loadHead] = NULL; - - incrLdIdx(loadHead); - - --loads; -} - -template <class Impl> -void -OzoneLSQ<Impl>::commitLoad(InstSeqNum &inst) -{ - // Hopefully I don't use this function too much - panic("Don't use this function!"); - - int i = loadHead; - while (1) { - if (i == loadTail) { - assert(0 && "Load not in the queue!"); - } else if (loadQueue[i]->seqNum == inst) { - break; - } - - ++i; - if (i >= LQEntries) { - i = 0; - } - } - -// loadQueue[i]->removeInLSQ(); - loadQueue[i] = NULL; - --loads; -} - -template <class Impl> -void -OzoneLSQ<Impl>::commitLoads(InstSeqNum &youngest_inst) -{ - assert(loads == 0 || loadQueue[loadHead]); - - while (loads != 0 && loadQueue[loadHead]->seqNum <= youngest_inst) { - commitLoad(); - } -} - -template <class Impl> -void -OzoneLSQ<Impl>::commitStores(InstSeqNum &youngest_inst) -{ - assert(stores == 0 || storeQueue[storeHead].inst); - - int store_idx = storeHead; - - while (store_idx != storeTail) { - assert(storeQueue[store_idx].inst); - if (!storeQueue[store_idx].canWB) { - if (storeQueue[store_idx].inst->seqNum > youngest_inst) { - break; - } - DPRINTF(OzoneLSQ, "Marking store as able to write back, PC " - "%#x [sn:%lli]\n", - storeQueue[store_idx].inst->readPC(), - storeQueue[store_idx].inst->seqNum); - - storeQueue[store_idx].canWB = true; - -// --stores; - ++storesToWB; - } - - incrStIdx(store_idx); - } -} - -template <class Impl> -void -OzoneLSQ<Impl>::writebackStores() -{ - while (storesToWB > 0 && - storeWBIdx != storeTail && - storeQueue[storeWBIdx].inst && - storeQueue[storeWBIdx].canWB && - usedPorts < cachePorts) { - - if (storeQueue[storeWBIdx].size == 0) { - completeStore(storeWBIdx); - - incrStIdx(storeWBIdx); - - continue; - } - - if (dcacheInterface && dcacheInterface->isBlocked()) { - DPRINTF(OzoneLSQ, "Unable to write back any more stores, cache" - " is blocked!\n"); - break; - } - - ++usedPorts; - - if (storeQueue[storeWBIdx].inst->isDataPrefetch()) { - incrStIdx(storeWBIdx); - - continue; - } - - assert(storeQueue[storeWBIdx].req); - assert(!storeQueue[storeWBIdx].committed); - - MemReqPtr req = storeQueue[storeWBIdx].req; - storeQueue[storeWBIdx].committed = true; - -// Fault fault = cpu->translateDataReadReq(req); - req->cmd = Write; - req->completionEvent = NULL; - req->time = curTick; - assert(!req->data); - req->data = new uint8_t[64]; - memcpy(req->data, (uint8_t *)&storeQueue[storeWBIdx].data, req->size); - - DPRINTF(OzoneLSQ, "D-Cache: Writing back store idx:%i PC:%#x " - "to Addr:%#x, data:%#x [sn:%lli]\n", - storeWBIdx,storeQueue[storeWBIdx].inst->readPC(), - req->paddr, *(req->data), - storeQueue[storeWBIdx].inst->seqNum); - -// if (fault != NoFault) { - //What should we do if there is a fault??? - //for now panic -// panic("Page Table Fault!!!!!\n"); -// } - - if (dcacheInterface) { - MemAccessResult result = dcacheInterface->access(req); - - //@todo temp fix for LL/SC (works fine for 1 CPU) - if (req->flags & LOCKED) { - req->result=1; - panic("LL/SC! oh no no support!!!"); - } - - if (isStalled() && - storeQueue[storeWBIdx].inst->seqNum == stallingStoreIsn) { - DPRINTF(OzoneLSQ, "Unstalling, stalling store [sn:%lli] " - "load idx:%i\n", - stallingStoreIsn, stallingLoadIdx); - stalled = false; - stallingStoreIsn = 0; - be->replayMemInst(loadQueue[stallingLoadIdx]); - } - - if (result != MA_HIT && dcacheInterface->doEvents()) { - Event *wb = NULL; -/* - typename IEW::LdWritebackEvent *wb = NULL; - if (req->flags & LOCKED) { - // Stx_C does not generate a system port transaction. - req->result=0; - wb = new typename IEW::LdWritebackEvent(storeQueue[storeWBIdx].inst, - iewStage); - } -*/ - DPRINTF(OzoneLSQ,"D-Cache Write Miss!\n"); - -// DPRINTF(Activity, "Active st accessing mem miss [sn:%lli]\n", -// storeQueue[storeWBIdx].inst->seqNum); - - // Will stores need their own kind of writeback events? - // Do stores even need writeback events? - assert(!req->completionEvent); - req->completionEvent = new - StoreCompletionEvent(storeWBIdx, wb, this); - - lastDcacheStall = curTick; - - _status = DcacheMissStall; - - //mshrSeqNums.push_back(storeQueue[storeWBIdx].inst->seqNum); - - //DPRINTF(OzoneLSQ, "Added MSHR. count = %i\n",mshrSeqNums.size()); - - // Increment stat here or something - } else { - DPRINTF(OzoneLSQ,"D-Cache: Write Hit on idx:%i !\n", - storeWBIdx); - -// DPRINTF(Activity, "Active st accessing mem hit [sn:%lli]\n", -// storeQueue[storeWBIdx].inst->seqNum); - - if (req->flags & LOCKED) { - // Stx_C does not generate a system port transaction. - req->result=1; - typename BackEnd::LdWritebackEvent *wb = - new typename BackEnd::LdWritebackEvent(storeQueue[storeWBIdx].inst, - be); - wb->schedule(curTick); - } - - completeStore(storeWBIdx); - } - - incrStIdx(storeWBIdx); - } else { - panic("Must HAVE DCACHE!!!!!\n"); - } - } - - // Not sure this should set it to 0. - usedPorts = 0; - - assert(stores >= 0 && storesToWB >= 0); -} - -/*template <class Impl> -void -OzoneLSQ<Impl>::removeMSHR(InstSeqNum seqNum) -{ - list<InstSeqNum>::iterator mshr_it = find(mshrSeqNums.begin(), - mshrSeqNums.end(), - seqNum); - - if (mshr_it != mshrSeqNums.end()) { - mshrSeqNums.erase(mshr_it); - DPRINTF(OzoneLSQ, "Removing MSHR. count = %i\n",mshrSeqNums.size()); - } -}*/ - -template <class Impl> -void -OzoneLSQ<Impl>::squash(const InstSeqNum &squashed_num) -{ - DPRINTF(OzoneLSQ, "Squashing until [sn:%lli]!" - "(Loads:%i Stores:%i)\n",squashed_num,loads,stores); - - int load_idx = loadTail; - decrLdIdx(load_idx); - - while (loads != 0 && loadQueue[load_idx]->seqNum > squashed_num) { - - // Clear the smart pointer to make sure it is decremented. - DPRINTF(OzoneLSQ,"Load Instruction PC %#x squashed, " - "[sn:%lli]\n", - loadQueue[load_idx]->readPC(), - loadQueue[load_idx]->seqNum); - - if (isStalled() && load_idx == stallingLoadIdx) { - stalled = false; - stallingStoreIsn = 0; - stallingLoadIdx = 0; - } - -// loadQueue[load_idx]->squashed = true; - loadQueue[load_idx] = NULL; - --loads; - - // Inefficient! - loadTail = load_idx; - - decrLdIdx(load_idx); - } - - int store_idx = storeTail; - decrStIdx(store_idx); - - while (stores != 0 && storeQueue[store_idx].inst->seqNum > squashed_num) { - - // Clear the smart pointer to make sure it is decremented. - DPRINTF(OzoneLSQ,"Store Instruction PC %#x squashed, " - "idx:%i [sn:%lli]\n", - storeQueue[store_idx].inst->readPC(), - store_idx, storeQueue[store_idx].inst->seqNum); - - // I don't think this can happen. It should have been cleared by the - // stalling load. - if (isStalled() && - storeQueue[store_idx].inst->seqNum == stallingStoreIsn) { - panic("Is stalled should have been cleared by stalling load!\n"); - stalled = false; - stallingStoreIsn = 0; - } - -// storeQueue[store_idx].inst->squashed = true; - storeQueue[store_idx].inst = NULL; - storeQueue[store_idx].canWB = 0; - - if (storeQueue[store_idx].req) { - assert(!storeQueue[store_idx].req->completionEvent); - } - storeQueue[store_idx].req = NULL; - --stores; - - // Inefficient! - storeTail = store_idx; - - decrStIdx(store_idx); - } -} - -template <class Impl> -void -OzoneLSQ<Impl>::dumpInsts() -{ - cprintf("Load store queue: Dumping instructions.\n"); - cprintf("Load queue size: %i\n", loads); - cprintf("Load queue: "); - - int load_idx = loadHead; - - while (load_idx != loadTail && loadQueue[load_idx]) { - cprintf("[sn:%lli] %#x ", loadQueue[load_idx]->seqNum, - loadQueue[load_idx]->readPC()); - - incrLdIdx(load_idx); - } - - cprintf("\nStore queue size: %i\n", stores); - cprintf("Store queue: "); - - int store_idx = storeHead; - - while (store_idx != storeTail && storeQueue[store_idx].inst) { - cprintf("[sn:%lli] %#x ", storeQueue[store_idx].inst->seqNum, - storeQueue[store_idx].inst->readPC()); - - incrStIdx(store_idx); - } - - cprintf("\n"); -} - -template <class Impl> -void -OzoneLSQ<Impl>::completeStore(int store_idx) -{ - assert(storeQueue[store_idx].inst); - storeQueue[store_idx].completed = true; - --storesToWB; - // A bit conservative because a store completion may not free up entries, - // but hopefully avoids two store completions in one cycle from making - // the CPU tick twice. -// cpu->activityThisCycle(); - - if (store_idx == storeHead) { - do { - incrStIdx(storeHead); - - --stores; - } while (storeQueue[storeHead].completed && - storeHead != storeTail); - -// be->updateLSQNextCycle = true; - } - - DPRINTF(OzoneLSQ, "Store head idx:%i\n", storeHead); - - if (isStalled() && - storeQueue[store_idx].inst->seqNum == stallingStoreIsn) { - DPRINTF(OzoneLSQ, "Unstalling, stalling store [sn:%lli] " - "load idx:%i\n", - stallingStoreIsn, stallingLoadIdx); - stalled = false; - stallingStoreIsn = 0; - be->replayMemInst(loadQueue[stallingLoadIdx]); - } -} - -template <class Impl> -inline void -OzoneLSQ<Impl>::incrStIdx(int &store_idx) -{ - if (++store_idx >= SQEntries) - store_idx = 0; -} - -template <class Impl> -inline void -OzoneLSQ<Impl>::decrStIdx(int &store_idx) -{ - if (--store_idx < 0) - store_idx += SQEntries; -} - -template <class Impl> -inline void -OzoneLSQ<Impl>::incrLdIdx(int &load_idx) -{ - if (++load_idx >= LQEntries) - load_idx = 0; -} - -template <class Impl> -inline void -OzoneLSQ<Impl>::decrLdIdx(int &load_idx) -{ - if (--load_idx < 0) - load_idx += LQEntries; -} diff --git a/cpu/ozone/lw_back_end.cc b/cpu/ozone/lw_back_end.cc deleted file mode 100644 index 8e9a56ef5..000000000 --- a/cpu/ozone/lw_back_end.cc +++ /dev/null @@ -1,5 +0,0 @@ - -#include "cpu/ozone/lw_back_end_impl.hh" -#include "cpu/ozone/ozone_impl.hh" - -template class LWBackEnd<OzoneImpl>; diff --git a/cpu/ozone/lw_back_end.hh b/cpu/ozone/lw_back_end.hh deleted file mode 100644 index 1c03ffb73..000000000 --- a/cpu/ozone/lw_back_end.hh +++ /dev/null @@ -1,473 +0,0 @@ -/* - * Copyright (c) 2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_OZONE_LW_BACK_END_HH__ -#define __CPU_OZONE_LW_BACK_END_HH__ - -#include <list> -#include <queue> -#include <set> -#include <string> - -#include "arch/faults.hh" -#include "base/timebuf.hh" -#include "cpu/inst_seq.hh" -#include "cpu/ozone/rename_table.hh" -#include "cpu/ozone/thread_state.hh" -#include "mem/functional/functional.hh" -#include "mem/mem_interface.hh" -#include "mem/mem_req.hh" -#include "sim/eventq.hh" - -template <class> -class Checker; -class ExecContext; - -template <class Impl> -class OzoneThreadState; - -template <class Impl> -class LWBackEnd -{ - public: - typedef OzoneThreadState<Impl> Thread; - - typedef typename Impl::Params Params; - typedef typename Impl::DynInst DynInst; - typedef typename Impl::DynInstPtr DynInstPtr; - typedef typename Impl::FullCPU FullCPU; - typedef typename Impl::FrontEnd FrontEnd; - typedef typename Impl::FullCPU::CommStruct CommStruct; - - struct SizeStruct { - int size; - }; - - typedef SizeStruct DispatchToIssue; - typedef SizeStruct IssueToExec; - typedef SizeStruct ExecToCommit; - typedef SizeStruct Writeback; - - TimeBuffer<DispatchToIssue> d2i; - typename TimeBuffer<DispatchToIssue>::wire instsToDispatch; - TimeBuffer<IssueToExec> i2e; - typename TimeBuffer<IssueToExec>::wire instsToExecute; - TimeBuffer<ExecToCommit> e2c; - TimeBuffer<Writeback> numInstsToWB; - - TimeBuffer<CommStruct> *comm; - typename TimeBuffer<CommStruct>::wire toIEW; - typename TimeBuffer<CommStruct>::wire fromCommit; - - class TrapEvent : public Event { - private: - LWBackEnd<Impl> *be; - - public: - TrapEvent(LWBackEnd<Impl> *_be); - - void process(); - const char *description(); - }; - - /** LdWriteback event for a load completion. */ - class LdWritebackEvent : public Event { - private: - /** Instruction that is writing back data to the register file. */ - DynInstPtr inst; - /** Pointer to IEW stage. */ - LWBackEnd *be; - - bool dcacheMiss; - - public: - /** Constructs a load writeback event. */ - LdWritebackEvent(DynInstPtr &_inst, LWBackEnd *be); - - /** Processes writeback event. */ - virtual void process(); - /** Returns the description of the writeback event. */ - virtual const char *description(); - - void setDcacheMiss() { dcacheMiss = true; be->addDcacheMiss(inst); } - }; - - LWBackEnd(Params *params); - - std::string name() const; - - void regStats(); - - void setCPU(FullCPU *cpu_ptr); - - void setFrontEnd(FrontEnd *front_end_ptr) - { frontEnd = front_end_ptr; } - - void setXC(ExecContext *xc_ptr) - { xc = xc_ptr; } - - void setThreadState(Thread *thread_ptr) - { thread = thread_ptr; } - - void setCommBuffer(TimeBuffer<CommStruct> *_comm); - - void tick(); - void squash(); - void generateXCEvent() { xcSquash = true; } - void squashFromXC(); - void squashFromTrap(); - void checkInterrupts(); - bool trapSquash; - bool xcSquash; - - template <class T> - Fault read(MemReqPtr &req, T &data, int load_idx); - - template <class T> - Fault write(MemReqPtr &req, T &data, int store_idx); - - Addr readCommitPC() { return commitPC; } - - Addr commitPC; - - Tick lastCommitCycle; - - bool robEmpty() { return instList.empty(); } - - bool isFull() { return numInsts >= numROBEntries; } - bool isBlocked() { return status == Blocked || dispatchStatus == Blocked; } - - void fetchFault(Fault &fault); - - int wakeDependents(DynInstPtr &inst, bool memory_deps = false); - - /** Tells memory dependence unit that a memory instruction needs to be - * rescheduled. It will re-execute once replayMemInst() is called. - */ - void rescheduleMemInst(DynInstPtr &inst); - - /** Re-executes all rescheduled memory instructions. */ - void replayMemInst(DynInstPtr &inst); - - /** Completes memory instruction. */ - void completeMemInst(DynInstPtr &inst) { } - - void addDcacheMiss(DynInstPtr &inst) - { - waitingMemOps.insert(inst->seqNum); - numWaitingMemOps++; - DPRINTF(BE, "Adding a Dcache miss mem op [sn:%lli], total %i\n", - inst->seqNum, numWaitingMemOps); - } - - void removeDcacheMiss(DynInstPtr &inst) - { - assert(waitingMemOps.find(inst->seqNum) != waitingMemOps.end()); - waitingMemOps.erase(inst->seqNum); - numWaitingMemOps--; - DPRINTF(BE, "Removing a Dcache miss mem op [sn:%lli], total %i\n", - inst->seqNum, numWaitingMemOps); - } - - void addWaitingMemOp(DynInstPtr &inst) - { - waitingMemOps.insert(inst->seqNum); - numWaitingMemOps++; - DPRINTF(BE, "Adding a waiting mem op [sn:%lli], total %i\n", - inst->seqNum, numWaitingMemOps); - } - - void removeWaitingMemOp(DynInstPtr &inst) - { - assert(waitingMemOps.find(inst->seqNum) != waitingMemOps.end()); - waitingMemOps.erase(inst->seqNum); - numWaitingMemOps--; - DPRINTF(BE, "Removing a waiting mem op [sn:%lli], total %i\n", - inst->seqNum, numWaitingMemOps); - } - - void instToCommit(DynInstPtr &inst); - - void switchOut(); - void doSwitchOut(); - void takeOverFrom(ExecContext *old_xc = NULL); - - bool isSwitchedOut() { return switchedOut; } - - private: - void generateTrapEvent(Tick latency = 0); - void handleFault(Fault &fault, Tick latency = 0); - void updateStructures(); - void dispatchInsts(); - void dispatchStall(); - void checkDispatchStatus(); - void executeInsts(); - void commitInsts(); - void addToLSQ(DynInstPtr &inst); - void writebackInsts(); - bool commitInst(int inst_num); - void squash(const InstSeqNum &sn); - void squashDueToBranch(DynInstPtr &inst); - void squashDueToMemViolation(DynInstPtr &inst); - void squashDueToMemBlocked(DynInstPtr &inst); - void updateExeInstStats(DynInstPtr &inst); - void updateComInstStats(DynInstPtr &inst); - - public: - FullCPU *cpu; - - FrontEnd *frontEnd; - - ExecContext *xc; - - Thread *thread; - - enum Status { - Running, - Idle, - DcacheMissStall, - DcacheMissComplete, - Blocked, - TrapPending - }; - - Status status; - - Status dispatchStatus; - - Status commitStatus; - - Counter funcExeInst; - - private: - typedef typename Impl::LdstQueue LdstQueue; - - LdstQueue LSQ; - public: - RenameTable<Impl> commitRenameTable; - - RenameTable<Impl> renameTable; - private: - class DCacheCompletionEvent : public Event - { - private: - LWBackEnd *be; - - public: - DCacheCompletionEvent(LWBackEnd *_be); - - virtual void process(); - virtual const char *description(); - }; - - friend class DCacheCompletionEvent; - - DCacheCompletionEvent cacheCompletionEvent; - - MemInterface *dcacheInterface; - - MemReqPtr memReq; - - // General back end width. Used if the more specific isn't given. - int width; - - // Dispatch width. - int dispatchWidth; - int numDispatchEntries; - int dispatchSize; - - int waitingInsts; - - int issueWidth; - - // Writeback width - int wbWidth; - - // Commit width - int commitWidth; - - /** Index into queue of instructions being written back. */ - unsigned wbNumInst; - - /** Cycle number within the queue of instructions being written - * back. Used in case there are too many instructions writing - * back at the current cycle and writesbacks need to be scheduled - * for the future. See comments in instToCommit(). - */ - unsigned wbCycle; - - int numROBEntries; - int numInsts; - - std::set<InstSeqNum> waitingMemOps; - typedef std::set<InstSeqNum>::iterator MemIt; - int numWaitingMemOps; - unsigned maxOutstandingMemOps; - - bool squashPending; - InstSeqNum squashSeqNum; - Addr squashNextPC; - - Fault faultFromFetch; - bool fetchHasFault; - - bool switchedOut; - bool switchPending; - - DynInstPtr memBarrier; - - private: - struct pqCompare { - bool operator() (const DynInstPtr &lhs, const DynInstPtr &rhs) const - { - return lhs->seqNum > rhs->seqNum; - } - }; - - typedef typename std::priority_queue<DynInstPtr, std::vector<DynInstPtr>, pqCompare> ReadyInstQueue; - ReadyInstQueue exeList; - - typedef typename std::list<DynInstPtr>::iterator InstListIt; - - std::list<DynInstPtr> instList; - std::list<DynInstPtr> waitingList; - std::list<DynInstPtr> replayList; - std::list<DynInstPtr> writeback; - - int latency; - - int squashLatency; - - bool exactFullStall; - - // number of cycles stalled for D-cache misses -/* Stats::Scalar<> dcacheStallCycles; - Counter lastDcacheStall; -*/ - Stats::Vector<> rob_cap_events; - Stats::Vector<> rob_cap_inst_count; - Stats::Vector<> iq_cap_events; - Stats::Vector<> iq_cap_inst_count; - // total number of instructions executed - Stats::Vector<> exe_inst; - Stats::Vector<> exe_swp; - Stats::Vector<> exe_nop; - Stats::Vector<> exe_refs; - Stats::Vector<> exe_loads; - Stats::Vector<> exe_branches; - - Stats::Vector<> issued_ops; - - // total number of loads forwaded from LSQ stores - Stats::Vector<> lsq_forw_loads; - - // total number of loads ignored due to invalid addresses - Stats::Vector<> inv_addr_loads; - - // total number of software prefetches ignored due to invalid addresses - Stats::Vector<> inv_addr_swpfs; - // ready loads blocked due to memory disambiguation - Stats::Vector<> lsq_blocked_loads; - - Stats::Scalar<> lsqInversion; - - Stats::Vector<> n_issued_dist; - Stats::VectorDistribution<> issue_delay_dist; - - Stats::VectorDistribution<> queue_res_dist; -/* - Stats::Vector<> stat_fu_busy; - Stats::Vector2d<> stat_fuBusy; - Stats::Vector<> dist_unissued; - Stats::Vector2d<> stat_issued_inst_type; - - Stats::Formula misspec_cnt; - Stats::Formula misspec_ipc; - Stats::Formula issue_rate; - Stats::Formula issue_stores; - Stats::Formula issue_op_rate; - Stats::Formula fu_busy_rate; - Stats::Formula commit_stores; - Stats::Formula commit_ipc; - Stats::Formula commit_ipb; - Stats::Formula lsq_inv_rate; -*/ - Stats::Vector<> writeback_count; - Stats::Vector<> producer_inst; - Stats::Vector<> consumer_inst; - Stats::Vector<> wb_penalized; - - Stats::Formula wb_rate; - Stats::Formula wb_fanout; - Stats::Formula wb_penalized_rate; - - // total number of instructions committed - Stats::Vector<> stat_com_inst; - Stats::Vector<> stat_com_swp; - Stats::Vector<> stat_com_refs; - Stats::Vector<> stat_com_loads; - Stats::Vector<> stat_com_membars; - Stats::Vector<> stat_com_branches; - - Stats::Distribution<> n_committed_dist; - - Stats::Scalar<> commit_eligible_samples; - Stats::Vector<> commit_eligible; - - Stats::Vector<> squashedInsts; - Stats::Vector<> ROBSquashedInsts; - - Stats::Scalar<> ROB_fcount; - Stats::Formula ROB_full_rate; - - Stats::Vector<> ROB_count; // cumulative ROB occupancy - Stats::Formula ROB_occ_rate; - Stats::VectorDistribution<> ROB_occ_dist; - public: - void dumpInsts(); - - Checker<DynInstPtr> *checker; -}; - -template <class Impl> -template <class T> -Fault -LWBackEnd<Impl>::read(MemReqPtr &req, T &data, int load_idx) -{ - return LSQ.read(req, data, load_idx); -} - -template <class Impl> -template <class T> -Fault -LWBackEnd<Impl>::write(MemReqPtr &req, T &data, int store_idx) -{ - return LSQ.write(req, data, store_idx); -} - -#endif // __CPU_OZONE_LW_BACK_END_HH__ diff --git a/cpu/ozone/lw_back_end_impl.hh b/cpu/ozone/lw_back_end_impl.hh deleted file mode 100644 index 41b4ea24b..000000000 --- a/cpu/ozone/lw_back_end_impl.hh +++ /dev/null @@ -1,1693 +0,0 @@ -/* - * Copyright (c) 2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/checker/cpu.hh" -#include "cpu/ozone/lw_back_end.hh" -#include "encumbered/cpu/full/op_class.hh" - -template <class Impl> -void -LWBackEnd<Impl>::generateTrapEvent(Tick latency) -{ - DPRINTF(BE, "Generating trap event\n"); - - TrapEvent *trap = new TrapEvent(this); - - trap->schedule(curTick + cpu->cycles(latency)); - - thread->trapPending = true; -} - -template <class Impl> -int -LWBackEnd<Impl>::wakeDependents(DynInstPtr &inst, bool memory_deps) -{ - assert(!inst->isSquashed()); - std::vector<DynInstPtr> &dependents = memory_deps ? inst->getMemDeps() : - inst->getDependents(); - int num_outputs = dependents.size(); - - DPRINTF(BE, "Waking instruction [sn:%lli] dependents in IQ\n", inst->seqNum); - - for (int i = 0; i < num_outputs; i++) { - DynInstPtr dep_inst = dependents[i]; - if (!memory_deps) { - dep_inst->markSrcRegReady(); - } else { - if (!dep_inst->isSquashed()) - dep_inst->markMemInstReady(inst.get()); - } - - DPRINTF(BE, "Marking source reg ready [sn:%lli] in IQ\n", dep_inst->seqNum); - - if (dep_inst->readyToIssue() && dep_inst->isInROB() && - !dep_inst->isNonSpeculative() && !dep_inst->isStoreConditional() && - dep_inst->memDepReady() && !dep_inst->isMemBarrier() && - !dep_inst->isWriteBarrier()) { - DPRINTF(BE, "Adding instruction to exeList [sn:%lli]\n", - dep_inst->seqNum); - exeList.push(dep_inst); - if (dep_inst->iqItValid) { - DPRINTF(BE, "Removing instruction from waiting list\n"); - waitingList.erase(dep_inst->iqIt); - waitingInsts--; - dep_inst->iqItValid = false; - assert(waitingInsts >= 0); - } - if (dep_inst->isMemRef()) { - removeWaitingMemOp(dep_inst); - DPRINTF(BE, "Issued a waiting mem op [sn:%lli]\n", - dep_inst->seqNum); - } - } - } - return num_outputs; -} - -template <class Impl> -void -LWBackEnd<Impl>::rescheduleMemInst(DynInstPtr &inst) -{ - replayList.push_front(inst); -} - -template <class Impl> -LWBackEnd<Impl>::TrapEvent::TrapEvent(LWBackEnd<Impl> *_be) - : Event(&mainEventQueue, CPU_Tick_Pri), be(_be) -{ - this->setFlags(Event::AutoDelete); -} - -template <class Impl> -void -LWBackEnd<Impl>::TrapEvent::process() -{ - be->trapSquash = true; -} - -template <class Impl> -const char * -LWBackEnd<Impl>::TrapEvent::description() -{ - return "Trap event"; -} - -template <class Impl> -void -LWBackEnd<Impl>::replayMemInst(DynInstPtr &inst) -{ - bool found_inst = false; - while (!replayList.empty()) { - exeList.push(replayList.front()); - if (replayList.front() == inst) { - found_inst = true; - } - replayList.pop_front(); - } - assert(found_inst); -} - -template<class Impl> -LWBackEnd<Impl>::LdWritebackEvent::LdWritebackEvent(DynInstPtr &_inst, - LWBackEnd<Impl> *_be) - : Event(&mainEventQueue), inst(_inst), be(_be), dcacheMiss(false) -{ - this->setFlags(Event::AutoDelete); -} - -template<class Impl> -void -LWBackEnd<Impl>::LdWritebackEvent::process() -{ - DPRINTF(BE, "Load writeback event [sn:%lli]\n", inst->seqNum); -// DPRINTF(Activity, "Activity: Ld Writeback event [sn:%lli]\n", inst->seqNum); - - //iewStage->ldstQueue.removeMSHR(inst->threadNumber,inst->seqNum); - -// iewStage->wakeCPU(); - - if (be->isSwitchedOut()) - return; - - if (dcacheMiss) { - be->removeDcacheMiss(inst); - } - - if (inst->isSquashed()) { - inst = NULL; - return; - } - - if (!inst->isExecuted()) { - inst->setExecuted(); - - // Execute again to copy data to proper place. - inst->completeAcc(); - } - - // Need to insert instruction into queue to commit - be->instToCommit(inst); - - //wroteToTimeBuffer = true; -// iewStage->activityThisCycle(); - - inst = NULL; -} - -template<class Impl> -const char * -LWBackEnd<Impl>::LdWritebackEvent::description() -{ - return "Load writeback event"; -} - - -template <class Impl> -LWBackEnd<Impl>::DCacheCompletionEvent::DCacheCompletionEvent(LWBackEnd *_be) - : Event(&mainEventQueue, CPU_Tick_Pri), be(_be) -{ -} - -template <class Impl> -void -LWBackEnd<Impl>::DCacheCompletionEvent::process() -{ -} - -template <class Impl> -const char * -LWBackEnd<Impl>::DCacheCompletionEvent::description() -{ - return "Cache completion event"; -} - -template <class Impl> -LWBackEnd<Impl>::LWBackEnd(Params *params) - : d2i(5, 5), i2e(5, 5), e2c(5, 5), numInstsToWB(5, 5), - trapSquash(false), xcSquash(false), cacheCompletionEvent(this), - dcacheInterface(params->dcacheInterface), width(params->backEndWidth), - exactFullStall(true) -{ - numROBEntries = params->numROBEntries; - numInsts = 0; - numDispatchEntries = 32; - maxOutstandingMemOps = params->maxOutstandingMemOps; - numWaitingMemOps = 0; - waitingInsts = 0; - switchedOut = false; - switchPending = false; - - LSQ.setBE(this); - - // Setup IQ and LSQ with their parameters here. - instsToDispatch = d2i.getWire(-1); - - instsToExecute = i2e.getWire(-1); - - dispatchWidth = params->dispatchWidth ? params->dispatchWidth : width; - issueWidth = params->issueWidth ? params->issueWidth : width; - wbWidth = params->wbWidth ? params->wbWidth : width; - commitWidth = params->commitWidth ? params->commitWidth : width; - - LSQ.init(params, params->LQEntries, params->SQEntries, 0); - - dispatchStatus = Running; -} - -template <class Impl> -std::string -LWBackEnd<Impl>::name() const -{ - return cpu->name() + ".backend"; -} - -template <class Impl> -void -LWBackEnd<Impl>::regStats() -{ - using namespace Stats; - rob_cap_events - .init(cpu->number_of_threads) - .name(name() + ".ROB:cap_events") - .desc("number of cycles where ROB cap was active") - .flags(total) - ; - - rob_cap_inst_count - .init(cpu->number_of_threads) - .name(name() + ".ROB:cap_inst") - .desc("number of instructions held up by ROB cap") - .flags(total) - ; - - iq_cap_events - .init(cpu->number_of_threads) - .name(name() +".IQ:cap_events" ) - .desc("number of cycles where IQ cap was active") - .flags(total) - ; - - iq_cap_inst_count - .init(cpu->number_of_threads) - .name(name() + ".IQ:cap_inst") - .desc("number of instructions held up by IQ cap") - .flags(total) - ; - - - exe_inst - .init(cpu->number_of_threads) - .name(name() + ".ISSUE:count") - .desc("number of insts issued") - .flags(total) - ; - - exe_swp - .init(cpu->number_of_threads) - .name(name() + ".ISSUE:swp") - .desc("number of swp insts issued") - .flags(total) - ; - - exe_nop - .init(cpu->number_of_threads) - .name(name() + ".ISSUE:nop") - .desc("number of nop insts issued") - .flags(total) - ; - - exe_refs - .init(cpu->number_of_threads) - .name(name() + ".ISSUE:refs") - .desc("number of memory reference insts issued") - .flags(total) - ; - - exe_loads - .init(cpu->number_of_threads) - .name(name() + ".ISSUE:loads") - .desc("number of load insts issued") - .flags(total) - ; - - exe_branches - .init(cpu->number_of_threads) - .name(name() + ".ISSUE:branches") - .desc("Number of branches issued") - .flags(total) - ; - - issued_ops - .init(cpu->number_of_threads) - .name(name() + ".ISSUE:op_count") - .desc("number of insts issued") - .flags(total) - ; - -/* - for (int i=0; i<Num_OpClasses; ++i) { - stringstream subname; - subname << opClassStrings[i] << "_delay"; - issue_delay_dist.subname(i, subname.str()); - } -*/ - // - // Other stats - // - lsq_forw_loads - .init(cpu->number_of_threads) - .name(name() + ".LSQ:forw_loads") - .desc("number of loads forwarded via LSQ") - .flags(total) - ; - - inv_addr_loads - .init(cpu->number_of_threads) - .name(name() + ".ISSUE:addr_loads") - .desc("number of invalid-address loads") - .flags(total) - ; - - inv_addr_swpfs - .init(cpu->number_of_threads) - .name(name() + ".ISSUE:addr_swpfs") - .desc("number of invalid-address SW prefetches") - .flags(total) - ; - - lsq_blocked_loads - .init(cpu->number_of_threads) - .name(name() + ".LSQ:blocked_loads") - .desc("number of ready loads not issued due to memory disambiguation") - .flags(total) - ; - - lsqInversion - .name(name() + ".ISSUE:lsq_invert") - .desc("Number of times LSQ instruction issued early") - ; - - n_issued_dist - .init(issueWidth + 1) - .name(name() + ".ISSUE:issued_per_cycle") - .desc("Number of insts issued each cycle") - .flags(total | pdf | dist) - ; - issue_delay_dist - .init(Num_OpClasses,0,99,2) - .name(name() + ".ISSUE:") - .desc("cycles from operands ready to issue") - .flags(pdf | cdf) - ; - - queue_res_dist - .init(Num_OpClasses, 0, 99, 2) - .name(name() + ".IQ:residence:") - .desc("cycles from dispatch to issue") - .flags(total | pdf | cdf ) - ; - for (int i = 0; i < Num_OpClasses; ++i) { - queue_res_dist.subname(i, opClassStrings[i]); - } - - writeback_count - .init(cpu->number_of_threads) - .name(name() + ".WB:count") - .desc("cumulative count of insts written-back") - .flags(total) - ; - - producer_inst - .init(cpu->number_of_threads) - .name(name() + ".WB:producers") - .desc("num instructions producing a value") - .flags(total) - ; - - consumer_inst - .init(cpu->number_of_threads) - .name(name() + ".WB:consumers") - .desc("num instructions consuming a value") - .flags(total) - ; - - wb_penalized - .init(cpu->number_of_threads) - .name(name() + ".WB:penalized") - .desc("number of instrctions required to write to 'other' IQ") - .flags(total) - ; - - - wb_penalized_rate - .name(name() + ".WB:penalized_rate") - .desc ("fraction of instructions written-back that wrote to 'other' IQ") - .flags(total) - ; - - wb_penalized_rate = wb_penalized / writeback_count; - - wb_fanout - .name(name() + ".WB:fanout") - .desc("average fanout of values written-back") - .flags(total) - ; - - wb_fanout = producer_inst / consumer_inst; - - wb_rate - .name(name() + ".WB:rate") - .desc("insts written-back per cycle") - .flags(total) - ; - wb_rate = writeback_count / cpu->numCycles; - - stat_com_inst - .init(cpu->number_of_threads) - .name(name() + ".COM:count") - .desc("Number of instructions committed") - .flags(total) - ; - - stat_com_swp - .init(cpu->number_of_threads) - .name(name() + ".COM:swp_count") - .desc("Number of s/w prefetches committed") - .flags(total) - ; - - stat_com_refs - .init(cpu->number_of_threads) - .name(name() + ".COM:refs") - .desc("Number of memory references committed") - .flags(total) - ; - - stat_com_loads - .init(cpu->number_of_threads) - .name(name() + ".COM:loads") - .desc("Number of loads committed") - .flags(total) - ; - - stat_com_membars - .init(cpu->number_of_threads) - .name(name() + ".COM:membars") - .desc("Number of memory barriers committed") - .flags(total) - ; - - stat_com_branches - .init(cpu->number_of_threads) - .name(name() + ".COM:branches") - .desc("Number of branches committed") - .flags(total) - ; - n_committed_dist - .init(0,commitWidth,1) - .name(name() + ".COM:committed_per_cycle") - .desc("Number of insts commited each cycle") - .flags(pdf) - ; - - // - // Commit-Eligible instructions... - // - // -> The number of instructions eligible to commit in those - // cycles where we reached our commit BW limit (less the number - // actually committed) - // - // -> The average value is computed over ALL CYCLES... not just - // the BW limited cycles - // - // -> The standard deviation is computed only over cycles where - // we reached the BW limit - // - commit_eligible - .init(cpu->number_of_threads) - .name(name() + ".COM:bw_limited") - .desc("number of insts not committed due to BW limits") - .flags(total) - ; - - commit_eligible_samples - .name(name() + ".COM:bw_lim_events") - .desc("number cycles where commit BW limit reached") - ; - - squashedInsts - .init(cpu->number_of_threads) - .name(name() + ".COM:squashed_insts") - .desc("Number of instructions removed from inst list") - ; - - ROBSquashedInsts - .init(cpu->number_of_threads) - .name(name() + ".COM:rob_squashed_insts") - .desc("Number of instructions removed from inst list when they reached the head of the ROB") - ; - - ROB_fcount - .name(name() + ".ROB:full_count") - .desc("number of cycles where ROB was full") - ; - - ROB_count - .init(cpu->number_of_threads) - .name(name() + ".ROB:occupancy") - .desc(name() + ".ROB occupancy (cumulative)") - .flags(total) - ; - - ROB_full_rate - .name(name() + ".ROB:full_rate") - .desc("ROB full per cycle") - ; - ROB_full_rate = ROB_fcount / cpu->numCycles; - - ROB_occ_rate - .name(name() + ".ROB:occ_rate") - .desc("ROB occupancy rate") - .flags(total) - ; - ROB_occ_rate = ROB_count / cpu->numCycles; - - ROB_occ_dist - .init(cpu->number_of_threads,0,numROBEntries,2) - .name(name() + ".ROB:occ_dist") - .desc("ROB Occupancy per cycle") - .flags(total | cdf) - ; -} - -template <class Impl> -void -LWBackEnd<Impl>::setCPU(FullCPU *cpu_ptr) -{ - cpu = cpu_ptr; - LSQ.setCPU(cpu_ptr); - checker = cpu->checker; -} - -template <class Impl> -void -LWBackEnd<Impl>::setCommBuffer(TimeBuffer<CommStruct> *_comm) -{ - comm = _comm; - toIEW = comm->getWire(0); - fromCommit = comm->getWire(-1); -} - -#if FULL_SYSTEM -template <class Impl> -void -LWBackEnd<Impl>::checkInterrupts() -{ - if (cpu->checkInterrupts && - cpu->check_interrupts() && - !cpu->inPalMode(thread->readPC()) && - !trapSquash && - !xcSquash) { - frontEnd->interruptPending = true; - if (robEmpty() && !LSQ.hasStoresToWB()) { - // Will need to squash all instructions currently in flight and have - // the interrupt handler restart at the last non-committed inst. - // Most of that can be handled through the trap() function. The - // processInterrupts() function really just checks for interrupts - // and then calls trap() if there is an interrupt present. - - // Not sure which thread should be the one to interrupt. For now - // always do thread 0. - assert(!thread->inSyscall); - thread->inSyscall = true; - - // CPU will handle implementation of the interrupt. - cpu->processInterrupts(); - - // Now squash or record that I need to squash this cycle. - commitStatus = TrapPending; - - // Exit state update mode to avoid accidental updating. - thread->inSyscall = false; - - // Generate trap squash event. - generateTrapEvent(); - - DPRINTF(BE, "Interrupt detected.\n"); - } else { - DPRINTF(BE, "Interrupt must wait for ROB to drain.\n"); - } - } -} - -template <class Impl> -void -LWBackEnd<Impl>::handleFault(Fault &fault, Tick latency) -{ - DPRINTF(BE, "Handling fault!\n"); - - assert(!thread->inSyscall); - - thread->inSyscall = true; - - // Consider holding onto the trap and waiting until the trap event - // happens for this to be executed. - fault->invoke(thread->getXCProxy()); - - // Exit state update mode to avoid accidental updating. - thread->inSyscall = false; - - commitStatus = TrapPending; - - // Generate trap squash event. - generateTrapEvent(latency); -} -#endif - -template <class Impl> -void -LWBackEnd<Impl>::tick() -{ - DPRINTF(BE, "Ticking back end\n"); - - if (switchPending && robEmpty() && !LSQ.hasStoresToWB()) { - cpu->signalSwitched(); - return; - } - - ROB_count[0]+= numInsts; - - wbCycle = 0; - - // Read in any done instruction information and update the IQ or LSQ. - updateStructures(); - -#if FULL_SYSTEM - checkInterrupts(); - - if (trapSquash) { - assert(!xcSquash); - squashFromTrap(); - } else if (xcSquash) { - squashFromXC(); - } -#endif - - if (dispatchStatus != Blocked) { - dispatchInsts(); - } else { - checkDispatchStatus(); - } - - if (commitStatus != TrapPending) { - executeInsts(); - - commitInsts(); - } - - LSQ.writebackStores(); - - DPRINTF(BE, "Waiting insts: %i, mem ops: %i, ROB entries in use: %i, " - "LSQ loads: %i, LSQ stores: %i\n", - waitingInsts, numWaitingMemOps, numInsts, - LSQ.numLoads(), LSQ.numStores()); - -#ifdef DEBUG - assert(numInsts == instList.size()); - assert(waitingInsts == waitingList.size()); - assert(numWaitingMemOps == waitingMemOps.size()); - assert(!switchedOut); -#endif -} - -template <class Impl> -void -LWBackEnd<Impl>::updateStructures() -{ - if (fromCommit->doneSeqNum) { - LSQ.commitLoads(fromCommit->doneSeqNum); - LSQ.commitStores(fromCommit->doneSeqNum); - } - - if (fromCommit->nonSpecSeqNum) { - if (fromCommit->uncached) { -// LSQ.executeLoad(fromCommit->lqIdx); - } else { -// IQ.scheduleNonSpec( -// fromCommit->nonSpecSeqNum); - } - } -} - -template <class Impl> -void -LWBackEnd<Impl>::addToLSQ(DynInstPtr &inst) -{ - // Do anything LSQ specific here? - LSQ.insert(inst); -} - -template <class Impl> -void -LWBackEnd<Impl>::dispatchInsts() -{ - DPRINTF(BE, "Trying to dispatch instructions.\n"); - - while (numInsts < numROBEntries && - numWaitingMemOps < maxOutstandingMemOps) { - // Get instruction from front of time buffer - DynInstPtr inst = frontEnd->getInst(); - if (!inst) { - break; - } else if (inst->isSquashed()) { - continue; - } - - ++numInsts; - instList.push_front(inst); - - inst->setInROB(); - - DPRINTF(BE, "Dispatching instruction [sn:%lli] PC:%#x\n", - inst->seqNum, inst->readPC()); - - for (int i = 0; i < inst->numDestRegs(); ++i) - renameTable[inst->destRegIdx(i)] = inst; - - if (inst->isMemBarrier() || inst->isWriteBarrier()) { - if (memBarrier) { - DPRINTF(BE, "Instruction [sn:%lli] is waiting on " - "barrier [sn:%lli].\n", - inst->seqNum, memBarrier->seqNum); - memBarrier->addMemDependent(inst); - inst->addSrcMemInst(memBarrier); - } - memBarrier = inst; - inst->setCanCommit(); - } else if (inst->readyToIssue() && - !inst->isNonSpeculative() && - !inst->isStoreConditional()) { - if (inst->isMemRef()) { - - LSQ.insert(inst); - if (memBarrier) { - DPRINTF(BE, "Instruction [sn:%lli] is waiting on " - "barrier [sn:%lli].\n", - inst->seqNum, memBarrier->seqNum); - memBarrier->addMemDependent(inst); - inst->addSrcMemInst(memBarrier); - addWaitingMemOp(inst); - - waitingList.push_front(inst); - inst->iqIt = waitingList.begin(); - inst->iqItValid = true; - waitingInsts++; - } else { - DPRINTF(BE, "Instruction [sn:%lli] ready, addding to " - "exeList.\n", - inst->seqNum); - exeList.push(inst); - } - } else if (inst->isNop()) { - DPRINTF(BE, "Nop encountered [sn:%lli], skipping exeList.\n", - inst->seqNum); - inst->setIssued(); - inst->setExecuted(); - inst->setCanCommit(); - } else { - DPRINTF(BE, "Instruction [sn:%lli] ready, addding to " - "exeList.\n", - inst->seqNum); - exeList.push(inst); - } - } else { - if (inst->isNonSpeculative() || inst->isStoreConditional()) { - inst->setCanCommit(); - DPRINTF(BE, "Adding non speculative instruction\n"); - } - - if (inst->isMemRef()) { - addWaitingMemOp(inst); - LSQ.insert(inst); - if (memBarrier) { - memBarrier->addMemDependent(inst); - inst->addSrcMemInst(memBarrier); - - DPRINTF(BE, "Instruction [sn:%lli] is waiting on " - "barrier [sn:%lli].\n", - inst->seqNum, memBarrier->seqNum); - } - } - - DPRINTF(BE, "Instruction [sn:%lli] not ready, addding to " - "waitingList.\n", - inst->seqNum); - waitingList.push_front(inst); - inst->iqIt = waitingList.begin(); - inst->iqItValid = true; - waitingInsts++; - } - } - - // Check if IQ or LSQ is full. If so we'll need to break and stop - // removing instructions. Also update the number of insts to remove - // from the queue. Check here if we don't care about exact stall - // conditions. -/* - bool stall = false; - if (IQ.isFull()) { - DPRINTF(BE, "IQ is full!\n"); - stall = true; - } else if (LSQ.isFull()) { - DPRINTF(BE, "LSQ is full!\n"); - stall = true; - } else if (isFull()) { - DPRINTF(BE, "ROB is full!\n"); - stall = true; - ROB_fcount++; - } - if (stall) { - d2i.advance(); - dispatchStall(); - return; - } -*/ -} - -template <class Impl> -void -LWBackEnd<Impl>::dispatchStall() -{ - dispatchStatus = Blocked; - if (!cpu->decoupledFrontEnd) { - // Tell front end to stall here through a timebuffer, or just tell - // it directly. - } -} - -template <class Impl> -void -LWBackEnd<Impl>::checkDispatchStatus() -{ - DPRINTF(BE, "Checking dispatch status\n"); - assert(dispatchStatus == Blocked); - if (!LSQ.isFull() && !isFull()) { - DPRINTF(BE, "Dispatch no longer blocked\n"); - dispatchStatus = Running; - dispatchInsts(); - } -} - -template <class Impl> -void -LWBackEnd<Impl>::executeInsts() -{ - DPRINTF(BE, "Trying to execute instructions\n"); - - int num_executed = 0; - while (!exeList.empty() && num_executed < issueWidth) { - DynInstPtr inst = exeList.top(); - - DPRINTF(BE, "Executing inst [sn:%lli] PC: %#x\n", - inst->seqNum, inst->readPC()); - - // Check if the instruction is squashed; if so then skip it - // and don't count it towards the FU usage. - if (inst->isSquashed()) { - DPRINTF(BE, "Execute: Instruction was squashed.\n"); - - // Not sure how to handle this plus the method of sending # of - // instructions to use. Probably will just have to count it - // towards the bandwidth usage, but not the FU usage. - ++num_executed; - - // Consider this instruction executed so that commit can go - // ahead and retire the instruction. - inst->setExecuted(); - - // Not sure if I should set this here or just let commit try to - // commit any squashed instructions. I like the latter a bit more. - inst->setCanCommit(); - -// ++iewExecSquashedInsts; - exeList.pop(); - - continue; - } - - Fault fault = NoFault; - - // Execute instruction. - // Note that if the instruction faults, it will be handled - // at the commit stage. - if (inst->isMemRef() && - (!inst->isDataPrefetch() && !inst->isInstPrefetch())) { - if (dcacheInterface->isBlocked()) { - // Should I move the instruction aside? - DPRINTF(BE, "Execute: dcache is blocked\n"); - break; - } - DPRINTF(BE, "Execute: Initiating access for memory " - "reference.\n"); - - if (inst->isLoad()) { - LSQ.executeLoad(inst); - } else if (inst->isStore()) { - LSQ.executeStore(inst); - if (inst->req && !(inst->req->flags & LOCKED)) { - inst->setExecuted(); - - instToCommit(inst); - } - } else { - panic("Unknown mem type!"); - } - } else { - inst->execute(); - - inst->setExecuted(); - - instToCommit(inst); - } - - updateExeInstStats(inst); - - ++funcExeInst; - ++num_executed; - - exeList.pop(); - - if (inst->mispredicted()) { - squashDueToBranch(inst); - break; - } else if (LSQ.violation()) { - // Get the DynInst that caused the violation. Note that this - // clears the violation signal. - DynInstPtr violator; - violator = LSQ.getMemDepViolator(); - - DPRINTF(BE, "LDSTQ detected a violation. Violator PC: " - "%#x, inst PC: %#x. Addr is: %#x.\n", - violator->readPC(), inst->readPC(), inst->physEffAddr); - - // Squash. - squashDueToMemViolation(inst); - } - } - - issued_ops[0]+= num_executed; - n_issued_dist[num_executed]++; -} - -template<class Impl> -void -LWBackEnd<Impl>::instToCommit(DynInstPtr &inst) -{ - - DPRINTF(BE, "Sending instructions to commit [sn:%lli] PC %#x.\n", - inst->seqNum, inst->readPC()); - - if (!inst->isSquashed()) { - DPRINTF(BE, "Writing back instruction [sn:%lli] PC %#x.\n", - inst->seqNum, inst->readPC()); - - inst->setCanCommit(); - - if (inst->isExecuted()) { - inst->setResultReady(); - int dependents = wakeDependents(inst); - if (dependents) { - producer_inst[0]++; - consumer_inst[0]+= dependents; - } - } - } - - writeback_count[0]++; -} -#if 0 -template <class Impl> -void -LWBackEnd<Impl>::writebackInsts() -{ - int wb_width = wbWidth; - // Using this method I'm not quite sure how to prevent an - // instruction from waking its own dependents multiple times, - // without the guarantee that commit always has enough bandwidth - // to accept all instructions being written back. This guarantee - // might not be too unrealistic. - InstListIt wb_inst_it = writeback.begin(); - InstListIt wb_end_it = writeback.end(); - int inst_num = 0; - int consumer_insts = 0; - - for (; inst_num < wb_width && - wb_inst_it != wb_end_it; inst_num++) { - DynInstPtr inst = (*wb_inst_it); - - // Some instructions will be sent to commit without having - // executed because they need commit to handle them. - // E.g. Uncached loads have not actually executed when they - // are first sent to commit. Instead commit must tell the LSQ - // when it's ready to execute the uncached load. - if (!inst->isSquashed()) { - DPRINTF(BE, "Writing back instruction [sn:%lli] PC %#x.\n", - inst->seqNum, inst->readPC()); - - inst->setCanCommit(); - inst->setResultReady(); - - if (inst->isExecuted()) { - int dependents = wakeDependents(inst); - if (dependents) { - producer_inst[0]++; - consumer_insts+= dependents; - } - } - } - - writeback.erase(wb_inst_it++); - } - LSQ.writebackStores(); - consumer_inst[0]+= consumer_insts; - writeback_count[0]+= inst_num; -} -#endif -template <class Impl> -bool -LWBackEnd<Impl>::commitInst(int inst_num) -{ - // Read instruction from the head of the ROB - DynInstPtr inst = instList.back(); - - // Make sure instruction is valid - assert(inst); - - if (!inst->readyToCommit()) - return false; - - DPRINTF(BE, "Trying to commit instruction [sn:%lli] PC:%#x\n", - inst->seqNum, inst->readPC()); - - thread->setPC(inst->readPC()); - thread->setNextPC(inst->readNextPC()); - inst->reachedCommit = true; - - // If the instruction is not executed yet, then it is a non-speculative - // or store inst. Signal backwards that it should be executed. - if (!inst->isExecuted()) { - if (inst->isNonSpeculative() || - inst->isStoreConditional() || - inst->isMemBarrier() || - inst->isWriteBarrier()) { -#if !FULL_SYSTEM - // Hack to make sure syscalls aren't executed until all stores - // write back their data. This direct communication shouldn't - // be used for anything other than this. - if (inst_num > 0 || LSQ.hasStoresToWB()) -#else - if ((inst->isMemBarrier() || inst->isWriteBarrier() || - inst->isQuiesce()) && - LSQ.hasStoresToWB()) -#endif - { - DPRINTF(BE, "Waiting for all stores to writeback.\n"); - return false; - } - - DPRINTF(BE, "Encountered a store or non-speculative " - "instruction at the head of the ROB, PC %#x.\n", - inst->readPC()); - - if (inst->isMemBarrier() || inst->isWriteBarrier()) { - DPRINTF(BE, "Waking dependents on barrier [sn:%lli]\n", - inst->seqNum); - assert(memBarrier); - wakeDependents(inst, true); - if (memBarrier == inst) - memBarrier = NULL; - inst->clearMemDependents(); - } - - // Send back the non-speculative instruction's sequence number. - if (inst->iqItValid) { - DPRINTF(BE, "Removing instruction from waiting list\n"); - waitingList.erase(inst->iqIt); - inst->iqItValid = false; - waitingInsts--; - assert(waitingInsts >= 0); - if (inst->isStore()) - removeWaitingMemOp(inst); - } - - exeList.push(inst); - - // Change the instruction so it won't try to commit again until - // it is executed. - inst->clearCanCommit(); - -// ++commitNonSpecStalls; - - return false; - } else if (inst->isLoad()) { - DPRINTF(BE, "[sn:%lli]: Uncached load, PC %#x.\n", - inst->seqNum, inst->readPC()); - - // Send back the non-speculative instruction's sequence - // number. Maybe just tell the lsq to re-execute the load. - - // Send back the non-speculative instruction's sequence number. - if (inst->iqItValid) { - DPRINTF(BE, "Removing instruction from waiting list\n"); - waitingList.erase(inst->iqIt); - inst->iqItValid = false; - waitingInsts--; - assert(waitingInsts >= 0); - removeWaitingMemOp(inst); - } - replayMemInst(inst); - - inst->clearCanCommit(); - - return false; - } else { - panic("Trying to commit un-executed instruction " - "of unknown type!\n"); - } - } - - // Not handled for now. - assert(!inst->isThreadSync()); - assert(inst->memDepReady()); - // Stores will mark themselves as totally completed as they need - // to wait to writeback to memory. @todo: Hack...attempt to fix - // having the checker be forced to wait until a store completes in - // order to check all of the instructions. If the store at the - // head of the check list misses, but a later store hits, then - // loads in the checker may see the younger store values instead - // of the store they should see. Either the checker needs its own - // memory (annoying to update), its own store buffer (how to tell - // which value is correct?), or something else... - if (!inst->isStore()) { - inst->setCompleted(); - } - // Check if the instruction caused a fault. If so, trap. - Fault inst_fault = inst->getFault(); - - // Use checker prior to updating anything due to traps or PC - // based events. - if (checker) { - checker->tick(inst); - } - - if (inst_fault != NoFault) { - DPRINTF(BE, "Inst [sn:%lli] PC %#x has a fault\n", - inst->seqNum, inst->readPC()); - - // Instruction is completed as it has a fault. - inst->setCompleted(); - - if (LSQ.hasStoresToWB()) { - DPRINTF(BE, "Stores still in flight, will wait until drained.\n"); - return false; - } else if (inst_num != 0) { - DPRINTF(BE, "Will wait until instruction is head of commit group.\n"); - return false; - } else if (checker && inst->isStore()) { - checker->tick(inst); - } - - thread->setInst( - static_cast<TheISA::MachInst>(inst->staticInst->machInst)); -#if FULL_SYSTEM - handleFault(inst_fault); - return false; -#else // !FULL_SYSTEM - panic("fault (%d) detected @ PC %08p", inst_fault, - inst->PC); -#endif // FULL_SYSTEM - } - - int freed_regs = 0; - - for (int i = 0; i < inst->numDestRegs(); ++i) { - DPRINTF(BE, "Commit rename map setting reg %i to [sn:%lli]\n", - (int)inst->destRegIdx(i), inst->seqNum); - thread->renameTable[inst->destRegIdx(i)] = inst; - ++freed_regs; - } - - if (inst->traceData) { - inst->traceData->setFetchSeq(inst->seqNum); - inst->traceData->setCPSeq(thread->numInst); - inst->traceData->finalize(); - inst->traceData = NULL; - } - - inst->clearDependents(); - - frontEnd->addFreeRegs(freed_regs); - - instList.pop_back(); - - --numInsts; - ++thread->funcExeInst; - // Maybe move this to where the fault is handled; if the fault is - // handled, don't try to set this myself as the fault will set it. - // If not, then I set thread->PC = thread->nextPC and - // thread->nextPC = thread->nextPC + 4. - thread->setPC(thread->readNextPC()); - thread->setNextPC(thread->readNextPC() + sizeof(TheISA::MachInst)); - updateComInstStats(inst); - - // Write the done sequence number here. - toIEW->doneSeqNum = inst->seqNum; - lastCommitCycle = curTick; - -#if FULL_SYSTEM - int count = 0; - Addr oldpc; - do { - if (count == 0) - assert(!thread->inSyscall && !thread->trapPending); - oldpc = thread->readPC(); - cpu->system->pcEventQueue.service( - thread->getXCProxy()); - count++; - } while (oldpc != thread->readPC()); - if (count > 1) { - DPRINTF(BE, "PC skip function event, stopping commit\n"); - xcSquash = true; - return false; - } -#endif - return true; -} - -template <class Impl> -void -LWBackEnd<Impl>::commitInsts() -{ - // Not sure this should be a loop or not. - int inst_num = 0; - while (!instList.empty() && inst_num < commitWidth) { - if (instList.back()->isSquashed()) { - instList.back()->clearDependents(); - instList.pop_back(); - --numInsts; - ROBSquashedInsts[instList.back()->threadNumber]++; - continue; - } - - if (!commitInst(inst_num++)) { - DPRINTF(BE, "Can't commit, Instruction [sn:%lli] PC " - "%#x is head of ROB and not ready\n", - instList.back()->seqNum, instList.back()->readPC()); - --inst_num; - break; - } - } - n_committed_dist.sample(inst_num); -} - -template <class Impl> -void -LWBackEnd<Impl>::squash(const InstSeqNum &sn) -{ - LSQ.squash(sn); - - int freed_regs = 0; - InstListIt waiting_list_end = waitingList.end(); - InstListIt insts_it = waitingList.begin(); - - while (insts_it != waiting_list_end && (*insts_it)->seqNum > sn) - { - if ((*insts_it)->isSquashed()) { - ++insts_it; - continue; - } - DPRINTF(BE, "Squashing instruction on waitingList PC %#x, [sn:%lli].\n", - (*insts_it)->readPC(), - (*insts_it)->seqNum); - - if ((*insts_it)->isMemRef()) { - DPRINTF(BE, "Squashing a waiting mem op [sn:%lli]\n", - (*insts_it)->seqNum); - removeWaitingMemOp((*insts_it)); - } - - waitingList.erase(insts_it++); - waitingInsts--; - } - assert(waitingInsts >= 0); - - insts_it = instList.begin(); - - while (!instList.empty() && (*insts_it)->seqNum > sn) - { - if ((*insts_it)->isSquashed()) { - ++insts_it; - continue; - } - DPRINTF(BE, "Squashing instruction on inst list PC %#x, [sn:%lli].\n", - (*insts_it)->readPC(), - (*insts_it)->seqNum); - - // Mark the instruction as squashed, and ready to commit so that - // it can drain out of the pipeline. - (*insts_it)->setSquashed(); - - (*insts_it)->setCanCommit(); - - (*insts_it)->removeInROB(); - - for (int i = 0; i < (*insts_it)->numDestRegs(); ++i) { - DynInstPtr prev_dest = (*insts_it)->getPrevDestInst(i); - DPRINTF(BE, "Commit rename map setting reg %i to [sn:%lli]\n", - (int)(*insts_it)->destRegIdx(i), prev_dest->seqNum); - renameTable[(*insts_it)->destRegIdx(i)] = prev_dest; - ++freed_regs; - } - - (*insts_it)->clearDependents(); - - squashedInsts[(*insts_it)->threadNumber]++; - - instList.erase(insts_it++); - --numInsts; - } - - insts_it = waitingList.begin(); - while (!waitingList.empty() && insts_it != waitingList.end()) { - if ((*insts_it)->seqNum < sn) { - ++insts_it; - continue; - } - assert((*insts_it)->isSquashed()); - - waitingList.erase(insts_it++); - waitingInsts--; - } - - while (memBarrier && memBarrier->seqNum > sn) { - DPRINTF(BE, "[sn:%lli] Memory barrier squashed (or previously " - "squashed)\n", memBarrier->seqNum); - memBarrier->clearMemDependents(); - if (memBarrier->memDepReady()) { - DPRINTF(BE, "No previous barrier\n"); - memBarrier = NULL; - } else { - std::list<DynInstPtr> &srcs = memBarrier->getMemSrcs(); - memBarrier = srcs.front(); - srcs.pop_front(); - assert(srcs.empty()); - DPRINTF(BE, "Previous barrier: [sn:%lli]\n", - memBarrier->seqNum); - } - } - - frontEnd->addFreeRegs(freed_regs); -} - -template <class Impl> -void -LWBackEnd<Impl>::squashFromXC() -{ - InstSeqNum squashed_inst = robEmpty() ? 0 : instList.back()->seqNum - 1; - squash(squashed_inst); - frontEnd->squash(squashed_inst, thread->readPC(), - false, false); - frontEnd->interruptPending = false; - - thread->trapPending = false; - thread->inSyscall = false; - xcSquash = false; - commitStatus = Running; -} - -template <class Impl> -void -LWBackEnd<Impl>::squashFromTrap() -{ - InstSeqNum squashed_inst = robEmpty() ? 0 : instList.back()->seqNum - 1; - squash(squashed_inst); - frontEnd->squash(squashed_inst, thread->readPC(), - false, false); - frontEnd->interruptPending = false; - - thread->trapPending = false; - thread->inSyscall = false; - trapSquash = false; - commitStatus = Running; -} - -template <class Impl> -void -LWBackEnd<Impl>::squashDueToBranch(DynInstPtr &inst) -{ - // Update the branch predictor state I guess - DPRINTF(BE, "Squashing due to branch [sn:%lli], will restart at PC %#x\n", - inst->seqNum, inst->readNextPC()); - squash(inst->seqNum); - frontEnd->squash(inst->seqNum, inst->readNextPC(), - true, inst->mispredicted()); -} - -template <class Impl> -void -LWBackEnd<Impl>::squashDueToMemViolation(DynInstPtr &inst) -{ - // Update the branch predictor state I guess - DPRINTF(BE, "Squashing due to violation [sn:%lli], will restart at PC %#x\n", - inst->seqNum, inst->readNextPC()); - squash(inst->seqNum); - frontEnd->squash(inst->seqNum, inst->readNextPC(), - false, inst->mispredicted()); -} - -template <class Impl> -void -LWBackEnd<Impl>::squashDueToMemBlocked(DynInstPtr &inst) -{ - DPRINTF(IEW, "Memory blocked, squashing load and younger insts, " - "PC: %#x [sn:%i].\n", inst->readPC(), inst->seqNum); - - squash(inst->seqNum - 1); - frontEnd->squash(inst->seqNum - 1, inst->readPC()); -} - -template <class Impl> -void -LWBackEnd<Impl>::fetchFault(Fault &fault) -{ - faultFromFetch = fault; - fetchHasFault = true; -} - -template <class Impl> -void -LWBackEnd<Impl>::switchOut() -{ - switchPending = true; -} - -template <class Impl> -void -LWBackEnd<Impl>::doSwitchOut() -{ - switchedOut = true; - switchPending = false; - // Need to get rid of all committed, non-speculative state and write it - // to memory/XC. In this case this is stores that have committed and not - // yet written back. - assert(robEmpty()); - assert(!LSQ.hasStoresToWB()); - - LSQ.switchOut(); - - squash(0); -} - -template <class Impl> -void -LWBackEnd<Impl>::takeOverFrom(ExecContext *old_xc) -{ - switchedOut = false; - xcSquash = false; - trapSquash = false; - - numInsts = 0; - numWaitingMemOps = 0; - waitingMemOps.clear(); - waitingInsts = 0; - switchedOut = false; - dispatchStatus = Running; - commitStatus = Running; - LSQ.takeOverFrom(old_xc); -} - -template <class Impl> -void -LWBackEnd<Impl>::updateExeInstStats(DynInstPtr &inst) -{ - int thread_number = inst->threadNumber; - - // - // Pick off the software prefetches - // -#ifdef TARGET_ALPHA - if (inst->isDataPrefetch()) - exe_swp[thread_number]++; - else - exe_inst[thread_number]++; -#else - exe_inst[thread_number]++; -#endif - - // - // Control operations - // - if (inst->isControl()) - exe_branches[thread_number]++; - - // - // Memory operations - // - if (inst->isMemRef()) { - exe_refs[thread_number]++; - - if (inst->isLoad()) - exe_loads[thread_number]++; - } -} - -template <class Impl> -void -LWBackEnd<Impl>::updateComInstStats(DynInstPtr &inst) -{ - unsigned tid = inst->threadNumber; - - // keep an instruction count - thread->numInst++; - thread->numInsts++; - - cpu->numInst++; - // - // Pick off the software prefetches - // -#ifdef TARGET_ALPHA - if (inst->isDataPrefetch()) { - stat_com_swp[tid]++; - } else { - stat_com_inst[tid]++; - } -#else - stat_com_inst[tid]++; -#endif - - // - // Control Instructions - // - if (inst->isControl()) - stat_com_branches[tid]++; - - // - // Memory references - // - if (inst->isMemRef()) { - stat_com_refs[tid]++; - - if (inst->isLoad()) { - stat_com_loads[tid]++; - } - } - - if (inst->isMemBarrier()) { - stat_com_membars[tid]++; - } -} - -template <class Impl> -void -LWBackEnd<Impl>::dumpInsts() -{ - int num = 0; - int valid_num = 0; - - InstListIt inst_list_it = --(instList.end()); - - cprintf("ExeList size: %i\n", exeList.size()); - - cprintf("Inst list size: %i\n", instList.size()); - - while (inst_list_it != instList.end()) - { - cprintf("Instruction:%i\n", - num); - if (!(*inst_list_it)->isSquashed()) { - if (!(*inst_list_it)->isIssued()) { - ++valid_num; - cprintf("Count:%i\n", valid_num); - } else if ((*inst_list_it)->isMemRef() && - !(*inst_list_it)->memOpDone) { - // Loads that have not been marked as executed still count - // towards the total instructions. - ++valid_num; - cprintf("Count:%i\n", valid_num); - } - } - - cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" - "Issued:%i\nSquashed:%i\n", - (*inst_list_it)->readPC(), - (*inst_list_it)->seqNum, - (*inst_list_it)->threadNumber, - (*inst_list_it)->isIssued(), - (*inst_list_it)->isSquashed()); - - if ((*inst_list_it)->isMemRef()) { - cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone); - } - - cprintf("\n"); - - inst_list_it--; - ++num; - } - - cprintf("Waiting list size: %i\n", waitingList.size()); - - inst_list_it = --(waitingList.end()); - - while (inst_list_it != waitingList.end()) - { - cprintf("Instruction:%i\n", - num); - if (!(*inst_list_it)->isSquashed()) { - if (!(*inst_list_it)->isIssued()) { - ++valid_num; - cprintf("Count:%i\n", valid_num); - } else if ((*inst_list_it)->isMemRef() && - !(*inst_list_it)->memOpDone) { - // Loads that have not been marked as executed still count - // towards the total instructions. - ++valid_num; - cprintf("Count:%i\n", valid_num); - } - } - - cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" - "Issued:%i\nSquashed:%i\n", - (*inst_list_it)->readPC(), - (*inst_list_it)->seqNum, - (*inst_list_it)->threadNumber, - (*inst_list_it)->isIssued(), - (*inst_list_it)->isSquashed()); - - if ((*inst_list_it)->isMemRef()) { - cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone); - } - - cprintf("\n"); - - inst_list_it--; - ++num; - } - - cprintf("waitingMemOps list size: %i\n", waitingMemOps.size()); - - MemIt waiting_it = waitingMemOps.begin(); - - while (waiting_it != waitingMemOps.end()) - { - cprintf("[sn:%lli] ", (*waiting_it)); - waiting_it++; - ++num; - } - cprintf("\n"); -} diff --git a/cpu/ozone/lw_lsq.cc b/cpu/ozone/lw_lsq.cc deleted file mode 100644 index 922228b09..000000000 --- a/cpu/ozone/lw_lsq.cc +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "cpu/ozone/ozone_impl.hh" -#include "cpu/ozone/lw_lsq_impl.hh" - -// Force the instantiation of LDSTQ for all the implementations we care about. -template class OzoneLWLSQ<OzoneImpl>; - diff --git a/cpu/ozone/lw_lsq.hh b/cpu/ozone/lw_lsq.hh deleted file mode 100644 index 6fe343b42..000000000 --- a/cpu/ozone/lw_lsq.hh +++ /dev/null @@ -1,657 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_OZONE_LW_LSQ_HH__ -#define __CPU_OZONE_LW_LSQ_HH__ - -#include <list> -#include <map> -#include <queue> -#include <algorithm> - -#include "arch/faults.hh" -#include "arch/isa_traits.hh" -#include "config/full_system.hh" -#include "base/hashmap.hh" -#include "cpu/inst_seq.hh" -#include "mem/mem_interface.hh" -//#include "mem/page_table.hh" -#include "sim/debug.hh" -#include "sim/sim_object.hh" - -//class PageTable; - -/** - * Class that implements the actual LQ and SQ for each specific thread. - * Both are circular queues; load entries are freed upon committing, while - * store entries are freed once they writeback. The LSQUnit tracks if there - * are memory ordering violations, and also detects partial load to store - * forwarding cases (a store only has part of a load's data) that requires - * the load to wait until the store writes back. In the former case it - * holds onto the instruction until the dependence unit looks at it, and - * in the latter it stalls the LSQ until the store writes back. At that - * point the load is replayed. - */ -template <class Impl> -class OzoneLWLSQ { - public: - typedef typename Impl::Params Params; - typedef typename Impl::FullCPU FullCPU; - typedef typename Impl::BackEnd BackEnd; - typedef typename Impl::DynInstPtr DynInstPtr; - typedef typename Impl::IssueStruct IssueStruct; - - typedef TheISA::IntReg IntReg; - - typedef typename std::map<InstSeqNum, DynInstPtr>::iterator LdMapIt; - - private: - class StoreCompletionEvent : public Event { - public: - /** Constructs a store completion event. */ - StoreCompletionEvent(DynInstPtr &inst, BackEnd *be, - Event *wb_event, OzoneLWLSQ *lsq_ptr); - - /** Processes the store completion event. */ - void process(); - - /** Returns the description of this event. */ - const char *description(); - - private: - /** The store index of the store being written back. */ - DynInstPtr inst; - - BackEnd *be; - /** The writeback event for the store. Needed for store - * conditionals. - */ - public: - Event *wbEvent; - bool miss; - private: - /** The pointer to the LSQ unit that issued the store. */ - OzoneLWLSQ<Impl> *lsqPtr; - }; - - public: - /** Constructs an LSQ unit. init() must be called prior to use. */ - OzoneLWLSQ(); - - /** Initializes the LSQ unit with the specified number of entries. */ - void init(Params *params, unsigned maxLQEntries, - unsigned maxSQEntries, unsigned id); - - /** Returns the name of the LSQ unit. */ - std::string name() const; - - /** Sets the CPU pointer. */ - void setCPU(FullCPU *cpu_ptr) - { cpu = cpu_ptr; } - - /** Sets the back-end stage pointer. */ - void setBE(BackEnd *be_ptr) - { be = be_ptr; } - - /** Sets the page table pointer. */ -// void setPageTable(PageTable *pt_ptr); - - /** Ticks the LSQ unit, which in this case only resets the number of - * used cache ports. - * @todo: Move the number of used ports up to the LSQ level so it can - * be shared by all LSQ units. - */ - void tick() { usedPorts = 0; } - - /** Inserts an instruction. */ - void insert(DynInstPtr &inst); - /** Inserts a load instruction. */ - void insertLoad(DynInstPtr &load_inst); - /** Inserts a store instruction. */ - void insertStore(DynInstPtr &store_inst); - - /** Executes a load instruction. */ - Fault executeLoad(DynInstPtr &inst); - - /** Executes a store instruction. */ - Fault executeStore(DynInstPtr &inst); - - /** Commits the head load. */ - void commitLoad(); - /** Commits loads older than a specific sequence number. */ - void commitLoads(InstSeqNum &youngest_inst); - - /** Commits stores older than a specific sequence number. */ - void commitStores(InstSeqNum &youngest_inst); - - /** Writes back stores. */ - void writebackStores(); - - // @todo: Include stats in the LSQ unit. - //void regStats(); - - /** Clears all the entries in the LQ. */ - void clearLQ(); - - /** Clears all the entries in the SQ. */ - void clearSQ(); - - /** Resizes the LQ to a given size. */ - void resizeLQ(unsigned size); - - /** Resizes the SQ to a given size. */ - void resizeSQ(unsigned size); - - /** Squashes all instructions younger than a specific sequence number. */ - void squash(const InstSeqNum &squashed_num); - - /** Returns if there is a memory ordering violation. Value is reset upon - * call to getMemDepViolator(). - */ - bool violation() { return memDepViolator; } - - /** Returns the memory ordering violator. */ - DynInstPtr getMemDepViolator(); - - /** Returns if a load became blocked due to the memory system. It clears - * the bool's value upon this being called. - */ - bool loadBlocked() - { return isLoadBlocked; } - - void clearLoadBlocked() - { isLoadBlocked = false; } - - bool isLoadBlockedHandled() - { return loadBlockedHandled; } - - void setLoadBlockedHandled() - { loadBlockedHandled = true; } - - /** Returns the number of free entries (min of free LQ and SQ entries). */ - unsigned numFreeEntries(); - - /** Returns the number of loads ready to execute. */ - int numLoadsReady(); - - /** Returns the number of loads in the LQ. */ - int numLoads() { return loads; } - - /** Returns the number of stores in the SQ. */ - int numStores() { return stores; } - - /** Returns if either the LQ or SQ is full. */ - bool isFull() { return lqFull() || sqFull(); } - - /** Returns if the LQ is full. */ - bool lqFull() { return loads >= (LQEntries - 1); } - - /** Returns if the SQ is full. */ - bool sqFull() { return stores >= (SQEntries - 1); } - - /** Debugging function to dump instructions in the LSQ. */ - void dumpInsts(); - - /** Returns the number of instructions in the LSQ. */ - unsigned getCount() { return loads + stores; } - - /** Returns if there are any stores to writeback. */ - bool hasStoresToWB() { return storesToWB; } - - /** Returns the number of stores to writeback. */ - int numStoresToWB() { return storesToWB; } - - /** Returns if the LSQ unit will writeback on this cycle. */ - bool willWB() { return storeQueue.back().canWB && - !storeQueue.back().completed && - !dcacheInterface->isBlocked(); } - - void switchOut(); - - void takeOverFrom(ExecContext *old_xc = NULL); - - bool isSwitchedOut() { return switchedOut; } - - bool switchedOut; - - private: - /** Completes the store at the specified index. */ - void completeStore(int store_idx); - - private: - /** Pointer to the CPU. */ - FullCPU *cpu; - - /** Pointer to the back-end stage. */ - BackEnd *be; - - /** Pointer to the D-cache. */ - MemInterface *dcacheInterface; - - /** Pointer to the page table. */ -// PageTable *pTable; - - public: - struct SQEntry { - /** Constructs an empty store queue entry. */ - SQEntry() - : inst(NULL), req(NULL), size(0), data(0), - canWB(0), committed(0), completed(0), lqIt(NULL) - { } - - /** Constructs a store queue entry for a given instruction. */ - SQEntry(DynInstPtr &_inst) - : inst(_inst), req(NULL), size(0), data(0), - canWB(0), committed(0), completed(0), lqIt(NULL) - { } - - /** The store instruction. */ - DynInstPtr inst; - /** The memory request for the store. */ - MemReqPtr req; - /** The size of the store. */ - int size; - /** The store data. */ - IntReg data; - /** Whether or not the store can writeback. */ - bool canWB; - /** Whether or not the store is committed. */ - bool committed; - /** Whether or not the store is completed. */ - bool completed; - - typename std::list<DynInstPtr>::iterator lqIt; - }; - - enum Status { - Running, - Idle, - DcacheMissStall, - DcacheMissSwitch - }; - - private: - /** The OzoneLWLSQ thread id. */ - unsigned lsqID; - - /** The status of the LSQ unit. */ - Status _status; - - /** The store queue. */ - std::list<SQEntry> storeQueue; - /** The load queue. */ - std::list<DynInstPtr> loadQueue; - - typedef typename std::list<SQEntry>::iterator SQIt; - typedef typename std::list<DynInstPtr>::iterator LQIt; - - - struct HashFn { - size_t operator() (const int a) const - { - unsigned hash = (((a >> 14) ^ ((a >> 2) & 0xffff))) & 0x7FFFFFFF; - - return hash; - } - }; - - m5::hash_map<int, SQIt, HashFn> SQItHash; - std::queue<int> SQIndices; - m5::hash_map<int, LQIt, HashFn> LQItHash; - std::queue<int> LQIndices; - - typedef typename m5::hash_map<int, LQIt, HashFn>::iterator LQHashIt; - typedef typename m5::hash_map<int, SQIt, HashFn>::iterator SQHashIt; - // Consider making these 16 bits - /** The number of LQ entries. */ - unsigned LQEntries; - /** The number of SQ entries. */ - unsigned SQEntries; - - /** The number of load instructions in the LQ. */ - int loads; - /** The number of store instructions in the SQ (excludes those waiting to - * writeback). - */ - int stores; - - int storesToWB; - - /// @todo Consider moving to a more advanced model with write vs read ports - /** The number of cache ports available each cycle. */ - int cachePorts; - - /** The number of used cache ports in this cycle. */ - int usedPorts; - - //list<InstSeqNum> mshrSeqNums; - - //Stats::Scalar<> dcacheStallCycles; - Counter lastDcacheStall; - - // Make these per thread? - /** Whether or not the LSQ is stalled. */ - bool stalled; - /** The store that causes the stall due to partial store to load - * forwarding. - */ - InstSeqNum stallingStoreIsn; - /** The index of the above store. */ - LQIt stallingLoad; - - /** Whether or not a load is blocked due to the memory system. It is - * cleared when this value is checked via loadBlocked(). - */ - bool isLoadBlocked; - - bool loadBlockedHandled; - - InstSeqNum blockedLoadSeqNum; - - /** The oldest faulting load instruction. */ - DynInstPtr loadFaultInst; - /** The oldest faulting store instruction. */ - DynInstPtr storeFaultInst; - - /** The oldest load that caused a memory ordering violation. */ - DynInstPtr memDepViolator; - - // Will also need how many read/write ports the Dcache has. Or keep track - // of that in stage that is one level up, and only call executeLoad/Store - // the appropriate number of times. - - public: - /** Executes the load at the given index. */ - template <class T> - Fault read(MemReqPtr &req, T &data, int load_idx); - - /** Executes the store at the given index. */ - template <class T> - Fault write(MemReqPtr &req, T &data, int store_idx); - - /** Returns the sequence number of the head load instruction. */ - InstSeqNum getLoadHeadSeqNum() - { - if (!loadQueue.empty()) { - return loadQueue.back()->seqNum; - } else { - return 0; - } - - } - - /** Returns the sequence number of the head store instruction. */ - InstSeqNum getStoreHeadSeqNum() - { - if (!storeQueue.empty()) { - return storeQueue.back().inst->seqNum; - } else { - return 0; - } - - } - - /** Returns whether or not the LSQ unit is stalled. */ - bool isStalled() { return stalled; } -}; - -template <class Impl> -template <class T> -Fault -OzoneLWLSQ<Impl>::read(MemReqPtr &req, T &data, int load_idx) -{ - //Depending on issue2execute delay a squashed load could - //execute if it is found to be squashed in the same - //cycle it is scheduled to execute - typename m5::hash_map<int, LQIt, HashFn>::iterator - lq_hash_it = LQItHash.find(load_idx); - assert(lq_hash_it != LQItHash.end()); - DynInstPtr inst = (*(*lq_hash_it).second); - - if (inst->isExecuted()) { - panic("Should not reach this point with split ops!"); - - memcpy(&data,req->data,req->size); - - return NoFault; - } - - // Make sure this isn't an uncacheable access - // A bit of a hackish way to get uncached accesses to work only if they're - // at the head of the LSQ and are ready to commit (at the head of the ROB - // too). - // @todo: Fix uncached accesses. - if (req->flags & UNCACHEABLE && - (inst != loadQueue.back() || !inst->reachedCommit)) { - DPRINTF(OzoneLSQ, "[sn:%lli] Uncached load and not head of " - "commit/LSQ!\n", - inst->seqNum); - be->rescheduleMemInst(inst); - return TheISA::genMachineCheckFault(); - } - - // Check the SQ for any previous stores that might lead to forwarding - SQIt sq_it = storeQueue.begin(); - int store_size = 0; - - DPRINTF(OzoneLSQ, "Read called, load idx: %i addr: %#x\n", - load_idx, req->paddr); - - while (sq_it != storeQueue.end() && (*sq_it).inst->seqNum > inst->seqNum) - ++sq_it; - - while (1) { - // End once we've reached the top of the LSQ - if (sq_it == storeQueue.end()) { - break; - } - - assert((*sq_it).inst); - - store_size = (*sq_it).size; - - if (store_size == 0) { - sq_it++; - continue; - } - - // Check if the store data is within the lower and upper bounds of - // addresses that the request needs. - bool store_has_lower_limit = - req->vaddr >= (*sq_it).inst->effAddr; - bool store_has_upper_limit = - (req->vaddr + req->size) <= ((*sq_it).inst->effAddr + - store_size); - bool lower_load_has_store_part = - req->vaddr < ((*sq_it).inst->effAddr + - store_size); - bool upper_load_has_store_part = - (req->vaddr + req->size) > (*sq_it).inst->effAddr; - - // If the store's data has all of the data needed, we can forward. - if (store_has_lower_limit && store_has_upper_limit) { - - int shift_amt = req->vaddr & (store_size - 1); - // Assumes byte addressing - shift_amt = shift_amt << 3; - - // Cast this to type T? - data = (*sq_it).data >> shift_amt; - - req->cmd = Read; - assert(!req->completionEvent); - req->completionEvent = NULL; - req->time = curTick; - assert(!req->data); - req->data = new uint8_t[64]; - - memcpy(req->data, &data, req->size); - - DPRINTF(OzoneLSQ, "Forwarding from store [sn:%lli] to load to " - "[sn:%lli] addr %#x, data %#x\n", - (*sq_it).inst->seqNum, inst->seqNum, req->vaddr, *(req->data)); - - typename BackEnd::LdWritebackEvent *wb = - new typename BackEnd::LdWritebackEvent(inst, - be); - - // We'll say this has a 1 cycle load-store forwarding latency - // for now. - // FIXME - Need to make this a parameter. - wb->schedule(curTick); - - // Should keep track of stat for forwarded data - return NoFault; - } else if ((store_has_lower_limit && lower_load_has_store_part) || - (store_has_upper_limit && upper_load_has_store_part) || - (lower_load_has_store_part && upper_load_has_store_part)) { - // This is the partial store-load forwarding case where a store - // has only part of the load's data. - - // If it's already been written back, then don't worry about - // stalling on it. - if ((*sq_it).completed) { - sq_it++; - break; - } - - // Must stall load and force it to retry, so long as it's the oldest - // load that needs to do so. - if (!stalled || - (stalled && - inst->seqNum < - (*stallingLoad)->seqNum)) { - stalled = true; - stallingStoreIsn = (*sq_it).inst->seqNum; - stallingLoad = (*lq_hash_it).second; - } - - // Tell IQ/mem dep unit that this instruction will need to be - // rescheduled eventually - be->rescheduleMemInst(inst); - - DPRINTF(OzoneLSQ, "Load-store forwarding mis-match. " - "Store [sn:%lli] to load addr %#x\n", - (*sq_it).inst->seqNum, req->vaddr); - - return NoFault; - } - sq_it++; - } - - // If there's no forwarding case, then go access memory - DPRINTF(OzoneLSQ, "Doing functional access for inst PC %#x\n", - inst->readPC()); - - // Setup MemReq pointer - req->cmd = Read; - req->completionEvent = NULL; - req->time = curTick; - assert(!req->data); - req->data = new uint8_t[64]; - Fault fault = cpu->read(req, data); - memcpy(req->data, &data, sizeof(T)); - - ++usedPorts; - - // if we have a cache, do cache access too - if (dcacheInterface) { - if (dcacheInterface->isBlocked()) { - // There's an older load that's already going to squash. - if (isLoadBlocked && blockedLoadSeqNum < inst->seqNum) - return NoFault; - - isLoadBlocked = true; - loadBlockedHandled = false; - blockedLoadSeqNum = inst->seqNum; - // No fault occurred, even though the interface is blocked. - return NoFault; - } - - DPRINTF(OzoneLSQ, "D-cache: PC:%#x reading from paddr:%#x " - "vaddr:%#x flags:%i\n", - inst->readPC(), req->paddr, req->vaddr, req->flags); - - assert(!req->completionEvent); - req->completionEvent = - new typename BackEnd::LdWritebackEvent(inst, be); - - // Do Cache Access - MemAccessResult result = dcacheInterface->access(req); - - // Ugly hack to get an event scheduled *only* if the access is - // a miss. We really should add first-class support for this - // at some point. - // @todo: Probably should support having no events - if (result != MA_HIT) { - DPRINTF(OzoneLSQ, "D-cache miss!\n"); - DPRINTF(Activity, "Activity: ld accessing mem miss [sn:%lli]\n", - inst->seqNum); - - lastDcacheStall = curTick; - - _status = DcacheMissStall; - - } else { - DPRINTF(OzoneLSQ, "D-cache hit!\n"); - } - } else { - fatal("Must use D-cache with new memory system"); - } - - return NoFault; -} - -template <class Impl> -template <class T> -Fault -OzoneLWLSQ<Impl>::write(MemReqPtr &req, T &data, int store_idx) -{ - SQHashIt sq_hash_it = SQItHash.find(store_idx); - assert(sq_hash_it != SQItHash.end()); - - SQIt sq_it = (*sq_hash_it).second; - assert((*sq_it).inst); - - DPRINTF(OzoneLSQ, "Doing write to store idx %i, addr %#x data %#x" - " | [sn:%lli]\n", - store_idx, req->paddr, data, (*sq_it).inst->seqNum); - - (*sq_it).req = req; - (*sq_it).size = sizeof(T); - (*sq_it).data = data; - assert(!req->data); - req->data = new uint8_t[64]; - memcpy(req->data, (uint8_t *)&(*sq_it).data, req->size); - - // This function only writes the data to the store queue, so no fault - // can happen here. - return NoFault; -} - -#endif // __CPU_OZONE_LW_LSQ_HH__ diff --git a/cpu/ozone/lw_lsq_impl.hh b/cpu/ozone/lw_lsq_impl.hh deleted file mode 100644 index f72bbb1cc..000000000 --- a/cpu/ozone/lw_lsq_impl.hh +++ /dev/null @@ -1,874 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "arch/isa_traits.hh" -#include "base/str.hh" -#include "cpu/ozone/lw_lsq.hh" -#include "cpu/checker/cpu.hh" - -template <class Impl> -OzoneLWLSQ<Impl>::StoreCompletionEvent::StoreCompletionEvent(DynInstPtr &_inst, - BackEnd *_be, - Event *wb_event, - OzoneLWLSQ<Impl> *lsq_ptr) - : Event(&mainEventQueue), - inst(_inst), - be(_be), - wbEvent(wb_event), - miss(false), - lsqPtr(lsq_ptr) -{ - this->setFlags(Event::AutoDelete); -} - -template <class Impl> -void -OzoneLWLSQ<Impl>::StoreCompletionEvent::process() -{ - DPRINTF(OzoneLSQ, "Cache miss complete for store [sn:%lli]\n", - inst->seqNum); - - //lsqPtr->removeMSHR(lsqPtr->storeQueue[storeIdx].inst->seqNum); - -// lsqPtr->cpu->wakeCPU(); - if (lsqPtr->isSwitchedOut()) { - if (wbEvent) - delete wbEvent; - - return; - } - - if (wbEvent) { - wbEvent->process(); - delete wbEvent; - } - - lsqPtr->completeStore(inst->sqIdx); - if (miss) - be->removeDcacheMiss(inst); -} - -template <class Impl> -const char * -OzoneLWLSQ<Impl>::StoreCompletionEvent::description() -{ - return "LSQ store completion event"; -} - -template <class Impl> -OzoneLWLSQ<Impl>::OzoneLWLSQ() - : loads(0), stores(0), storesToWB(0), stalled(false), isLoadBlocked(false), - loadBlockedHandled(false) -{ -} - -template<class Impl> -void -OzoneLWLSQ<Impl>::init(Params *params, unsigned maxLQEntries, - unsigned maxSQEntries, unsigned id) -{ - DPRINTF(OzoneLSQ, "Creating OzoneLWLSQ%i object.\n",id); - - lsqID = id; - - LQEntries = maxLQEntries; - SQEntries = maxSQEntries; - - for (int i = 0; i < LQEntries * 2; i++) { - LQIndices.push(i); - SQIndices.push(i); - } - - usedPorts = 0; - cachePorts = params->cachePorts; - - dcacheInterface = params->dcacheInterface; - - loadFaultInst = storeFaultInst = memDepViolator = NULL; - - blockedLoadSeqNum = 0; -} - -template<class Impl> -std::string -OzoneLWLSQ<Impl>::name() const -{ - return "lsqunit"; -} - -template<class Impl> -void -OzoneLWLSQ<Impl>::clearLQ() -{ - loadQueue.clear(); -} - -template<class Impl> -void -OzoneLWLSQ<Impl>::clearSQ() -{ - storeQueue.clear(); -} -/* -template<class Impl> -void -OzoneLWLSQ<Impl>::setPageTable(PageTable *pt_ptr) -{ - DPRINTF(OzoneLSQ, "Setting the page table pointer.\n"); - pTable = pt_ptr; -} -*/ -template<class Impl> -void -OzoneLWLSQ<Impl>::resizeLQ(unsigned size) -{ - assert( size >= LQEntries); - - if (size > LQEntries) { - while (size > loadQueue.size()) { - DynInstPtr dummy; - loadQueue.push_back(dummy); - LQEntries++; - } - } else { - LQEntries = size; - } - -} - -template<class Impl> -void -OzoneLWLSQ<Impl>::resizeSQ(unsigned size) -{ - if (size > SQEntries) { - while (size > storeQueue.size()) { - SQEntry dummy; - storeQueue.push_back(dummy); - SQEntries++; - } - } else { - SQEntries = size; - } -} - -template <class Impl> -void -OzoneLWLSQ<Impl>::insert(DynInstPtr &inst) -{ - // Make sure we really have a memory reference. - assert(inst->isMemRef()); - - // Make sure it's one of the two classes of memory references. - assert(inst->isLoad() || inst->isStore()); - - if (inst->isLoad()) { - insertLoad(inst); - } else { - insertStore(inst); - } -} - -template <class Impl> -void -OzoneLWLSQ<Impl>::insertLoad(DynInstPtr &load_inst) -{ - assert(loads < LQEntries * 2); - assert(!LQIndices.empty()); - int load_index = LQIndices.front(); - LQIndices.pop(); - - DPRINTF(OzoneLSQ, "Inserting load PC %#x, idx:%i [sn:%lli]\n", - load_inst->readPC(), load_index, load_inst->seqNum); - - load_inst->lqIdx = load_index; - - loadQueue.push_front(load_inst); - LQItHash[load_index] = loadQueue.begin(); - - ++loads; -} - -template <class Impl> -void -OzoneLWLSQ<Impl>::insertStore(DynInstPtr &store_inst) -{ - // Make sure it is not full before inserting an instruction. - assert(stores - storesToWB < SQEntries); - - assert(!SQIndices.empty()); - int store_index = SQIndices.front(); - SQIndices.pop(); - - DPRINTF(OzoneLSQ, "Inserting store PC %#x, idx:%i [sn:%lli]\n", - store_inst->readPC(), store_index, store_inst->seqNum); - - store_inst->sqIdx = store_index; - SQEntry entry(store_inst); - if (loadQueue.empty()) { - entry.lqIt = loadQueue.end(); - } else { - entry.lqIt = loadQueue.begin(); - } - storeQueue.push_front(entry); - - SQItHash[store_index] = storeQueue.begin(); - - ++stores; -} - -template <class Impl> -typename Impl::DynInstPtr -OzoneLWLSQ<Impl>::getMemDepViolator() -{ - DynInstPtr temp = memDepViolator; - - memDepViolator = NULL; - - return temp; -} - -template <class Impl> -unsigned -OzoneLWLSQ<Impl>::numFreeEntries() -{ - unsigned free_lq_entries = LQEntries - loads; - unsigned free_sq_entries = SQEntries - stores; - - // Both the LQ and SQ entries have an extra dummy entry to differentiate - // empty/full conditions. Subtract 1 from the free entries. - if (free_lq_entries < free_sq_entries) { - return free_lq_entries - 1; - } else { - return free_sq_entries - 1; - } -} - -template <class Impl> -int -OzoneLWLSQ<Impl>::numLoadsReady() -{ - int retval = 0; - LQIt lq_it = loadQueue.begin(); - LQIt end_it = loadQueue.end(); - - while (lq_it != end_it) { - if ((*lq_it)->readyToIssue()) { - ++retval; - } - } - - return retval; -} - -template <class Impl> -Fault -OzoneLWLSQ<Impl>::executeLoad(DynInstPtr &inst) -{ - // Execute a specific load. - Fault load_fault = NoFault; - - DPRINTF(OzoneLSQ, "Executing load PC %#x, [sn:%lli]\n", - inst->readPC(),inst->seqNum); - - // Make sure it's really in the list. - // Normally it should always be in the list. However, - /* due to a syscall it may not be the list. -#ifdef DEBUG - int i = loadHead; - while (1) { - if (i == loadTail && !find(inst)) { - assert(0 && "Load not in the queue!"); - } else if (loadQueue[i] == inst) { - break; - } - - i = i + 1; - if (i >= LQEntries) { - i = 0; - } - } -#endif // DEBUG*/ - - load_fault = inst->initiateAcc(); - - // Might want to make sure that I'm not overwriting a previously faulting - // instruction that hasn't been checked yet. - // Actually probably want the oldest faulting load - if (load_fault != NoFault) { - DPRINTF(OzoneLSQ, "Load [sn:%lli] has a fault\n", inst->seqNum); - // Maybe just set it as can commit here, although that might cause - // some other problems with sending traps to the ROB too quickly. - be->instToCommit(inst); -// iewStage->activityThisCycle(); - } - - return load_fault; -} - -template <class Impl> -Fault -OzoneLWLSQ<Impl>::executeStore(DynInstPtr &store_inst) -{ - // Make sure that a store exists. - assert(stores != 0); - - int store_idx = store_inst->sqIdx; - SQHashIt sq_hash_it = SQItHash.find(store_idx); - assert(sq_hash_it != SQItHash.end()); - DPRINTF(OzoneLSQ, "Executing store PC %#x [sn:%lli]\n", - store_inst->readPC(), store_inst->seqNum); - - SQIt sq_it = (*sq_hash_it).second; - - Fault store_fault = store_inst->initiateAcc(); - - // Store size should now be available. Use it to get proper offset for - // addr comparisons. - int size = (*sq_it).size; - - if (size == 0) { - DPRINTF(OzoneLSQ,"Fault on Store PC %#x, [sn:%lli],Size = 0\n", - store_inst->readPC(),store_inst->seqNum); - - return store_fault; - } - - assert(store_fault == NoFault); - - if (!storeFaultInst) { - if (store_fault != NoFault) { - panic("Fault in a store instruction!"); - storeFaultInst = store_inst; - } else if (store_inst->isStoreConditional()) { - // Store conditionals need to set themselves as able to - // writeback if we haven't had a fault by here. - (*sq_it).canWB = true; - - ++storesToWB; - DPRINTF(OzoneLSQ, "Nonspeculative store! storesToWB:%i\n", - storesToWB); - } - } - - LQIt lq_it = --(loadQueue.end()); - - if (!memDepViolator) { - while (lq_it != loadQueue.end()) { - if ((*lq_it)->seqNum < store_inst->seqNum) { - lq_it--; - continue; - } - // Actually should only check loads that have actually executed - // Might be safe because effAddr is set to InvalAddr when the - // dyn inst is created. - - // Must actually check all addrs in the proper size range - // Which is more correct than needs to be. What if for now we just - // assume all loads are quad-word loads, and do the addr based - // on that. - // @todo: Fix this, magic number being used here - if (((*lq_it)->effAddr >> 8) == - (store_inst->effAddr >> 8)) { - // A load incorrectly passed this store. Squash and refetch. - // For now return a fault to show that it was unsuccessful. - memDepViolator = (*lq_it); - - return TheISA::genMachineCheckFault(); - } - - lq_it--; - } - - // If we've reached this point, there was no violation. - memDepViolator = NULL; - } - - return store_fault; -} - -template <class Impl> -void -OzoneLWLSQ<Impl>::commitLoad() -{ - assert(!loadQueue.empty()); - - DPRINTF(OzoneLSQ, "[sn:%lli] Committing head load instruction, PC %#x\n", - loadQueue.back()->seqNum, loadQueue.back()->readPC()); - - LQIndices.push(loadQueue.back()->lqIdx); - LQItHash.erase(loadQueue.back()->lqIdx); - - loadQueue.pop_back(); - - --loads; -} - -template <class Impl> -void -OzoneLWLSQ<Impl>::commitLoads(InstSeqNum &youngest_inst) -{ - assert(loads == 0 || !loadQueue.empty()); - - while (loads != 0 && - loadQueue.back()->seqNum <= youngest_inst) { - commitLoad(); - } -} - -template <class Impl> -void -OzoneLWLSQ<Impl>::commitStores(InstSeqNum &youngest_inst) -{ - assert(stores == 0 || !storeQueue.empty()); - - SQIt sq_it = --(storeQueue.end()); - while (!storeQueue.empty() && sq_it != storeQueue.end()) { - assert((*sq_it).inst); - if (!(*sq_it).canWB) { - if ((*sq_it).inst->seqNum > youngest_inst) { - break; - } - ++storesToWB; - - DPRINTF(OzoneLSQ, "Marking store as able to write back, PC " - "%#x [sn:%lli], storesToWB:%i\n", - (*sq_it).inst->readPC(), - (*sq_it).inst->seqNum, - storesToWB); - - (*sq_it).canWB = true; - } - - sq_it--; - } -} - -template <class Impl> -void -OzoneLWLSQ<Impl>::writebackStores() -{ - SQIt sq_it = --(storeQueue.end()); - while (storesToWB > 0 && - sq_it != storeQueue.end() && - (*sq_it).inst && - (*sq_it).canWB && - usedPorts < cachePorts) { - - DynInstPtr inst = (*sq_it).inst; - - if ((*sq_it).size == 0 && !(*sq_it).completed) { - sq_it--; - completeStore(inst->sqIdx); - - continue; - } - - if (inst->isDataPrefetch() || (*sq_it).committed) { - sq_it--; - continue; - } - - if (dcacheInterface && dcacheInterface->isBlocked()) { - DPRINTF(OzoneLSQ, "Unable to write back any more stores, cache" - " is blocked!\n"); - break; - } - - ++usedPorts; - - assert((*sq_it).req); - assert(!(*sq_it).committed); - - (*sq_it).committed = true; - - MemReqPtr req = (*sq_it).req; - - req->cmd = Write; - req->completionEvent = NULL; - req->time = curTick; - - switch((*sq_it).size) { - case 1: - cpu->write(req, (uint8_t &)(*sq_it).data); - break; - case 2: - cpu->write(req, (uint16_t &)(*sq_it).data); - break; - case 4: - cpu->write(req, (uint32_t &)(*sq_it).data); - break; - case 8: - cpu->write(req, (uint64_t &)(*sq_it).data); - break; - default: - panic("Unexpected store size!\n"); - } - if (!(req->flags & LOCKED)) { - (*sq_it).inst->setCompleted(); - if (cpu->checker) { - cpu->checker->tick((*sq_it).inst); - } - } - - DPRINTF(OzoneLSQ, "D-Cache: Writing back store idx:%i PC:%#x " - "to Addr:%#x, data:%#x [sn:%lli]\n", - inst->sqIdx,inst->readPC(), - req->paddr, *(req->data), - inst->seqNum); - - if (dcacheInterface) { - assert(!req->completionEvent); - StoreCompletionEvent *store_event = new - StoreCompletionEvent(inst, be, NULL, this); - req->completionEvent = store_event; - - MemAccessResult result = dcacheInterface->access(req); - - if (isStalled() && - inst->seqNum == stallingStoreIsn) { - DPRINTF(OzoneLSQ, "Unstalling, stalling store [sn:%lli] " - "load [sn:%lli]\n", - stallingStoreIsn, (*stallingLoad)->seqNum); - stalled = false; - stallingStoreIsn = 0; - be->replayMemInst((*stallingLoad)); - } - - if (result != MA_HIT && dcacheInterface->doEvents()) { - store_event->miss = true; - typename BackEnd::LdWritebackEvent *wb = NULL; - if (req->flags & LOCKED) { - wb = new typename BackEnd::LdWritebackEvent(inst, - be); - store_event->wbEvent = wb; - } - - DPRINTF(OzoneLSQ,"D-Cache Write Miss!\n"); - -// DPRINTF(Activity, "Active st accessing mem miss [sn:%lli]\n", -// inst->seqNum); - - be->addDcacheMiss(inst); - - lastDcacheStall = curTick; - - _status = DcacheMissStall; - - // Increment stat here or something - - sq_it--; - } else { - DPRINTF(OzoneLSQ,"D-Cache: Write Hit on idx:%i !\n", - inst->sqIdx); - -// DPRINTF(Activity, "Active st accessing mem hit [sn:%lli]\n", -// inst->seqNum); - - if (req->flags & LOCKED) { - // Stx_C does not generate a system port - // transaction in the 21264, but that might be - // hard to accomplish in this model. - - typename BackEnd::LdWritebackEvent *wb = - new typename BackEnd::LdWritebackEvent(inst, - be); - store_event->wbEvent = wb; - } - sq_it--; - } - } else { - panic("Must HAVE DCACHE!!!!!\n"); - } - } - - // Not sure this should set it to 0. - usedPorts = 0; - - assert(stores >= 0 && storesToWB >= 0); -} - -template <class Impl> -void -OzoneLWLSQ<Impl>::squash(const InstSeqNum &squashed_num) -{ - DPRINTF(OzoneLSQ, "Squashing until [sn:%lli]!" - "(Loads:%i Stores:%i)\n",squashed_num,loads,stores); - - - LQIt lq_it = loadQueue.begin(); - - while (loads != 0 && (*lq_it)->seqNum > squashed_num) { - assert(!loadQueue.empty()); - // Clear the smart pointer to make sure it is decremented. - DPRINTF(OzoneLSQ,"Load Instruction PC %#x squashed, " - "[sn:%lli]\n", - (*lq_it)->readPC(), - (*lq_it)->seqNum); - - if (isStalled() && lq_it == stallingLoad) { - stalled = false; - stallingStoreIsn = 0; - stallingLoad = NULL; - } - - --loads; - - // Inefficient! - LQHashIt lq_hash_it = LQItHash.find((*lq_it)->lqIdx); - assert(lq_hash_it != LQItHash.end()); - LQItHash.erase(lq_hash_it); - LQIndices.push((*lq_it)->lqIdx); - loadQueue.erase(lq_it++); - } - - if (isLoadBlocked) { - if (squashed_num < blockedLoadSeqNum) { - isLoadBlocked = false; - loadBlockedHandled = false; - blockedLoadSeqNum = 0; - } - } - - SQIt sq_it = storeQueue.begin(); - - while (stores != 0 && (*sq_it).inst->seqNum > squashed_num) { - assert(!storeQueue.empty()); - - if ((*sq_it).canWB) { - break; - } - - // Clear the smart pointer to make sure it is decremented. - DPRINTF(OzoneLSQ,"Store Instruction PC %#x idx:%i squashed [sn:%lli]\n", - (*sq_it).inst->readPC(), (*sq_it).inst->sqIdx, - (*sq_it).inst->seqNum); - - // I don't think this can happen. It should have been cleared by the - // stalling load. - if (isStalled() && - (*sq_it).inst->seqNum == stallingStoreIsn) { - panic("Is stalled should have been cleared by stalling load!\n"); - stalled = false; - stallingStoreIsn = 0; - } - - SQHashIt sq_hash_it = SQItHash.find((*sq_it).inst->sqIdx); - assert(sq_hash_it != SQItHash.end()); - SQItHash.erase(sq_hash_it); - SQIndices.push((*sq_it).inst->sqIdx); - (*sq_it).inst = NULL; - (*sq_it).canWB = 0; - - if ((*sq_it).req) { - assert(!(*sq_it).req->completionEvent); - } - (*sq_it).req = NULL; - --stores; - storeQueue.erase(sq_it++); - } -} - -template <class Impl> -void -OzoneLWLSQ<Impl>::dumpInsts() -{ - cprintf("Load store queue: Dumping instructions.\n"); - cprintf("Load queue size: %i\n", loads); - cprintf("Load queue: "); - - LQIt lq_it = --(loadQueue.end()); - - while (lq_it != loadQueue.end() && (*lq_it)) { - cprintf("[sn:%lli] %#x ", (*lq_it)->seqNum, - (*lq_it)->readPC()); - - lq_it--; - } - - cprintf("\nStore queue size: %i\n", stores); - cprintf("Store queue: "); - - SQIt sq_it = --(storeQueue.end()); - - while (sq_it != storeQueue.end() && (*sq_it).inst) { - cprintf("[sn:%lli]\nPC:%#x\nSize:%i\nCommitted:%i\nCompleted:%i\ncanWB:%i\n", - (*sq_it).inst->seqNum, - (*sq_it).inst->readPC(), - (*sq_it).size, - (*sq_it).committed, - (*sq_it).completed, - (*sq_it).canWB); - - sq_it--; - } - - cprintf("\n"); -} - -template <class Impl> -void -OzoneLWLSQ<Impl>::completeStore(int store_idx) -{ - SQHashIt sq_hash_it = SQItHash.find(store_idx); - assert(sq_hash_it != SQItHash.end()); - SQIt sq_it = (*sq_hash_it).second; - - assert((*sq_it).inst); - (*sq_it).completed = true; - DynInstPtr inst = (*sq_it).inst; - - --storesToWB; - - if (isStalled() && - inst->seqNum == stallingStoreIsn) { - DPRINTF(OzoneLSQ, "Unstalling, stalling store [sn:%lli] " - "load [sn:%lli]\n", - stallingStoreIsn, (*stallingLoad)->seqNum); - stalled = false; - stallingStoreIsn = 0; - be->replayMemInst((*stallingLoad)); - } - - DPRINTF(OzoneLSQ, "Completing store idx:%i [sn:%lli], storesToWB:%i\n", - inst->sqIdx, inst->seqNum, storesToWB); - - assert(!storeQueue.empty()); - SQItHash.erase(sq_hash_it); - SQIndices.push(inst->sqIdx); - storeQueue.erase(sq_it); - --stores; - - inst->setCompleted(); - if (cpu->checker) { - cpu->checker->tick(inst); - } -} - -template <class Impl> -void -OzoneLWLSQ<Impl>::switchOut() -{ - assert(storesToWB == 0); - switchedOut = true; - SQIt sq_it = --(storeQueue.end()); - while (storesToWB > 0 && - sq_it != storeQueue.end() && - (*sq_it).inst && - (*sq_it).canWB) { - - DynInstPtr inst = (*sq_it).inst; - - if ((*sq_it).size == 0 && !(*sq_it).completed) { - sq_it--; - continue; - } - - // Store conditionals don't complete until *after* they have written - // back. If it's here and not yet sent to memory, then don't bother - // as it's not part of committed state. - if (inst->isDataPrefetch() || (*sq_it).committed) { - sq_it--; - continue; - } else if ((*sq_it).req->flags & LOCKED) { - sq_it--; - assert(!(*sq_it).canWB || - ((*sq_it).canWB && (*sq_it).req->flags & LOCKED)); - continue; - } - - assert((*sq_it).req); - assert(!(*sq_it).committed); - - MemReqPtr req = (*sq_it).req; - (*sq_it).committed = true; - - req->cmd = Write; - req->completionEvent = NULL; - req->time = curTick; - assert(!req->data); - req->data = new uint8_t[64]; - memcpy(req->data, (uint8_t *)&(*sq_it).data, req->size); - - DPRINTF(OzoneLSQ, "Switching out : Writing back store idx:%i PC:%#x " - "to Addr:%#x, data:%#x directly to memory [sn:%lli]\n", - inst->sqIdx,inst->readPC(), - req->paddr, *(req->data), - inst->seqNum); - - switch((*sq_it).size) { - case 1: - cpu->write(req, (uint8_t &)(*sq_it).data); - break; - case 2: - cpu->write(req, (uint16_t &)(*sq_it).data); - break; - case 4: - cpu->write(req, (uint32_t &)(*sq_it).data); - break; - case 8: - cpu->write(req, (uint64_t &)(*sq_it).data); - break; - default: - panic("Unexpected store size!\n"); - } - } - - // Clear the queue to free up resources - storeQueue.clear(); - loadQueue.clear(); - loads = stores = storesToWB = 0; -} - -template <class Impl> -void -OzoneLWLSQ<Impl>::takeOverFrom(ExecContext *old_xc) -{ - // Clear out any old state. May be redundant if this is the first time - // the CPU is being used. - stalled = false; - isLoadBlocked = false; - loadBlockedHandled = false; - switchedOut = false; - - // Could do simple checks here to see if indices are on twice - while (!LQIndices.empty()) - LQIndices.pop(); - while (!SQIndices.empty()) - SQIndices.pop(); - - for (int i = 0; i < LQEntries * 2; i++) { - LQIndices.push(i); - SQIndices.push(i); - } - - usedPorts = 0; - - loadFaultInst = storeFaultInst = memDepViolator = NULL; - - blockedLoadSeqNum = 0; -} diff --git a/cpu/ozone/null_predictor.hh b/cpu/ozone/null_predictor.hh deleted file mode 100644 index d19e2cd1c..000000000 --- a/cpu/ozone/null_predictor.hh +++ /dev/null @@ -1,76 +0,0 @@ - -#ifndef __CPU_OZONE_NULL_PREDICTOR_HH__ -#define __CPU_OZONE_NULL_PREDICTOR_HH__ - -#include "arch/isa_traits.hh" -#include "cpu/inst_seq.hh" - -template <class Impl> -class NullPredictor -{ - public: - typedef typename Impl::Params Params; - typedef typename Impl::DynInstPtr DynInstPtr; - - NullPredictor(Params *p) { } - - struct BPredInfo { - BPredInfo() - : PC(0), nextPC(0) - { } - - BPredInfo(const Addr &pc, const Addr &next_pc) - : PC(pc), nextPC(next_pc) - { } - - Addr PC; - Addr nextPC; - }; - - BPredInfo lookup(Addr &PC) { return BPredInfo(PC, PC+4); } - - void undo(BPredInfo &bp_info) { return; } - - /** - * Predicts whether or not the instruction is a taken branch, and the - * target of the branch if it is taken. - * @param inst The branch instruction. - * @param PC The predicted PC is passed back through this parameter. - * @param tid The thread id. - * @return Returns if the branch is taken or not. - */ - bool predict(DynInstPtr &inst, Addr &PC, unsigned tid) - { return false; } - - /** - * Tells the branch predictor to commit any updates until the given - * sequence number. - * @param done_sn The sequence number to commit any older updates up until. - * @param tid The thread id. - */ - void update(const InstSeqNum &done_sn, unsigned tid) { } - - /** - * Squashes all outstanding updates until a given sequence number. - * @param squashed_sn The sequence number to squash any younger updates up - * until. - * @param tid The thread id. - */ - void squash(const InstSeqNum &squashed_sn, unsigned tid) { } - - /** - * Squashes all outstanding updates until a given sequence number, and - * corrects that sn's update with the proper address and taken/not taken. - * @param squashed_sn The sequence number to squash any younger updates up - * until. - * @param corr_target The correct branch target. - * @param actually_taken The correct branch direction. - * @param tid The thread id. - */ - void squash(const InstSeqNum &squashed_sn, const Addr &corr_target, - bool actually_taken, unsigned tid) - { } - -}; - -#endif // __CPU_OZONE_NULL_PREDICTOR_HH__ diff --git a/cpu/ozone/ozone_impl.hh b/cpu/ozone/ozone_impl.hh deleted file mode 100644 index 1f543ec6e..000000000 --- a/cpu/ozone/ozone_impl.hh +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_OZONE_OZONE_IMPL_HH__ -#define __CPU_OZONE_OZONE_IMPL_HH__ - -#include "arch/alpha/isa_traits.hh" -#include "cpu/o3/bpred_unit.hh" -#include "cpu/ozone/back_end.hh" -#include "cpu/ozone/front_end.hh" -#include "cpu/ozone/inst_queue.hh" -#include "cpu/ozone/lsq_unit.hh" -#include "cpu/ozone/lw_lsq.hh" -#include "cpu/ozone/lw_back_end.hh" -#include "cpu/ozone/null_predictor.hh" -#include "cpu/ozone/dyn_inst.hh" -#include "cpu/ozone/simple_params.hh" - -template <class Impl> -class OzoneCPU; - -template <class Impl> -class OzoneDynInst; - -struct OzoneImpl { - typedef SimpleParams Params; - typedef OzoneCPU<OzoneImpl> OzoneCPU; - typedef OzoneCPU FullCPU; - - // Would like to put these into their own area. -// typedef NullPredictor BranchPred; - typedef TwobitBPredUnit<OzoneImpl> BranchPred; - typedef FrontEnd<OzoneImpl> FrontEnd; - // Will need IQ, LSQ eventually - typedef LWBackEnd<OzoneImpl> BackEnd; - - typedef InstQueue<OzoneImpl> InstQueue; - typedef OzoneLWLSQ<OzoneImpl> LdstQueue; - - typedef OzoneDynInst<OzoneImpl> DynInst; - typedef RefCountingPtr<DynInst> DynInstPtr; - - typedef uint64_t IssueStruct; - - enum { - MaxThreads = 1 - }; -}; - -#endif // __CPU_OZONE_OZONE_IMPL_HH__ diff --git a/cpu/ozone/rename_table.cc b/cpu/ozone/rename_table.cc deleted file mode 100644 index fff41903e..000000000 --- a/cpu/ozone/rename_table.cc +++ /dev/null @@ -1,7 +0,0 @@ - -#include "cpu/ozone/rename_table_impl.hh" -#include "cpu/ozone/ozone_impl.hh" -#include "cpu/ozone/simple_impl.hh" - -template class RenameTable<OzoneImpl>; -template class RenameTable<SimpleImpl>; diff --git a/cpu/ozone/rename_table.hh b/cpu/ozone/rename_table.hh deleted file mode 100644 index 6ee23b21b..000000000 --- a/cpu/ozone/rename_table.hh +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_OZONE_RENAME_TABLE_HH__ -#define __CPU_OZONE_RENAME_TABLE_HH__ - -#include "arch/isa_traits.hh" - -/** Rename table that holds the rename of each architectural register to - * producing DynInst. Needs to support copying from one table to another. - */ - -template <class Impl> -class RenameTable { - public: - typedef typename Impl::DynInstPtr DynInstPtr; - - RenameTable(); - - void copyFrom(const RenameTable<Impl> &table_to_copy); - - DynInstPtr &operator [] (int index) - { return table[index]; } - - DynInstPtr table[TheISA::TotalNumRegs]; -}; - -#endif // __CPU_OZONE_RENAME_TABLE_HH__ diff --git a/cpu/ozone/rename_table_impl.hh b/cpu/ozone/rename_table_impl.hh deleted file mode 100644 index 86fc1cc55..000000000 --- a/cpu/ozone/rename_table_impl.hh +++ /dev/null @@ -1,23 +0,0 @@ - -#include <cstdlib> // Not really sure what to include to get NULL -#include "cpu/ozone/rename_table.hh" - -template <class Impl> -RenameTable<Impl>::RenameTable() -{ - // Actually should set these to dummy dyn insts that have the initial value - // and force their values to be initialized. This keeps everything the - // same. - for (int i = 0; i < TheISA::TotalNumRegs; ++i) { - table[i] = NULL; - } -} - -template <class Impl> -void -RenameTable<Impl>::copyFrom(const RenameTable<Impl> &table_to_copy) -{ - for (int i = 0; i < TheISA::TotalNumRegs; ++i) { - table[i] = table_to_copy.table[i]; - } -} diff --git a/cpu/ozone/simple_impl.hh b/cpu/ozone/simple_impl.hh deleted file mode 100644 index 961bf2ea9..000000000 --- a/cpu/ozone/simple_impl.hh +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_OZONE_SIMPLE_IMPL_HH__ -#define __CPU_OZONE_SIMPLE_IMPL_HH__ - -#include "arch/isa_traits.hh" -#include "cpu/o3/bpred_unit.hh" -#include "cpu/ozone/cpu.hh" -#include "cpu/ozone/front_end.hh" -#include "cpu/ozone/inorder_back_end.hh" -#include "cpu/ozone/null_predictor.hh" -#include "cpu/ozone/dyn_inst.hh" -#include "cpu/ozone/simple_params.hh" - -//template <class Impl> -//class OzoneCPU; - -template <class Impl> -class OzoneDynInst; - -struct SimpleImpl { - typedef SimpleParams Params; - typedef OzoneCPU<SimpleImpl> OzoneCPU; - typedef OzoneCPU FullCPU; - - // Would like to put these into their own area. -// typedef NullPredictor BranchPred; - typedef TwobitBPredUnit<SimpleImpl> BranchPred; - typedef FrontEnd<SimpleImpl> FrontEnd; - // Will need IQ, LSQ eventually - typedef InorderBackEnd<SimpleImpl> BackEnd; - - typedef OzoneDynInst<SimpleImpl> DynInst; - typedef RefCountingPtr<DynInst> DynInstPtr; - - typedef uint64_t IssueStruct; - - enum { - MaxThreads = 1 - }; -}; - -#endif // __CPU_OZONE_SIMPLE_IMPL_HH__ diff --git a/cpu/ozone/simple_params.hh b/cpu/ozone/simple_params.hh deleted file mode 100644 index 647da1781..000000000 --- a/cpu/ozone/simple_params.hh +++ /dev/null @@ -1,165 +0,0 @@ - - -#ifndef __CPU_OZONE_SIMPLE_PARAMS_HH__ -#define __CPU_OZONE_SIMPLE_PARAMS_HH__ - -#include "cpu/ozone/cpu.hh" - -//Forward declarations -class AlphaDTB; -class AlphaITB; -class FUPool; -class FunctionalMemory; -class MemInterface; -class PageTable; -class Process; -class System; - -/** - * This file defines the parameters that will be used for the OzoneCPU. - * 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 SimpleParams : public BaseCPU::Params -{ - public: - -#if FULL_SYSTEM - AlphaITB *itb; AlphaDTB *dtb; -#else - std::vector<Process *> workload; -// Process *process; -#endif // FULL_SYSTEM - - //Page Table - PageTable *pTable; - - FunctionalMemory *mem; - - // - // Caches - // - MemInterface *icacheInterface; - MemInterface *dcacheInterface; - - unsigned cachePorts; - unsigned width; - unsigned frontEndWidth; - unsigned backEndWidth; - unsigned backEndSquashLatency; - unsigned backEndLatency; - unsigned maxInstBufferSize; - unsigned numPhysicalRegs; - unsigned maxOutstandingMemOps; - // - // Fetch - // - unsigned decodeToFetchDelay; - unsigned renameToFetchDelay; - unsigned iewToFetchDelay; - unsigned commitToFetchDelay; - unsigned fetchWidth; - - // - // Decode - // - unsigned renameToDecodeDelay; - unsigned iewToDecodeDelay; - unsigned commitToDecodeDelay; - unsigned fetchToDecodeDelay; - unsigned decodeWidth; - - // - // Rename - // - unsigned iewToRenameDelay; - unsigned commitToRenameDelay; - unsigned decodeToRenameDelay; - unsigned renameWidth; - - // - // IEW - // - unsigned commitToIEWDelay; - unsigned renameToIEWDelay; - unsigned issueToExecuteDelay; - unsigned issueWidth; - unsigned executeWidth; - unsigned executeIntWidth; - unsigned executeFloatWidth; - unsigned executeBranchWidth; - unsigned executeMemoryWidth; - FUPool *fuPool; - - // - // Commit - // - unsigned iewToCommitDelay; - unsigned renameToROBDelay; - unsigned commitWidth; - unsigned squashWidth; - - // - // Branch predictor (BP & BTB) - // - unsigned localPredictorSize; - unsigned localCtrBits; - unsigned localHistoryTableSize; - unsigned localHistoryBits; - unsigned globalPredictorSize; - unsigned globalCtrBits; - unsigned globalHistoryBits; - unsigned choicePredictorSize; - unsigned choiceCtrBits; - - unsigned BTBEntries; - unsigned BTBTagSize; - - unsigned RASSize; - - // - // Load store queue - // - unsigned LQEntries; - unsigned SQEntries; - - // - // Memory dependence - // - unsigned SSITSize; - unsigned LFSTSize; - - // - // Miscellaneous - // - unsigned numPhysIntRegs; - unsigned numPhysFloatRegs; - unsigned numIQEntries; - unsigned numROBEntries; - - bool decoupledFrontEnd; - int dispatchWidth; - int wbWidth; - - //SMT Parameters - unsigned smtNumFetchingThreads; - - std::string smtFetchPolicy; - - std::string smtIQPolicy; - unsigned smtIQThreshold; - - std::string smtLSQPolicy; - unsigned smtLSQThreshold; - - std::string smtCommitPolicy; - - std::string smtROBPolicy; - unsigned smtROBThreshold; - - // Probably can get this from somewhere. - unsigned instShiftAmt; -}; - -#endif // __CPU_OZONE_SIMPLE_PARAMS_HH__ diff --git a/cpu/ozone/thread_state.hh b/cpu/ozone/thread_state.hh deleted file mode 100644 index c86c3a720..000000000 --- a/cpu/ozone/thread_state.hh +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright (c) 2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_OZONE_THREAD_STATE_HH__ -#define __CPU_OZONE_THREAD_STATE_HH__ - -#include "arch/faults.hh" -#include "arch/isa_traits.hh" -#include "cpu/exec_context.hh" -#include "cpu/thread_state.hh" -#include "sim/process.hh" - -class Event; -//class Process; - -#if FULL_SYSTEM -class EndQuiesceEvent; -class FunctionProfile; -class ProfileNode; -#else -class Process; -class FunctionalMemory; -#endif - -// Maybe this ozone thread state should only really have committed state? -// I need to think about why I'm using this and what it's useful for. Clearly -// has benefits for SMT; basically serves same use as CPUExecContext. -// Makes the ExecContext proxy easier. Gives organization/central access point -// to state of a thread that can be accessed normally (i.e. not in-flight -// stuff within a OoO processor). Does this need an XC proxy within it? -template <class Impl> -struct OzoneThreadState : public ThreadState { - typedef typename ExecContext::Status Status; - typedef typename Impl::FullCPU FullCPU; - typedef TheISA::MiscReg MiscReg; - -#if FULL_SYSTEM - OzoneThreadState(FullCPU *_cpu, int _thread_num, FunctionalMemory *_mem) - : ThreadState(-1, _thread_num, _mem), - inSyscall(0), trapPending(0) - { - memset(®s, 0, sizeof(TheISA::RegFile)); - } -#else - OzoneThreadState(FullCPU *_cpu, int _thread_num, Process *_process, int _asid) - : ThreadState(-1, _thread_num, _process->getMemory(), _process, _asid), - cpu(_cpu), inSyscall(0), trapPending(0) - { - memset(®s, 0, sizeof(TheISA::RegFile)); - } - - OzoneThreadState(FullCPU *_cpu, int _thread_num, FunctionalMemory *_mem, - int _asid) - : ThreadState(-1, _thread_num, _mem, NULL, _asid), - cpu(_cpu), inSyscall(0), trapPending(0) - { - memset(®s, 0, sizeof(TheISA::RegFile)); - } -#endif - - Status _status; - - Status status() const { return _status; } - - void setStatus(Status new_status) { _status = new_status; } - - RenameTable<Impl> renameTable; - Addr PC; - Addr nextPC; - - // Current instruction - TheISA::MachInst inst; - - TheISA::RegFile regs; - - typename Impl::FullCPU *cpu; - - bool inSyscall; - - bool trapPending; - - ExecContext *xcProxy; - - ExecContext *getXCProxy() { return xcProxy; } - -#if !FULL_SYSTEM - - Fault dummyTranslation(MemReqPtr &req) - { -#if 0 - assert((req->vaddr >> 48 & 0xffff) == 0); -#endif - - // put the asid in the upper 16 bits of the paddr - req->paddr = req->vaddr & ~((Addr)0xffff << sizeof(Addr) * 8 - 16); - req->paddr = req->paddr | (Addr)req->asid << sizeof(Addr) * 8 - 16; - return NoFault; - } - Fault translateInstReq(MemReqPtr &req) - { - return dummyTranslation(req); - } - Fault translateDataReadReq(MemReqPtr &req) - { - return dummyTranslation(req); - } - Fault translateDataWriteReq(MemReqPtr &req) - { - return dummyTranslation(req); - } -#else - Fault translateInstReq(MemReqPtr &req) - { - return cpu->itb->translate(req); - } - - Fault translateDataReadReq(MemReqPtr &req) - { - return cpu->dtb->translate(req, false); - } - - Fault translateDataWriteReq(MemReqPtr &req) - { - return cpu->dtb->translate(req, true); - } -#endif - - MiscReg readMiscReg(int misc_reg) - { - return regs.miscRegs.readReg(misc_reg); - } - - MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) - { - return regs.miscRegs.readRegWithEffect(misc_reg, fault, xcProxy); - } - - Fault setMiscReg(int misc_reg, const MiscReg &val) - { - return regs.miscRegs.setReg(misc_reg, val); - } - - Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) - { - return regs.miscRegs.setRegWithEffect(misc_reg, val, xcProxy); - } - - uint64_t readPC() - { return PC; } - - void setPC(uint64_t val) - { PC = val; } - - uint64_t readNextPC() - { return nextPC; } - - void setNextPC(uint64_t val) - { nextPC = val; } - - bool misspeculating() { return false; } - - void setInst(TheISA::MachInst _inst) { inst = _inst; } - - Counter readFuncExeInst() { return funcExeInst; } - - void setFuncExeInst(Counter new_val) { funcExeInst = new_val; } -}; - -#endif // __CPU_OZONE_THREAD_STATE_HH__ diff --git a/cpu/pc_event.cc b/cpu/pc_event.cc deleted file mode 100644 index 050bf1a88..000000000 --- a/cpu/pc_event.cc +++ /dev/null @@ -1,155 +0,0 @@ -/* - * 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. - */ - -#include <algorithm> -#include <map> -#include <string> -#include <utility> - -#include "base/trace.hh" -#include "config/full_system.hh" -#include "cpu/base.hh" -#include "cpu/exec_context.hh" -#include "cpu/pc_event.hh" -#include "sim/debug.hh" -#include "sim/root.hh" -#include "sim/system.hh" - -using namespace std; - -PCEventQueue::PCEventQueue() -{} - -PCEventQueue::~PCEventQueue() -{} - -bool -PCEventQueue::remove(PCEvent *event) -{ - int removed = 0; - range_t range = equal_range(event); - for (iterator i = range.first; i != range.second; ++i) { - if (*i == event) { - DPRINTF(PCEvent, "PC based event removed at %#x: %s\n", - event->pc(), event->descr()); - pc_map.erase(i); - ++removed; - } - } - - return removed > 0; -} - -bool -PCEventQueue::schedule(PCEvent *event) -{ - pc_map.push_back(event); - sort(pc_map.begin(), pc_map.end(), MapCompare()); - - DPRINTF(PCEvent, "PC based event scheduled for %#x: %s\n", - event->pc(), event->descr()); - - return true; -} - -bool -PCEventQueue::doService(ExecContext *xc) -{ - Addr pc = xc->readPC() & ~0x3; - int serviced = 0; - range_t range = equal_range(pc); - for (iterator i = range.first; i != range.second; ++i) { - // Make sure that the pc wasn't changed as the side effect of - // another event. This for example, prevents two invocations - // of the SkipFuncEvent. Maybe we should have separate PC - // event queues for each processor? - if (pc != (xc->readPC() & ~0x3)) - continue; - - DPRINTF(PCEvent, "PC based event serviced at %#x: %s\n", - (*i)->pc(), (*i)->descr()); - - (*i)->process(xc); - ++serviced; - } - - return serviced > 0; -} - -void -PCEventQueue::dump() const -{ - const_iterator i = pc_map.begin(); - const_iterator e = pc_map.end(); - - for (; i != e; ++i) - cprintf("%d: event at %#x: %s\n", curTick, (*i)->pc(), - (*i)->descr()); -} - -PCEventQueue::range_t -PCEventQueue::equal_range(Addr pc) -{ - return std::equal_range(pc_map.begin(), pc_map.end(), pc, MapCompare()); -} - -BreakPCEvent::BreakPCEvent(PCEventQueue *q, const std::string &desc, Addr addr, - bool del) - : PCEvent(q, desc, addr), remove(del) -{ -} - -void -BreakPCEvent::process(ExecContext *xc) -{ - StringWrap name(xc->getCpuPtr()->name() + ".break_event"); - DPRINTFN("break event %s triggered\n", descr()); - debug_break(); - if (remove) - delete this; -} - -#if FULL_SYSTEM -extern "C" -void -sched_break_pc_sys(System *sys, Addr addr) -{ - new BreakPCEvent(&sys->pcEventQueue, "debug break", addr, true); -} - -extern "C" -void -sched_break_pc(Addr addr) -{ - for (vector<System *>::iterator sysi = System::systemList.begin(); - sysi != System::systemList.end(); ++sysi) { - sched_break_pc_sys(*sysi, addr); - } - -} -#endif diff --git a/cpu/pc_event.hh b/cpu/pc_event.hh deleted file mode 100644 index 7fa3902cc..000000000 --- a/cpu/pc_event.hh +++ /dev/null @@ -1,143 +0,0 @@ -/* - * 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. - */ - -#ifndef __PC_EVENT_HH__ -#define __PC_EVENT_HH__ - -#include <vector> - -#include "mem/mem_req.hh" - -class ExecContext; -class PCEventQueue; - -class PCEvent -{ - protected: - static const Addr badpc = MemReq::inval_addr; - - protected: - std::string description; - PCEventQueue *queue; - Addr evpc; - - public: - PCEvent(PCEventQueue *q, const std::string &desc, Addr pc); - - virtual ~PCEvent() { if (queue) remove(); } - - // for DPRINTF - virtual const std::string name() const { return description; } - - std::string descr() const { return description; } - Addr pc() const { return evpc; } - - bool remove(); - virtual void process(ExecContext *xc) = 0; -}; - -class PCEventQueue -{ - protected: - typedef PCEvent * record_t; - class MapCompare { - public: - bool operator()(const record_t &l, const record_t &r) const { - return l->pc() < r->pc(); - } - bool operator()(const record_t &l, Addr pc) const { - return l->pc() < pc; - } - bool operator()(Addr pc, const record_t &r) const { - return pc < r->pc(); - } - }; - typedef std::vector<record_t> map_t; - - public: - typedef map_t::iterator iterator; - typedef map_t::const_iterator const_iterator; - - protected: - typedef std::pair<iterator, iterator> range_t; - typedef std::pair<const_iterator, const_iterator> const_range_t; - - protected: - map_t pc_map; - - bool doService(ExecContext *xc); - - public: - PCEventQueue(); - ~PCEventQueue(); - - bool remove(PCEvent *event); - bool schedule(PCEvent *event); - bool service(ExecContext *xc) - { - if (pc_map.empty()) - return false; - - return doService(xc); - } - - range_t equal_range(Addr pc); - range_t equal_range(PCEvent *event) { return equal_range(event->pc()); } - - void dump() const; -}; - - -inline -PCEvent::PCEvent(PCEventQueue *q, const std::string &desc, Addr pc) - : description(desc), queue(q), evpc(pc) -{ - queue->schedule(this); -} - -inline bool -PCEvent::remove() -{ - if (!queue) - panic("cannot remove an uninitialized event;"); - - return queue->remove(this); -} - -class BreakPCEvent : public PCEvent -{ - protected: - bool remove; - - public: - BreakPCEvent(PCEventQueue *q, const std::string &desc, Addr addr, - bool del = false); - virtual void process(ExecContext *xc); -}; - -#endif // __PC_EVENT_HH__ diff --git a/cpu/profile.cc b/cpu/profile.cc deleted file mode 100644 index fe3458b61..000000000 --- a/cpu/profile.cc +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include <string> - -#include "base/bitfield.hh" -#include "base/callback.hh" -#include "base/statistics.hh" -#include "base/trace.hh" -#include "base/loader/symtab.hh" -#include "cpu/base.hh" -#include "cpu/exec_context.hh" -#include "cpu/profile.hh" - -using namespace std; - -ProfileNode::ProfileNode() - : count(0) -{ } - -void -ProfileNode::dump(const string &symbol, uint64_t id, const SymbolTable *symtab, - ostream &os) const -{ - ccprintf(os, "%#x %s %d ", id, symbol, count); - ChildList::const_iterator i, end = children.end(); - for (i = children.begin(); i != end; ++i) { - const ProfileNode *node = i->second; - ccprintf(os, "%#x ", (intptr_t)node); - } - - ccprintf(os, "\n"); - - for (i = children.begin(); i != end; ++i) { - Addr addr = i->first; - string symbol; - if (addr == 1) - symbol = "user"; - else if (addr == 2) - symbol = "console"; - else if (addr == 3) - symbol = "unknown"; - else if (!symtab->findSymbol(addr, symbol)) - panic("could not find symbol for address %#x\n", addr); - - const ProfileNode *node = i->second; - node->dump(symbol, (intptr_t)node, symtab, os); - } -} - -void -ProfileNode::clear() -{ - count = 0; - ChildList::iterator i, end = children.end(); - for (i = children.begin(); i != end; ++i) - i->second->clear(); -} - -FunctionProfile::FunctionProfile(const SymbolTable *_symtab) - : reset(0), symtab(_symtab) -{ - reset = new MakeCallback<FunctionProfile, &FunctionProfile::clear>(this); - Stats::registerResetCallback(reset); -} - -FunctionProfile::~FunctionProfile() -{ - if (reset) - delete reset; -} - -ProfileNode * -FunctionProfile::consume(const vector<Addr> &stack) -{ - ProfileNode *current = ⊤ - for (int i = 0, size = stack.size(); i < size; ++i) { - ProfileNode *&ptr = current->children[stack[size - i - 1]]; - if (ptr == NULL) - ptr = new ProfileNode; - - current = ptr; - } - - return current; -} - -void -FunctionProfile::clear() -{ - top.clear(); - pc_count.clear(); -} - -void -FunctionProfile::dump(ExecContext *xc, ostream &os) const -{ - ccprintf(os, ">>>PC data\n"); - map<Addr, Counter>::const_iterator i, end = pc_count.end(); - for (i = pc_count.begin(); i != end; ++i) { - Addr pc = i->first; - Counter count = i->second; - - std::string symbol; - if (pc == 1) - ccprintf(os, "user %d\n", count); - else if (symtab->findSymbol(pc, symbol) && !symbol.empty()) - ccprintf(os, "%s %d\n", symbol, count); - else - ccprintf(os, "%#x %d\n", pc, count); - } - - ccprintf(os, ">>>function data\n"); - top.dump("top", 0, symtab, os); -} - -void -FunctionProfile::sample(ProfileNode *node, Addr pc) -{ - node->count++; - - Addr symaddr; - if (symtab->findNearestAddr(pc, symaddr)) { - pc_count[symaddr]++; - } else { - // record PC even if we don't have a symbol to avoid - // silently biasing the histogram - pc_count[pc]++; - } -} diff --git a/cpu/profile.hh b/cpu/profile.hh deleted file mode 100644 index d55c9eec9..000000000 --- a/cpu/profile.hh +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __CPU_PROFILE_HH__ -#define __CPU_PROFILE_HH__ - -#include <map> - -#include "cpu/static_inst.hh" -#include "sim/host.hh" -#include "arch/stacktrace.hh" - -class ExecContext; - -class ProfileNode -{ - private: - friend class FunctionProfile; - - typedef std::map<Addr, ProfileNode *> ChildList; - ChildList children; - - public: - Counter count; - - public: - ProfileNode(); - - void dump(const std::string &symbol, uint64_t id, - const SymbolTable *symtab, std::ostream &os) const; - void clear(); -}; - -class Callback; -class FunctionProfile -{ - private: - Callback *reset; - const SymbolTable *symtab; - ProfileNode top; - std::map<Addr, Counter> pc_count; - StackTrace trace; - - public: - FunctionProfile(const SymbolTable *symtab); - ~FunctionProfile(); - - ProfileNode *consume(ExecContext *xc, StaticInstPtr inst); - ProfileNode *consume(const std::vector<Addr> &stack); - void clear(); - void dump(ExecContext *xc, std::ostream &out) const; - void sample(ProfileNode *node, Addr pc); -}; - -inline ProfileNode * -FunctionProfile::consume(ExecContext *xc, StaticInstPtr inst) -{ - if (!trace.trace(xc, inst)) - return NULL; - trace.dprintf(); - return consume(trace.getstack()); -} - -#endif // __CPU_PROFILE_HH__ diff --git a/cpu/quiesce_event.cc b/cpu/quiesce_event.cc deleted file mode 100644 index 37814ae09..000000000 --- a/cpu/quiesce_event.cc +++ /dev/null @@ -1,20 +0,0 @@ - -#include "cpu/exec_context.hh" -#include "cpu/quiesce_event.hh" - -EndQuiesceEvent::EndQuiesceEvent(ExecContext *_xc) - : Event(&mainEventQueue), xc(_xc) -{ -} - -void -EndQuiesceEvent::process() -{ - xc->activate(); -} - -const char* -EndQuiesceEvent::description() -{ - return "End Quiesce Event."; -} diff --git a/cpu/quiesce_event.hh b/cpu/quiesce_event.hh deleted file mode 100644 index 18e88ecce..000000000 --- a/cpu/quiesce_event.hh +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef __CPU_QUIESCE_EVENT_HH__ -#define __CPU_QUIESCE_EVENT_HH__ - -#include "sim/eventq.hh" - -class ExecContext; - -/** Event for timing out quiesce instruction */ -struct EndQuiesceEvent : public Event -{ - /** A pointer to the execution context that is quiesced */ - ExecContext *xc; - - EndQuiesceEvent(ExecContext *_xc); - - /** Event process to occur at interrupt*/ - virtual void process(); - - /** Event description */ - virtual const char *description(); -}; - -#endif // __CPU_QUIESCE_EVENT_HH__ diff --git a/cpu/simple/cpu.cc b/cpu/simple/cpu.cc deleted file mode 100644 index 6e584f171..000000000 --- a/cpu/simple/cpu.cc +++ /dev/null @@ -1,950 +0,0 @@ -/* - * 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. - */ - -#include <cmath> -#include <cstdio> -#include <cstdlib> -#include <iostream> -#include <iomanip> -#include <list> -#include <sstream> -#include <string> - -#include "base/cprintf.hh" -#include "base/inifile.hh" -#include "base/loader/symtab.hh" -#include "base/misc.hh" -#include "base/pollevent.hh" -#include "base/range.hh" -#include "base/stats/events.hh" -#include "base/trace.hh" -#include "cpu/base.hh" -#include "cpu/cpu_exec_context.hh" -#include "cpu/exec_context.hh" -#include "cpu/exetrace.hh" -#include "cpu/profile.hh" -#include "cpu/sampler/sampler.hh" -#include "cpu/simple/cpu.hh" -#include "cpu/smt.hh" -#include "cpu/static_inst.hh" -#include "kern/kernel_stats.hh" -#include "mem/base_mem.hh" -#include "mem/mem_interface.hh" -#include "sim/byteswap.hh" -#include "sim/builder.hh" -#include "sim/debug.hh" -#include "sim/host.hh" -#include "sim/sim_events.hh" -#include "sim/sim_object.hh" -#include "sim/stats.hh" - -#if FULL_SYSTEM -#include "base/remote_gdb.hh" -#include "mem/functional/memory_control.hh" -#include "mem/functional/physical.hh" -#include "sim/system.hh" -#include "arch/tlb.hh" -#include "arch/stacktrace.hh" -#include "arch/vtophys.hh" -#else // !FULL_SYSTEM -#include "mem/functional/functional.hh" -#endif // FULL_SYSTEM - -using namespace std; -//The SimpleCPU does alpha only -using namespace AlphaISA; - - -SimpleCPU::TickEvent::TickEvent(SimpleCPU *c, int w) - : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c), width(w) -{ -} - - -void -SimpleCPU::init() -{ - BaseCPU::init(); -#if FULL_SYSTEM - for (int i = 0; i < execContexts.size(); ++i) { - ExecContext *xc = execContexts[i]; - - // initialize CPU, including PC - TheISA::initCPU(xc, xc->readCpuId()); - } -#endif -} - -void -SimpleCPU::TickEvent::process() -{ - int count = width; - do { - cpu->tick(); - } while (--count > 0 && cpu->status() == Running); -} - -const char * -SimpleCPU::TickEvent::description() -{ - return "SimpleCPU tick event"; -} - - -SimpleCPU::CacheCompletionEvent::CacheCompletionEvent(SimpleCPU *_cpu) - : Event(&mainEventQueue), cpu(_cpu) -{ -} - -void SimpleCPU::CacheCompletionEvent::process() -{ - cpu->processCacheCompletion(); -} - -const char * -SimpleCPU::CacheCompletionEvent::description() -{ - return "SimpleCPU cache completion event"; -} - -SimpleCPU::SimpleCPU(Params *p) - : BaseCPU(p), tickEvent(this, p->width), cpuXC(NULL), - cacheCompletionEvent(this) -{ - _status = Idle; -#if FULL_SYSTEM - cpuXC = new CPUExecContext(this, 0, p->system, p->itb, p->dtb, p->mem); - -#else - cpuXC = new CPUExecContext(this, /* thread_num */ 0, p->process, - /* asid */ 0); -#endif // !FULL_SYSTEM - cpuXC->setStatus(ExecContext::Suspended); - xcProxy = cpuXC->getProxy(); - - icacheInterface = p->icache_interface; - dcacheInterface = p->dcache_interface; - - memReq = new MemReq(); - memReq->xc = xcProxy; - memReq->asid = 0; - memReq->data = new uint8_t[64]; - - numInst = 0; - startNumInst = 0; - numLoad = 0; - startNumLoad = 0; - lastIcacheStall = 0; - lastDcacheStall = 0; - - execContexts.push_back(xcProxy); -} - -SimpleCPU::~SimpleCPU() -{ -} - -void -SimpleCPU::switchOut(Sampler *s) -{ - sampler = s; - if (status() == DcacheMissStall) { - DPRINTF(Sampler,"Outstanding dcache access, waiting for completion\n"); - _status = DcacheMissSwitch; - } - else { - _status = SwitchedOut; - - if (tickEvent.scheduled()) - tickEvent.squash(); - - sampler->signalSwitched(); - } -} - - -void -SimpleCPU::takeOverFrom(BaseCPU *oldCPU) -{ - BaseCPU::takeOverFrom(oldCPU); - - assert(!tickEvent.scheduled()); - - // if any of this CPU's ExecContexts are active, mark the CPU as - // running and schedule its tick event. - for (int i = 0; i < execContexts.size(); ++i) { - ExecContext *xc = execContexts[i]; - if (xc->status() == ExecContext::Active && _status != Running) { - _status = Running; - tickEvent.schedule(curTick); - } - } -} - - -void -SimpleCPU::activateContext(int thread_num, int delay) -{ - assert(thread_num == 0); - assert(cpuXC); - - assert(_status == Idle || _status == SwitchedOut); - notIdleFraction++; - scheduleTickEvent(delay); - _status = Running; -} - - -void -SimpleCPU::suspendContext(int thread_num) -{ - assert(thread_num == 0); - assert(cpuXC); - - assert(_status == Running || _status == SwitchedOut); - notIdleFraction--; - unscheduleTickEvent(); - _status = Idle; -} - - -void -SimpleCPU::deallocateContext(int thread_num) -{ - // for now, these are equivalent - suspendContext(thread_num); -} - - -void -SimpleCPU::haltContext(int thread_num) -{ - // for now, these are equivalent - suspendContext(thread_num); -} - - -void -SimpleCPU::regStats() -{ - using namespace Stats; - - BaseCPU::regStats(); - - numInsts - .name(name() + ".num_insts") - .desc("Number of instructions executed") - ; - - numMemRefs - .name(name() + ".num_refs") - .desc("Number of memory references") - ; - - notIdleFraction - .name(name() + ".not_idle_fraction") - .desc("Percentage of non-idle cycles") - ; - - idleFraction - .name(name() + ".idle_fraction") - .desc("Percentage of idle cycles") - ; - - icacheStallCycles - .name(name() + ".icache_stall_cycles") - .desc("ICache total stall cycles") - .prereq(icacheStallCycles) - ; - - dcacheStallCycles - .name(name() + ".dcache_stall_cycles") - .desc("DCache total stall cycles") - .prereq(dcacheStallCycles) - ; - - idleFraction = constant(1.0) - notIdleFraction; -} - -void -SimpleCPU::resetStats() -{ - startNumInst = numInst; - notIdleFraction = (_status != Idle); -} - -void -SimpleCPU::serialize(ostream &os) -{ - BaseCPU::serialize(os); - SERIALIZE_ENUM(_status); - SERIALIZE_SCALAR(inst); - nameOut(os, csprintf("%s.xc", name())); - cpuXC->serialize(os); - nameOut(os, csprintf("%s.tickEvent", name())); - tickEvent.serialize(os); - nameOut(os, csprintf("%s.cacheCompletionEvent", name())); - cacheCompletionEvent.serialize(os); -} - -void -SimpleCPU::unserialize(Checkpoint *cp, const string §ion) -{ - BaseCPU::unserialize(cp, section); - UNSERIALIZE_ENUM(_status); - UNSERIALIZE_SCALAR(inst); - cpuXC->unserialize(cp, csprintf("%s.xc", section)); - tickEvent.unserialize(cp, csprintf("%s.tickEvent", section)); - cacheCompletionEvent - .unserialize(cp, csprintf("%s.cacheCompletionEvent", section)); -} - -void -change_thread_state(int thread_number, int activate, int priority) -{ -} - -Fault -SimpleCPU::copySrcTranslate(Addr src) -{ - static bool no_warn = true; - int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; - // Only support block sizes of 64 atm. - assert(blk_size == 64); - int offset = src & (blk_size - 1); - - // Make sure block doesn't span page - if (no_warn && - (src & PageMask) != ((src + blk_size) & PageMask) && - (src >> 40) != 0xfffffc) { - warn("Copied block source spans pages %x.", src); - no_warn = false; - } - - memReq->reset(src & ~(blk_size - 1), blk_size); - - // translate to physical address - Fault fault = cpuXC->translateDataReadReq(memReq); - - if (fault == NoFault) { - cpuXC->copySrcAddr = src; - cpuXC->copySrcPhysAddr = memReq->paddr + offset; - } else { - assert(!fault->isAlignmentFault()); - - cpuXC->copySrcAddr = 0; - cpuXC->copySrcPhysAddr = 0; - } - return fault; -} - -Fault -SimpleCPU::copy(Addr dest) -{ - static bool no_warn = true; - int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; - // Only support block sizes of 64 atm. - assert(blk_size == 64); - uint8_t data[blk_size]; - //assert(cpuXC->copySrcAddr); - int offset = dest & (blk_size - 1); - - // Make sure block doesn't span page - if (no_warn && - (dest & PageMask) != ((dest + blk_size) & PageMask) && - (dest >> 40) != 0xfffffc) { - no_warn = false; - warn("Copied block destination spans pages %x. ", dest); - } - - memReq->reset(dest & ~(blk_size -1), blk_size); - // translate to physical address - Fault fault = cpuXC->translateDataWriteReq(memReq); - - if (fault == NoFault) { - Addr dest_addr = memReq->paddr + offset; - // Need to read straight from memory since we have more than 8 bytes. - memReq->paddr = cpuXC->copySrcPhysAddr; - cpuXC->mem->read(memReq, data); - memReq->paddr = dest_addr; - cpuXC->mem->write(memReq, data); - if (dcacheInterface) { - memReq->cmd = Copy; - memReq->completionEvent = NULL; - memReq->paddr = cpuXC->copySrcPhysAddr; - memReq->dest = dest_addr; - memReq->size = 64; - memReq->time = curTick; - memReq->flags &= ~INST_READ; - dcacheInterface->access(memReq); - } - } - else - assert(!fault->isAlignmentFault()); - - return fault; -} - -// precise architected memory state accessor macros -template <class T> -Fault -SimpleCPU::read(Addr addr, T &data, unsigned flags) -{ - if (status() == DcacheMissStall || status() == DcacheMissSwitch) { - Fault fault = cpuXC->read(memReq,data); - - if (traceData) { - traceData->setAddr(memReq->vaddr); - } - return fault; - } - - memReq->reset(addr, sizeof(T), flags); - - // translate to physical address - Fault fault = cpuXC->translateDataReadReq(memReq); - - // if we have a cache, do cache access too - if (fault == NoFault && dcacheInterface) { - memReq->cmd = Read; - memReq->completionEvent = NULL; - memReq->time = curTick; - memReq->flags &= ~INST_READ; - MemAccessResult result = dcacheInterface->access(memReq); - - // Ugly hack to get an event scheduled *only* if the access is - // a miss. We really should add first-class support for this - // at some point. - if (result != MA_HIT && dcacheInterface->doEvents()) { - memReq->completionEvent = &cacheCompletionEvent; - lastDcacheStall = curTick; - unscheduleTickEvent(); - _status = DcacheMissStall; - } else { - // do functional access - fault = cpuXC->read(memReq, data); - - } - } else if(fault == NoFault) { - // do functional access - fault = cpuXC->read(memReq, data); - - } - - if (!dcacheInterface && (memReq->flags & UNCACHEABLE)) - recordEvent("Uncached Read"); - - return fault; -} - -#ifndef DOXYGEN_SHOULD_SKIP_THIS - -template -Fault -SimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); - -template -Fault -SimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); - -template -Fault -SimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); - -template -Fault -SimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); - -#endif //DOXYGEN_SHOULD_SKIP_THIS - -template<> -Fault -SimpleCPU::read(Addr addr, double &data, unsigned flags) -{ - return read(addr, *(uint64_t*)&data, flags); -} - -template<> -Fault -SimpleCPU::read(Addr addr, float &data, unsigned flags) -{ - return read(addr, *(uint32_t*)&data, flags); -} - - -template<> -Fault -SimpleCPU::read(Addr addr, int32_t &data, unsigned flags) -{ - return read(addr, (uint32_t&)data, flags); -} - - -template <class T> -Fault -SimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) -{ - memReq->reset(addr, sizeof(T), flags); - - // translate to physical address - Fault fault = cpuXC->translateDataWriteReq(memReq); - - // do functional access - if (fault == NoFault) - fault = cpuXC->write(memReq, data); - - if (fault == NoFault && dcacheInterface) { - memReq->cmd = Write; - memcpy(memReq->data,(uint8_t *)&data,memReq->size); - memReq->completionEvent = NULL; - memReq->time = curTick; - memReq->flags &= ~INST_READ; - MemAccessResult result = dcacheInterface->access(memReq); - - // Ugly hack to get an event scheduled *only* if the access is - // a miss. We really should add first-class support for this - // at some point. - if (result != MA_HIT && dcacheInterface->doEvents()) { - memReq->completionEvent = &cacheCompletionEvent; - lastDcacheStall = curTick; - unscheduleTickEvent(); - _status = DcacheMissStall; - } - } - - if (res && (fault == NoFault)) - *res = memReq->result; - - if (!dcacheInterface && (memReq->flags & UNCACHEABLE)) - recordEvent("Uncached Write"); - - return fault; -} - - -#ifndef DOXYGEN_SHOULD_SKIP_THIS -template -Fault -SimpleCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res); - -template -Fault -SimpleCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res); - -template -Fault -SimpleCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res); - -template -Fault -SimpleCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res); - -#endif //DOXYGEN_SHOULD_SKIP_THIS - -template<> -Fault -SimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) -{ - return write(*(uint64_t*)&data, addr, flags, res); -} - -template<> -Fault -SimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) -{ - return write(*(uint32_t*)&data, addr, flags, res); -} - - -template<> -Fault -SimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) -{ - return write((uint32_t)data, addr, flags, res); -} - - -#if FULL_SYSTEM -Addr -SimpleCPU::dbg_vtophys(Addr addr) -{ - return vtophys(xcProxy, addr); -} -#endif // FULL_SYSTEM - -void -SimpleCPU::processCacheCompletion() -{ - switch (status()) { - case IcacheMissStall: - icacheStallCycles += curTick - lastIcacheStall; - _status = IcacheMissComplete; - scheduleTickEvent(1); - break; - case DcacheMissStall: - if (memReq->cmd.isRead()) { - curStaticInst->execute(this,traceData); - if (traceData) - traceData->finalize(); - } - dcacheStallCycles += curTick - lastDcacheStall; - _status = Running; - scheduleTickEvent(1); - break; - case DcacheMissSwitch: - if (memReq->cmd.isRead()) { - curStaticInst->execute(this,traceData); - if (traceData) - traceData->finalize(); - } - _status = SwitchedOut; - sampler->signalSwitched(); - case SwitchedOut: - // If this CPU has been switched out due to sampling/warm-up, - // ignore any further status changes (e.g., due to cache - // misses outstanding at the time of the switch). - return; - default: - panic("SimpleCPU::processCacheCompletion: bad state"); - break; - } -} - -#if FULL_SYSTEM -void -SimpleCPU::post_interrupt(int int_num, int index) -{ - BaseCPU::post_interrupt(int_num, index); - - if (cpuXC->status() == ExecContext::Suspended) { - DPRINTF(IPI,"Suspended Processor awoke\n"); - cpuXC->activate(); - } -} -#endif // FULL_SYSTEM - -/* start simulation, program loaded, processor precise state initialized */ -void -SimpleCPU::tick() -{ - numCycles++; - - traceData = NULL; - - Fault fault = NoFault; - -#if FULL_SYSTEM - if (checkInterrupts && check_interrupts() && !cpuXC->inPalMode() && - status() != IcacheMissComplete) { - int ipl = 0; - int summary = 0; - checkInterrupts = false; - - if (cpuXC->readMiscReg(IPR_SIRR)) { - for (int i = INTLEVEL_SOFTWARE_MIN; - i < INTLEVEL_SOFTWARE_MAX; i++) { - if (cpuXC->readMiscReg(IPR_SIRR) & (ULL(1) << i)) { - // See table 4-19 of 21164 hardware reference - ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1; - summary |= (ULL(1) << i); - } - } - } - - uint64_t interrupts = cpuXC->cpu->intr_status(); - for (int i = INTLEVEL_EXTERNAL_MIN; - i < INTLEVEL_EXTERNAL_MAX; i++) { - if (interrupts & (ULL(1) << i)) { - // See table 4-19 of 21164 hardware reference - ipl = i; - summary |= (ULL(1) << i); - } - } - - if (cpuXC->readMiscReg(IPR_ASTRR)) - panic("asynchronous traps not implemented\n"); - - if (ipl && ipl > cpuXC->readMiscReg(IPR_IPLR)) { - cpuXC->setMiscReg(IPR_ISR, summary); - cpuXC->setMiscReg(IPR_INTID, ipl); - - Fault(new InterruptFault)->invoke(xcProxy); - - DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", - cpuXC->readMiscReg(IPR_IPLR), ipl, summary); - } - } -#endif - - // maintain $r0 semantics - cpuXC->setIntReg(ZeroReg, 0); -#ifdef TARGET_ALPHA - cpuXC->setFloatRegDouble(ZeroReg, 0.0); -#endif // TARGET_ALPHA - - if (status() == IcacheMissComplete) { - // We've already fetched an instruction and were stalled on an - // I-cache miss. No need to fetch it again. - - // Set status to running; tick event will get rescheduled if - // necessary at end of tick() function. - _status = Running; - } - else { - // Try to fetch an instruction - - // set up memory request for instruction fetch -#if FULL_SYSTEM -#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0 -#else -#define IFETCH_FLAGS(pc) 0 -#endif - - memReq->cmd = Read; - memReq->reset(cpuXC->readPC() & ~3, sizeof(uint32_t), - IFETCH_FLAGS(cpuXC->readPC())); - - fault = cpuXC->translateInstReq(memReq); - - if (fault == NoFault) - fault = cpuXC->mem->read(memReq, inst); - - if (icacheInterface && fault == NoFault) { - memReq->completionEvent = NULL; - - memReq->time = curTick; - memReq->flags |= INST_READ; - MemAccessResult result = icacheInterface->access(memReq); - - // Ugly hack to get an event scheduled *only* if the access is - // a miss. We really should add first-class support for this - // at some point. - if (result != MA_HIT && icacheInterface->doEvents()) { - memReq->completionEvent = &cacheCompletionEvent; - lastIcacheStall = curTick; - unscheduleTickEvent(); - _status = IcacheMissStall; - return; - } - } - } - - // If we've got a valid instruction (i.e., no fault on instruction - // fetch), then execute it. - if (fault == NoFault) { - - // keep an instruction count - numInst++; - numInsts++; - - // check for instruction-count-based events - comInstEventQueue[0]->serviceEvents(numInst); - - // decode the instruction - inst = gtoh(inst); - curStaticInst = StaticInst::decode(makeExtMI(inst, cpuXC->readPC())); - - traceData = Trace::getInstRecord(curTick, xcProxy, this, curStaticInst, - cpuXC->readPC()); - -#if FULL_SYSTEM - cpuXC->setInst(inst); -#endif // FULL_SYSTEM - - cpuXC->func_exe_inst++; - - fault = curStaticInst->execute(this, traceData); - -#if FULL_SYSTEM - if (cpuXC->profile) { - bool usermode = - (cpuXC->readMiscReg(AlphaISA::IPR_DTB_CM) & 0x18) != 0; - cpuXC->profilePC = usermode ? 1 : cpuXC->readPC(); - ProfileNode *node = cpuXC->profile->consume(xcProxy, inst); - if (node) - cpuXC->profileNode = node; - } -#endif - - if (curStaticInst->isMemRef()) { - numMemRefs++; - } - - if (curStaticInst->isLoad()) { - ++numLoad; - comLoadEventQueue[0]->serviceEvents(numLoad); - } - - // If we have a dcache miss, then we can't finialize the instruction - // trace yet because we want to populate it with the data later - if (traceData && - !(status() == DcacheMissStall && memReq->cmd.isRead())) { - traceData->finalize(); - } - - traceFunctions(cpuXC->readPC()); - - } // if (fault == NoFault) - - if (fault != NoFault) { -#if FULL_SYSTEM - fault->invoke(xcProxy); -#else // !FULL_SYSTEM - fatal("fault (%d) detected @ PC 0x%08p", fault, cpuXC->readPC()); -#endif // FULL_SYSTEM - } - else { -#if THE_ISA != MIPS_ISA - // go to the next instruction - cpuXC->setPC(cpuXC->readNextPC()); - cpuXC->setNextPC(cpuXC->readNextPC() + sizeof(MachInst)); -#else - // go to the next instruction - cpuXC->setPC(cpuXC->readNextPC()); - cpuXC->setNextPC(cpuXC->readNextNPC()); - cpuXC->setNextNPC(cpuXC->readNextNPC() + sizeof(MachInst)); -#endif - - } - -#if FULL_SYSTEM - Addr oldpc; - do { - oldpc = cpuXC->readPC(); - system->pcEventQueue.service(xcProxy); - } while (oldpc != cpuXC->readPC()); -#endif - - assert(status() == Running || - status() == Idle || - status() == DcacheMissStall); - - if (status() == Running && !tickEvent.scheduled()) - tickEvent.schedule(curTick + cycles(1)); -} - -//////////////////////////////////////////////////////////////////////// -// -// SimpleCPU Simulation Object -// -BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) - - Param<Counter> max_insts_any_thread; - Param<Counter> max_insts_all_threads; - Param<Counter> max_loads_any_thread; - Param<Counter> max_loads_all_threads; - -#if FULL_SYSTEM - SimObjectParam<AlphaITB *> itb; - SimObjectParam<AlphaDTB *> dtb; - SimObjectParam<FunctionalMemory *> mem; - SimObjectParam<System *> system; - Param<int> cpu_id; - Param<Tick> profile; -#else - SimObjectParam<Process *> workload; -#endif // FULL_SYSTEM - - Param<int> clock; - SimObjectParam<BaseMem *> icache; - SimObjectParam<BaseMem *> dcache; - - Param<bool> defer_registration; - Param<int> width; - Param<bool> function_trace; - Param<Tick> function_trace_start; - -END_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) - -BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU) - - INIT_PARAM(max_insts_any_thread, - "terminate when any thread reaches this inst count"), - INIT_PARAM(max_insts_all_threads, - "terminate when all threads have reached this inst count"), - INIT_PARAM(max_loads_any_thread, - "terminate when any thread reaches this load count"), - INIT_PARAM(max_loads_all_threads, - "terminate when all threads have reached this load count"), - -#if FULL_SYSTEM - INIT_PARAM(itb, "Instruction TLB"), - INIT_PARAM(dtb, "Data TLB"), - INIT_PARAM(mem, "memory"), - INIT_PARAM(system, "system object"), - INIT_PARAM(cpu_id, "processor ID"), - INIT_PARAM(profile, ""), -#else - INIT_PARAM(workload, "processes to run"), -#endif // FULL_SYSTEM - - INIT_PARAM(clock, "clock speed"), - INIT_PARAM(icache, "L1 instruction cache object"), - INIT_PARAM(dcache, "L1 data cache object"), - INIT_PARAM(defer_registration, "defer system registration (for sampling)"), - INIT_PARAM(width, "cpu width"), - INIT_PARAM(function_trace, "Enable function trace"), - INIT_PARAM(function_trace_start, "Cycle to start function trace") - -END_INIT_SIM_OBJECT_PARAMS(SimpleCPU) - - -CREATE_SIM_OBJECT(SimpleCPU) -{ - SimpleCPU::Params *params = new SimpleCPU::Params(); - params->name = getInstanceName(); - params->numberOfThreads = 1; - params->max_insts_any_thread = max_insts_any_thread; - params->max_insts_all_threads = max_insts_all_threads; - params->max_loads_any_thread = max_loads_any_thread; - params->max_loads_all_threads = max_loads_all_threads; - params->deferRegistration = defer_registration; - params->clock = clock; - params->functionTrace = function_trace; - params->functionTraceStart = function_trace_start; - params->icache_interface = (icache) ? icache->getInterface() : NULL; - params->dcache_interface = (dcache) ? dcache->getInterface() : NULL; - params->width = width; - -#if FULL_SYSTEM - params->itb = itb; - params->dtb = dtb; - params->mem = mem; - params->system = system; - params->cpu_id = cpu_id; - params->profile = profile; -#else - params->process = workload; -#endif - - SimpleCPU *cpu = new SimpleCPU(params); - return cpu; -} - -REGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU) - diff --git a/cpu/simple/cpu.hh b/cpu/simple/cpu.hh deleted file mode 100644 index 4ab9a1c3e..000000000 --- a/cpu/simple/cpu.hh +++ /dev/null @@ -1,363 +0,0 @@ -/* - * 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. - */ - -#ifndef __CPU_SIMPLE_CPU_SIMPLE_CPU_HH__ -#define __CPU_SIMPLE_CPU_SIMPLE_CPU_HH__ - -#include "base/statistics.hh" -#include "config/full_system.hh" -#include "cpu/base.hh" -#include "cpu/cpu_exec_context.hh" -#include "cpu/pc_event.hh" -#include "cpu/sampler/sampler.hh" -#include "cpu/static_inst.hh" -#include "sim/eventq.hh" - -// forward declarations -#if FULL_SYSTEM -class Processor; -class AlphaITB; -class AlphaDTB; -class PhysicalMemory; - -class RemoteGDB; -class GDBListener; - -#else - -class Process; - -#endif // FULL_SYSTEM - -class ExecContext; -class MemInterface; -class Checkpoint; - -namespace Trace { - class InstRecord; -} - -class SimpleCPU : public BaseCPU -{ - protected: - typedef TheISA::MachInst MachInst; - typedef TheISA::MiscReg MiscReg; - public: - // main simulation loop (one cycle) - void tick(); - virtual void init(); - - private: - struct TickEvent : public Event - { - SimpleCPU *cpu; - int width; - - TickEvent(SimpleCPU *c, int w); - void process(); - const char *description(); - }; - - TickEvent tickEvent; - - /// Schedule tick event, regardless of its current state. - void scheduleTickEvent(int numCycles) - { - if (tickEvent.squashed()) - tickEvent.reschedule(curTick + cycles(numCycles)); - else if (!tickEvent.scheduled()) - tickEvent.schedule(curTick + cycles(numCycles)); - } - - /// Unschedule tick event, regardless of its current state. - void unscheduleTickEvent() - { - if (tickEvent.scheduled()) - tickEvent.squash(); - } - - private: - Trace::InstRecord *traceData; - - public: - // - enum Status { - Running, - Idle, - IcacheMissStall, - IcacheMissComplete, - DcacheMissStall, - DcacheMissSwitch, - SwitchedOut - }; - - private: - Status _status; - - public: - void post_interrupt(int int_num, int index); - - void zero_fill_64(Addr addr) { - static int warned = 0; - if (!warned) { - warn ("WH64 is not implemented"); - warned = 1; - } - }; - - public: - struct Params : public BaseCPU::Params - { - MemInterface *icache_interface; - MemInterface *dcache_interface; - int width; -#if FULL_SYSTEM - AlphaITB *itb; - AlphaDTB *dtb; - FunctionalMemory *mem; -#else - Process *process; -#endif - }; - SimpleCPU(Params *params); - virtual ~SimpleCPU(); - - public: - // execution context - CPUExecContext *cpuXC; - - ExecContext *xcProxy; - - void switchOut(Sampler *s); - void takeOverFrom(BaseCPU *oldCPU); - -#if FULL_SYSTEM - Addr dbg_vtophys(Addr addr); - - bool interval_stats; -#endif - - // L1 instruction cache - MemInterface *icacheInterface; - - // L1 data cache - MemInterface *dcacheInterface; - - // current instruction - MachInst inst; - - // Refcounted pointer to the one memory request. - MemReqPtr memReq; - - // Pointer to the sampler that is telling us to switchover. - // Used to signal the completion of the pipe drain and schedule - // the next switchover - Sampler *sampler; - - StaticInstPtr curStaticInst; - - class CacheCompletionEvent : public Event - { - private: - SimpleCPU *cpu; - - public: - CacheCompletionEvent(SimpleCPU *_cpu); - - virtual void process(); - virtual const char *description(); - }; - - CacheCompletionEvent cacheCompletionEvent; - - Status status() const { return _status; } - - virtual void activateContext(int thread_num, int delay); - virtual void suspendContext(int thread_num); - virtual void deallocateContext(int thread_num); - virtual void haltContext(int thread_num); - - // statistics - virtual void regStats(); - virtual void resetStats(); - - // number of simulated instructions - Counter numInst; - Counter startNumInst; - Stats::Scalar<> numInsts; - - virtual Counter totalInstructions() const - { - return numInst - startNumInst; - } - - // number of simulated memory references - Stats::Scalar<> numMemRefs; - - // number of simulated loads - Counter numLoad; - Counter startNumLoad; - - // number of idle cycles - Stats::Average<> notIdleFraction; - Stats::Formula idleFraction; - - // number of cycles stalled for I-cache misses - Stats::Scalar<> icacheStallCycles; - Counter lastIcacheStall; - - // number of cycles stalled for D-cache misses - Stats::Scalar<> dcacheStallCycles; - Counter lastDcacheStall; - - void processCacheCompletion(); - - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); - - template <class T> - Fault read(Addr addr, T &data, unsigned flags); - - template <class T> - Fault write(T data, Addr addr, unsigned flags, uint64_t *res); - - // 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"); } - - void prefetch(Addr addr, unsigned flags) - { - // need to do this... - } - - void writeHint(Addr addr, int size, unsigned flags) - { - // need to do this... - } - - Fault copySrcTranslate(Addr src); - - Fault copy(Addr dest); - - // 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 readIntReg(const StaticInst *si, int idx) - { - return cpuXC->readIntReg(si->srcRegIdx(idx)); - } - - float readFloatRegSingle(const StaticInst *si, int idx) - { - int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag; - return cpuXC->readFloatRegSingle(reg_idx); - } - - double readFloatRegDouble(const StaticInst *si, int idx) - { - int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag; - return cpuXC->readFloatRegDouble(reg_idx); - } - - uint64_t readFloatRegInt(const StaticInst *si, int idx) - { - int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag; - return cpuXC->readFloatRegInt(reg_idx); - } - - void setIntReg(const StaticInst *si, int idx, uint64_t val) - { - cpuXC->setIntReg(si->destRegIdx(idx), val); - } - - void setFloatRegSingle(const StaticInst *si, int idx, float val) - { - int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag; - cpuXC->setFloatRegSingle(reg_idx, val); - } - - void setFloatRegDouble(const StaticInst *si, int idx, double val) - { - int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag; - cpuXC->setFloatRegDouble(reg_idx, val); - } - - void setFloatRegInt(const StaticInst *si, int idx, uint64_t val) - { - int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag; - cpuXC->setFloatRegInt(reg_idx, val); - } - - uint64_t readPC() { return cpuXC->readPC(); } - void setNextPC(uint64_t val) { cpuXC->setNextPC(val); } - - MiscReg readMiscReg(int misc_reg) - { - return cpuXC->readMiscReg(misc_reg); - } - - MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) - { - return cpuXC->readMiscRegWithEffect(misc_reg, fault); - } - - Fault setMiscReg(int misc_reg, const MiscReg &val) - { - return cpuXC->setMiscReg(misc_reg, val); - } - - Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) - { - return cpuXC->setMiscRegWithEffect(misc_reg, val); - } - -#if FULL_SYSTEM - Fault hwrei() { return cpuXC->hwrei(); } - int readIntrFlag() { return cpuXC->readIntrFlag(); } - void setIntrFlag(int val) { cpuXC->setIntrFlag(val); } - bool inPalMode() { return cpuXC->inPalMode(); } - void ev5_trap(Fault fault) { fault->invoke(xcProxy); } - bool simPalCheck(int palFunc) { return cpuXC->simPalCheck(palFunc); } -#else - void syscall() { cpuXC->syscall(); } -#endif - - bool misspeculating() { return cpuXC->misspeculating(); } - ExecContext *xcBase() { return xcProxy; } -}; - -#endif // __CPU_SIMPLE_CPU_SIMPLE_CPU_HH__ diff --git a/cpu/smt.hh b/cpu/smt.hh deleted file mode 100644 index 9c52abf95..000000000 --- a/cpu/smt.hh +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 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. - */ - -/** - * @file - * Defines SMT_MAX_THREADS. - */ - -#ifndef __SMT_HH__ -#define __SMT_HH__ - -#ifndef SMT_MAX_THREADS -/** The number of TPUs in any processor. */ -#define SMT_MAX_THREADS 4 -#endif - -/** - * The maximum number of active threads across all cpus. Used to - * initialize per-thread statistics in the cache. - * - * NB: Be careful to only use it once all the CPUs that you care about - * have been initialized - */ -extern int maxThreadsPerCPU; - -/** - * Changes the status and priority of the thread with the given number. - * @param thread_number The thread to change. - * @param activate The new active status. - * @param priority The new priority. - */ -void change_thread_state(int thread_number, int activate, int priority); - -#endif // __SMT_HH__ diff --git a/cpu/static_inst.cc b/cpu/static_inst.cc deleted file mode 100644 index c307dc6fc..000000000 --- a/cpu/static_inst.cc +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include <iostream> -#include "cpu/static_inst.hh" -#include "sim/root.hh" - -StaticInstPtr StaticInst::nullStaticInstPtr; - -// Define the decode cache hash map. -StaticInst::DecodeCache StaticInst::decodeCache; - -void -StaticInst::dumpDecodeCacheStats() -{ - using namespace std; - - cerr << "Decode hash table stats @ " << curTick << ":" << endl; - cerr << "\tnum entries = " << decodeCache.size() << endl; - cerr << "\tnum buckets = " << decodeCache.bucket_count() << endl; - vector<int> hist(100, 0); - int max_hist = 0; - for (int i = 0; i < decodeCache.bucket_count(); ++i) { - int count = decodeCache.elems_in_bucket(i); - if (count > max_hist) - max_hist = count; - hist[count]++; - } - for (int i = 0; i <= max_hist; ++i) { - cerr << "\tbuckets of size " << i << " = " << hist[i] << endl; - } -} - -bool -StaticInst::hasBranchTarget(Addr pc, ExecContext *xc, Addr &tgt) const -{ - if (isDirectCtrl()) { - tgt = branchTarget(pc); - return true; - } - - if (isIndirectCtrl()) { - tgt = branchTarget(xc); - return true; - } - - return false; -} - diff --git a/cpu/static_inst.hh b/cpu/static_inst.hh deleted file mode 100644 index b9d782b7b..000000000 --- a/cpu/static_inst.hh +++ /dev/null @@ -1,475 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __CPU_STATIC_INST_HH__ -#define __CPU_STATIC_INST_HH__ - -#include <bitset> -#include <string> - -#include "base/hashmap.hh" -#include "base/refcnt.hh" -#include "encumbered/cpu/full/op_class.hh" -#include "sim/host.hh" -#include "arch/isa_traits.hh" - -// forward declarations -struct AlphaSimpleImpl; -struct OzoneImpl; -struct SimpleImpl; -class ExecContext; -class DynInst; - -template <class Impl> -class AlphaDynInst; - -template <class Impl> -class OzoneDynInst; - -class CheckerCPU; -class FastCPU; -class SimpleCPU; -class InorderCPU; -class SymbolTable; - -namespace Trace { - class InstRecord; -} - -/** - * Base, ISA-independent static instruction class. - * - * The main component of this class is the vector of flags and the - * associated methods for reading them. Any object that can rely - * solely on these flags can process instructions without being - * recompiled for multiple ISAs. - */ -class StaticInstBase : public RefCounted -{ - protected: - - /// Set of boolean static instruction properties. - /// - /// Notes: - /// - The IsInteger and IsFloating flags are based on the class of - /// registers accessed by the instruction. Although most - /// instructions will have exactly one of these two flags set, it - /// is possible for an instruction to have neither (e.g., direct - /// unconditional branches, memory barriers) or both (e.g., an - /// FP/int conversion). - /// - If IsMemRef is set, then exactly one of IsLoad or IsStore - /// will be set. - /// - If IsControl is set, then exactly one of IsDirectControl or - /// IsIndirect Control will be set, and exactly one of - /// IsCondControl or IsUncondControl will be set. - /// - IsSerializing, IsMemBarrier, and IsWriteBarrier are - /// implemented as flags since in the current model there's no - /// other way for instructions to inject behavior into the - /// pipeline outside of fetch. Once we go to an exec-in-exec CPU - /// model we should be able to get rid of these flags and - /// implement this behavior via the execute() methods. - /// - enum Flags { - IsNop, ///< Is a no-op (no effect at all). - - IsInteger, ///< References integer regs. - IsFloating, ///< References FP regs. - - IsMemRef, ///< References memory (load, store, or prefetch). - IsLoad, ///< Reads from memory (load or prefetch). - IsStore, ///< Writes to memory. - IsStoreConditional, ///< Store conditional instruction. - IsInstPrefetch, ///< Instruction-cache prefetch. - IsDataPrefetch, ///< Data-cache prefetch. - IsCopy, ///< Fast Cache block copy - - IsControl, ///< Control transfer instruction. - IsDirectControl, ///< PC relative control transfer. - IsIndirectControl, ///< Register indirect control transfer. - IsCondControl, ///< Conditional control transfer. - IsUncondControl, ///< Unconditional control transfer. - IsCall, ///< Subroutine call. - IsReturn, ///< Subroutine return. - - IsCondDelaySlot,///< Conditional Delay-Slot Instruction - - IsThreadSync, ///< Thread synchronization operation. - - IsSerializing, ///< Serializes pipeline: won't execute until all - /// older instructions have committed. - IsSerializeBefore, - IsSerializeAfter, - IsMemBarrier, ///< Is a memory barrier - IsWriteBarrier, ///< Is a write barrier - - IsNonSpeculative, ///< Should not be executed speculatively - IsQuiesce, ///< Is a quiesce instruction - - IsIprAccess, ///< Accesses IPRs - IsUnverifiable, ///< Can't be verified by a checker - - NumFlags - }; - - /// Flag values for this instruction. - std::bitset<NumFlags> flags; - - /// See opClass(). - OpClass _opClass; - - /// See numSrcRegs(). - int8_t _numSrcRegs; - - /// See numDestRegs(). - int8_t _numDestRegs; - - /// The following are used to track physical register usage - /// for machines with separate int & FP reg files. - //@{ - int8_t _numFPDestRegs; - int8_t _numIntDestRegs; - //@} - - /// Constructor. - /// It's important to initialize everything here to a sane - /// default, since the decoder generally only overrides - /// the fields that are meaningful for the particular - /// instruction. - StaticInstBase(OpClass __opClass) - : _opClass(__opClass), _numSrcRegs(0), _numDestRegs(0), - _numFPDestRegs(0), _numIntDestRegs(0) - { - } - - public: - - /// @name Register information. - /// The sum of numFPDestRegs() and numIntDestRegs() equals - /// numDestRegs(). The former two functions are used to track - /// physical register usage for machines with separate int & FP - /// reg files. - //@{ - /// Number of source registers. - int8_t numSrcRegs() const { return _numSrcRegs; } - /// Number of destination registers. - int8_t numDestRegs() const { return _numDestRegs; } - /// Number of floating-point destination regs. - int8_t numFPDestRegs() const { return _numFPDestRegs; } - /// Number of integer destination regs. - int8_t numIntDestRegs() const { return _numIntDestRegs; } - //@} - - /// @name Flag accessors. - /// These functions are used to access the values of the various - /// instruction property flags. See StaticInstBase::Flags for descriptions - /// of the individual flags. - //@{ - - bool isNop() const { return flags[IsNop]; } - - bool isMemRef() const { return flags[IsMemRef]; } - bool isLoad() const { return flags[IsLoad]; } - bool isStore() const { return flags[IsStore]; } - bool isStoreConditional() const { return flags[IsStoreConditional]; } - bool isInstPrefetch() const { return flags[IsInstPrefetch]; } - bool isDataPrefetch() const { return flags[IsDataPrefetch]; } - bool isCopy() const { return flags[IsCopy];} - - bool isInteger() const { return flags[IsInteger]; } - bool isFloating() const { return flags[IsFloating]; } - - bool isControl() const { return flags[IsControl]; } - bool isCall() const { return flags[IsCall]; } - bool isReturn() const { return flags[IsReturn]; } - bool isDirectCtrl() const { return flags[IsDirectControl]; } - bool isIndirectCtrl() const { return flags[IsIndirectControl]; } - bool isCondCtrl() const { return flags[IsCondControl]; } - bool isUncondCtrl() const { return flags[IsUncondControl]; } - - bool isThreadSync() const { return flags[IsThreadSync]; } - bool isSerializing() const { return flags[IsSerializing] || - flags[IsSerializeBefore] || - flags[IsSerializeAfter]; } - bool isSerializeBefore() const { return flags[IsSerializeBefore]; } - bool isSerializeAfter() const { return flags[IsSerializeAfter]; } - bool isMemBarrier() const { return flags[IsMemBarrier]; } - bool isWriteBarrier() const { return flags[IsWriteBarrier]; } - bool isNonSpeculative() const { return flags[IsNonSpeculative]; } - bool isQuiesce() const { return flags[IsQuiesce]; } - bool isIprAccess() const { return flags[IsIprAccess]; } - bool isUnverifiable() const { return flags[IsUnverifiable]; } - //@} - - /// Operation class. Used to select appropriate function unit in issue. - OpClass opClass() const { return _opClass; } -}; - - -// forward declaration -class StaticInstPtr; - -/** - * Generic yet ISA-dependent static instruction class. - * - * This class builds on StaticInstBase, defining fields and interfaces - * that are generic across all ISAs but that differ in details - * according to the specific ISA being used. - */ -class StaticInst : public StaticInstBase -{ - public: - - /// Binary machine instruction type. - typedef TheISA::MachInst MachInst; - /// Binary extended machine instruction type. - typedef TheISA::ExtMachInst ExtMachInst; - /// Logical register index type. - typedef TheISA::RegIndex RegIndex; - - enum { - MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs - MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs - }; - - - /// Return logical index (architectural reg num) of i'th destination reg. - /// Only the entries from 0 through numDestRegs()-1 are valid. - RegIndex destRegIdx(int i) const { return _destRegIdx[i]; } - - /// Return logical index (architectural reg num) of i'th source reg. - /// Only the entries from 0 through numSrcRegs()-1 are valid. - RegIndex srcRegIdx(int i) const { return _srcRegIdx[i]; } - - /// Pointer to a statically allocated "null" instruction object. - /// Used to give eaCompInst() and memAccInst() something to return - /// when called on non-memory instructions. - static StaticInstPtr nullStaticInstPtr; - - /** - * Memory references only: returns "fake" instruction representing - * the effective address part of the memory operation. Used to - * obtain the dependence info (numSrcRegs and srcRegIdx[]) for - * just the EA computation. - */ - virtual const - StaticInstPtr &eaCompInst() const { return nullStaticInstPtr; } - - /** - * Memory references only: returns "fake" instruction representing - * the memory access part of the memory operation. Used to - * obtain the dependence info (numSrcRegs and srcRegIdx[]) for - * just the memory access (not the EA computation). - */ - virtual const - StaticInstPtr &memAccInst() const { return nullStaticInstPtr; } - - /// The binary machine instruction. - const ExtMachInst machInst; - - protected: - - /// See destRegIdx(). - RegIndex _destRegIdx[MaxInstDestRegs]; - /// See srcRegIdx(). - RegIndex _srcRegIdx[MaxInstSrcRegs]; - - /** - * Base mnemonic (e.g., "add"). Used by generateDisassembly() - * methods. Also useful to readily identify instructions from - * within the debugger when #cachedDisassembly has not been - * initialized. - */ - const char *mnemonic; - - /** - * String representation of disassembly (lazily evaluated via - * disassemble()). - */ - mutable std::string *cachedDisassembly; - - /** - * Internal function to generate disassembly string. - */ - virtual std::string - generateDisassembly(Addr pc, const SymbolTable *symtab) const = 0; - - /// Constructor. - StaticInst(const char *_mnemonic, ExtMachInst _machInst, OpClass __opClass) - : StaticInstBase(__opClass), - machInst(_machInst), mnemonic(_mnemonic), cachedDisassembly(0) - { - } - - public: - - virtual ~StaticInst() - { - if (cachedDisassembly) - delete cachedDisassembly; - } - -/** - * The execute() signatures are auto-generated by scons based on the - * set of CPU models we are compiling in today. - */ -#include "cpu/static_inst_exec_sigs.hh" - - /** - * Return the target address for a PC-relative branch. - * Invalid if not a PC-relative branch (i.e. isDirectCtrl() - * should be true). - */ - virtual Addr branchTarget(Addr branchPC) const - { - panic("StaticInst::branchTarget() called on instruction " - "that is not a PC-relative branch."); - } - - /** - * Return the target address for an indirect branch (jump). The - * register value is read from the supplied execution context, so - * the result is valid only if the execution context is about to - * execute the branch in question. Invalid if not an indirect - * branch (i.e. isIndirectCtrl() should be true). - */ - virtual Addr branchTarget(ExecContext *xc) const - { - panic("StaticInst::branchTarget() called on instruction " - "that is not an indirect branch."); - } - - /** - * Return true if the instruction is a control transfer, and if so, - * return the target address as well. - */ - bool hasBranchTarget(Addr pc, ExecContext *xc, Addr &tgt) const; - - /** - * Return string representation of disassembled instruction. - * The default version of this function will call the internal - * virtual generateDisassembly() function to get the string, - * then cache it in #cachedDisassembly. If the disassembly - * should not be cached, this function should be overridden directly. - */ - virtual const std::string &disassemble(Addr pc, - const SymbolTable *symtab = 0) const - { - if (!cachedDisassembly) - cachedDisassembly = - new std::string(generateDisassembly(pc, symtab)); - - return *cachedDisassembly; - } - - /// Decoded instruction cache type. - /// For now we're using a generic hash_map; this seems to work - /// pretty well. - typedef m5::hash_map<ExtMachInst, StaticInstPtr> DecodeCache; - - /// A cache of decoded instruction objects. - static DecodeCache decodeCache; - - /** - * Dump some basic stats on the decode cache hash map. - * Only gets called if DECODE_CACHE_HASH_STATS is defined. - */ - static void dumpDecodeCacheStats(); - - /// Decode a machine instruction. - /// @param mach_inst The binary instruction to decode. - /// @retval A pointer to the corresponding StaticInst object. - //This is defined as inline below. - static StaticInstPtr decode(ExtMachInst mach_inst); -}; - -typedef RefCountingPtr<StaticInstBase> StaticInstBasePtr; - -/// Reference-counted pointer to a StaticInst object. -/// This type should be used instead of "StaticInst *" so that -/// StaticInst objects can be properly reference-counted. -class StaticInstPtr : public RefCountingPtr<StaticInst> -{ - public: - /// Constructor. - StaticInstPtr() - : RefCountingPtr<StaticInst>() - { - } - - /// Conversion from "StaticInst *". - StaticInstPtr(StaticInst *p) - : RefCountingPtr<StaticInst>(p) - { - } - - /// Copy constructor. - StaticInstPtr(const StaticInstPtr &r) - : RefCountingPtr<StaticInst>(r) - { - } - - /// Construct directly from machine instruction. - /// Calls StaticInst::decode(). - StaticInstPtr(TheISA::ExtMachInst mach_inst) - : RefCountingPtr<StaticInst>(StaticInst::decode(mach_inst)) - { - } - - /// Convert to pointer to StaticInstBase class. - operator const StaticInstBasePtr() - { - return this->get(); - } -}; - -inline StaticInstPtr -StaticInst::decode(StaticInst::ExtMachInst mach_inst) -{ -#ifdef DECODE_CACHE_HASH_STATS - // Simple stats on decode hash_map. Turns out the default - // hash function is as good as anything I could come up with. - const int dump_every_n = 10000000; - static int decodes_til_dump = dump_every_n; - - if (--decodes_til_dump == 0) { - dumpDecodeCacheStats(); - decodes_til_dump = dump_every_n; - } -#endif - - DecodeCache::iterator iter = decodeCache.find(mach_inst); - if (iter != decodeCache.end()) { - return iter->second; - } - - StaticInstPtr si = TheISA::decodeInst(mach_inst); - decodeCache[mach_inst] = si; - return si; -} - -#endif // __CPU_STATIC_INST_HH__ diff --git a/cpu/thread_state.hh b/cpu/thread_state.hh deleted file mode 100644 index e09cb12fd..000000000 --- a/cpu/thread_state.hh +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CPU_THREAD_STATE_HH__ -#define __CPU_THREAD_STATE_HH__ - -#include "cpu/exec_context.hh" - -#if FULL_SYSTEM -class EndQuiesceEvent; -class FunctionProfile; -class ProfileNode; -namespace Kernel { - class Statistics; -}; -#else -class FunctionalMemory; -class Process; -#endif - -/** - * Struct for holding general thread state that is needed across CPU - * models. This includes things such as pointers to the process, - * memory, quiesce events, and certain stats. This can be expanded - * to hold more thread-specific stats within it. - */ -struct ThreadState { -#if FULL_SYSTEM - ThreadState(int _cpuId, int _tid, FunctionalMemory *_mem) - : cpuId(_cpuId), tid(_tid), mem(_mem), lastActivate(0), lastSuspend(0), - profile(NULL), profileNode(NULL), profilePC(0), quiesceEvent(NULL) -#else - ThreadState(int _cpuId, int _tid, FunctionalMemory *_mem, - Process *_process, short _asid) - : cpuId(_cpuId), tid(_tid), mem(_mem), process(_process), asid(_asid) -#endif - { - funcExeInst = 0; - storeCondFailures = 0; - } - - ExecContext::Status status; - - int cpuId; - - // Index of hardware thread context on the CPU that this represents. - int tid; - - Counter numInst; - Stats::Scalar<> numInsts; - Stats::Scalar<> numMemRefs; - - // number of simulated loads - Counter numLoad; - Counter startNumLoad; - - FunctionalMemory *mem; // functional storage for process address space - -#if FULL_SYSTEM - Tick lastActivate; - Tick lastSuspend; - - FunctionProfile *profile; - ProfileNode *profileNode; - Addr profilePC; - - EndQuiesceEvent *quiesceEvent; - - Kernel::Statistics *kernelStats; -#else - Process *process; - - // Address space ID. Note that this is used for TIMING cache - // simulation only; all functional memory accesses should use - // one of the FunctionalMemory pointers above. - short asid; - -#endif - - /** - * Temporary storage to pass the source address from copy_load to - * copy_store. - * @todo Remove this temporary when we have a better way to do it. - */ - Addr copySrcAddr; - /** - * Temp storage for the physical source address of a copy. - * @todo Remove this temporary when we have a better way to do it. - */ - Addr copySrcPhysAddr; - - /* - * number of executed instructions, for matching with syscall trace - * points in EIO files. - */ - Counter funcExeInst; - - // - // Count failed store conditionals so we can warn of apparent - // application deadlock situations. - unsigned storeCondFailures; -}; - -#endif // __CPU_THREAD_STATE_HH__ diff --git a/cpu/trace/opt_cpu.cc b/cpu/trace/opt_cpu.cc deleted file mode 100644 index 6cd23b0dd..000000000 --- a/cpu/trace/opt_cpu.cc +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * Definition of a memory trace CPU object for optimal caches. Uses a memory - * trace to access a fully associative cache with optimal replacement. - */ - -#include <algorithm> // For heap functions. - -#include "cpu/trace/opt_cpu.hh" -#include "cpu/trace/reader/mem_trace_reader.hh" - -#include "sim/builder.hh" -#include "sim/sim_events.hh" - -using namespace std; - -OptCPU::OptCPU(const string &name, - MemTraceReader *_trace, - int block_size, - int cache_size, - int _assoc) - : SimObject(name), tickEvent(this), trace(_trace), - numBlks(cache_size/block_size), assoc(_assoc), numSets(numBlks/assoc), - setMask(numSets - 1) -{ - int log_block_size = 0; - int tmp_block_size = block_size; - while (tmp_block_size > 1) { - ++log_block_size; - tmp_block_size = tmp_block_size >> 1; - } - assert(1<<log_block_size == block_size); - MemReqPtr req; - trace->getNextReq(req); - refInfo.resize(numSets); - while (req) { - RefInfo temp; - temp.addr = req->paddr >> log_block_size; - int set = temp.addr & setMask; - refInfo[set].push_back(temp); - trace->getNextReq(req); - } - - // Initialize top level of lookup table. - lookupTable.resize(16); - - // Annotate references with next ref time. - for (int k = 0; k < numSets; ++k) { - for (RefIndex i = refInfo[k].size() - 1; i >= 0; --i) { - Addr addr = refInfo[k][i].addr; - initTable(addr, InfiniteRef); - refInfo[k][i].nextRefTime = lookupValue(addr); - setValue(addr, i); - } - } - - // Reset the lookup table - for (int j = 0; j < 16; ++j) { - if (lookupTable[j].size() == (1<<16)) { - for (int k = 0; k < (1<<16); ++k) { - if (lookupTable[j][k].size() == (1<<16)) { - for (int l = 0; l < (1<<16); ++l) { - lookupTable[j][k][l] = -1; - } - } - } - } - } - - tickEvent.schedule(0); - - hits = 0; - misses = 0; -} - -void -OptCPU::processSet(int set) -{ - // Initialize cache - int blks_in_cache = 0; - RefIndex i = 0; - cacheHeap.clear(); - cacheHeap.resize(assoc); - - while (blks_in_cache < assoc) { - RefIndex cache_index = lookupValue(refInfo[set][i].addr); - if (cache_index == -1) { - // First reference to this block - misses++; - cache_index = blks_in_cache++; - setValue(refInfo[set][i].addr, cache_index); - } else { - hits++; - } - // update cache heap to most recent reference - cacheHeap[cache_index] = i; - if (++i >= refInfo[set].size()) { - return; - } - } - for (int start = assoc/2; start >= 0; --start) { - heapify(set,start); - } - //verifyHeap(set,0); - - for (; i < refInfo[set].size(); ++i) { - RefIndex cache_index = lookupValue(refInfo[set][i].addr); - if (cache_index == -1) { - // miss - misses++; - // replace from cacheHeap[0] - // mark replaced block as absent - setValue(refInfo[set][cacheHeap[0]].addr, -1); - setValue(refInfo[set][i].addr, 0); - cacheHeap[0] = i; - heapify(set, 0); - // Make sure its in the cache - assert(lookupValue(refInfo[set][i].addr) != -1); - } else { - // hit - hits++; - assert(refInfo[set][cacheHeap[cache_index]].addr == - refInfo[set][i].addr); - assert(refInfo[set][cacheHeap[cache_index]].nextRefTime == i); - assert(heapLeft(cache_index) >= assoc); - - cacheHeap[cache_index] = i; - processRankIncrease(set, cache_index); - assert(lookupValue(refInfo[set][i].addr) != -1); - } - } -} -void -OptCPU::tick() -{ - // Do opt simulation - - int references = 0; - for (int set = 0; set < numSets; ++set) { - if (!refInfo[set].empty()) { - processSet(set); - } - references += refInfo[set].size(); - } - // exit; - fprintf(stderr,"sys.cpu.misses %d #opt cache misses\n",misses); - fprintf(stderr,"sys.cpu.hits %d #opt cache hits\n", hits); - fprintf(stderr,"sys.cpu.accesses %d #opt cache acceses\n", references); - new SimExitEvent("Finshed Memory Trace"); -} - -void -OptCPU::initTable(Addr addr, RefIndex index) -{ - int l1_index = (addr >> 32) & 0x0f; - int l2_index = (addr >> 16) & 0xffff; - assert(l1_index == addr >> 32); - if (lookupTable[l1_index].size() != (1<<16)) { - lookupTable[l1_index].resize(1<<16); - } - if (lookupTable[l1_index][l2_index].size() != (1<<16)) { - lookupTable[l1_index][l2_index].resize(1<<16, index); - } -} - -OptCPU::TickEvent::TickEvent(OptCPU *c) - : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) -{ -} - -void -OptCPU::TickEvent::process() -{ - cpu->tick(); -} - -const char * -OptCPU::TickEvent::description() -{ - return "OptCPU tick event"; -} - - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(OptCPU) - - SimObjectParam<MemTraceReader *> data_trace; - Param<int> size; - Param<int> block_size; -Param<int> assoc; - -END_DECLARE_SIM_OBJECT_PARAMS(OptCPU) - -BEGIN_INIT_SIM_OBJECT_PARAMS(OptCPU) - - INIT_PARAM_DFLT(data_trace, "memory trace", NULL), - INIT_PARAM(size, "cache size"), - INIT_PARAM(block_size, "block size"), - INIT_PARAM(assoc,"associativity") - -END_INIT_SIM_OBJECT_PARAMS(OptCPU) - -CREATE_SIM_OBJECT(OptCPU) -{ - return new OptCPU(getInstanceName(), - data_trace, - block_size, - size, - assoc); -} - -REGISTER_SIM_OBJECT("OptCPU", OptCPU) diff --git a/cpu/trace/opt_cpu.hh b/cpu/trace/opt_cpu.hh deleted file mode 100644 index f81691733..000000000 --- a/cpu/trace/opt_cpu.hh +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * Declaration of a memory trace CPU object for optimal caches. Uses a memory - * trace to access a fully associative cache with optimal replacement. - */ - -#ifndef __CPU_TRACE_OPT_CPU_HH__ -#define __CPU_TRACE_OPT_CPU_HH__ - -#include <vector> - -#include "mem/mem_req.hh" // for MemReqPtr -#include "sim/eventq.hh" // for Event -#include "sim/sim_object.hh" - -// Forward Declaration -class MemTraceReader; - -/** - * A CPU object to simulate a fully-associative cache with optimal replacement. - */ -class OptCPU : public SimObject -{ - private: - typedef int RefIndex; - - typedef std::vector<RefIndex> L3Table; - typedef std::vector<L3Table> L2Table; - typedef std::vector<L2Table> L1Table; - - /** - * Event to call OptCPU::tick - */ - class TickEvent : public Event - { - private: - /** The associated CPU */ - OptCPU *cpu; - - public: - /** - * Construct this event; - */ - TickEvent(OptCPU *c); - - /** - * Call the tick function. - */ - void process(); - - /** - * Return a string description of this event. - */ - const char *description(); - }; - - TickEvent tickEvent; - - class RefInfo - { - public: - RefIndex nextRefTime; - Addr addr; - }; - - /** Reference Information, per set. */ - std::vector<std::vector<RefInfo> > refInfo; - - /** Lookup table to track blocks in the cache heap */ - L1Table lookupTable; - - /** - * Return the correct value in the lookup table. - */ - RefIndex lookupValue(Addr addr) - { - int l1_index = (addr >> 32) & 0x0f; - int l2_index = (addr >> 16) & 0xffff; - int l3_index = addr & 0xffff; - assert(l1_index == addr >> 32); - return lookupTable[l1_index][l2_index][l3_index]; - } - - /** - * Set the value in the lookup table. - */ - void setValue(Addr addr, RefIndex index) - { - int l1_index = (addr >> 32) & 0x0f; - int l2_index = (addr >> 16) & 0xffff; - int l3_index = addr & 0xffff; - assert(l1_index == addr >> 32); - lookupTable[l1_index][l2_index][l3_index]=index; - } - - /** - * Initialize the lookup table to the given value. - */ - void initTable(Addr addr, RefIndex index); - - void heapSwap(int set, int a, int b) { - RefIndex tmp = cacheHeap[a]; - cacheHeap[a] = cacheHeap[b]; - cacheHeap[b] = tmp; - - setValue(refInfo[set][cacheHeap[a]].addr, a); - setValue(refInfo[set][cacheHeap[b]].addr, b); - } - - int heapLeft(int index) { return index + index + 1; } - int heapRight(int index) { return index + index + 2; } - int heapParent(int index) { return (index - 1) >> 1; } - - RefIndex heapRank(int set, int index) { - return refInfo[set][cacheHeap[index]].nextRefTime; - } - - void heapify(int set, int start){ - int left = heapLeft(start); - int right = heapRight(start); - int max = start; - if (left < assoc && heapRank(set, left) > heapRank(set, start)) { - max = left; - } - if (right < assoc && heapRank(set, right) > heapRank(set, max)) { - max = right; - } - - if (max != start) { - heapSwap(set, start, max); - heapify(set, max); - } - } - - void verifyHeap(int set, int start) { - int left = heapLeft(start); - int right = heapRight(start); - - if (left < assoc) { - assert(heapRank(set, start) >= heapRank(set, left)); - verifyHeap(set, left); - } - if (right < assoc) { - assert(heapRank(set, start) >= heapRank(set, right)); - verifyHeap(set, right); - } - } - - void processRankIncrease(int set, int start) { - int parent = heapParent(start); - while (start > 0 && heapRank(set,parent) < heapRank(set,start)) { - heapSwap(set, parent, start); - start = parent; - parent = heapParent(start); - } - } - - void processSet(int set); - - static const RefIndex InfiniteRef = 0x7fffffff; - - /** Memory reference trace. */ - MemTraceReader *trace; - - /** Cache heap for replacement. */ - std::vector<RefIndex> cacheHeap; - - /** The number of blocks in the cache. */ - const int numBlks; - - const int assoc; - const int numSets; - const int setMask; - - - int misses; - int hits; - - public: - /** - * Construct a OptCPU object. - */ - OptCPU(const std::string &name, - MemTraceReader *_trace, - int block_size, - int cache_size, - int assoc); - - /** - * Perform the optimal replacement simulation. - */ - void tick(); -}; - -#endif // __CPU_TRACE_OPT_CPU_HH__ diff --git a/cpu/trace/reader/ibm_reader.cc b/cpu/trace/reader/ibm_reader.cc deleted file mode 100644 index 420101b63..000000000 --- a/cpu/trace/reader/ibm_reader.cc +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * Declaration of a IBM memory trace format reader. - */ -#include <sstream> - -#include "cpu/trace/reader/ibm_reader.hh" -#include "sim/builder.hh" -#include "base/misc.hh" // for fatal - -using namespace std; - -IBMReader::IBMReader(const string &name, const string &filename) - : MemTraceReader(name) -{ - if (strcmp((filename.c_str() + filename.length() -3), ".gz") == 0) { - // Compressed file, need to use a pipe to gzip. - stringstream buf; - buf << "gzip -d -c " << filename << endl; - trace = popen(buf.str().c_str(), "r"); - } else { - trace = fopen(filename.c_str(), "rb"); - } - if (!trace) { - fatal("Can't open file %s", filename); - } -} - -Tick -IBMReader::getNextReq(MemReqPtr &req) -{ - MemReqPtr tmp_req; - - int c = getc(trace); - if (c != EOF) { - tmp_req = new MemReq(); - //int cpu_id = (c & 0xf0) >> 4; - int type = c & 0x0f; - // We have L1 miss traces, so all accesses are 128 bytes - tmp_req->size = 128; - - tmp_req->paddr = 0; - for (int i = 2; i >= 0; --i) { - c = getc(trace); - if (c == EOF) { - fatal("Unexpected end of file"); - } - tmp_req->paddr |= ((c & 0xff) << (8 * i)); - } - tmp_req->paddr = tmp_req->paddr << 7; - - switch(type) { - case IBM_COND_EXCLUSIVE_FETCH: - case IBM_READ_ONLY_FETCH: - tmp_req->cmd = Read; - break; - case IBM_EXCLUSIVE_FETCH: - case IBM_FETCH_NO_DATA: - tmp_req->cmd = Write; - break; - case IBM_INST_FETCH: - tmp_req->cmd = Read; - break; - default: - fatal("Unknown trace entry type."); - } - - } - req = tmp_req; - return 0; -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(IBMReader) - - Param<string> filename; - -END_DECLARE_SIM_OBJECT_PARAMS(IBMReader) - - -BEGIN_INIT_SIM_OBJECT_PARAMS(IBMReader) - - INIT_PARAM(filename, "trace file") - -END_INIT_SIM_OBJECT_PARAMS(IBMReader) - - -CREATE_SIM_OBJECT(IBMReader) -{ - return new IBMReader(getInstanceName(), filename); -} - -REGISTER_SIM_OBJECT("IBMReader", IBMReader) diff --git a/cpu/trace/reader/ibm_reader.hh b/cpu/trace/reader/ibm_reader.hh deleted file mode 100644 index ce29206a2..000000000 --- a/cpu/trace/reader/ibm_reader.hh +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * Definition of a IBM memory trace format reader. - */ - -#ifndef __IBM_READER_HH__ -#define __IBM_READER_HH__ - -#include <stdio.h> -#include "cpu/trace/reader/mem_trace_reader.hh" -#include "mem/mem_req.hh" - -/** - * A memory trace reader for the IBM memory trace format. - */ -class IBMReader : public MemTraceReader -{ - /** IBM trace file. */ - FILE* trace; - - enum IBMType { - IBM_INST_FETCH, - IBM_READ_ONLY_FETCH, - IBM_COND_EXCLUSIVE_FETCH, - IBM_EXCLUSIVE_FETCH, - IBM_FETCH_NO_DATA - }; - - public: - /** - * Construct an IBMReader. - */ - IBMReader(const std::string &name, const std::string &filename); - - /** - * Read the next request from the trace. Returns the request in the - * provided MemReqPtr and the cycle of the request in the return value. - * @param req Return the next request from the trace. - * @return IBM traces don't store timing information, return 0 - */ - virtual Tick getNextReq(MemReqPtr &req); -}; - -#endif //__IBM_READER_HH__ - diff --git a/cpu/trace/reader/itx_reader.cc b/cpu/trace/reader/itx_reader.cc deleted file mode 100644 index 39ba27393..000000000 --- a/cpu/trace/reader/itx_reader.cc +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * Declaration of a Intel ITX memory trace format reader. - */ -#include <sstream> - -#include "cpu/trace/reader/itx_reader.hh" -#include "sim/builder.hh" -#include "base/misc.hh" // for fatal - -using namespace std; - -ITXReader::ITXReader(const string &name, const string &filename) - : MemTraceReader(name) -{ - if (strcmp((filename.c_str() + filename.length() -3), ".gz") == 0) { - // Compressed file, need to use a pipe to gzip. - stringstream buf; - buf << "gzip -d -c " << filename << endl; - trace = popen(buf.str().c_str(), "r"); - } else { - trace = fopen(filename.c_str(), "rb"); - } - if (!trace) { - fatal("Can't open file %s", filename); - } - traceFormat = 0; - int c; - for (int i = 0; i < 4; ++i) { - c = getc(trace); - if (c == EOF) { - fatal("Unexpected end of trace file."); - } - traceFormat |= (c & 0xff) << (8 * i); - } - if (traceFormat > 2) - fatal("Invalid trace format."); -} - -Tick -ITXReader::getNextReq(MemReqPtr &req) -{ - MemReqPtr tmp_req = new MemReq(); - bool phys_val; - do { - int c = getc(trace); - if (c != EOF) { - // Decode first byte - // phys_val<1> | type <2:0> | size <3:0> - phys_val = c & 0x80; - tmp_req->size = (c & 0x0f) + 1; - int type = (c & 0x70) >> 4; - - // Could be a compressed instruction entry, expand if necessary - if (type == ITXCodeComp) { - if (traceFormat != 2) { - fatal("Compressed code entry in non CompCode trace."); - } - if (!codeVirtValid) { - fatal("Corrupt CodeComp entry."); - } - - tmp_req->vaddr = codeVirtAddr; - codeVirtAddr += tmp_req->size; - if (phys_val) { - if (!codePhysValid) { - fatal("Corrupt CodeComp entry."); - } - tmp_req->paddr = codePhysAddr; - if (((tmp_req->paddr & 0xfff) + tmp_req->size) & ~0xfff) { - // Crossed page boundary, next physical address is - // invalid - codePhysValid = false; - } else { - codePhysAddr += tmp_req->size; - } - assert(tmp_req->paddr >> 36 == 0); - } else { - codePhysValid = false; - } - type = ITXCode; - tmp_req->cmd = Read; - } else { - // Normal entry - tmp_req->vaddr = 0; - for (int i = 0; i < 4; ++i) { - c = getc(trace); - if (c == EOF) { - fatal("Unexpected end of trace file."); - } - tmp_req->vaddr |= (c & 0xff) << (8 * i); - } - if (type == ITXCode) { - codeVirtAddr = tmp_req->vaddr + tmp_req->size; - codeVirtValid = true; - } - tmp_req->paddr = 0; - if (phys_val) { - c = getc(trace); - if (c == EOF) { - fatal("Unexpected end of trace file."); - } - // Get the page offset from the virtual address. - tmp_req->paddr = tmp_req->vaddr & 0xfff; - tmp_req->paddr |= (c & 0xf0) << 8; - tmp_req->paddr |= (Addr)(c & 0x0f) << 32; - for (int i = 2; i < 4; ++i) { - c = getc(trace); - if (c == EOF) { - fatal("Unexpected end of trace file."); - } - tmp_req->paddr |= (Addr)(c & 0xff) << (8 * i); - } - if (type == ITXCode) { - if (((tmp_req->paddr & 0xfff) + tmp_req->size) - & ~0xfff) { - // Crossing the page boundary, next physical - // address isn't valid - codePhysValid = false; - } else { - codePhysAddr = tmp_req->paddr + tmp_req->size; - codePhysValid = true; - } - } - assert(tmp_req->paddr >> 36 == 0); - } else if (type == ITXCode) { - codePhysValid = false; - } - switch(type) { - case ITXRead: - tmp_req->cmd = Read; - break; - case ITXWrite: - tmp_req->cmd = Write; - break; - case ITXWriteback: - tmp_req->cmd = Writeback; - break; - case ITXCode: - tmp_req->cmd = Read; - tmp_req->flags |= INST_READ; - break; - default: - fatal("Unknown ITX type"); - } - } - } else { - // EOF need to return a null request - MemReqPtr null_req; - req = null_req; - return 0; - } - } while (!phys_val); - req = tmp_req; - assert(!req || (req->paddr >> 36) == 0); - return 0; -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(ITXReader) - - Param<string> filename; - -END_DECLARE_SIM_OBJECT_PARAMS(ITXReader) - - -BEGIN_INIT_SIM_OBJECT_PARAMS(ITXReader) - - INIT_PARAM(filename, "trace file") - -END_INIT_SIM_OBJECT_PARAMS(ITXReader) - - -CREATE_SIM_OBJECT(ITXReader) -{ - return new ITXReader(getInstanceName(), filename); -} - -REGISTER_SIM_OBJECT("ITXReader", ITXReader) diff --git a/cpu/trace/reader/itx_reader.hh b/cpu/trace/reader/itx_reader.hh deleted file mode 100644 index a16a08085..000000000 --- a/cpu/trace/reader/itx_reader.hh +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * Definition of a Intel ITX memory trace format reader. - */ - -#ifndef __ITX_READER_HH__ -#define __ITX_READER_HH__ - -#include <stdio.h> -#include <string> - -#include "cpu/trace/reader/mem_trace_reader.hh" -#include "mem/mem_req.hh" - - -/** - * A memory trace reader for the Intel ITX memory trace format. - */ -class ITXReader : public MemTraceReader -{ - private: - /** Trace file. */ - FILE *trace; - - bool codeVirtValid; - Addr codeVirtAddr; - bool codePhysValid; - Addr codePhysAddr; - - int traceFormat; - - enum ITXType { - ITXRead, - ITXWrite, - ITXWriteback, - ITXCode, - ITXCodeComp - }; - - public: - /** - * Construct an ITXReader. - */ - ITXReader(const std::string &name, const std::string &filename); - - /** - * Read the next request from the trace. Returns the request in the - * provided MemReqPtr and the cycle of the request in the return value. - * @param req Return the next request from the trace. - * @return ITX traces don't store timing information, return 0 - */ - virtual Tick getNextReq(MemReqPtr &req); -}; - -#endif //__ITX_READER_HH__ - diff --git a/cpu/trace/reader/m5_reader.cc b/cpu/trace/reader/m5_reader.cc deleted file mode 100644 index ce44672f2..000000000 --- a/cpu/trace/reader/m5_reader.cc +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * Declaration of a memory trace reader for a M5 memory trace. - */ - -#include "cpu/trace/reader/m5_reader.hh" -#include "mem/trace/m5_format.hh" -#include "mem/mem_cmd.hh" -#include "sim/builder.hh" - -using namespace std; - -M5Reader::M5Reader(const string &name, const string &filename) - : MemTraceReader(name) -{ - traceFile.open(filename.c_str(), ios::binary); -} - -Tick -M5Reader::getNextReq(MemReqPtr &req) -{ - M5Format ref; - - MemReqPtr tmp_req; - // Need to read EOF char before eof() will return true. - traceFile.read((char*) &ref, sizeof(ref)); - if (!traceFile.eof()) { - //traceFile.read((char*) &ref, sizeof(ref)); -#ifndef NDEBUG - int gcount = traceFile.gcount(); - assert(gcount != 0 || traceFile.eof()); - assert(gcount == sizeof(ref)); - assert(ref.cmd < 12); -#endif - tmp_req = new MemReq(); - tmp_req->paddr = ref.paddr; - tmp_req->asid = ref.asid; - // Assume asid == thread_num - tmp_req->thread_num = ref.asid; - tmp_req->cmd = (MemCmdEnum)ref.cmd; - tmp_req->size = ref.size; - tmp_req->dest = ref.dest; - } else { - ref.cycle = 0; - } - req = tmp_req; - return ref.cycle; -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(M5Reader) - - Param<string> filename; - -END_DECLARE_SIM_OBJECT_PARAMS(M5Reader) - - -BEGIN_INIT_SIM_OBJECT_PARAMS(M5Reader) - - INIT_PARAM(filename, "trace file") - -END_INIT_SIM_OBJECT_PARAMS(M5Reader) - - -CREATE_SIM_OBJECT(M5Reader) -{ - return new M5Reader(getInstanceName(), filename); -} - -REGISTER_SIM_OBJECT("M5Reader", M5Reader) diff --git a/cpu/trace/reader/m5_reader.hh b/cpu/trace/reader/m5_reader.hh deleted file mode 100644 index 974a83ffa..000000000 --- a/cpu/trace/reader/m5_reader.hh +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * Definition of a memory trace reader for a M5 memory trace. - */ - -#ifndef __M5_READER_HH__ -#define __M5_READER_HH__ - -#include <fstream> - -#include "cpu/trace/reader/mem_trace_reader.hh" - -/** - * A memory trace reader for an M5 memory trace. @sa M5Writer. - */ -class M5Reader : public MemTraceReader -{ - /** The traceFile. */ - std::ifstream traceFile; - - std::string fn; - - public: - /** - * Construct an M5 memory trace reader. - */ - M5Reader(const std::string &name, const std::string &filename); - - - /** - * Read the next request from the trace. Returns the request in the - * provided MemReqPtr and the cycle of the request in the return value. - * @param req Return the next request from the trace. - * @return The cycle the reference was started. - */ - virtual Tick getNextReq(MemReqPtr &req); -}; - -#endif // __M5_READER_HH__ diff --git a/cpu/trace/reader/mem_trace_reader.cc b/cpu/trace/reader/mem_trace_reader.cc deleted file mode 100644 index 769f0be27..000000000 --- a/cpu/trace/reader/mem_trace_reader.cc +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * SimObject Declaration of pure virtual MemTraceReader class. - */ - -#include "cpu/trace/reader/mem_trace_reader.hh" -#include "sim/param.hh" - -DEFINE_SIM_OBJECT_CLASS_NAME("MemTraceReader", MemTraceReader); diff --git a/cpu/trace/reader/mem_trace_reader.hh b/cpu/trace/reader/mem_trace_reader.hh deleted file mode 100644 index b433cdbdd..000000000 --- a/cpu/trace/reader/mem_trace_reader.hh +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * Definitions for a pure virtual interface to a memory trace reader. - */ - -#ifndef __MEM_TRACE_READER_HH__ -#define __MEM_TRACE_READER_HH__ - -#include "sim/sim_object.hh" -#include "mem/mem_req.hh" // For MemReqPtr - -/** - * Pure virtual base class for memory trace readers. - */ -class MemTraceReader : public SimObject -{ - public: - /** Construct this MemoryTrace reader. */ - MemTraceReader(const std::string &name) : SimObject(name) {} - - /** - * Read the next request from the trace. Returns the request in the - * provided MemReqPtr and the cycle of the request in the return value. - * @param req Return the next request from the trace. - * @return The cycle of the request, 0 if none in trace. - */ - virtual Tick getNextReq(MemReqPtr &req) = 0; -}; - -#endif //__MEM_TRACE_READER_HH__ diff --git a/cpu/trace/trace_cpu.cc b/cpu/trace/trace_cpu.cc deleted file mode 100644 index 20d0a567f..000000000 --- a/cpu/trace/trace_cpu.cc +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * Declaration of a memory trace CPU object. Uses a memory trace to drive the - * provided memory hierarchy. - */ - -#include <algorithm> // For min - -#include "cpu/trace/trace_cpu.hh" -#include "cpu/trace/reader/mem_trace_reader.hh" -#include "mem/base_mem.hh" // For PARAM constructor -#include "mem/mem_interface.hh" -#include "sim/builder.hh" -#include "sim/sim_events.hh" - -using namespace std; - -TraceCPU::TraceCPU(const string &name, - MemInterface *icache_interface, - MemInterface *dcache_interface, - MemTraceReader *data_trace) - : SimObject(name), icacheInterface(icache_interface), - dcacheInterface(dcache_interface), - dataTrace(data_trace), outstandingRequests(0), tickEvent(this) -{ - assert(dcacheInterface); - nextCycle = dataTrace->getNextReq(nextReq); - tickEvent.schedule(0); -} - -void -TraceCPU::tick() -{ - assert(outstandingRequests >= 0); - assert(outstandingRequests < 1000); - int instReqs = 0; - int dataReqs = 0; - - while (nextReq && curTick >= nextCycle) { - assert(nextReq->thread_num < 4 && "Not enough threads"); - if (nextReq->isInstRead() && icacheInterface) { - if (icacheInterface->isBlocked()) - break; - - nextReq->time = curTick; - if (nextReq->cmd == Squash) { - icacheInterface->squash(nextReq->asid); - } else { - ++instReqs; - if (icacheInterface->doEvents()) { - nextReq->completionEvent = - new TraceCompleteEvent(nextReq, this); - icacheInterface->access(nextReq); - } else { - icacheInterface->access(nextReq); - completeRequest(nextReq); - } - } - } else { - if (dcacheInterface->isBlocked()) - break; - - ++dataReqs; - nextReq->time = curTick; - if (dcacheInterface->doEvents()) { - nextReq->completionEvent = - new TraceCompleteEvent(nextReq, this); - dcacheInterface->access(nextReq); - } else { - dcacheInterface->access(nextReq); - completeRequest(nextReq); - } - - } - nextCycle = dataTrace->getNextReq(nextReq); - } - - if (!nextReq) { - // No more requests to send. Finish trailing events and exit. - if (mainEventQueue.empty()) { - new SimExitEvent("Finshed Memory Trace"); - } else { - tickEvent.schedule(mainEventQueue.nextEventTime() + cycles(1)); - } - } else { - tickEvent.schedule(max(curTick + cycles(1), nextCycle)); - } -} - -void -TraceCPU::completeRequest(MemReqPtr& req) -{ -} - -void -TraceCompleteEvent::process() -{ - tester->completeRequest(req); -} - -const char * -TraceCompleteEvent::description() -{ - return "trace access complete"; -} - -TraceCPU::TickEvent::TickEvent(TraceCPU *c) - : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) -{ -} - -void -TraceCPU::TickEvent::process() -{ - cpu->tick(); -} - -const char * -TraceCPU::TickEvent::description() -{ - return "TraceCPU tick event"; -} - - - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(TraceCPU) - - SimObjectParam<BaseMem *> icache; - SimObjectParam<BaseMem *> dcache; - SimObjectParam<MemTraceReader *> data_trace; - -END_DECLARE_SIM_OBJECT_PARAMS(TraceCPU) - -BEGIN_INIT_SIM_OBJECT_PARAMS(TraceCPU) - - INIT_PARAM_DFLT(icache, "instruction cache", NULL), - INIT_PARAM_DFLT(dcache, "data cache", NULL), - INIT_PARAM_DFLT(data_trace, "data trace", NULL) - -END_INIT_SIM_OBJECT_PARAMS(TraceCPU) - -CREATE_SIM_OBJECT(TraceCPU) -{ - return new TraceCPU(getInstanceName(), - (icache) ? icache->getInterface() : NULL, - (dcache) ? dcache->getInterface() : NULL, - data_trace); -} - -REGISTER_SIM_OBJECT("TraceCPU", TraceCPU) - diff --git a/cpu/trace/trace_cpu.hh b/cpu/trace/trace_cpu.hh deleted file mode 100644 index 69ca35321..000000000 --- a/cpu/trace/trace_cpu.hh +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * Declaration of a memory trace CPU object. Uses a memory trace to drive the - * provided memory hierarchy. - */ - -#ifndef __CPU_TRACE_TRACE_CPU_HH__ -#define __CPU_TRACE_TRACE_CPU_HH__ - -#include <string> - -#include "mem/mem_req.hh" // for MemReqPtr -#include "sim/eventq.hh" // for Event -#include "sim/sim_object.hh" - -// Forward declaration. -class MemInterface; -class MemTraceReader; - -/** - * A cpu object for running memory traces through a memory hierarchy. - */ -class TraceCPU : public SimObject -{ - private: - /** Interface for instruction trace requests, if any. */ - MemInterface *icacheInterface; - /** Interface for data trace requests, if any. */ - MemInterface *dcacheInterface; - - /** Data reference trace. */ - MemTraceReader *dataTrace; - - /** Number of outstanding requests. */ - int outstandingRequests; - - /** Cycle of the next request, 0 if not available. */ - Tick nextCycle; - - /** Next request. */ - MemReqPtr nextReq; - - /** - * Event to call the TraceCPU::tick - */ - class TickEvent : public Event - { - private: - /** The associated CPU */ - TraceCPU *cpu; - - public: - /** - * Construct this event; - */ - TickEvent(TraceCPU *c); - - /** - * Call the tick function. - */ - void process(); - - /** - * Return a string description of this event. - */ - const char *description(); - }; - - TickEvent tickEvent; - - public: - /** - * Construct a TraceCPU object. - */ - TraceCPU(const std::string &name, - MemInterface *icache_interface, - MemInterface *dcache_interface, - MemTraceReader *data_trace); - - inline Tick cycles(int numCycles) { return numCycles; } - - /** - * Perform all the accesses for one cycle. - */ - void tick(); - - /** - * Handle a completed memory request. - */ - void completeRequest(MemReqPtr &req); -}; - -class TraceCompleteEvent : public Event -{ - MemReqPtr req; - TraceCPU *tester; - - public: - - TraceCompleteEvent(MemReqPtr &_req, TraceCPU *_tester) - : Event(&mainEventQueue), req(_req), tester(_tester) - { - setFlags(AutoDelete); - } - - void process(); - - virtual const char *description(); -}; - -#endif // __CPU_TRACE_TRACE_CPU_HH__ - diff --git a/dev/alpha_access.h b/dev/alpha_access.h deleted file mode 100644 index 5a1df6f39..000000000 --- a/dev/alpha_access.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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. - */ - -#ifndef __ALPHA_ACCESS_H__ -#define __ALPHA_ACCESS_H__ - -/** @file - * System Console Memory Mapped Register Definition - */ - -#define ALPHA_ACCESS_VERSION (1305) - -#ifdef CONSOLE -typedef unsigned uint32_t; -typedef unsigned long uint64_t; -#endif - -// This structure hacked up from simos -struct AlphaAccess -{ - uint32_t last_offset; // 00: must be first field - uint32_t version; // 04: - uint32_t numCPUs; // 08: - uint32_t intrClockFrequency; // 0C: Hz - uint64_t cpuClock; // 10: MHz - uint64_t mem_size; // 18: - - // Loaded kernel - uint64_t kernStart; // 20: - uint64_t kernEnd; // 28: - uint64_t entryPoint; // 30: - - // console disk stuff - uint64_t diskUnit; // 38: - uint64_t diskCount; // 40: - uint64_t diskPAddr; // 48: - uint64_t diskBlock; // 50: - uint64_t diskOperation; // 58: - - // console simple output stuff - uint64_t outputChar; // 60: Placeholder for output - uint64_t inputChar; // 68: Placeholder for input - - // MP boot - uint64_t cpuStack[64]; // 70: -}; - -#endif // __ALPHA_ACCESS_H__ diff --git a/dev/alpha_console.cc b/dev/alpha_console.cc deleted file mode 100644 index 6ca5e3a06..000000000 --- a/dev/alpha_console.cc +++ /dev/null @@ -1,356 +0,0 @@ -/* - * 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. - */ - -/** @file - * Alpha Console Definition - */ - -#include <cstddef> -#include <cstdio> -#include <string> - -#include "arch/alpha/system.hh" -#include "base/inifile.hh" -#include "base/str.hh" -#include "base/trace.hh" -#include "cpu/base.hh" -#include "cpu/exec_context.hh" -#include "dev/alpha_console.hh" -#include "dev/simconsole.hh" -#include "dev/simple_disk.hh" -#include "dev/tsunami_io.hh" -#include "mem/bus/bus.hh" -#include "mem/bus/pio_interface.hh" -#include "mem/bus/pio_interface_impl.hh" -#include "mem/functional/memory_control.hh" -#include "mem/functional/physical.hh" -#include "sim/builder.hh" -#include "sim/sim_object.hh" - -using namespace std; -using namespace AlphaISA; - -AlphaConsole::AlphaConsole(const string &name, SimConsole *cons, SimpleDisk *d, - AlphaSystem *s, BaseCPU *c, Platform *p, - MemoryController *mmu, Addr a, - HierParams *hier, Bus *pio_bus) - : PioDevice(name, p), disk(d), console(cons), system(s), cpu(c), addr(a) -{ - mmu->add_child(this, RangeSize(addr, size)); - - if (pio_bus) { - pioInterface = newPioInterface(name + ".pio", hier, pio_bus, this, - &AlphaConsole::cacheAccess); - pioInterface->addAddrRange(RangeSize(addr, size)); - } - - alphaAccess = new Access; - alphaAccess->last_offset = size - 1; - - alphaAccess->version = ALPHA_ACCESS_VERSION; - alphaAccess->diskUnit = 1; - - alphaAccess->diskCount = 0; - alphaAccess->diskPAddr = 0; - alphaAccess->diskBlock = 0; - alphaAccess->diskOperation = 0; - alphaAccess->outputChar = 0; - alphaAccess->inputChar = 0; - bzero(alphaAccess->cpuStack, sizeof(alphaAccess->cpuStack)); - - system->setAlphaAccess(addr); -} - -void -AlphaConsole::startup() -{ - alphaAccess->numCPUs = system->getNumCPUs(); - alphaAccess->kernStart = system->getKernelStart(); - alphaAccess->kernEnd = system->getKernelEnd(); - alphaAccess->entryPoint = system->getKernelEntry(); - alphaAccess->mem_size = system->physmem->size(); - alphaAccess->cpuClock = cpu->frequency() / 1000000; // In MHz - alphaAccess->intrClockFrequency = platform->intrFrequency(); -} - -Fault -AlphaConsole::read(MemReqPtr &req, uint8_t *data) -{ - memset(data, 0, req->size); - - Addr daddr = req->paddr - (addr & EV5::PAddrImplMask); - - switch (req->size) - { - case sizeof(uint32_t): - DPRINTF(AlphaConsole, "read: offset=%#x val=%#x\n", daddr, - *(uint32_t*)data); - switch (daddr) - { - case offsetof(AlphaAccess, last_offset): - *(uint32_t*)data = alphaAccess->last_offset; - break; - case offsetof(AlphaAccess, version): - *(uint32_t*)data = alphaAccess->version; - break; - case offsetof(AlphaAccess, numCPUs): - *(uint32_t*)data = alphaAccess->numCPUs; - break; - case offsetof(AlphaAccess, intrClockFrequency): - *(uint32_t*)data = alphaAccess->intrClockFrequency; - break; - default: - // Old console code read in everyting as a 32bit int - *(uint32_t*)data = *(uint32_t*)(consoleData + daddr); - - } - break; - case sizeof(uint64_t): - DPRINTF(AlphaConsole, "read: offset=%#x val=%#x\n", daddr, - *(uint64_t*)data); - switch (daddr) - { - case offsetof(AlphaAccess, inputChar): - *(uint64_t*)data = console->console_in(); - break; - case offsetof(AlphaAccess, cpuClock): - *(uint64_t*)data = alphaAccess->cpuClock; - break; - case offsetof(AlphaAccess, mem_size): - *(uint64_t*)data = alphaAccess->mem_size; - break; - case offsetof(AlphaAccess, kernStart): - *(uint64_t*)data = alphaAccess->kernStart; - break; - case offsetof(AlphaAccess, kernEnd): - *(uint64_t*)data = alphaAccess->kernEnd; - break; - case offsetof(AlphaAccess, entryPoint): - *(uint64_t*)data = alphaAccess->entryPoint; - break; - case offsetof(AlphaAccess, diskUnit): - *(uint64_t*)data = alphaAccess->diskUnit; - break; - case offsetof(AlphaAccess, diskCount): - *(uint64_t*)data = alphaAccess->diskCount; - break; - case offsetof(AlphaAccess, diskPAddr): - *(uint64_t*)data = alphaAccess->diskPAddr; - break; - case offsetof(AlphaAccess, diskBlock): - *(uint64_t*)data = alphaAccess->diskBlock; - break; - case offsetof(AlphaAccess, diskOperation): - *(uint64_t*)data = alphaAccess->diskOperation; - break; - case offsetof(AlphaAccess, outputChar): - *(uint64_t*)data = alphaAccess->outputChar; - break; - default: - int cpunum = (daddr - offsetof(AlphaAccess, cpuStack)) / - sizeof(alphaAccess->cpuStack[0]); - - if (cpunum >= 0 && cpunum < 64) - *(uint64_t*)data = alphaAccess->cpuStack[cpunum]; - else - panic("Unknown 64bit access, %#x\n", daddr); - } - break; - default: - return genMachineCheckFault(); - } - - return NoFault; -} - -Fault -AlphaConsole::write(MemReqPtr &req, const uint8_t *data) -{ - uint64_t val; - - switch (req->size) { - case sizeof(uint32_t): - val = *(uint32_t *)data; - break; - - case sizeof(uint64_t): - val = *(uint64_t *)data; - break; - default: - return genMachineCheckFault(); - } - - Addr daddr = req->paddr - (addr & EV5::PAddrImplMask); - ExecContext *other_xc; - - switch (daddr) { - case offsetof(AlphaAccess, diskUnit): - alphaAccess->diskUnit = val; - break; - - case offsetof(AlphaAccess, diskCount): - alphaAccess->diskCount = val; - break; - - case offsetof(AlphaAccess, diskPAddr): - alphaAccess->diskPAddr = val; - break; - - case offsetof(AlphaAccess, diskBlock): - alphaAccess->diskBlock = val; - break; - - case offsetof(AlphaAccess, diskOperation): - if (val == 0x13) - disk->read(alphaAccess->diskPAddr, alphaAccess->diskBlock, - alphaAccess->diskCount); - else - panic("Invalid disk operation!"); - - break; - - case offsetof(AlphaAccess, outputChar): - console->out((char)(val & 0xff)); - break; - - other_xc->activate(); //Start the cpu - break; - - default: - int cpunum = (daddr - offsetof(AlphaAccess, cpuStack)) / - sizeof(alphaAccess->cpuStack[0]); - warn("%d: Trying to launch CPU number %d!", curTick, cpunum); - assert(val > 0 && "Must not access primary cpu"); - if (cpunum >= 0 && cpunum < 64) - alphaAccess->cpuStack[cpunum] = val; - else - panic("Unknown 64bit access, %#x\n", daddr); - } - - return NoFault; -} - -Tick -AlphaConsole::cacheAccess(MemReqPtr &req) -{ - return curTick + 1000; -} - -void -AlphaConsole::Access::serialize(ostream &os) -{ - SERIALIZE_SCALAR(last_offset); - SERIALIZE_SCALAR(version); - SERIALIZE_SCALAR(numCPUs); - SERIALIZE_SCALAR(mem_size); - SERIALIZE_SCALAR(cpuClock); - SERIALIZE_SCALAR(intrClockFrequency); - SERIALIZE_SCALAR(kernStart); - SERIALIZE_SCALAR(kernEnd); - SERIALIZE_SCALAR(entryPoint); - SERIALIZE_SCALAR(diskUnit); - SERIALIZE_SCALAR(diskCount); - SERIALIZE_SCALAR(diskPAddr); - SERIALIZE_SCALAR(diskBlock); - SERIALIZE_SCALAR(diskOperation); - SERIALIZE_SCALAR(outputChar); - SERIALIZE_SCALAR(inputChar); - SERIALIZE_ARRAY(cpuStack,64); -} - -void -AlphaConsole::Access::unserialize(Checkpoint *cp, const std::string §ion) -{ - UNSERIALIZE_SCALAR(last_offset); - UNSERIALIZE_SCALAR(version); - UNSERIALIZE_SCALAR(numCPUs); - UNSERIALIZE_SCALAR(mem_size); - UNSERIALIZE_SCALAR(cpuClock); - UNSERIALIZE_SCALAR(intrClockFrequency); - UNSERIALIZE_SCALAR(kernStart); - UNSERIALIZE_SCALAR(kernEnd); - UNSERIALIZE_SCALAR(entryPoint); - UNSERIALIZE_SCALAR(diskUnit); - UNSERIALIZE_SCALAR(diskCount); - UNSERIALIZE_SCALAR(diskPAddr); - UNSERIALIZE_SCALAR(diskBlock); - UNSERIALIZE_SCALAR(diskOperation); - UNSERIALIZE_SCALAR(outputChar); - UNSERIALIZE_SCALAR(inputChar); - UNSERIALIZE_ARRAY(cpuStack, 64); -} - -void -AlphaConsole::serialize(ostream &os) -{ - alphaAccess->serialize(os); -} - -void -AlphaConsole::unserialize(Checkpoint *cp, const std::string §ion) -{ - alphaAccess->unserialize(cp, section); -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaConsole) - - SimObjectParam<SimConsole *> sim_console; - SimObjectParam<SimpleDisk *> disk; - SimObjectParam<MemoryController *> mmu; - Param<Addr> addr; - SimObjectParam<AlphaSystem *> system; - SimObjectParam<BaseCPU *> cpu; - SimObjectParam<Platform *> platform; - SimObjectParam<Bus*> pio_bus; - Param<Tick> pio_latency; - SimObjectParam<HierParams *> hier; - -END_DECLARE_SIM_OBJECT_PARAMS(AlphaConsole) - -BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaConsole) - - INIT_PARAM(sim_console, "The Simulator Console"), - INIT_PARAM(disk, "Simple Disk"), - INIT_PARAM(mmu, "Memory Controller"), - INIT_PARAM(addr, "Device Address"), - INIT_PARAM(system, "system object"), - INIT_PARAM(cpu, "Processor"), - INIT_PARAM(platform, "platform"), - INIT_PARAM(pio_bus, "The IO Bus to attach to"), - INIT_PARAM_DFLT(pio_latency, "Programmed IO latency", 1000), - INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams) - -END_INIT_SIM_OBJECT_PARAMS(AlphaConsole) - -CREATE_SIM_OBJECT(AlphaConsole) -{ - return new AlphaConsole(getInstanceName(), sim_console, disk, - system, cpu, platform, mmu, addr, hier, pio_bus); -} - -REGISTER_SIM_OBJECT("AlphaConsole", AlphaConsole) diff --git a/dev/alpha_console.hh b/dev/alpha_console.hh deleted file mode 100644 index f63c6ad7e..000000000 --- a/dev/alpha_console.hh +++ /dev/null @@ -1,127 +0,0 @@ -/* - * 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. - */ - -/** @file - * System Console Interface - */ - -#ifndef __ALPHA_CONSOLE_HH__ -#define __ALPHA_CONSOLE_HH__ - -#include "base/range.hh" -#include "dev/alpha_access.h" -#include "dev/io_device.hh" -#include "sim/host.hh" -#include "sim/sim_object.hh" - -class BaseCPU; -class SimConsole; -class AlphaSystem; -class SimpleDisk; -class MemoryController; - -/** - * Memory mapped interface to the system console. This device - * represents a shared data region between the OS Kernel and the - * System Console. - * - * The system console is a small standalone program that is initially - * run when the system boots. It contains the necessary code to - * access the boot disk, to read/write from the console, and to pass - * boot parameters to the kernel. - * - * This version of the system console is very different from the one - * that would be found in a real system. Many of the functions use - * some sort of backdoor to get their job done. For example, reading - * from the boot device on a real system would require a minimal - * device driver to access the disk controller, but since we have a - * simulator here, we are able to bypass the disk controller and - * access the disk image directly. There are also some things like - * reading the kernel off the disk image into memory that are normally - * taken care of by the console that are now taken care of by the - * simulator. - * - * These shortcuts are acceptable since the system console is - * primarily used doing boot before the kernel has loaded its device - * drivers. - */ -class AlphaConsole : public PioDevice -{ - protected: - struct Access : public AlphaAccess - { - void serialize(std::ostream &os); - void unserialize(Checkpoint *cp, const std::string §ion); - }; - - union { - Access *alphaAccess; - uint8_t *consoleData; - }; - - /** the disk must be accessed from the console */ - SimpleDisk *disk; - - /** the system console (the terminal) is accessable from the console */ - SimConsole *console; - - /** a pointer to the system we are running in */ - AlphaSystem *system; - - /** a pointer to the CPU boot cpu */ - BaseCPU *cpu; - - Addr addr; - static const Addr size = sizeof(struct AlphaAccess); - - public: - /** Standard Constructor */ - AlphaConsole(const std::string &name, SimConsole *cons, SimpleDisk *d, - AlphaSystem *s, BaseCPU *c, Platform *platform, - MemoryController *mmu, Addr addr, - HierParams *hier, Bus *pio_bus); - - virtual void startup(); - - /** - * memory mapped reads and writes - */ - virtual Fault read(MemReqPtr &req, uint8_t *data); - virtual Fault write(MemReqPtr &req, const uint8_t *data); - - /** - * standard serialization routines for checkpointing - */ - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); - - public: - Tick cacheAccess(MemReqPtr &req); -}; - -#endif // __ALPHA_CONSOLE_HH__ diff --git a/dev/baddev.cc b/dev/baddev.cc deleted file mode 100644 index 87d683a5d..000000000 --- a/dev/baddev.cc +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * BadDevice implemenation - */ - -#include <deque> -#include <string> -#include <vector> - -#include "base/trace.hh" -#include "cpu/exec_context.hh" -#include "dev/baddev.hh" -#include "dev/platform.hh" -#include "mem/bus/bus.hh" -#include "mem/bus/pio_interface.hh" -#include "mem/bus/pio_interface_impl.hh" -#include "mem/functional/memory_control.hh" -#include "sim/builder.hh" -#include "sim/system.hh" - -using namespace std; -using namespace TheISA; - -BadDevice::BadDevice(const string &name, Addr a, MemoryController *mmu, - HierParams *hier, Bus *pio_bus, const string &devicename) - : PioDevice(name, NULL), addr(a), devname(devicename) -{ - mmu->add_child(this, RangeSize(addr, size)); - - if (pio_bus) { - pioInterface = newPioInterface(name, hier, pio_bus, this, - &BadDevice::cacheAccess); - pioInterface->addAddrRange(RangeSize(addr, size)); - } - -} - -Fault -BadDevice::read(MemReqPtr &req, uint8_t *data) -{ - - panic("Device %s not imlpmented\n", devname); - return NoFault; -} - -Fault -BadDevice::write(MemReqPtr &req, const uint8_t *data) -{ - panic("Device %s not imlpmented\n", devname); - return NoFault; -} - -Tick -BadDevice::cacheAccess(MemReqPtr &req) -{ - return curTick; -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(BadDevice) - - SimObjectParam<Platform *> platform; - SimObjectParam<MemoryController *> mmu; - Param<Addr> addr; - SimObjectParam<HierParams *> hier; - SimObjectParam<Bus*> pio_bus; - Param<Tick> pio_latency; - Param<string> devicename; - -END_DECLARE_SIM_OBJECT_PARAMS(BadDevice) - -BEGIN_INIT_SIM_OBJECT_PARAMS(BadDevice) - - INIT_PARAM(platform, "Platform"), - INIT_PARAM(mmu, "Memory Controller"), - INIT_PARAM(addr, "Device Address"), - INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams), - INIT_PARAM_DFLT(pio_bus, "The IO Bus to attach to", NULL), - INIT_PARAM_DFLT(pio_latency, "Programmed IO latency", 1000), - INIT_PARAM(devicename, "Name of device to error on") - -END_INIT_SIM_OBJECT_PARAMS(BadDevice) - -CREATE_SIM_OBJECT(BadDevice) -{ - return new BadDevice(getInstanceName(), addr, mmu, hier, pio_bus, - devicename); -} - -REGISTER_SIM_OBJECT("BadDevice", BadDevice) diff --git a/dev/baddev.hh b/dev/baddev.hh deleted file mode 100644 index 189f28331..000000000 --- a/dev/baddev.hh +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * This devices just panics when touched. For example if you have a - * kernel that touches the frame buffer which isn't allowed. - */ - -#ifndef __DEV_BADDEV_HH__ -#define __DEV_BADDEV_HH__ - -#include "base/range.hh" -#include "dev/io_device.hh" - -class MemoryController; - -/** - * BadDevice - * This device just panics when accessed. It is supposed to warn - * the user that the kernel they are running has unsupported - * options (i.e. frame buffer) - */ -class BadDevice : public PioDevice -{ - private: - Addr addr; - static const Addr size = 0xf; - - std::string devname; - - public: - /** - * Constructor for the Baddev Class. - * @param name name of the object - * @param a base address of the write - * @param mmu the memory controller - * @param hier object to store parameters universal the device hierarchy - * @param bus The bus that this device is attached to - * @param devicename device that is not implemented - */ - BadDevice(const std::string &name, Addr a, MemoryController *mmu, - HierParams *hier, Bus *bus, const std::string &devicename); - - /** - * On a read event we just panic aand hopefully print a - * meaningful error message. - * @param req Contains the address to read from. - * @param data A pointer to write the read data to. - * @return The fault condition of the access. - */ - virtual Fault read(MemReqPtr &req, uint8_t *data); - - /** - * On a write event we just panic aand hopefully print a - * meaningful error message. - * @param req Contains the address to write to. - * @param data The data to write. - * @return The fault condition of the access. - */ - virtual Fault write(MemReqPtr &req, const uint8_t *data); - - /** - * Return how long this access will take. - * @param req the memory request to calcuate - * @return Tick when the request is done - */ - Tick cacheAccess(MemReqPtr &req); -}; - -#endif // __DEV_BADDEV_HH__ diff --git a/dev/disk_image.cc b/dev/disk_image.cc deleted file mode 100644 index 447c54697..000000000 --- a/dev/disk_image.cc +++ /dev/null @@ -1,471 +0,0 @@ -/* - * 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. - */ - -/** @file - * Disk Image Definitions - */ - -#include <sys/types.h> -#include <sys/uio.h> -#include <errno.h> -#include <unistd.h> - -#include <cstdio> -#include <cstring> -#include <fstream> -#include <string> - -#include "base/callback.hh" -#include "base/misc.hh" -#include "base/trace.hh" -#include "dev/disk_image.hh" -#include "sim/builder.hh" -#include "sim/sim_exit.hh" -#include "sim/byteswap.hh" - -using namespace std; - -//////////////////////////////////////////////////////////////////////// -// -// Raw Disk image -// -RawDiskImage::RawDiskImage(const string &name, const string &filename, - bool rd_only) - : DiskImage(name), disk_size(0) -{ open(filename, rd_only); } - -RawDiskImage::~RawDiskImage() -{ close(); } - -void -RawDiskImage::open(const string &filename, bool rd_only) -{ - if (!filename.empty()) { - initialized = true; - readonly = rd_only; - file = filename; - - ios::openmode mode = ios::in | ios::binary; - if (!readonly) - mode |= ios::out; - stream.open(file.c_str(), mode); - if (!stream.is_open()) - panic("Error opening %s", filename); - } -} - -void -RawDiskImage::close() -{ - stream.close(); -} - -off_t -RawDiskImage::size() const -{ - if (disk_size == 0) { - if (!stream.is_open()) - panic("file not open!\n"); - stream.seekg(0, ios::end); - disk_size = stream.tellg(); - } - - return disk_size / SectorSize; -} - -off_t -RawDiskImage::read(uint8_t *data, off_t offset) const -{ - if (!initialized) - panic("RawDiskImage not initialized"); - - if (!stream.is_open()) - panic("file not open!\n"); - - if (stream.seekg(offset * SectorSize, ios::beg) < 0) - panic("Could not seek to location in file"); - - streampos pos = stream.tellg(); - stream.read((char *)data, SectorSize); - - DPRINTF(DiskImageRead, "read: offset=%d\n", (uint64_t)offset); - DDUMP(DiskImageRead, data, SectorSize); - - return stream.tellg() - pos; -} - -off_t -RawDiskImage::write(const uint8_t *data, off_t offset) -{ - if (!initialized) - panic("RawDiskImage not initialized"); - - if (readonly) - panic("Cannot write to a read only disk image"); - - if (!stream.is_open()) - panic("file not open!\n"); - - if (stream.seekp(offset * SectorSize, ios::beg) < 0) - panic("Could not seek to location in file"); - - DPRINTF(DiskImageWrite, "write: offset=%d\n", (uint64_t)offset); - DDUMP(DiskImageWrite, data, SectorSize); - - streampos pos = stream.tellp(); - stream.write((const char *)data, SectorSize); - return stream.tellp() - pos; -} - -DEFINE_SIM_OBJECT_CLASS_NAME("DiskImage", DiskImage) - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(RawDiskImage) - - Param<string> image_file; - Param<bool> read_only; - -END_DECLARE_SIM_OBJECT_PARAMS(RawDiskImage) - -BEGIN_INIT_SIM_OBJECT_PARAMS(RawDiskImage) - - INIT_PARAM(image_file, "disk image file"), - INIT_PARAM_DFLT(read_only, "read only image", false) - -END_INIT_SIM_OBJECT_PARAMS(RawDiskImage) - - -CREATE_SIM_OBJECT(RawDiskImage) -{ - return new RawDiskImage(getInstanceName(), image_file, read_only); -} - -REGISTER_SIM_OBJECT("RawDiskImage", RawDiskImage) - -//////////////////////////////////////////////////////////////////////// -// -// Copy on Write Disk image -// -const int CowDiskImage::VersionMajor = 1; -const int CowDiskImage::VersionMinor = 0; - -CowDiskImage::CowDiskImage(const string &name, DiskImage *kid, int hash_size) - : DiskImage(name), child(kid), table(NULL) -{ init(hash_size); } - -class CowDiskCallback : public Callback -{ - private: - CowDiskImage *image; - - public: - CowDiskCallback(CowDiskImage *i) : image(i) {} - void process() { image->save(); delete this; } -}; - -CowDiskImage::CowDiskImage(const string &name, DiskImage *kid, int hash_size, - const string &file, bool read_only) - : DiskImage(name), filename(file), child(kid), table(NULL) -{ - if (!open(filename)) { - assert(!read_only && "why have a non-existent read only file?"); - init(hash_size); - } - - if (!read_only) - registerExitCallback(new CowDiskCallback(this)); -} - -CowDiskImage::~CowDiskImage() -{ - SectorTable::iterator i = table->begin(); - SectorTable::iterator end = table->end(); - - while (i != end) { - delete (*i).second; - ++i; - } -} - -void -SafeRead(ifstream &stream, void *data, int count) -{ - stream.read((char *)data, count); - if (!stream.is_open()) - panic("file not open"); - - if (stream.eof()) - panic("premature end-of-file"); - - if (stream.bad() || stream.fail()) - panic("error reading cowdisk image"); -} - -template<class T> -void -SafeRead(ifstream &stream, T &data) -{ - SafeRead(stream, &data, sizeof(data)); -} - -template<class T> -void -SafeReadSwap(ifstream &stream, T &data) -{ - SafeRead(stream, &data, sizeof(data)); - data = letoh(data); //is this the proper byte order conversion? -} - -bool -CowDiskImage::open(const string &file) -{ - ifstream stream(file.c_str()); - if (!stream.is_open()) - return false; - - if (stream.fail() || stream.bad()) - panic("Error opening %s", file); - - uint64_t magic; - SafeRead(stream, magic); - - if (memcmp(&magic, "COWDISK!", sizeof(magic)) != 0) - panic("Could not open %s: Invalid magic", file); - - uint32_t major, minor; - SafeReadSwap(stream, major); - SafeReadSwap(stream, minor); - - if (major != VersionMajor && minor != VersionMinor) - panic("Could not open %s: invalid version %d.%d != %d.%d", - file, major, minor, VersionMajor, VersionMinor); - - uint64_t sector_count; - SafeReadSwap(stream, sector_count); - table = new SectorTable(sector_count); - - - for (uint64_t i = 0; i < sector_count; i++) { - uint64_t offset; - SafeReadSwap(stream, offset); - - Sector *sector = new Sector; - SafeRead(stream, sector, sizeof(Sector)); - - assert(table->find(offset) == table->end()); - (*table)[offset] = sector; - } - - stream.close(); - - initialized = true; - return true; -} - -void -CowDiskImage::init(int hash_size) -{ - table = new SectorTable(hash_size); - - initialized = true; -} - -void -SafeWrite(ofstream &stream, const void *data, int count) -{ - stream.write((const char *)data, count); - if (!stream.is_open()) - panic("file not open"); - - if (stream.eof()) - panic("premature end-of-file"); - - if (stream.bad() || stream.fail()) - panic("error reading cowdisk image"); -} - -template<class T> -void -SafeWrite(ofstream &stream, const T &data) -{ - SafeWrite(stream, &data, sizeof(data)); -} - -template<class T> -void -SafeWriteSwap(ofstream &stream, const T &data) -{ - T swappeddata = letoh(data); //is this the proper byte order conversion? - SafeWrite(stream, &swappeddata, sizeof(data)); -} -void -CowDiskImage::save() -{ - save(filename); -} - -void -CowDiskImage::save(const string &file) -{ - if (!initialized) - panic("RawDiskImage not initialized"); - - ofstream stream(file.c_str()); - if (!stream.is_open() || stream.fail() || stream.bad()) - panic("Error opening %s", file); - - uint64_t magic; - memcpy(&magic, "COWDISK!", sizeof(magic)); - SafeWrite(stream, magic); - - SafeWriteSwap(stream, (uint32_t)VersionMajor); - SafeWriteSwap(stream, (uint32_t)VersionMinor); - SafeWriteSwap(stream, (uint64_t)table->size()); - - uint64_t size = table->size(); - SectorTable::iterator iter = table->begin(); - SectorTable::iterator end = table->end(); - - for (uint64_t i = 0; i < size; i++) { - if (iter == end) - panic("Incorrect Table Size during save of COW disk image"); - - SafeWriteSwap(stream, (uint64_t)(*iter).first); - SafeWrite(stream, (*iter).second->data, sizeof(Sector)); - ++iter; - } - - stream.close(); -} - -void -CowDiskImage::writeback() -{ - SectorTable::iterator i = table->begin(); - SectorTable::iterator end = table->end(); - - while (i != end) { - child->write((*i).second->data, (*i).first); - ++i; - } -} - -off_t -CowDiskImage::size() const -{ return child->size(); } - -off_t -CowDiskImage::read(uint8_t *data, off_t offset) const -{ - if (!initialized) - panic("CowDiskImage not initialized"); - - if (offset > size()) - panic("access out of bounds"); - - SectorTable::const_iterator i = table->find(offset); - if (i == table->end()) - return child->read(data, offset); - else { - memcpy(data, (*i).second->data, SectorSize); - DPRINTF(DiskImageRead, "read: offset=%d\n", (uint64_t)offset); - DDUMP(DiskImageRead, data, SectorSize); - return SectorSize; - } -} - -off_t -CowDiskImage::write(const uint8_t *data, off_t offset) -{ - if (!initialized) - panic("RawDiskImage not initialized"); - - if (offset > size()) - panic("access out of bounds"); - - SectorTable::iterator i = table->find(offset); - if (i == table->end()) { - Sector *sector = new Sector; - memcpy(sector, data, SectorSize); - table->insert(make_pair(offset, sector)); - } else { - memcpy((*i).second->data, data, SectorSize); - } - - DPRINTF(DiskImageWrite, "write: offset=%d\n", (uint64_t)offset); - DDUMP(DiskImageWrite, data, SectorSize); - - return SectorSize; -} - -void -CowDiskImage::serialize(ostream &os) -{ - string cowFilename = name() + ".cow"; - SERIALIZE_SCALAR(cowFilename); - save(Checkpoint::dir() + "/" + cowFilename); -} - -void -CowDiskImage::unserialize(Checkpoint *cp, const string §ion) -{ - string cowFilename; - UNSERIALIZE_SCALAR(cowFilename); - cowFilename = cp->cptDir + "/" + cowFilename; - open(cowFilename); -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(CowDiskImage) - - SimObjectParam<DiskImage *> child; - Param<string> image_file; - Param<int> table_size; - Param<bool> read_only; - -END_DECLARE_SIM_OBJECT_PARAMS(CowDiskImage) - -BEGIN_INIT_SIM_OBJECT_PARAMS(CowDiskImage) - - INIT_PARAM(child, "child image"), - INIT_PARAM_DFLT(image_file, "disk image file", ""), - INIT_PARAM_DFLT(table_size, "initial table size", 65536), - INIT_PARAM_DFLT(read_only, "don't write back to the copy-on-write file", - true) - -END_INIT_SIM_OBJECT_PARAMS(CowDiskImage) - - -CREATE_SIM_OBJECT(CowDiskImage) -{ - if (((string)image_file).empty()) - return new CowDiskImage(getInstanceName(), child, table_size); - else - return new CowDiskImage(getInstanceName(), child, table_size, - image_file, read_only); -} - -REGISTER_SIM_OBJECT("CowDiskImage", CowDiskImage) diff --git a/dev/disk_image.hh b/dev/disk_image.hh deleted file mode 100644 index 648aa20c6..000000000 --- a/dev/disk_image.hh +++ /dev/null @@ -1,133 +0,0 @@ -/* - * 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. - */ - -/** @file - * Disk Image Interfaces - */ - -#ifndef __DISK_IMAGE_HH__ -#define __DISK_IMAGE_HH__ - -#include <fstream> - -#include "base/hashmap.hh" -#include "sim/sim_object.hh" - -#define SectorSize (512) - -/** - * Basic interface for accessing a disk image. - */ -class DiskImage : public SimObject -{ - protected: - bool initialized; - - public: - DiskImage(const std::string &name) : SimObject(name), initialized(false) {} - virtual ~DiskImage() {} - - virtual off_t size() const = 0; - - virtual off_t read(uint8_t *data, off_t offset) const = 0; - virtual off_t write(const uint8_t *data, off_t offset) = 0; -}; - -/** - * Specialization for accessing a raw disk image - */ -class RawDiskImage : public DiskImage -{ - protected: - mutable std::fstream stream; - std::string file; - bool readonly; - mutable off_t disk_size; - - public: - RawDiskImage(const std::string &name, const std::string &filename, - bool rd_only); - ~RawDiskImage(); - - void close(); - void open(const std::string &filename, bool rd_only = false); - - virtual off_t size() const; - - virtual off_t read(uint8_t *data, off_t offset) const; - virtual off_t write(const uint8_t *data, off_t offset); -}; - -/** - * Specialization for accessing a copy-on-write disk image layer. - * A copy-on-write(COW) layer must be stacked on top of another disk - * image layer this layer can be another CowDiskImage, or a - * RawDiskImage. - * - * This object is designed to provide a mechanism for persistant - * changes to a main disk image, or to provide a place for temporary - * changes to the image to take place that later may be thrown away. - */ -class CowDiskImage : public DiskImage -{ - public: - static const int VersionMajor; - static const int VersionMinor; - - protected: - struct Sector { - uint8_t data[SectorSize]; - }; - typedef m5::hash_map<uint64_t, Sector *> SectorTable; - - protected: - std::string filename; - DiskImage *child; - SectorTable *table; - - public: - CowDiskImage(const std::string &name, DiskImage *kid, int hash_size); - CowDiskImage(const std::string &name, DiskImage *kid, int hash_size, - const std::string &filename, bool read_only); - ~CowDiskImage(); - - void init(int hash_size); - bool open(const std::string &file); - void save(); - void save(const std::string &file); - void writeback(); - void serialize(std::ostream &os); - void unserialize(Checkpoint *cp, const std::string §ion); - - virtual off_t size() const; - - virtual off_t read(uint8_t *data, off_t offset) const; - virtual off_t write(const uint8_t *data, off_t offset); -}; - -#endif // __DISK_IMAGE_HH__ diff --git a/dev/etherbus.cc b/dev/etherbus.cc deleted file mode 100644 index c6b131e8e..000000000 --- a/dev/etherbus.cc +++ /dev/null @@ -1,125 +0,0 @@ -/* - * 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. - */ - -/* @file - * Device module for modelling an ethernet hub - */ - -#include <cmath> -#include <deque> -#include <string> -#include <vector> - -#include "base/trace.hh" -#include "dev/etherbus.hh" -#include "dev/etherdump.hh" -#include "dev/etherint.hh" -#include "dev/etherpkt.hh" -#include "sim/builder.hh" -#include "sim/root.hh" - -using namespace std; - -EtherBus::EtherBus(const string &name, double speed, bool loop, - EtherDump *packet_dump) - : SimObject(name), ticksPerByte(speed), loopback(loop), - event(&mainEventQueue, this), sender(0), dump(packet_dump) -{ -} - -void -EtherBus::txDone() -{ - devlist_t::iterator i = devlist.begin(); - devlist_t::iterator end = devlist.end(); - - DPRINTF(Ethernet, "ethernet packet received: length=%d\n", packet->length); - DDUMP(EthernetData, packet->data, packet->length); - - while (i != end) { - if (loopback || *i != sender) - (*i)->sendPacket(packet); - ++i; - } - - sender->sendDone(); - - if (dump) - dump->dump(packet); - - sender = 0; - packet = 0; -} - -void -EtherBus::reg(EtherInt *dev) -{ devlist.push_back(dev); } - -bool -EtherBus::send(EtherInt *sndr, PacketPtr &pkt) -{ - if (busy()) { - DPRINTF(Ethernet, "ethernet packet not sent, bus busy\n", curTick); - return false; - } - - DPRINTF(Ethernet, "ethernet packet sent: length=%d\n", pkt->length); - DDUMP(EthernetData, pkt->data, pkt->length); - - packet = pkt; - sender = sndr; - int delay = (int)ceil(((double)pkt->length * ticksPerByte) + 1.0); - DPRINTF(Ethernet, "scheduling packet: delay=%d, (rate=%f)\n", - delay, ticksPerByte); - event.schedule(curTick + delay); - - return true; -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherBus) - - Param<bool> loopback; - Param<double> speed; - SimObjectParam<EtherDump *> packet_dump; - -END_DECLARE_SIM_OBJECT_PARAMS(EtherBus) - -BEGIN_INIT_SIM_OBJECT_PARAMS(EtherBus) - - INIT_PARAM(loopback, "send the packet back to the sending interface"), - INIT_PARAM(speed, "bus speed in ticks per byte"), - INIT_PARAM(packet_dump, "object to dump network packets to") - -END_INIT_SIM_OBJECT_PARAMS(EtherBus) - -CREATE_SIM_OBJECT(EtherBus) -{ - return new EtherBus(getInstanceName(), speed, loopback, packet_dump); -} - -REGISTER_SIM_OBJECT("EtherBus", EtherBus) diff --git a/dev/etherbus.hh b/dev/etherbus.hh deleted file mode 100644 index ca859d85f..000000000 --- a/dev/etherbus.hh +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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. - */ - -/* @file - * Device module for modelling an ethernet hub - */ - -#ifndef __ETHERBUS_H__ -#define __ETHERBUS_H__ - -#include "sim/eventq.hh" -#include "dev/etherpkt.hh" -#include "sim/sim_object.hh" - -class EtherDump; -class EtherInt; -class EtherBus : public SimObject -{ - protected: - typedef std::list<EtherInt *> devlist_t; - devlist_t devlist; - double ticksPerByte; - bool loopback; - - protected: - class DoneEvent : public Event - { - protected: - EtherBus *bus; - - public: - DoneEvent(EventQueue *q, EtherBus *b) - : Event(q), bus(b) {} - virtual void process() { bus->txDone(); } - virtual const char *description() { return "ethernet bus completion"; } - }; - - DoneEvent event; - PacketPtr packet; - EtherInt *sender; - EtherDump *dump; - - public: - EtherBus(const std::string &name, double speed, bool loopback, - EtherDump *dump); - virtual ~EtherBus() {} - - void txDone(); - void reg(EtherInt *dev); - bool busy() const { return (bool)packet; } - bool send(EtherInt *sender, PacketPtr &packet); -}; - -#endif // __ETHERBUS_H__ diff --git a/dev/etherdump.cc b/dev/etherdump.cc deleted file mode 100644 index d8a51fc5b..000000000 --- a/dev/etherdump.cc +++ /dev/null @@ -1,136 +0,0 @@ -/* - * 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. - */ - -/* @file - * Simple object for creating a simple pcap style packet trace - */ - -#include <sys/time.h> - -#include <algorithm> -#include <string> - -#include "base/misc.hh" -#include "base/output.hh" -#include "dev/etherdump.hh" -#include "sim/builder.hh" -#include "sim/root.hh" - -using std::string; - -EtherDump::EtherDump(const string &name, const string &file, int max) - : SimObject(name), stream(file.c_str()), maxlen(max) -{ -} - -#define DLT_EN10MB 1 // Ethernet (10Mb) -#define TCPDUMP_MAGIC 0xa1b2c3d4 -#define PCAP_VERSION_MAJOR 2 -#define PCAP_VERSION_MINOR 4 - -struct pcap_file_header { - uint32_t magic; - uint16_t version_major; - uint16_t version_minor; - int32_t thiszone; // gmt to local correction - uint32_t sigfigs; // accuracy of timestamps - uint32_t snaplen; // max length saved portion of each pkt - uint32_t linktype; // data link type (DLT_*) -}; - -struct pcap_pkthdr { - uint32_t seconds; - uint32_t microseconds; - uint32_t caplen; // length of portion present - uint32_t len; // length this packet (off wire) -}; - -void -EtherDump::init() -{ - curtime = time(NULL); - struct pcap_file_header hdr; - hdr.magic = TCPDUMP_MAGIC; - hdr.version_major = PCAP_VERSION_MAJOR; - hdr.version_minor = PCAP_VERSION_MINOR; - - hdr.thiszone = -5 * 3600; - hdr.snaplen = 1500; - hdr.sigfigs = 0; - hdr.linktype = DLT_EN10MB; - - stream.write(reinterpret_cast<char *>(&hdr), sizeof(hdr)); - - /* - * output an empty packet with the current time so that we know - * when the simulation began. This allows us to correlate packets - * to sim_cycles. - */ - pcap_pkthdr pkthdr; - pkthdr.seconds = curtime; - pkthdr.microseconds = 0; - pkthdr.caplen = 0; - pkthdr.len = 0; - stream.write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr)); - - stream.flush(); -} - -void -EtherDump::dumpPacket(PacketPtr &packet) -{ - pcap_pkthdr pkthdr; - pkthdr.seconds = curtime + (curTick / Clock::Int::s); - pkthdr.microseconds = (curTick / Clock::Int::us) % ULL(1000000); - pkthdr.caplen = std::min(packet->length, maxlen); - pkthdr.len = packet->length; - stream.write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr)); - stream.write(reinterpret_cast<char *>(packet->data), pkthdr.caplen); - stream.flush(); -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherDump) - - Param<string> file; - Param<int> maxlen; - -END_DECLARE_SIM_OBJECT_PARAMS(EtherDump) - -BEGIN_INIT_SIM_OBJECT_PARAMS(EtherDump) - - INIT_PARAM(file, "file to dump packets to"), - INIT_PARAM(maxlen, "max portion of packet data to dump") - -END_INIT_SIM_OBJECT_PARAMS(EtherDump) - -CREATE_SIM_OBJECT(EtherDump) -{ - return new EtherDump(getInstanceName(), simout.resolve(file), maxlen); -} - -REGISTER_SIM_OBJECT("EtherDump", EtherDump) diff --git a/dev/etherdump.hh b/dev/etherdump.hh deleted file mode 100644 index 149192cd7..000000000 --- a/dev/etherdump.hh +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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. - */ - -/* @file - * Simple object for creating a simple pcap style packet trace - */ - -#ifndef __ETHERDUMP_H__ -#define __ETHERDUMP_H__ - -#include <fstream> -#include "dev/etherpkt.hh" -#include "sim/sim_object.hh" - -/* - * Simple object for creating a simple pcap style packet trace - */ -class EtherDump : public SimObject -{ - private: - std::ofstream stream; - const int maxlen; - void dumpPacket(PacketPtr &packet); - void init(); - - Tick curtime; - - public: - EtherDump(const std::string &name, const std::string &file, int max); - - inline void dump(PacketPtr &pkt) { dumpPacket(pkt); } -}; - -#endif // __ETHERDUMP_H__ diff --git a/dev/etherint.cc b/dev/etherint.cc deleted file mode 100644 index 8fb047373..000000000 --- a/dev/etherint.cc +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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. - */ - -#include "dev/etherint.hh" -#include "base/misc.hh" -#include "sim/param.hh" -#include "sim/sim_object.hh" - -void -EtherInt::setPeer(EtherInt *p) -{ - if (peer && peer != p) - panic("You cannot change the peer once it is set.\n" - "Current peer=%s Desired peer=%s", peer->name(), p->name()); - - peer = p; -} - -DEFINE_SIM_OBJECT_CLASS_NAME("EtherInt", EtherInt) - diff --git a/dev/etherint.hh b/dev/etherint.hh deleted file mode 100644 index e397846ae..000000000 --- a/dev/etherint.hh +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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. - */ - -/* @file - * Class representing the actual interface between two ethernet - * components. - */ - -#ifndef __DEV_ETHERINT_HH__ -#define __DEV_ETHERINT_HH__ - -#include <string> - -#include "dev/etherpkt.hh" -#include "sim/sim_object.hh" - -/* - * Class representing the actual interface between two ethernet - * components. These components are intended to attach to another - * ethernet interface on one side and whatever device on the other. - */ -class EtherInt : public SimObject -{ - protected: - EtherInt *peer; - - public: - EtherInt(const std::string &name) : SimObject(name), peer(NULL) {} - virtual ~EtherInt() {} - - void setPeer(EtherInt *p); - - void recvDone() { peer->sendDone(); } - virtual void sendDone() = 0; - - bool sendPacket(PacketPtr packet) - { return peer ? peer->recvPacket(packet) : true; } - virtual bool recvPacket(PacketPtr packet) = 0; -}; - -#endif // __DEV_ETHERINT_HH__ diff --git a/dev/etherlink.cc b/dev/etherlink.cc deleted file mode 100644 index f68332926..000000000 --- a/dev/etherlink.cc +++ /dev/null @@ -1,300 +0,0 @@ -/* - * 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. - */ - -/* @file - * Device module for modelling a fixed bandwidth full duplex ethernet link - */ - -#include <cmath> -#include <deque> -#include <string> -#include <vector> - -#include "base/random.hh" -#include "base/trace.hh" -#include "dev/etherdump.hh" -#include "dev/etherint.hh" -#include "dev/etherlink.hh" -#include "dev/etherpkt.hh" -#include "sim/builder.hh" -#include "sim/serialize.hh" -#include "sim/system.hh" -#include "sim/root.hh" - -using namespace std; - -EtherLink::EtherLink(const string &name, EtherInt *peer0, EtherInt *peer1, - double rate, Tick delay, Tick delayVar, EtherDump *dump) - : SimObject(name) -{ - link[0] = new Link(name + ".link0", this, 0, rate, delay, delayVar, dump); - link[1] = new Link(name + ".link1", this, 1, rate, delay, delayVar, dump); - - interface[0] = new Interface(name + ".int0", link[0], link[1]); - interface[1] = new Interface(name + ".int1", link[1], link[0]); - - interface[0]->setPeer(peer0); - peer0->setPeer(interface[0]); - interface[1]->setPeer(peer1); - peer1->setPeer(interface[1]); -} - -EtherLink::~EtherLink() -{ - delete link[0]; - delete link[1]; - - delete interface[0]; - delete interface[1]; -} - -EtherLink::Interface::Interface(const string &name, Link *tx, Link *rx) - : EtherInt(name), txlink(tx) -{ - tx->setTxInt(this); - rx->setRxInt(this); -} - -EtherLink::Link::Link(const string &name, EtherLink *p, int num, - double rate, Tick delay, Tick delay_var, EtherDump *d) - : objName(name), parent(p), number(num), txint(NULL), rxint(NULL), - ticksPerByte(rate), linkDelay(delay), delayVar(delay_var), dump(d), - doneEvent(this) -{ } - -void -EtherLink::serialize(ostream &os) -{ - link[0]->serialize("link0", os); - link[1]->serialize("link1", os); -} - -void -EtherLink::unserialize(Checkpoint *cp, const string §ion) -{ - link[0]->unserialize("link0", cp, section); - link[1]->unserialize("link1", cp, section); -} - -void -EtherLink::Link::txComplete(PacketPtr packet) -{ - DPRINTF(Ethernet, "packet received: len=%d\n", packet->length); - DDUMP(EthernetData, packet->data, packet->length); - rxint->sendPacket(packet); -} - -class LinkDelayEvent : public Event -{ - protected: - EtherLink::Link *link; - PacketPtr packet; - - public: - // non-scheduling version for createForUnserialize() - LinkDelayEvent(); - LinkDelayEvent(EtherLink::Link *link, PacketPtr pkt, Tick when); - - void process(); - - virtual void serialize(ostream &os); - virtual void unserialize(Checkpoint *cp, const string §ion); - static Serializable *createForUnserialize(Checkpoint *cp, - const string §ion); -}; - -void -EtherLink::Link::txDone() -{ - if (dump) - dump->dump(packet); - - if (linkDelay > 0) { - DPRINTF(Ethernet, "packet delayed: delay=%d\n", linkDelay); - new LinkDelayEvent(this, packet, curTick + linkDelay); - } else { - txComplete(packet); - } - - packet = 0; - assert(!busy()); - - txint->sendDone(); -} - -bool -EtherLink::Link::transmit(PacketPtr pkt) -{ - if (busy()) { - DPRINTF(Ethernet, "packet not sent, link busy\n"); - return false; - } - - DPRINTF(Ethernet, "packet sent: len=%d\n", pkt->length); - DDUMP(EthernetData, pkt->data, pkt->length); - - packet = pkt; - Tick delay = (Tick)ceil(((double)pkt->length * ticksPerByte) + 1.0); - if (delayVar != 0) { - Random<Tick> var; - delay += var.uniform(0, delayVar); - } - DPRINTF(Ethernet, "scheduling packet: delay=%d, (rate=%f)\n", - delay, ticksPerByte); - doneEvent.schedule(curTick + delay); - - return true; -} - -void -EtherLink::Link::serialize(const string &base, ostream &os) -{ - bool packet_exists = packet; - paramOut(os, base + ".packet_exists", packet_exists); - if (packet_exists) - packet->serialize(base + ".packet", os); - - bool event_scheduled = doneEvent.scheduled(); - paramOut(os, base + ".event_scheduled", event_scheduled); - if (event_scheduled) { - Tick event_time = doneEvent.when(); - paramOut(os, base + ".event_time", event_time); - } - -} - -void -EtherLink::Link::unserialize(const string &base, Checkpoint *cp, - const string §ion) -{ - bool packet_exists; - paramIn(cp, section, base + ".packet_exists", packet_exists); - if (packet_exists) { - packet = new PacketData(16384); - packet->unserialize(base + ".packet", cp, section); - } - - bool event_scheduled; - paramIn(cp, section, base + ".event_scheduled", event_scheduled); - if (event_scheduled) { - Tick event_time; - paramIn(cp, section, base + ".event_time", event_time); - doneEvent.schedule(event_time); - } -} - -LinkDelayEvent::LinkDelayEvent() - : Event(&mainEventQueue), link(NULL) -{ - setFlags(AutoSerialize); - setFlags(AutoDelete); -} - -LinkDelayEvent::LinkDelayEvent(EtherLink::Link *l, PacketPtr p, Tick when) - : Event(&mainEventQueue), link(l), packet(p) -{ - setFlags(AutoSerialize); - setFlags(AutoDelete); - schedule(when); -} - -void -LinkDelayEvent::process() -{ - link->txComplete(packet); -} - -void -LinkDelayEvent::serialize(ostream &os) -{ - paramOut(os, "type", string("LinkDelayEvent")); - Event::serialize(os); - - EtherLink *parent = link->parent; - bool number = link->number; - SERIALIZE_OBJPTR(parent); - SERIALIZE_SCALAR(number); - - packet->serialize("packet", os); -} - - -void -LinkDelayEvent::unserialize(Checkpoint *cp, const string §ion) -{ - Event::unserialize(cp, section); - - EtherLink *parent; - bool number; - UNSERIALIZE_OBJPTR(parent); - UNSERIALIZE_SCALAR(number); - - link = parent->link[number]; - - packet = new PacketData(16384); - packet->unserialize("packet", cp, section); -} - - -Serializable * -LinkDelayEvent::createForUnserialize(Checkpoint *cp, const string §ion) -{ - return new LinkDelayEvent(); -} - -REGISTER_SERIALIZEABLE("LinkDelayEvent", LinkDelayEvent) - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherLink) - - SimObjectParam<EtherInt *> int1; - SimObjectParam<EtherInt *> int2; - Param<double> speed; - Param<Tick> delay; - Param<Tick> delay_var; - SimObjectParam<EtherDump *> dump; - -END_DECLARE_SIM_OBJECT_PARAMS(EtherLink) - -BEGIN_INIT_SIM_OBJECT_PARAMS(EtherLink) - - INIT_PARAM(int1, "interface 1"), - INIT_PARAM(int2, "interface 2"), - INIT_PARAM(speed, "link speed in bits per second"), - INIT_PARAM(delay, "transmit delay of packets in us"), - INIT_PARAM(delay_var, "Difference in amount of time to traverse wire"), - INIT_PARAM(dump, "object to dump network packets to") - -END_INIT_SIM_OBJECT_PARAMS(EtherLink) - -CREATE_SIM_OBJECT(EtherLink) -{ - return new EtherLink(getInstanceName(), int1, int2, speed, delay, delay_var, - dump); -} - -REGISTER_SIM_OBJECT("EtherLink", EtherLink) diff --git a/dev/etherlink.hh b/dev/etherlink.hh deleted file mode 100644 index 305007d9e..000000000 --- a/dev/etherlink.hh +++ /dev/null @@ -1,130 +0,0 @@ -/* - * 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. - */ - -/* @file - * Device module for modelling a fixed bandwidth full duplex ethernet link - */ - -#ifndef __DEV_ETHERLINK_HH__ -#define __DEV_ETHERLINK_HH__ - -#include "dev/etherint.hh" -#include "dev/etherpkt.hh" -#include "sim/eventq.hh" -#include "sim/host.hh" -#include "sim/sim_object.hh" - -class EtherDump; -class Checkpoint; -/* - * Model for a fixed bandwidth full duplex ethernet link - */ -class EtherLink : public SimObject -{ - protected: - class Interface; - - friend class LinkDelayEvent; - /* - * Model for a single uni-directional link - */ - class Link - { - protected: - std::string objName; - - EtherLink *parent; - int number; - - Interface *txint; - Interface *rxint; - - double ticksPerByte; - Tick linkDelay; - Tick delayVar; - EtherDump *dump; - - protected: - /* - * Transfer is complete - */ - PacketPtr packet; - void txDone(); - typedef EventWrapper<Link, &Link::txDone> DoneEvent; - friend void DoneEvent::process(); - DoneEvent doneEvent; - - friend class LinkDelayEvent; - void txComplete(PacketPtr packet); - - public: - Link(const std::string &name, EtherLink *p, int num, - double rate, Tick delay, Tick delay_var, EtherDump *dump); - ~Link() {} - - const std::string name() const { return objName; } - - bool busy() const { return (bool)packet; } - bool transmit(PacketPtr packet); - - void setTxInt(Interface *i) { assert(!txint); txint = i; } - void setRxInt(Interface *i) { assert(!rxint); rxint = i; } - - void serialize(const std::string &base, std::ostream &os); - void unserialize(const std::string &base, Checkpoint *cp, - const std::string §ion); - }; - - /* - * Interface at each end of the link - */ - class Interface : public EtherInt - { - private: - Link *txlink; - - public: - Interface(const std::string &name, Link *txlink, Link *rxlink); - bool recvPacket(PacketPtr packet) { return txlink->transmit(packet); } - void sendDone() { peer->sendDone(); } - }; - - Link *link[2]; - EtherInt *interface[2]; - - public: - EtherLink(const std::string &name, EtherInt *peer0, EtherInt *peer1, - double rate, Tick delay, Tick delayVar, EtherDump *dump); - virtual ~EtherLink(); - - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); - -}; - -#endif // __ETHERLINK_HH__ diff --git a/dev/etherpkt.cc b/dev/etherpkt.cc deleted file mode 100644 index 44dbd7c18..000000000 --- a/dev/etherpkt.cc +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <iostream> - -#include "base/misc.hh" -#include "dev/etherpkt.hh" -#include "sim/serialize.hh" - -using namespace std; - -void -PacketData::serialize(const string &base, ostream &os) -{ - paramOut(os, base + ".length", length); - paramOut(os, base + ".slack", slack); - arrayParamOut(os, base + ".data", data, length); -} - -void -PacketData::unserialize(const string &base, Checkpoint *cp, - const string §ion) -{ - paramIn(cp, section, base + ".length", length); - paramIn(cp, section, base + ".slack", slack); - if (length) - arrayParamIn(cp, section, base + ".data", data, length); -} diff --git a/dev/etherpkt.hh b/dev/etherpkt.hh deleted file mode 100644 index cb9022d72..000000000 --- a/dev/etherpkt.hh +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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. - */ - -/* @file - * Reference counted class containing ethernet packet data - */ - -#ifndef __ETHERPKT_HH__ -#define __ETHERPKT_HH__ - -#include <iosfwd> -#include <memory> -#include <assert.h> - -#include "base/refcnt.hh" -#include "sim/host.hh" - -/* - * Reference counted class containing ethernet packet data - */ -class Checkpoint; -class PacketData : public RefCounted -{ - public: - /* - * Pointer to packet data will be deleted - */ - uint8_t *data; - - /* - * Length of the current packet - */ - int length; - - /* - * Extra space taken up by the packet in whatever data structure - * it is in. - * - * NOTE: This can only be use by *one* data structure at a time! - */ - int slack; - - public: - PacketData() : data(NULL), length(0), slack(0) { } - explicit PacketData(size_t size) - : data(new uint8_t[size]), length(0), slack(0) { } - PacketData(std::auto_ptr<uint8_t> d, int l, int s = 0) - : data(d.release()), length(l), slack(s) { } - ~PacketData() { if (data) delete [] data; } - - public: - void serialize(const std::string &base, std::ostream &os); - void unserialize(const std::string &base, Checkpoint *cp, - const std::string §ion); -}; - -typedef RefCountingPtr<PacketData> PacketPtr; - -#endif // __ETHERPKT_HH__ diff --git a/dev/ethertap.cc b/dev/ethertap.cc deleted file mode 100644 index 7589991ef..000000000 --- a/dev/ethertap.cc +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Copyright (c) 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. - */ - -/* @file - * Interface to connect a simulated ethernet device to the real world - */ - -#if defined(__OpenBSD__) || defined(__APPLE__) -#include <sys/param.h> -#endif -#include <netinet/in.h> - -#include <unistd.h> - -#include <deque> -#include <string> - -#include "base/misc.hh" -#include "base/pollevent.hh" -#include "base/socket.hh" -#include "base/trace.hh" -#include "dev/etherdump.hh" -#include "dev/etherint.hh" -#include "dev/etherpkt.hh" -#include "dev/ethertap.hh" -#include "sim/builder.hh" - -using namespace std; - -/** - */ -class TapListener -{ - protected: - /** - */ - class Event : public PollEvent - { - protected: - TapListener *listener; - - public: - Event(TapListener *l, int fd, int e) - : PollEvent(fd, e), listener(l) {} - - virtual void process(int revent) { listener->accept(); } - }; - - friend class Event; - Event *event; - - protected: - ListenSocket listener; - EtherTap *tap; - int port; - - public: - TapListener(EtherTap *t, int p) - : event(NULL), tap(t), port(p) {} - ~TapListener() { if (event) delete event; } - - void accept(); - void listen(); -}; - -void -TapListener::listen() -{ - while (!listener.listen(port, true)) { - DPRINTF(Ethernet, "TapListener(listen): Can't bind port %d\n", port); - port++; - } - - ccprintf(cerr, "Listening for tap connection on port %d\n", port); - event = new Event(this, listener.getfd(), POLLIN|POLLERR); - pollQueue.schedule(event); -} - -void -TapListener::accept() -{ - if (!listener.islistening()) - panic("TapListener(accept): cannot accept if we're not listening!"); - - int sfd = listener.accept(true); - if (sfd != -1) - tap->attach(sfd); -} - -/** - */ -class TapEvent : public PollEvent -{ - protected: - EtherTap *tap; - - public: - TapEvent(EtherTap *_tap, int fd, int e) - : PollEvent(fd, e), tap(_tap) {} - virtual void process(int revent) { tap->process(revent); } -}; - -EtherTap::EtherTap(const string &name, EtherDump *d, int port, int bufsz) - : EtherInt(name), event(NULL), socket(-1), buflen(bufsz), dump(d), - txEvent(this) -{ - buffer = new char[buflen]; - listener = new TapListener(this, port); - listener->listen(); -} - -EtherTap::~EtherTap() -{ - if (event) - delete event; - if (buffer) - delete [] buffer; - - delete listener; -} - -void -EtherTap::attach(int fd) -{ - if (socket != -1) - close(fd); - - buffer_offset = 0; - data_len = 0; - socket = fd; - DPRINTF(Ethernet, "EtherTap attached\n"); - event = new TapEvent(this, socket, POLLIN|POLLERR); - pollQueue.schedule(event); -} - -void -EtherTap::detach() -{ - DPRINTF(Ethernet, "EtherTap detached\n"); - delete event; - event = 0; - close(socket); - socket = -1; -} - -bool -EtherTap::recvPacket(PacketPtr packet) -{ - if (dump) - dump->dump(packet); - - DPRINTF(Ethernet, "EtherTap output len=%d\n", packet->length); - DDUMP(EthernetData, packet->data, packet->length); - u_int32_t len = htonl(packet->length); - write(socket, &len, sizeof(len)); - write(socket, packet->data, packet->length); - - recvDone(); - - return true; -} - -void -EtherTap::sendDone() -{} - -void -EtherTap::process(int revent) -{ - if (revent & POLLERR) { - detach(); - return; - } - - char *data = buffer + sizeof(u_int32_t); - if (!(revent & POLLIN)) - return; - - if (buffer_offset < data_len + sizeof(u_int32_t)) { - int len = read(socket, buffer + buffer_offset, buflen - buffer_offset); - if (len == 0) { - detach(); - return; - } - - buffer_offset += len; - - if (data_len == 0) - data_len = ntohl(*(u_int32_t *)buffer); - - DPRINTF(Ethernet, "Received data from peer: len=%d buffer_offset=%d " - "data_len=%d\n", len, buffer_offset, data_len); - } - - while (data_len != 0 && buffer_offset >= data_len + sizeof(u_int32_t)) { - PacketPtr packet; - packet = new PacketData(data_len); - packet->length = data_len; - memcpy(packet->data, data, data_len); - - buffer_offset -= data_len + sizeof(u_int32_t); - assert(buffer_offset >= 0); - if (buffer_offset > 0) { - memmove(buffer, data + data_len, buffer_offset); - data_len = ntohl(*(u_int32_t *)buffer); - } else - data_len = 0; - - DPRINTF(Ethernet, "EtherTap input len=%d\n", packet->length); - DDUMP(EthernetData, packet->data, packet->length); - if (!sendPacket(packet)) { - DPRINTF(Ethernet, "bus busy...buffer for retransmission\n"); - packetBuffer.push(packet); - if (!txEvent.scheduled()) - txEvent.schedule(curTick + retryTime); - } else if (dump) { - dump->dump(packet); - } - } -} - -void -EtherTap::retransmit() -{ - if (packetBuffer.empty()) - return; - - PacketPtr packet = packetBuffer.front(); - if (sendPacket(packet)) { - if (dump) - dump->dump(packet); - DPRINTF(Ethernet, "EtherTap retransmit\n"); - packetBuffer.front() = NULL; - packetBuffer.pop(); - } - - if (!packetBuffer.empty() && !txEvent.scheduled()) - txEvent.schedule(curTick + retryTime); -} - -//===================================================================== - -void -EtherTap::serialize(ostream &os) -{ - SERIALIZE_SCALAR(socket); - SERIALIZE_SCALAR(buflen); - uint8_t *buffer = (uint8_t *)this->buffer; - SERIALIZE_ARRAY(buffer, buflen); - SERIALIZE_SCALAR(buffer_offset); - SERIALIZE_SCALAR(data_len); - - bool tapevent_present = false; - if (event) { - tapevent_present = true; - SERIALIZE_SCALAR(tapevent_present); - event->serialize(os); - } - else { - SERIALIZE_SCALAR(tapevent_present); - } -} - -void -EtherTap::unserialize(Checkpoint *cp, const std::string §ion) -{ - UNSERIALIZE_SCALAR(socket); - UNSERIALIZE_SCALAR(buflen); - uint8_t *buffer = (uint8_t *)this->buffer; - UNSERIALIZE_ARRAY(buffer, buflen); - UNSERIALIZE_SCALAR(buffer_offset); - UNSERIALIZE_SCALAR(data_len); - - bool tapevent_present; - UNSERIALIZE_SCALAR(tapevent_present); - if (tapevent_present) { - event = new TapEvent(this, socket, POLLIN|POLLERR); - - event->unserialize(cp,section); - - if (event->queued()) { - pollQueue.schedule(event); - } - } -} - -//===================================================================== - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherTap) - - SimObjectParam<EtherInt *> peer; - SimObjectParam<EtherDump *> dump; - Param<unsigned> port; - Param<unsigned> bufsz; - -END_DECLARE_SIM_OBJECT_PARAMS(EtherTap) - -BEGIN_INIT_SIM_OBJECT_PARAMS(EtherTap) - - INIT_PARAM_DFLT(peer, "peer interface", NULL), - INIT_PARAM_DFLT(dump, "object to dump network packets to", NULL), - INIT_PARAM_DFLT(port, "tap port", 3500), - INIT_PARAM_DFLT(bufsz, "tap buffer size", 10000) - -END_INIT_SIM_OBJECT_PARAMS(EtherTap) - - -CREATE_SIM_OBJECT(EtherTap) -{ - EtherTap *tap = new EtherTap(getInstanceName(), dump, port, bufsz); - - if (peer) { - tap->setPeer(peer); - peer->setPeer(tap); - } - - return tap; -} - -REGISTER_SIM_OBJECT("EtherTap", EtherTap) diff --git a/dev/ethertap.hh b/dev/ethertap.hh deleted file mode 100644 index 069ba734f..000000000 --- a/dev/ethertap.hh +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 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. - */ - -/* @file - * Interface to connect a simulated ethernet device to the real world - */ - -#ifndef __ETHERTAP_HH__ -#define __ETHERTAP_HH__ - -#include <queue> -#include <string> - -#include "dev/etherint.hh" -#include "dev/etherpkt.hh" -#include "sim/eventq.hh" -#include "base/pollevent.hh" -#include "sim/sim_object.hh" - -class TapEvent; -class TapListener; - -/* - * Interface to connect a simulated ethernet device to the real world - */ -class EtherTap : public EtherInt -{ - protected: - friend class TapEvent; - TapEvent *event; - - protected: - friend class TapListener; - TapListener *listener; - int socket; - char *buffer; - int buflen; - int32_t buffer_offset; - int32_t data_len; - - EtherDump *dump; - - void attach(int fd); - void detach(); - - protected: - std::string device; - std::queue<PacketPtr> packetBuffer; - - void process(int revent); - void enqueue(PacketData *packet); - void retransmit(); - - /* - */ - class TxEvent : public Event - { - protected: - EtherTap *tap; - - public: - TxEvent(EtherTap *_tap) - : Event(&mainEventQueue), tap(_tap) {} - void process() { tap->retransmit(); } - virtual const char *description() { return "retransmit event"; } - }; - - friend class TxEvent; - TxEvent txEvent; - - public: - EtherTap(const std::string &name, EtherDump *dump, int port, int bufsz); - virtual ~EtherTap(); - - virtual bool recvPacket(PacketPtr packet); - virtual void sendDone(); - - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); -}; - -#endif // __ETHERTAP_HH__ diff --git a/dev/ide_ctrl.cc b/dev/ide_ctrl.cc deleted file mode 100644 index 05c756f04..000000000 --- a/dev/ide_ctrl.cc +++ /dev/null @@ -1,813 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <cstddef> -#include <cstdlib> -#include <string> -#include <vector> - -#include "base/trace.hh" -#include "cpu/intr_control.hh" -#include "dev/ide_ctrl.hh" -#include "dev/ide_disk.hh" -#include "dev/pciconfigall.hh" -#include "dev/pcireg.h" -#include "dev/platform.hh" -#include "mem/bus/bus.hh" -#include "mem/bus/dma_interface.hh" -#include "mem/bus/pio_interface.hh" -#include "mem/bus/pio_interface_impl.hh" -#include "mem/functional/memory_control.hh" -#include "mem/functional/physical.hh" -#include "sim/builder.hh" -#include "sim/sim_object.hh" - -using namespace std; -using namespace TheISA; - -//// -// Initialization and destruction -//// - -IdeController::IdeController(Params *p) - : PciDev(p) -{ - // initialize the PIO interface addresses - pri_cmd_addr = 0; - pri_cmd_size = BARSize[0]; - - pri_ctrl_addr = 0; - pri_ctrl_size = BARSize[1]; - - sec_cmd_addr = 0; - sec_cmd_size = BARSize[2]; - - sec_ctrl_addr = 0; - sec_ctrl_size = BARSize[3]; - - // initialize the bus master interface (BMI) address to be configured - // via PCI - bmi_addr = 0; - bmi_size = BARSize[4]; - - // zero out all of the registers - memset(bmi_regs.data, 0, sizeof(bmi_regs)); - memset(config_regs.data, 0, sizeof(config_regs.data)); - - // setup initial values - // enable both channels - config_regs.idetim0 = htole((uint16_t)IDETIM_DECODE_EN); - config_regs.idetim1 = htole((uint16_t)IDETIM_DECODE_EN); - bmi_regs.bmis0 = DMA1CAP | DMA0CAP; - bmi_regs.bmis1 = DMA1CAP | DMA0CAP; - - // reset all internal variables - io_enabled = false; - bm_enabled = false; - memset(cmd_in_progress, 0, sizeof(cmd_in_progress)); - - pioInterface = NULL; - dmaInterface = NULL; - // create the PIO and DMA interfaces - if (params()->pio_bus) { - pioInterface = newPioInterface(name() + ".pio", params()->hier, - params()->pio_bus, this, - &IdeController::cacheAccess); - pioLatency = params()->pio_latency * params()->pio_bus->clockRate; - } - - if (params()->dma_bus) { - dmaInterface = new DMAInterface<Bus>(name() + ".dma", - params()->dma_bus, - params()->dma_bus, 1, true); - } - - // setup the disks attached to controller - memset(disks, 0, sizeof(disks)); - dev[0] = 0; - dev[1] = 0; - - if (params()->disks.size() > 3) - panic("IDE controllers support a maximum of 4 devices attached!\n"); - - for (int i = 0; i < params()->disks.size(); i++) { - disks[i] = params()->disks[i]; - disks[i]->setController(this, dmaInterface); - } -} - -IdeController::~IdeController() -{ - for (int i = 0; i < 4; i++) - if (disks[i]) - delete disks[i]; -} - -//// -// Utility functions -/// - -void -IdeController::parseAddr(const Addr &addr, Addr &offset, IdeChannel &channel, - IdeRegType ®_type) -{ - offset = addr; - - if (addr >= pri_cmd_addr && addr < (pri_cmd_addr + pri_cmd_size)) { - offset -= pri_cmd_addr; - reg_type = COMMAND_BLOCK; - channel = PRIMARY; - } else if (addr >= pri_ctrl_addr && - addr < (pri_ctrl_addr + pri_ctrl_size)) { - offset -= pri_ctrl_addr; - reg_type = CONTROL_BLOCK; - channel = PRIMARY; - } else if (addr >= sec_cmd_addr && - addr < (sec_cmd_addr + sec_cmd_size)) { - offset -= sec_cmd_addr; - reg_type = COMMAND_BLOCK; - channel = SECONDARY; - } else if (addr >= sec_ctrl_addr && - addr < (sec_ctrl_addr + sec_ctrl_size)) { - offset -= sec_ctrl_addr; - reg_type = CONTROL_BLOCK; - channel = SECONDARY; - } else if (addr >= bmi_addr && addr < (bmi_addr + bmi_size)) { - offset -= bmi_addr; - reg_type = BMI_BLOCK; - channel = (offset < BMIC1) ? PRIMARY : SECONDARY; - } else { - panic("IDE controller access to invalid address: %#x\n", addr); - } -} - -int -IdeController::getDisk(IdeChannel channel) -{ - int disk = 0; - uint8_t *devBit = &dev[0]; - - if (channel == SECONDARY) { - disk += 2; - devBit = &dev[1]; - } - - disk += *devBit; - - assert(*devBit == 0 || *devBit == 1); - - return disk; -} - -int -IdeController::getDisk(IdeDisk *diskPtr) -{ - for (int i = 0; i < 4; i++) { - if ((long)diskPtr == (long)disks[i]) - return i; - } - return -1; -} - -bool -IdeController::isDiskSelected(IdeDisk *diskPtr) -{ - for (int i = 0; i < 4; i++) { - if ((long)diskPtr == (long)disks[i]) { - // is disk is on primary or secondary channel - int channel = i/2; - // is disk the master or slave - int devID = i%2; - - return (dev[channel] == devID); - } - } - panic("Unable to find disk by pointer!!\n"); -} - -//// -// Command completion -//// - -void -IdeController::setDmaComplete(IdeDisk *disk) -{ - int diskNum = getDisk(disk); - - if (diskNum < 0) - panic("Unable to find disk based on pointer %#x\n", disk); - - if (diskNum < 2) { - // clear the start/stop bit in the command register - bmi_regs.bmic0 &= ~SSBM; - // clear the bus master active bit in the status register - bmi_regs.bmis0 &= ~BMIDEA; - // set the interrupt bit - bmi_regs.bmis0 |= IDEINTS; - } else { - // clear the start/stop bit in the command register - bmi_regs.bmic1 &= ~SSBM; - // clear the bus master active bit in the status register - bmi_regs.bmis1 &= ~BMIDEA; - // set the interrupt bit - bmi_regs.bmis1 |= IDEINTS; - } -} - -//// -// Bus timing and bus access functions -//// - -Tick -IdeController::cacheAccess(MemReqPtr &req) -{ - // @todo Add more accurate timing to cache access - return curTick + pioLatency; -} - -//// -// Read and write handling -//// - -void -IdeController::readConfig(int offset, int size, uint8_t *data) -{ - int config_offset; - - if (offset < PCI_DEVICE_SPECIFIC) { - PciDev::readConfig(offset, size, data); - } else if (offset >= IDE_CTRL_CONF_START && - (offset + size) <= IDE_CTRL_CONF_END) { - - config_offset = offset - IDE_CTRL_CONF_START; - - switch (size) { - case sizeof(uint8_t): - *data = config_regs.data[config_offset]; - break; - case sizeof(uint16_t): - *(uint16_t*)data = *(uint16_t*)&config_regs.data[config_offset]; - break; - case sizeof(uint32_t): - *(uint32_t*)data = *(uint32_t*)&config_regs.data[config_offset]; - break; - default: - panic("Invalid PCI configuration read size!\n"); - } - - - - } else { - panic("Read of unimplemented PCI config. register: %x\n", offset); - } - switch (size) { - case sizeof(uint8_t): - DPRINTF(IdeCtrl, "PCI read offset: %#x size: %d data: %#x\n", - offset, size, (uint32_t)*data); - break; - case sizeof(uint16_t): - DPRINTF(IdeCtrl, "PCI read offset: %#x size: %d data: %#x\n", - offset, size, *(uint16_t*)data); - break; - case sizeof(uint32_t): - DPRINTF(IdeCtrl, "PCI read offset: %#x size: %d data: %#x\n", - offset, size, *(uint32_t*)data); - break; - default: - panic("Invalid PCI configuration read size!\n"); - } - -} - -void -IdeController::writeConfig(int offset, int size, const uint8_t *data) -{ - int config_offset; - - if (offset < PCI_DEVICE_SPECIFIC) { - PciDev::writeConfig(offset, size, data); - } else if (offset >= IDE_CTRL_CONF_START && - (offset + size) <= IDE_CTRL_CONF_END) { - - config_offset = offset - IDE_CTRL_CONF_START; - - switch(size) { - case sizeof(uint8_t): - config_regs.data[config_offset] = *data; - break; - case sizeof(uint16_t): - *(uint16_t*)&config_regs.data[config_offset] = *(uint16_t*)data; - break; - case sizeof(uint32_t): - *(uint32_t*)&config_regs.data[config_offset] = *(uint32_t*)data; - break; - default: - panic("Invalid PCI configuration write size!\n"); - } - } else { - panic("Write of unimplemented PCI config. register: %x\n", offset); - } - - switch(size) { - case sizeof(uint8_t): - DPRINTF(IdeCtrl, "PCI write offset: %#x size: %d data: %#x\n", - offset, size, (uint32_t)*data); - break; - case sizeof(uint16_t): - DPRINTF(IdeCtrl, "PCI write offset: %#x size: %d data: %#x\n", - offset, size, *(uint16_t*)data); - break; - case sizeof(uint32_t): - DPRINTF(IdeCtrl, "PCI write offset: %#x size: %d data: %#x\n", - offset, size, *(uint32_t*)data); - break; - default: - panic("Invalid PCI configuration write size!\n"); - } - - // Catch the writes to specific PCI registers that have side affects - // (like updating the PIO ranges) - switch (offset) { - case PCI_COMMAND: - if (letoh(config.command) & PCI_CMD_IOSE) - io_enabled = true; - else - io_enabled = false; - - if (letoh(config.command) & PCI_CMD_BME) - bm_enabled = true; - else - bm_enabled = false; - break; - - case PCI0_BASE_ADDR0: - if (BARAddrs[0] != 0) { - pri_cmd_addr = BARAddrs[0]; - if (pioInterface) - pioInterface->addAddrRange(RangeSize(pri_cmd_addr, - pri_cmd_size)); - - pri_cmd_addr &= EV5::PAddrUncachedMask; - } - break; - - case PCI0_BASE_ADDR1: - if (BARAddrs[1] != 0) { - pri_ctrl_addr = BARAddrs[1]; - if (pioInterface) - pioInterface->addAddrRange(RangeSize(pri_ctrl_addr, - pri_ctrl_size)); - - pri_ctrl_addr &= EV5::PAddrUncachedMask; - } - break; - - case PCI0_BASE_ADDR2: - if (BARAddrs[2] != 0) { - sec_cmd_addr = BARAddrs[2]; - if (pioInterface) - pioInterface->addAddrRange(RangeSize(sec_cmd_addr, - sec_cmd_size)); - - sec_cmd_addr &= EV5::PAddrUncachedMask; - } - break; - - case PCI0_BASE_ADDR3: - if (BARAddrs[3] != 0) { - sec_ctrl_addr = BARAddrs[3]; - if (pioInterface) - pioInterface->addAddrRange(RangeSize(sec_ctrl_addr, - sec_ctrl_size)); - - sec_ctrl_addr &= EV5::PAddrUncachedMask; - } - break; - - case PCI0_BASE_ADDR4: - if (BARAddrs[4] != 0) { - bmi_addr = BARAddrs[4]; - if (pioInterface) - pioInterface->addAddrRange(RangeSize(bmi_addr, bmi_size)); - - bmi_addr &= EV5::PAddrUncachedMask; - } - break; - } -} - -Fault -IdeController::read(MemReqPtr &req, uint8_t *data) -{ - Addr offset; - IdeChannel channel; - IdeRegType reg_type; - int disk; - - parseAddr(req->paddr, offset, channel, reg_type); - - if (!io_enabled) - return NoFault; - - switch (reg_type) { - case BMI_BLOCK: - switch (req->size) { - case sizeof(uint8_t): - *data = bmi_regs.data[offset]; - break; - case sizeof(uint16_t): - *(uint16_t*)data = *(uint16_t*)&bmi_regs.data[offset]; - break; - case sizeof(uint32_t): - *(uint32_t*)data = *(uint32_t*)&bmi_regs.data[offset]; - break; - default: - panic("IDE read of BMI reg invalid size: %#x\n", req->size); - } - break; - - case COMMAND_BLOCK: - case CONTROL_BLOCK: - disk = getDisk(channel); - - if (disks[disk] == NULL) - break; - - switch (offset) { - case DATA_OFFSET: - switch (req->size) { - case sizeof(uint16_t): - disks[disk]->read(offset, reg_type, data); - break; - - case sizeof(uint32_t): - disks[disk]->read(offset, reg_type, data); - disks[disk]->read(offset, reg_type, &data[2]); - break; - - default: - panic("IDE read of data reg invalid size: %#x\n", req->size); - } - break; - default: - if (req->size == sizeof(uint8_t)) { - disks[disk]->read(offset, reg_type, data); - } else - panic("IDE read of command reg of invalid size: %#x\n", req->size); - } - break; - default: - panic("IDE controller read of unknown register block type!\n"); - } - - if (req->size == 1) - DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n", - offset, req->size, (uint32_t)*data); - else if (req->size == 2) - DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n", - offset, req->size, *(uint16_t*)data); - else - DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n", - offset, req->size, *(uint32_t*)data); - - return NoFault; -} - -Fault -IdeController::write(MemReqPtr &req, const uint8_t *data) -{ - Addr offset; - IdeChannel channel; - IdeRegType reg_type; - int disk; - uint8_t oldVal, newVal; - - parseAddr(req->paddr, offset, channel, reg_type); - - if (!io_enabled) - return NoFault; - - switch (reg_type) { - case BMI_BLOCK: - if (!bm_enabled) - return NoFault; - - switch (offset) { - // Bus master IDE command register - case BMIC1: - case BMIC0: - if (req->size != sizeof(uint8_t)) - panic("Invalid BMIC write size: %x\n", req->size); - - // select the current disk based on DEV bit - disk = getDisk(channel); - - oldVal = bmi_regs.chan[channel].bmic; - newVal = *data; - - // if a DMA transfer is in progress, R/W control cannot change - if (oldVal & SSBM) { - if ((oldVal & RWCON) ^ (newVal & RWCON)) { - (oldVal & RWCON) ? newVal |= RWCON : newVal &= ~RWCON; - } - } - - // see if the start/stop bit is being changed - if ((oldVal & SSBM) ^ (newVal & SSBM)) { - if (oldVal & SSBM) { - // stopping DMA transfer - DPRINTF(IdeCtrl, "Stopping DMA transfer\n"); - - // clear the BMIDEA bit - bmi_regs.chan[channel].bmis = - bmi_regs.chan[channel].bmis & ~BMIDEA; - - if (disks[disk] == NULL) - panic("DMA stop for disk %d which does not exist\n", - disk); - - // inform the disk of the DMA transfer abort - disks[disk]->abortDma(); - } else { - // starting DMA transfer - DPRINTF(IdeCtrl, "Starting DMA transfer\n"); - - // set the BMIDEA bit - bmi_regs.chan[channel].bmis = - bmi_regs.chan[channel].bmis | BMIDEA; - - if (disks[disk] == NULL) - panic("DMA start for disk %d which does not exist\n", - disk); - - // inform the disk of the DMA transfer start - disks[disk]->startDma(letoh(bmi_regs.chan[channel].bmidtp)); - } - } - - // update the register value - bmi_regs.chan[channel].bmic = newVal; - break; - - // Bus master IDE status register - case BMIS0: - case BMIS1: - if (req->size != sizeof(uint8_t)) - panic("Invalid BMIS write size: %x\n", req->size); - - oldVal = bmi_regs.chan[channel].bmis; - newVal = *data; - - // the BMIDEA bit is RO - newVal |= (oldVal & BMIDEA); - - // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each - if ((oldVal & IDEINTS) && (newVal & IDEINTS)) - newVal &= ~IDEINTS; // clear the interrupt? - else - (oldVal & IDEINTS) ? newVal |= IDEINTS : newVal &= ~IDEINTS; - - if ((oldVal & IDEDMAE) && (newVal & IDEDMAE)) - newVal &= ~IDEDMAE; - else - (oldVal & IDEDMAE) ? newVal |= IDEDMAE : newVal &= ~IDEDMAE; - - bmi_regs.chan[channel].bmis = newVal; - break; - - // Bus master IDE descriptor table pointer register - case BMIDTP0: - case BMIDTP1: - { - if (req->size != sizeof(uint32_t)) - panic("Invalid BMIDTP write size: %x\n", req->size); - - uint32_t host_data = letoh(*(uint32_t*)data); - host_data &= ~0x3; - bmi_regs.chan[channel].bmidtp = htole(host_data); - } - break; - - default: - if (req->size != sizeof(uint8_t) && - req->size != sizeof(uint16_t) && - req->size != sizeof(uint32_t)) - panic("IDE controller write of invalid write size: %x\n", - req->size); - - // do a default copy of data into the registers - memcpy(&bmi_regs.data[offset], data, req->size); - } - break; - case COMMAND_BLOCK: - if (offset == IDE_SELECT_OFFSET) { - uint8_t *devBit = &dev[channel]; - *devBit = (letoh(*data) & IDE_SELECT_DEV_BIT) ? 1 : 0; - } - // fall-through ok! - case CONTROL_BLOCK: - disk = getDisk(channel); - - if (disks[disk] == NULL) - break; - - switch (offset) { - case DATA_OFFSET: - switch (req->size) { - case sizeof(uint16_t): - disks[disk]->write(offset, reg_type, data); - break; - - case sizeof(uint32_t): - disks[disk]->write(offset, reg_type, data); - disks[disk]->write(offset, reg_type, &data[2]); - break; - default: - panic("IDE write of data reg invalid size: %#x\n", req->size); - } - break; - default: - if (req->size == sizeof(uint8_t)) { - disks[disk]->write(offset, reg_type, data); - } else - panic("IDE write of command reg of invalid size: %#x\n", req->size); - } - break; - default: - panic("IDE controller write of unknown register block type!\n"); - } - if (req->size == 1) - DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n", - offset, req->size, (uint32_t)*data); - else if (req->size == 2) - DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n", - offset, req->size, *(uint16_t*)data); - else - DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n", - offset, req->size, *(uint32_t*)data); - - return NoFault; -} - -//// -// Serialization -//// - -void -IdeController::serialize(std::ostream &os) -{ - // Serialize the PciDev base class - PciDev::serialize(os); - - // Serialize register addresses and sizes - SERIALIZE_SCALAR(pri_cmd_addr); - SERIALIZE_SCALAR(pri_cmd_size); - SERIALIZE_SCALAR(pri_ctrl_addr); - SERIALIZE_SCALAR(pri_ctrl_size); - SERIALIZE_SCALAR(sec_cmd_addr); - SERIALIZE_SCALAR(sec_cmd_size); - SERIALIZE_SCALAR(sec_ctrl_addr); - SERIALIZE_SCALAR(sec_ctrl_size); - SERIALIZE_SCALAR(bmi_addr); - SERIALIZE_SCALAR(bmi_size); - - // Serialize registers - SERIALIZE_ARRAY(bmi_regs.data, - sizeof(bmi_regs.data) / sizeof(bmi_regs.data[0])); - SERIALIZE_ARRAY(dev, sizeof(dev) / sizeof(dev[0])); - SERIALIZE_ARRAY(config_regs.data, - sizeof(config_regs.data) / sizeof(config_regs.data[0])); - - // Serialize internal state - SERIALIZE_SCALAR(io_enabled); - SERIALIZE_SCALAR(bm_enabled); - SERIALIZE_ARRAY(cmd_in_progress, - sizeof(cmd_in_progress) / sizeof(cmd_in_progress[0])); -} - -void -IdeController::unserialize(Checkpoint *cp, const std::string §ion) -{ - // Unserialize the PciDev base class - PciDev::unserialize(cp, section); - - // Unserialize register addresses and sizes - UNSERIALIZE_SCALAR(pri_cmd_addr); - UNSERIALIZE_SCALAR(pri_cmd_size); - UNSERIALIZE_SCALAR(pri_ctrl_addr); - UNSERIALIZE_SCALAR(pri_ctrl_size); - UNSERIALIZE_SCALAR(sec_cmd_addr); - UNSERIALIZE_SCALAR(sec_cmd_size); - UNSERIALIZE_SCALAR(sec_ctrl_addr); - UNSERIALIZE_SCALAR(sec_ctrl_size); - UNSERIALIZE_SCALAR(bmi_addr); - UNSERIALIZE_SCALAR(bmi_size); - - // Unserialize registers - UNSERIALIZE_ARRAY(bmi_regs.data, - sizeof(bmi_regs.data) / sizeof(bmi_regs.data[0])); - UNSERIALIZE_ARRAY(dev, sizeof(dev) / sizeof(dev[0])); - UNSERIALIZE_ARRAY(config_regs.data, - sizeof(config_regs.data) / sizeof(config_regs.data[0])); - - // Unserialize internal state - UNSERIALIZE_SCALAR(io_enabled); - UNSERIALIZE_SCALAR(bm_enabled); - UNSERIALIZE_ARRAY(cmd_in_progress, - sizeof(cmd_in_progress) / sizeof(cmd_in_progress[0])); - - if (pioInterface) { - pioInterface->addAddrRange(RangeSize(pri_cmd_addr, pri_cmd_size)); - pioInterface->addAddrRange(RangeSize(pri_ctrl_addr, pri_ctrl_size)); - pioInterface->addAddrRange(RangeSize(sec_cmd_addr, sec_cmd_size)); - pioInterface->addAddrRange(RangeSize(sec_ctrl_addr, sec_ctrl_size)); - pioInterface->addAddrRange(RangeSize(bmi_addr, bmi_size)); - } -} - -#ifndef DOXYGEN_SHOULD_SKIP_THIS - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeController) - - Param<Addr> addr; - SimObjectVectorParam<IdeDisk *> disks; - SimObjectParam<MemoryController *> mmu; - SimObjectParam<PciConfigAll *> configspace; - SimObjectParam<PciConfigData *> configdata; - SimObjectParam<Platform *> platform; - Param<uint32_t> pci_bus; - Param<uint32_t> pci_dev; - Param<uint32_t> pci_func; - SimObjectParam<Bus *> pio_bus; - SimObjectParam<Bus *> dma_bus; - Param<Tick> pio_latency; - SimObjectParam<HierParams *> hier; - -END_DECLARE_SIM_OBJECT_PARAMS(IdeController) - -BEGIN_INIT_SIM_OBJECT_PARAMS(IdeController) - - INIT_PARAM(addr, "Device Address"), - INIT_PARAM(disks, "IDE disks attached to this controller"), - INIT_PARAM(mmu, "Memory controller"), - INIT_PARAM(configspace, "PCI Configspace"), - INIT_PARAM(configdata, "PCI Config data"), - INIT_PARAM(platform, "Platform pointer"), - INIT_PARAM(pci_bus, "PCI bus ID"), - INIT_PARAM(pci_dev, "PCI device number"), - INIT_PARAM(pci_func, "PCI function code"), - INIT_PARAM(pio_bus, ""), - INIT_PARAM(dma_bus, ""), - INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), - INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams) - -END_INIT_SIM_OBJECT_PARAMS(IdeController) - -CREATE_SIM_OBJECT(IdeController) -{ - IdeController::Params *params = new IdeController::Params; - params->name = getInstanceName(); - params->mmu = mmu; - params->configSpace = configspace; - params->configData = configdata; - params->plat = platform; - params->busNum = pci_bus; - params->deviceNum = pci_dev; - params->functionNum = pci_func; - - params->disks = disks; - params->pio_bus = pio_bus; - params->dma_bus = dma_bus; - params->pio_latency = pio_latency; - params->hier = hier; - return new IdeController(params); -} - -REGISTER_SIM_OBJECT("IdeController", IdeController) - -#endif //DOXYGEN_SHOULD_SKIP_THIS diff --git a/dev/ide_ctrl.hh b/dev/ide_ctrl.hh deleted file mode 100644 index 0fbaf9207..000000000 --- a/dev/ide_ctrl.hh +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Simple PCI IDE controller with bus mastering capability and UDMA - * modeled after controller in the Intel PIIX4 chip - */ - -#ifndef __IDE_CTRL_HH__ -#define __IDE_CTRL_HH__ - -#include "dev/pcidev.hh" -#include "dev/pcireg.h" -#include "dev/io_device.hh" - -#define BMIC0 0x0 // Bus master IDE command register -#define BMIS0 0x2 // Bus master IDE status register -#define BMIDTP0 0x4 // Bus master IDE descriptor table pointer register -#define BMIC1 0x8 // Bus master IDE command register -#define BMIS1 0xa // Bus master IDE status register -#define BMIDTP1 0xc // Bus master IDE descriptor table pointer register - -// Bus master IDE command register bit fields -#define RWCON 0x08 // Bus master read/write control -#define SSBM 0x01 // Start/stop bus master - -// Bus master IDE status register bit fields -#define DMA1CAP 0x40 // Drive 1 DMA capable -#define DMA0CAP 0x20 // Drive 0 DMA capable -#define IDEINTS 0x04 // IDE Interrupt Status -#define IDEDMAE 0x02 // IDE DMA error -#define BMIDEA 0x01 // Bus master IDE active - -// IDE Command byte fields -#define IDE_SELECT_OFFSET (6) -#define IDE_SELECT_DEV_BIT 0x10 - -#define IDE_FEATURE_OFFSET IDE_ERROR_OFFSET -#define IDE_COMMAND_OFFSET IDE_STATUS_OFFSET - -// IDE Timing Register bit fields -#define IDETIM_DECODE_EN 0x8000 - -// PCI device specific register byte offsets -#define IDE_CTRL_CONF_START 0x40 -#define IDE_CTRL_CONF_END ((IDE_CTRL_CONF_START) + sizeof(config_regs)) - - -enum IdeRegType { - COMMAND_BLOCK, - CONTROL_BLOCK, - BMI_BLOCK -}; - -class BaseInterface; -class Bus; -class HierParams; -class IdeDisk; -class IntrControl; -class PciConfigAll; -class PhysicalMemory; -class Platform; - -/** - * Device model for an Intel PIIX4 IDE controller - */ - -class IdeController : public PciDev -{ - friend class IdeDisk; - - enum IdeChannel { - PRIMARY = 0, - SECONDARY = 1 - }; - - private: - /** Primary command block registers */ - Addr pri_cmd_addr; - Addr pri_cmd_size; - /** Primary control block registers */ - Addr pri_ctrl_addr; - Addr pri_ctrl_size; - /** Secondary command block registers */ - Addr sec_cmd_addr; - Addr sec_cmd_size; - /** Secondary control block registers */ - Addr sec_ctrl_addr; - Addr sec_ctrl_size; - /** Bus master interface (BMI) registers */ - Addr bmi_addr; - Addr bmi_size; - - private: - /** Registers used for bus master interface */ - union { - uint8_t data[16]; - - struct { - uint8_t bmic0; - uint8_t reserved_0; - uint8_t bmis0; - uint8_t reserved_1; - uint32_t bmidtp0; - uint8_t bmic1; - uint8_t reserved_2; - uint8_t bmis1; - uint8_t reserved_3; - uint32_t bmidtp1; - }; - - struct { - uint8_t bmic; - uint8_t reserved_4; - uint8_t bmis; - uint8_t reserved_5; - uint32_t bmidtp; - } chan[2]; - - } bmi_regs; - /** Shadows of the device select bit */ - uint8_t dev[2]; - /** Registers used in device specific PCI configuration */ - union { - uint8_t data[22]; - - struct { - uint16_t idetim0; - uint16_t idetim1; - uint8_t sidetim; - uint8_t reserved_0[3]; - uint8_t udmactl; - uint8_t reserved_1; - uint16_t udmatim; - uint8_t reserved_2[8]; - uint16_t ideconfig; - }; - } config_regs; - - // Internal management variables - bool io_enabled; - bool bm_enabled; - bool cmd_in_progress[4]; - - private: - /** IDE disks connected to controller */ - IdeDisk *disks[4]; - - private: - /** Parse the access address to pass on to device */ - void parseAddr(const Addr &addr, Addr &offset, IdeChannel &channel, - IdeRegType ®_type); - - /** Select the disk based on the channel and device bit */ - int getDisk(IdeChannel channel); - - /** Select the disk based on a pointer */ - int getDisk(IdeDisk *diskPtr); - - public: - /** See if a disk is selected based on its pointer */ - bool isDiskSelected(IdeDisk *diskPtr); - - public: - struct Params : public PciDev::Params - { - /** Array of disk objects */ - std::vector<IdeDisk *> disks; - Bus *pio_bus; - Bus *dma_bus; - Tick pio_latency; - HierParams *hier; - }; - const Params *params() const { return (const Params *)_params; } - - public: - IdeController(Params *p); - ~IdeController(); - - virtual void writeConfig(int offset, int size, const uint8_t *data); - virtual void readConfig(int offset, int size, uint8_t *data); - - void setDmaComplete(IdeDisk *disk); - - /** - * Read a done field for a given target. - * @param req Contains the address of the field to read. - * @param data Return the field read. - * @return The fault condition of the access. - */ - virtual Fault read(MemReqPtr &req, uint8_t *data); - - /** - * Write to the mmapped I/O control registers. - * @param req Contains the address to write to. - * @param data The data to write. - * @return The fault condition of the access. - */ - virtual Fault write(MemReqPtr &req, const uint8_t *data); - - /** - * Serialize this object to the given output stream. - * @param os The stream to serialize to. - */ - virtual void serialize(std::ostream &os); - - /** - * Reconstruct the state of this object from a checkpoint. - * @param cp The checkpoint use. - * @param section The section name of this object - */ - virtual void unserialize(Checkpoint *cp, const std::string §ion); - - /** - * Return how long this access will take. - * @param req the memory request to calcuate - * @return Tick when the request is done - */ - Tick cacheAccess(MemReqPtr &req); -}; -#endif // __IDE_CTRL_HH_ diff --git a/dev/ide_disk.cc b/dev/ide_disk.cc deleted file mode 100644 index c13556ed6..000000000 --- a/dev/ide_disk.cc +++ /dev/null @@ -1,1286 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Device model implementation for an IDE disk - */ - -#include <cerrno> -#include <cstring> -#include <deque> -#include <string> - -#include "base/cprintf.hh" // csprintf -#include "base/trace.hh" -#include "dev/disk_image.hh" -#include "dev/ide_disk.hh" -#include "dev/ide_ctrl.hh" -#include "dev/tsunami.hh" -#include "dev/tsunami_pchip.hh" -#include "mem/functional/physical.hh" -#include "mem/bus/bus.hh" -#include "mem/bus/dma_interface.hh" -#include "mem/bus/pio_interface.hh" -#include "mem/bus/pio_interface_impl.hh" -#include "sim/builder.hh" -#include "sim/sim_object.hh" -#include "sim/root.hh" -#include "arch/isa_traits.hh" - -using namespace std; -using namespace TheISA; - -IdeDisk::IdeDisk(const string &name, DiskImage *img, PhysicalMemory *phys, - int id, Tick delay) - : SimObject(name), ctrl(NULL), image(img), physmem(phys), diskDelay(delay), - dmaTransferEvent(this), dmaReadWaitEvent(this), - dmaWriteWaitEvent(this), dmaPrdReadEvent(this), - dmaReadEvent(this), dmaWriteEvent(this) -{ - // Reset the device state - reset(id); - - // fill out the drive ID structure - memset(&driveID, 0, sizeof(struct ataparams)); - - // Calculate LBA and C/H/S values - uint16_t cylinders; - uint8_t heads; - uint8_t sectors; - - uint32_t lba_size = image->size(); - if (lba_size >= 16383*16*63) { - cylinders = 16383; - heads = 16; - sectors = 63; - } else { - if (lba_size >= 63) - sectors = 63; - else - sectors = lba_size; - - if ((lba_size / sectors) >= 16) - heads = 16; - else - heads = (lba_size / sectors); - - cylinders = lba_size / (heads * sectors); - } - - // Setup the model name - strncpy((char *)driveID.atap_model, "5MI EDD si k", - sizeof(driveID.atap_model)); - // Set the maximum multisector transfer size - driveID.atap_multi = MAX_MULTSECT; - // IORDY supported, IORDY disabled, LBA enabled, DMA enabled - driveID.atap_capabilities1 = 0x7; - // UDMA support, EIDE support - driveID.atap_extensions = 0x6; - // Setup default C/H/S settings - driveID.atap_cylinders = cylinders; - driveID.atap_sectors = sectors; - driveID.atap_heads = heads; - // Setup the current multisector transfer size - driveID.atap_curmulti = MAX_MULTSECT; - driveID.atap_curmulti_valid = 0x1; - // Number of sectors on disk - driveID.atap_capacity = lba_size; - // Multiword DMA mode 2 and below supported - driveID.atap_dmamode_supp = 0x400; - // Set PIO mode 4 and 3 supported - driveID.atap_piomode_supp = 0x3; - // Set DMA mode 4 and below supported - driveID.atap_udmamode_supp = 0x1f; - // Statically set hardware config word - driveID.atap_hwreset_res = 0x4001; - - //arbitrary for now... - driveID.atap_ata_major = WDC_VER_ATA7; -} - -IdeDisk::~IdeDisk() -{ - // destroy the data buffer - delete [] dataBuffer; -} - -void -IdeDisk::reset(int id) -{ - // initialize the data buffer and shadow registers - dataBuffer = new uint8_t[MAX_DMA_SIZE]; - - memset(dataBuffer, 0, MAX_DMA_SIZE); - memset(&cmdReg, 0, sizeof(CommandReg_t)); - memset(&curPrd.entry, 0, sizeof(PrdEntry_t)); - - dmaInterfaceBytes = 0; - curPrdAddr = 0; - curSector = 0; - cmdBytes = 0; - cmdBytesLeft = 0; - drqBytesLeft = 0; - dmaRead = false; - intrPending = false; - - // set the device state to idle - dmaState = Dma_Idle; - - if (id == DEV0) { - devState = Device_Idle_S; - devID = DEV0; - } else if (id == DEV1) { - devState = Device_Idle_NS; - devID = DEV1; - } else { - panic("Invalid device ID: %#x\n", id); - } - - // set the device ready bit - status = STATUS_DRDY_BIT; - - /* The error register must be set to 0x1 on start-up to - indicate that no diagnostic error was detected */ - cmdReg.error = 0x1; -} - -//// -// Utility functions -//// - -bool -IdeDisk::isDEVSelect() -{ - return ctrl->isDiskSelected(this); -} - -Addr -IdeDisk::pciToDma(Addr pciAddr) -{ - if (ctrl) - return ctrl->plat->pciToDma(pciAddr); - else - panic("Access to unset controller!\n"); -} - -uint32_t -IdeDisk::bytesInDmaPage(Addr curAddr, uint32_t bytesLeft) -{ - uint32_t bytesInPage = 0; - - // First calculate how many bytes could be in the page - if (bytesLeft > TheISA::PageBytes) - bytesInPage = TheISA::PageBytes; - else - bytesInPage = bytesLeft; - - // Next, see if we have crossed a page boundary, and adjust - Addr upperBound = curAddr + bytesInPage; - Addr pageBound = TheISA::TruncPage(curAddr) + TheISA::PageBytes; - - assert(upperBound >= curAddr && "DMA read wraps around address space!\n"); - - if (upperBound >= pageBound) - bytesInPage = pageBound - curAddr; - - return bytesInPage; -} - -//// -// Device registers read/write -//// - -void -IdeDisk::read(const Addr &offset, IdeRegType reg_type, uint8_t *data) -{ - DevAction_t action = ACT_NONE; - - switch (reg_type) { - case COMMAND_BLOCK: - switch (offset) { - // Data transfers occur two bytes at a time - case DATA_OFFSET: - *(uint16_t*)data = cmdReg.data; - action = ACT_DATA_READ_SHORT; - break; - case ERROR_OFFSET: - *data = cmdReg.error; - break; - case NSECTOR_OFFSET: - *data = cmdReg.sec_count; - break; - case SECTOR_OFFSET: - *data = cmdReg.sec_num; - break; - case LCYL_OFFSET: - *data = cmdReg.cyl_low; - break; - case HCYL_OFFSET: - *data = cmdReg.cyl_high; - break; - case DRIVE_OFFSET: - *data = cmdReg.drive; - break; - case STATUS_OFFSET: - *data = status; - action = ACT_STAT_READ; - break; - default: - panic("Invalid IDE command register offset: %#x\n", offset); - } - break; - case CONTROL_BLOCK: - if (offset == ALTSTAT_OFFSET) - *data = status; - else - panic("Invalid IDE control register offset: %#x\n", offset); - break; - default: - panic("Unknown register block!\n"); - } - - if (action != ACT_NONE) - updateState(action); -} - -void -IdeDisk::write(const Addr &offset, IdeRegType reg_type, const uint8_t *data) -{ - DevAction_t action = ACT_NONE; - - switch (reg_type) { - case COMMAND_BLOCK: - switch (offset) { - case DATA_OFFSET: - cmdReg.data = *(uint16_t*)data; - action = ACT_DATA_WRITE_SHORT; - break; - case FEATURES_OFFSET: - break; - case NSECTOR_OFFSET: - cmdReg.sec_count = *data; - break; - case SECTOR_OFFSET: - cmdReg.sec_num = *data; - break; - case LCYL_OFFSET: - cmdReg.cyl_low = *data; - break; - case HCYL_OFFSET: - cmdReg.cyl_high = *data; - break; - case DRIVE_OFFSET: - cmdReg.drive = *data; - action = ACT_SELECT_WRITE; - break; - case COMMAND_OFFSET: - cmdReg.command = *data; - action = ACT_CMD_WRITE; - break; - default: - panic("Invalid IDE command register offset: %#x\n", offset); - } - break; - case CONTROL_BLOCK: - if (offset == CONTROL_OFFSET) { - if (*data & CONTROL_RST_BIT) { - // force the device into the reset state - devState = Device_Srst; - action = ACT_SRST_SET; - } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT)) - action = ACT_SRST_CLEAR; - - nIENBit = (*data & CONTROL_IEN_BIT) ? true : false; - } - else - panic("Invalid IDE control register offset: %#x\n", offset); - break; - default: - panic("Unknown register block!\n"); - } - - if (action != ACT_NONE) - updateState(action); -} - -//// -// Perform DMA transactions -//// - -void -IdeDisk::doDmaTransfer() -{ - if (dmaState != Dma_Transfer || devState != Transfer_Data_Dma) - panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n", - dmaState, devState); - - // first read the current PRD - if (dmaInterface) { - if (dmaInterface->busy()) { - // reschedule after waiting period - dmaTransferEvent.schedule(curTick + DMA_BACKOFF_PERIOD); - return; - } - - dmaInterface->doDMA(Read, curPrdAddr, sizeof(PrdEntry_t), curTick, - &dmaPrdReadEvent); - } else { - dmaPrdReadDone(); - } -} - -void -IdeDisk::dmaPrdReadDone() -{ - // actually copy the PRD from physical memory - memcpy((void *)&curPrd.entry, - physmem->dma_addr(curPrdAddr, sizeof(PrdEntry_t)), - sizeof(PrdEntry_t)); - - DPRINTF(IdeDisk, - "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n", - curPrd.getBaseAddr(), pciToDma(curPrd.getBaseAddr()), - curPrd.getByteCount(), (cmdBytesLeft/SectorSize), - curPrd.getEOT(), curSector); - - // the prd pointer has already been translated, so just do an increment - curPrdAddr = curPrdAddr + sizeof(PrdEntry_t); - - if (dmaRead) - doDmaRead(); - else - doDmaWrite(); -} - -void -IdeDisk::regStats() -{ - using namespace Stats; - dmaReadFullPages - .name(name() + ".dma_read_full_pages") - .desc("Number of full page size DMA reads (not PRD).") - ; - dmaReadBytes - .name(name() + ".dma_read_bytes") - .desc("Number of bytes transfered via DMA reads (not PRD).") - ; - dmaReadTxs - .name(name() + ".dma_read_txs") - .desc("Number of DMA read transactions (not PRD).") - ; - - dmaWriteFullPages - .name(name() + ".dma_write_full_pages") - .desc("Number of full page size DMA writes.") - ; - dmaWriteBytes - .name(name() + ".dma_write_bytes") - .desc("Number of bytes transfered via DMA writes.") - ; - dmaWriteTxs - .name(name() + ".dma_write_txs") - .desc("Number of DMA write transactions.") - ; -} - -void -IdeDisk::doDmaRead() -{ - /** @todo we need to figure out what the delay actually will be */ - Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize); - - DPRINTF(IdeDisk, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n", - diskDelay, totalDiskDelay); - if (dmaInterface) { - if (dmaInterface->busy()) { - // reschedule after waiting period - dmaReadWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD); - return; - } - - Addr dmaAddr = pciToDma(curPrd.getBaseAddr()); - - uint32_t bytesInPage = bytesInDmaPage(curPrd.getBaseAddr(), - (uint32_t)curPrd.getByteCount()); - - dmaInterfaceBytes = bytesInPage; - - if (bytesInPage == TheISA::VMPageSize) - dmaReadFullPages++; - dmaReadBytes += bytesInPage; - dmaReadTxs++; - dmaInterface->doDMA(Read, dmaAddr, bytesInPage, - curTick + totalDiskDelay, &dmaReadEvent); - } else { - // schedule dmaReadEvent with sectorDelay (dmaReadDone) - dmaReadEvent.schedule(curTick + totalDiskDelay); - } -} - -void -IdeDisk::dmaReadDone() -{ - - Addr curAddr = 0, dmaAddr = 0; - uint32_t bytesWritten = 0, bytesInPage = 0, bytesLeft = 0; - - // continue to use the DMA interface until all pages are read - if (dmaInterface && (dmaInterfaceBytes < curPrd.getByteCount())) { - // see if the interface is busy - if (dmaInterface->busy()) { - // reschedule after waiting period - dmaReadEvent.schedule(curTick + DMA_BACKOFF_PERIOD); - return; - } - - uint32_t bytesLeft = curPrd.getByteCount() - dmaInterfaceBytes; - curAddr = curPrd.getBaseAddr() + dmaInterfaceBytes; - dmaAddr = pciToDma(curAddr); - - bytesInPage = bytesInDmaPage(curAddr, bytesLeft); - dmaInterfaceBytes += bytesInPage; - - if (bytesInPage == TheISA::VMPageSize) - dmaReadFullPages++; - dmaReadBytes += bytesInPage; - dmaReadTxs++; - - dmaInterface->doDMA(Read, dmaAddr, bytesInPage, - curTick, &dmaReadEvent); - - return; - } - - // set initial address - curAddr = curPrd.getBaseAddr(); - - // clear out the data buffer - memset(dataBuffer, 0, MAX_DMA_SIZE); - - // read the data from memory via DMA into a data buffer - while (bytesWritten < curPrd.getByteCount()) { - if (cmdBytesLeft <= 0) - panic("DMA data is larger than # of sectors specified\n"); - - dmaAddr = pciToDma(curAddr); - - // calculate how many bytes are in the current page - bytesLeft = curPrd.getByteCount() - bytesWritten; - bytesInPage = bytesInDmaPage(curAddr, bytesLeft); - - // copy the data from memory into the data buffer - memcpy((void *)(dataBuffer + bytesWritten), - physmem->dma_addr(dmaAddr, bytesInPage), - bytesInPage); - - curAddr += bytesInPage; - bytesWritten += bytesInPage; - cmdBytesLeft -= bytesInPage; - } - - // write the data to the disk image - for (bytesWritten = 0; - bytesWritten < curPrd.getByteCount(); - bytesWritten += SectorSize) { - - writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten)); - } - - // check for the EOT - if (curPrd.getEOT()) { - assert(cmdBytesLeft == 0); - dmaState = Dma_Idle; - updateState(ACT_DMA_DONE); - } else { - doDmaTransfer(); - } -} - -void -IdeDisk::doDmaWrite() -{ - /** @todo we need to figure out what the delay actually will be */ - Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize); - - DPRINTF(IdeDisk, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n", - diskDelay, totalDiskDelay); - - if (dmaInterface) { - if (dmaInterface->busy()) { - // reschedule after waiting period - dmaWriteWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD); - return; - } - - Addr dmaAddr = pciToDma(curPrd.getBaseAddr()); - - uint32_t bytesInPage = bytesInDmaPage(curPrd.getBaseAddr(), - (uint32_t)curPrd.getByteCount()); - - dmaInterfaceBytes = bytesInPage; - - if (bytesInPage == TheISA::VMPageSize) - dmaWriteFullPages++; - dmaWriteBytes += bytesInPage; - dmaWriteTxs++; - - dmaInterface->doDMA(WriteInvalidate, dmaAddr, - bytesInPage, curTick + totalDiskDelay, - &dmaWriteEvent); - } else { - // schedule event with disk delay (dmaWriteDone) - dmaWriteEvent.schedule(curTick + totalDiskDelay); - } -} - -void -IdeDisk::dmaWriteDone() -{ - Addr curAddr = 0, pageAddr = 0, dmaAddr = 0; - uint32_t bytesRead = 0, bytesInPage = 0; - - // continue to use the DMA interface until all pages are read - if (dmaInterface && (dmaInterfaceBytes < curPrd.getByteCount())) { - // see if the interface is busy - if (dmaInterface->busy()) { - // reschedule after waiting period - dmaWriteEvent.schedule(curTick + DMA_BACKOFF_PERIOD); - return; - } - - uint32_t bytesLeft = curPrd.getByteCount() - dmaInterfaceBytes; - curAddr = curPrd.getBaseAddr() + dmaInterfaceBytes; - dmaAddr = pciToDma(curAddr); - - bytesInPage = bytesInDmaPage(curAddr, bytesLeft); - dmaInterfaceBytes += bytesInPage; - - if (bytesInPage == TheISA::VMPageSize) - dmaWriteFullPages++; - dmaWriteBytes += bytesInPage; - dmaWriteTxs++; - - dmaInterface->doDMA(WriteInvalidate, dmaAddr, - bytesInPage, curTick, - &dmaWriteEvent); - - return; - } - - // setup the initial page and DMA address - curAddr = curPrd.getBaseAddr(); - pageAddr = TheISA::TruncPage(curAddr); - dmaAddr = pciToDma(curAddr); - - // clear out the data buffer - memset(dataBuffer, 0, MAX_DMA_SIZE); - - while (bytesRead < curPrd.getByteCount()) { - // see if we have crossed into a new page - if (pageAddr != TheISA::TruncPage(curAddr)) { - // write the data to memory - memcpy(physmem->dma_addr(dmaAddr, bytesInPage), - (void *)(dataBuffer + (bytesRead - bytesInPage)), - bytesInPage); - - // update the DMA address and page address - pageAddr = TheISA::TruncPage(curAddr); - dmaAddr = pciToDma(curAddr); - - bytesInPage = 0; - } - - if (cmdBytesLeft <= 0) - panic("DMA requested data is larger than # sectors specified\n"); - - readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead)); - - curAddr += SectorSize; - bytesRead += SectorSize; - bytesInPage += SectorSize; - cmdBytesLeft -= SectorSize; - } - - // write the last page worth read to memory - if (bytesInPage != 0) { - memcpy(physmem->dma_addr(dmaAddr, bytesInPage), - (void *)(dataBuffer + (bytesRead - bytesInPage)), - bytesInPage); - } - - // check for the EOT - if (curPrd.getEOT()) { - assert(cmdBytesLeft == 0); - dmaState = Dma_Idle; - updateState(ACT_DMA_DONE); - } else { - doDmaTransfer(); - } -} - -//// -// Disk utility routines -/// - -void -IdeDisk::readDisk(uint32_t sector, uint8_t *data) -{ - uint32_t bytesRead = image->read(data, sector); - - if (bytesRead != SectorSize) - panic("Can't read from %s. Only %d of %d read. errno=%d\n", - name(), bytesRead, SectorSize, errno); -} - -void -IdeDisk::writeDisk(uint32_t sector, uint8_t *data) -{ - uint32_t bytesWritten = image->write(data, sector); - - if (bytesWritten != SectorSize) - panic("Can't write to %s. Only %d of %d written. errno=%d\n", - name(), bytesWritten, SectorSize, errno); -} - -//// -// Setup and handle commands -//// - -void -IdeDisk::startDma(const uint32_t &prdTableBase) -{ - if (dmaState != Dma_Start) - panic("Inconsistent DMA state, should be in Dma_Start!\n"); - - if (devState != Transfer_Data_Dma) - panic("Inconsistent device state for DMA start!\n"); - - // PRD base address is given by bits 31:2 - curPrdAddr = pciToDma((Addr)(prdTableBase & ~ULL(0x3))); - - dmaState = Dma_Transfer; - - // schedule dma transfer (doDmaTransfer) - dmaTransferEvent.schedule(curTick + 1); -} - -void -IdeDisk::abortDma() -{ - if (dmaState == Dma_Idle) - panic("Inconsistent DMA state, should be Start or Transfer!"); - - if (devState != Transfer_Data_Dma && devState != Prepare_Data_Dma) - panic("Inconsistent device state, should be Transfer or Prepare!\n"); - - updateState(ACT_CMD_ERROR); -} - -void -IdeDisk::startCommand() -{ - DevAction_t action = ACT_NONE; - uint32_t size = 0; - dmaRead = false; - - // Decode commands - switch (cmdReg.command) { - // Supported non-data commands - case WDSF_READ_NATIVE_MAX: - size = image->size() - 1; - cmdReg.sec_num = (size & 0xff); - cmdReg.cyl_low = ((size & 0xff00) >> 8); - cmdReg.cyl_high = ((size & 0xff0000) >> 16); - cmdReg.head = ((size & 0xf000000) >> 24); - - devState = Command_Execution; - action = ACT_CMD_COMPLETE; - break; - - case WDCC_RECAL: - case WDCC_IDP: - case WDCC_STANDBY_IMMED: - case WDCC_FLUSHCACHE: - case WDSF_VERIFY: - case WDSF_SEEK: - case SET_FEATURES: - case WDCC_SETMULTI: - devState = Command_Execution; - action = ACT_CMD_COMPLETE; - break; - - // Supported PIO data-in commands - case WDCC_IDENTIFY: - cmdBytes = cmdBytesLeft = sizeof(struct ataparams); - devState = Prepare_Data_In; - action = ACT_DATA_READY; - break; - - case WDCC_READMULTI: - case WDCC_READ: - if (!(cmdReg.drive & DRIVE_LBA_BIT)) - panic("Attempt to perform CHS access, only supports LBA\n"); - - if (cmdReg.sec_count == 0) - cmdBytes = cmdBytesLeft = (256 * SectorSize); - else - cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); - - curSector = getLBABase(); - - /** @todo make this a scheduled event to simulate disk delay */ - devState = Prepare_Data_In; - action = ACT_DATA_READY; - break; - - // Supported PIO data-out commands - case WDCC_WRITEMULTI: - case WDCC_WRITE: - if (!(cmdReg.drive & DRIVE_LBA_BIT)) - panic("Attempt to perform CHS access, only supports LBA\n"); - - if (cmdReg.sec_count == 0) - cmdBytes = cmdBytesLeft = (256 * SectorSize); - else - cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); - - curSector = getLBABase(); - - devState = Prepare_Data_Out; - action = ACT_DATA_READY; - break; - - // Supported DMA commands - case WDCC_WRITEDMA: - dmaRead = true; // a write to the disk is a DMA read from memory - case WDCC_READDMA: - if (!(cmdReg.drive & DRIVE_LBA_BIT)) - panic("Attempt to perform CHS access, only supports LBA\n"); - - if (cmdReg.sec_count == 0) - cmdBytes = cmdBytesLeft = (256 * SectorSize); - else - cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); - - curSector = getLBABase(); - - devState = Prepare_Data_Dma; - action = ACT_DMA_READY; - break; - - default: - panic("Unsupported ATA command: %#x\n", cmdReg.command); - } - - if (action != ACT_NONE) { - // set the BSY bit - status |= STATUS_BSY_BIT; - // clear the DRQ bit - status &= ~STATUS_DRQ_BIT; - // clear the DF bit - status &= ~STATUS_DF_BIT; - - updateState(action); - } -} - -//// -// Handle setting and clearing interrupts -//// - -void -IdeDisk::intrPost() -{ - DPRINTF(IdeDisk, "Posting Interrupt\n"); - if (intrPending) - panic("Attempt to post an interrupt with one pending\n"); - - intrPending = true; - - // talk to controller to set interrupt - if (ctrl) { - ctrl->bmi_regs.bmis0 |= IDEINTS; - ctrl->intrPost(); - } -} - -void -IdeDisk::intrClear() -{ - DPRINTF(IdeDisk, "Clearing Interrupt\n"); - if (!intrPending) - panic("Attempt to clear a non-pending interrupt\n"); - - intrPending = false; - - // talk to controller to clear interrupt - if (ctrl) - ctrl->intrClear(); -} - -//// -// Manage the device internal state machine -//// - -void -IdeDisk::updateState(DevAction_t action) -{ - switch (devState) { - case Device_Srst: - if (action == ACT_SRST_SET) { - // set the BSY bit - status |= STATUS_BSY_BIT; - } else if (action == ACT_SRST_CLEAR) { - // clear the BSY bit - status &= ~STATUS_BSY_BIT; - - // reset the device state - reset(devID); - } - break; - - case Device_Idle_S: - if (action == ACT_SELECT_WRITE && !isDEVSelect()) { - devState = Device_Idle_NS; - } else if (action == ACT_CMD_WRITE) { - startCommand(); - } - - break; - - case Device_Idle_SI: - if (action == ACT_SELECT_WRITE && !isDEVSelect()) { - devState = Device_Idle_NS; - intrClear(); - } else if (action == ACT_STAT_READ || isIENSet()) { - devState = Device_Idle_S; - intrClear(); - } else if (action == ACT_CMD_WRITE) { - intrClear(); - startCommand(); - } - - break; - - case Device_Idle_NS: - if (action == ACT_SELECT_WRITE && isDEVSelect()) { - if (!isIENSet() && intrPending) { - devState = Device_Idle_SI; - intrPost(); - } - if (isIENSet() || !intrPending) { - devState = Device_Idle_S; - } - } - break; - - case Command_Execution: - if (action == ACT_CMD_COMPLETE) { - // clear the BSY bit - setComplete(); - - if (!isIENSet()) { - devState = Device_Idle_SI; - intrPost(); - } else { - devState = Device_Idle_S; - } - } - break; - - case Prepare_Data_In: - if (action == ACT_CMD_ERROR) { - // clear the BSY bit - setComplete(); - - if (!isIENSet()) { - devState = Device_Idle_SI; - intrPost(); - } else { - devState = Device_Idle_S; - } - } else if (action == ACT_DATA_READY) { - // clear the BSY bit - status &= ~STATUS_BSY_BIT; - // set the DRQ bit - status |= STATUS_DRQ_BIT; - - // copy the data into the data buffer - if (cmdReg.command == WDCC_IDENTIFY) { - // Reset the drqBytes for this block - drqBytesLeft = sizeof(struct ataparams); - - memcpy((void *)dataBuffer, (void *)&driveID, - sizeof(struct ataparams)); - } else { - // Reset the drqBytes for this block - drqBytesLeft = SectorSize; - - readDisk(curSector++, dataBuffer); - } - - // put the first two bytes into the data register - memcpy((void *)&cmdReg.data, (void *)dataBuffer, - sizeof(uint16_t)); - - if (!isIENSet()) { - devState = Data_Ready_INTRQ_In; - intrPost(); - } else { - devState = Transfer_Data_In; - } - } - break; - - case Data_Ready_INTRQ_In: - if (action == ACT_STAT_READ) { - devState = Transfer_Data_In; - intrClear(); - } - break; - - case Transfer_Data_In: - if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) { - if (action == ACT_DATA_READ_BYTE) { - panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n"); - } else { - drqBytesLeft -= 2; - cmdBytesLeft -= 2; - - // copy next short into data registers - if (drqBytesLeft) - memcpy((void *)&cmdReg.data, - (void *)&dataBuffer[SectorSize - drqBytesLeft], - sizeof(uint16_t)); - } - - if (drqBytesLeft == 0) { - if (cmdBytesLeft == 0) { - // Clear the BSY bit - setComplete(); - devState = Device_Idle_S; - } else { - devState = Prepare_Data_In; - // set the BSY_BIT - status |= STATUS_BSY_BIT; - // clear the DRQ_BIT - status &= ~STATUS_DRQ_BIT; - - /** @todo change this to a scheduled event to simulate - disk delay */ - updateState(ACT_DATA_READY); - } - } - } - break; - - case Prepare_Data_Out: - if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) { - // clear the BSY bit - setComplete(); - - if (!isIENSet()) { - devState = Device_Idle_SI; - intrPost(); - } else { - devState = Device_Idle_S; - } - } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) { - // clear the BSY bit - status &= ~STATUS_BSY_BIT; - // set the DRQ bit - status |= STATUS_DRQ_BIT; - - // clear the data buffer to get it ready for writes - memset(dataBuffer, 0, MAX_DMA_SIZE); - - // reset the drqBytes for this block - drqBytesLeft = SectorSize; - - if (cmdBytesLeft == cmdBytes || isIENSet()) { - devState = Transfer_Data_Out; - } else { - devState = Data_Ready_INTRQ_Out; - intrPost(); - } - } - break; - - case Data_Ready_INTRQ_Out: - if (action == ACT_STAT_READ) { - devState = Transfer_Data_Out; - intrClear(); - } - break; - - case Transfer_Data_Out: - if (action == ACT_DATA_WRITE_BYTE || - action == ACT_DATA_WRITE_SHORT) { - - if (action == ACT_DATA_READ_BYTE) { - panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n"); - } else { - // copy the latest short into the data buffer - memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft], - (void *)&cmdReg.data, - sizeof(uint16_t)); - - drqBytesLeft -= 2; - cmdBytesLeft -= 2; - } - - if (drqBytesLeft == 0) { - // copy the block to the disk - writeDisk(curSector++, dataBuffer); - - // set the BSY bit - status |= STATUS_BSY_BIT; - // set the seek bit - status |= STATUS_SEEK_BIT; - // clear the DRQ bit - status &= ~STATUS_DRQ_BIT; - - devState = Prepare_Data_Out; - - /** @todo change this to a scheduled event to simulate - disk delay */ - updateState(ACT_DATA_READY); - } - } - break; - - case Prepare_Data_Dma: - if (action == ACT_CMD_ERROR) { - // clear the BSY bit - setComplete(); - - if (!isIENSet()) { - devState = Device_Idle_SI; - intrPost(); - } else { - devState = Device_Idle_S; - } - } else if (action == ACT_DMA_READY) { - // clear the BSY bit - status &= ~STATUS_BSY_BIT; - // set the DRQ bit - status |= STATUS_DRQ_BIT; - - devState = Transfer_Data_Dma; - - if (dmaState != Dma_Idle) - panic("Inconsistent DMA state, should be Dma_Idle\n"); - - dmaState = Dma_Start; - // wait for the write to the DMA start bit - } - break; - - case Transfer_Data_Dma: - if (action == ACT_CMD_ERROR || action == ACT_DMA_DONE) { - // clear the BSY bit - setComplete(); - // set the seek bit - status |= STATUS_SEEK_BIT; - // clear the controller state for DMA transfer - ctrl->setDmaComplete(this); - - if (!isIENSet()) { - devState = Device_Idle_SI; - intrPost(); - } else { - devState = Device_Idle_S; - } - } - break; - - default: - panic("Unknown IDE device state: %#x\n", devState); - } -} - -void -IdeDisk::serialize(ostream &os) -{ - // Check all outstanding events to see if they are scheduled - // these are all mutually exclusive - Tick reschedule = 0; - Events_t event = None; - - int eventCount = 0; - - if (dmaTransferEvent.scheduled()) { - reschedule = dmaTransferEvent.when(); - event = Transfer; - eventCount++; - } - if (dmaReadWaitEvent.scheduled()) { - reschedule = dmaReadWaitEvent.when(); - event = ReadWait; - eventCount++; - } - if (dmaWriteWaitEvent.scheduled()) { - reschedule = dmaWriteWaitEvent.when(); - event = WriteWait; - eventCount++; - } - if (dmaPrdReadEvent.scheduled()) { - reschedule = dmaPrdReadEvent.when(); - event = PrdRead; - eventCount++; - } - if (dmaReadEvent.scheduled()) { - reschedule = dmaReadEvent.when(); - event = DmaRead; - eventCount++; - } - if (dmaWriteEvent.scheduled()) { - reschedule = dmaWriteEvent.when(); - event = DmaWrite; - eventCount++; - } - - assert(eventCount <= 1); - - SERIALIZE_SCALAR(reschedule); - SERIALIZE_ENUM(event); - - // Serialize device registers - SERIALIZE_SCALAR(cmdReg.data); - SERIALIZE_SCALAR(cmdReg.sec_count); - SERIALIZE_SCALAR(cmdReg.sec_num); - SERIALIZE_SCALAR(cmdReg.cyl_low); - SERIALIZE_SCALAR(cmdReg.cyl_high); - SERIALIZE_SCALAR(cmdReg.drive); - SERIALIZE_SCALAR(cmdReg.command); - SERIALIZE_SCALAR(status); - SERIALIZE_SCALAR(nIENBit); - SERIALIZE_SCALAR(devID); - - // Serialize the PRD related information - SERIALIZE_SCALAR(curPrd.entry.baseAddr); - SERIALIZE_SCALAR(curPrd.entry.byteCount); - SERIALIZE_SCALAR(curPrd.entry.endOfTable); - SERIALIZE_SCALAR(curPrdAddr); - - // Serialize current transfer related information - SERIALIZE_SCALAR(cmdBytesLeft); - SERIALIZE_SCALAR(cmdBytes); - SERIALIZE_SCALAR(drqBytesLeft); - SERIALIZE_SCALAR(curSector); - SERIALIZE_SCALAR(dmaRead); - SERIALIZE_SCALAR(dmaInterfaceBytes); - SERIALIZE_SCALAR(intrPending); - SERIALIZE_ENUM(devState); - SERIALIZE_ENUM(dmaState); - SERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE); -} - -void -IdeDisk::unserialize(Checkpoint *cp, const string §ion) -{ - // Reschedule events that were outstanding - // these are all mutually exclusive - Tick reschedule = 0; - Events_t event = None; - - UNSERIALIZE_SCALAR(reschedule); - UNSERIALIZE_ENUM(event); - - switch (event) { - case None : break; - case Transfer : dmaTransferEvent.schedule(reschedule); break; - case ReadWait : dmaReadWaitEvent.schedule(reschedule); break; - case WriteWait : dmaWriteWaitEvent.schedule(reschedule); break; - case PrdRead : dmaPrdReadEvent.schedule(reschedule); break; - case DmaRead : dmaReadEvent.schedule(reschedule); break; - case DmaWrite : dmaWriteEvent.schedule(reschedule); break; - } - - // Unserialize device registers - UNSERIALIZE_SCALAR(cmdReg.data); - UNSERIALIZE_SCALAR(cmdReg.sec_count); - UNSERIALIZE_SCALAR(cmdReg.sec_num); - UNSERIALIZE_SCALAR(cmdReg.cyl_low); - UNSERIALIZE_SCALAR(cmdReg.cyl_high); - UNSERIALIZE_SCALAR(cmdReg.drive); - UNSERIALIZE_SCALAR(cmdReg.command); - UNSERIALIZE_SCALAR(status); - UNSERIALIZE_SCALAR(nIENBit); - UNSERIALIZE_SCALAR(devID); - - // Unserialize the PRD related information - UNSERIALIZE_SCALAR(curPrd.entry.baseAddr); - UNSERIALIZE_SCALAR(curPrd.entry.byteCount); - UNSERIALIZE_SCALAR(curPrd.entry.endOfTable); - UNSERIALIZE_SCALAR(curPrdAddr); - - // Unserialize current transfer related information - UNSERIALIZE_SCALAR(cmdBytes); - UNSERIALIZE_SCALAR(cmdBytesLeft); - UNSERIALIZE_SCALAR(drqBytesLeft); - UNSERIALIZE_SCALAR(curSector); - UNSERIALIZE_SCALAR(dmaRead); - UNSERIALIZE_SCALAR(dmaInterfaceBytes); - UNSERIALIZE_SCALAR(intrPending); - UNSERIALIZE_ENUM(devState); - UNSERIALIZE_ENUM(dmaState); - UNSERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE); -} - -#ifndef DOXYGEN_SHOULD_SKIP_THIS - -enum DriveID { master, slave }; -static const char *DriveID_strings[] = { "master", "slave" }; -BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeDisk) - - SimObjectParam<DiskImage *> image; - SimObjectParam<PhysicalMemory *> physmem; - SimpleEnumParam<DriveID> driveID; - Param<int> delay; - -END_DECLARE_SIM_OBJECT_PARAMS(IdeDisk) - -BEGIN_INIT_SIM_OBJECT_PARAMS(IdeDisk) - - INIT_PARAM(image, "Disk image"), - INIT_PARAM(physmem, "Physical memory"), - INIT_ENUM_PARAM(driveID, "Drive ID (0=master 1=slave)", DriveID_strings), - INIT_PARAM_DFLT(delay, "Fixed disk delay in microseconds", 1) - -END_INIT_SIM_OBJECT_PARAMS(IdeDisk) - - -CREATE_SIM_OBJECT(IdeDisk) -{ - return new IdeDisk(getInstanceName(), image, physmem, driveID, delay); -} - -REGISTER_SIM_OBJECT("IdeDisk", IdeDisk) - -#endif //DOXYGEN_SHOULD_SKIP_THIS diff --git a/dev/ide_disk.hh b/dev/ide_disk.hh deleted file mode 100644 index 402ae44ee..000000000 --- a/dev/ide_disk.hh +++ /dev/null @@ -1,373 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Device model for an IDE disk - */ - -#ifndef __IDE_DISK_HH__ -#define __IDE_DISK_HH__ - -#include "base/statistics.hh" -#include "dev/disk_image.hh" -#include "dev/ide_atareg.h" -#include "dev/ide_ctrl.hh" -#include "dev/ide_wdcreg.h" -#include "dev/io_device.hh" -#include "sim/eventq.hh" - -#define DMA_BACKOFF_PERIOD 200 - -#define MAX_DMA_SIZE (131072) // 128K -#define MAX_MULTSECT (128) - -#define PRD_BASE_MASK 0xfffffffe -#define PRD_COUNT_MASK 0xfffe -#define PRD_EOT_MASK 0x8000 - -typedef struct PrdEntry { - uint32_t baseAddr; - uint16_t byteCount; - uint16_t endOfTable; -} PrdEntry_t; - -class PrdTableEntry { - public: - PrdEntry_t entry; - - uint32_t getBaseAddr() - { - return (entry.baseAddr & PRD_BASE_MASK); - } - - uint32_t getByteCount() - { - return ((entry.byteCount == 0) ? MAX_DMA_SIZE : - (entry.byteCount & PRD_COUNT_MASK)); - } - - uint16_t getEOT() - { - return (entry.endOfTable & PRD_EOT_MASK); - } -}; - -#define DATA_OFFSET (0) -#define ERROR_OFFSET (1) -#define FEATURES_OFFSET (1) -#define NSECTOR_OFFSET (2) -#define SECTOR_OFFSET (3) -#define LCYL_OFFSET (4) -#define HCYL_OFFSET (5) -#define SELECT_OFFSET (6) -#define DRIVE_OFFSET (6) -#define STATUS_OFFSET (7) -#define COMMAND_OFFSET (7) - -#define CONTROL_OFFSET (2) -#define ALTSTAT_OFFSET (2) - -#define SELECT_DEV_BIT 0x10 -#define CONTROL_RST_BIT 0x04 -#define CONTROL_IEN_BIT 0x02 -#define STATUS_BSY_BIT 0x80 -#define STATUS_DRDY_BIT 0x40 -#define STATUS_DRQ_BIT 0x08 -#define STATUS_SEEK_BIT 0x10 -#define STATUS_DF_BIT 0x20 -#define DRIVE_LBA_BIT 0x40 - -#define DEV0 (0) -#define DEV1 (1) - -typedef struct CommandReg { - uint16_t data; - uint8_t error; - uint8_t sec_count; - uint8_t sec_num; - uint8_t cyl_low; - uint8_t cyl_high; - union { - uint8_t drive; - uint8_t head; - }; - uint8_t command; -} CommandReg_t; - -typedef enum Events { - None = 0, - Transfer, - ReadWait, - WriteWait, - PrdRead, - DmaRead, - DmaWrite -} Events_t; - -typedef enum DevAction { - ACT_NONE = 0, - ACT_CMD_WRITE, - ACT_CMD_COMPLETE, - ACT_CMD_ERROR, - ACT_SELECT_WRITE, - ACT_STAT_READ, - ACT_DATA_READY, - ACT_DATA_READ_BYTE, - ACT_DATA_READ_SHORT, - ACT_DATA_WRITE_BYTE, - ACT_DATA_WRITE_SHORT, - ACT_DMA_READY, - ACT_DMA_DONE, - ACT_SRST_SET, - ACT_SRST_CLEAR -} DevAction_t; - -typedef enum DevState { - // Device idle - Device_Idle_S = 0, - Device_Idle_SI, - Device_Idle_NS, - - // Software reset - Device_Srst, - - // Non-data commands - Command_Execution, - - // PIO data-in (data to host) - Prepare_Data_In, - Data_Ready_INTRQ_In, - Transfer_Data_In, - - // PIO data-out (data from host) - Prepare_Data_Out, - Data_Ready_INTRQ_Out, - Transfer_Data_Out, - - // DMA protocol - Prepare_Data_Dma, - Transfer_Data_Dma -} DevState_t; - -typedef enum DmaState { - Dma_Idle = 0, - Dma_Start, - Dma_Transfer -} DmaState_t; - -class PhysicalMemory; -class IdeController; - -/** - * IDE Disk device model - */ -class IdeDisk : public SimObject -{ - protected: - /** The IDE controller for this disk. */ - IdeController *ctrl; - /** The DMA interface to use for transfers */ - DMAInterface<Bus> *dmaInterface; - /** The image that contains the data of this disk. */ - DiskImage *image; - /** Pointer to physical memory for DMA transfers */ - PhysicalMemory *physmem; - - protected: - /** The disk delay in microseconds. */ - int diskDelay; - - private: - /** Drive identification structure for this disk */ - struct ataparams driveID; - /** Data buffer for transfers */ - uint8_t *dataBuffer; - /** Number of bytes in command data transfer */ - uint32_t cmdBytes; - /** Number of bytes left in command data transfer */ - uint32_t cmdBytesLeft; - /** Number of bytes left in DRQ block */ - uint32_t drqBytesLeft; - /** Current sector in access */ - uint32_t curSector; - /** Command block registers */ - CommandReg_t cmdReg; - /** Status register */ - uint8_t status; - /** Interrupt enable bit */ - bool nIENBit; - /** Device state */ - DevState_t devState; - /** Dma state */ - DmaState_t dmaState; - /** Dma transaction is a read */ - bool dmaRead; - /** PRD table base address */ - uint32_t curPrdAddr; - /** PRD entry */ - PrdTableEntry curPrd; - /** Number of bytes transfered by DMA interface for current transfer */ - uint32_t dmaInterfaceBytes; - /** Device ID (master=0/slave=1) */ - int devID; - /** Interrupt pending */ - bool intrPending; - - Stats::Scalar<> dmaReadFullPages; - Stats::Scalar<> dmaReadBytes; - Stats::Scalar<> dmaReadTxs; - Stats::Scalar<> dmaWriteFullPages; - Stats::Scalar<> dmaWriteBytes; - Stats::Scalar<> dmaWriteTxs; - - public: - /** - * Create and initialize this Disk. - * @param name The name of this disk. - * @param img The disk image of this disk. - * @param phys Pointer to physical memory - * @param id The disk ID (master=0/slave=1) - * @param disk_delay The disk delay in milliseconds - */ - IdeDisk(const std::string &name, DiskImage *img, PhysicalMemory *phys, - int id, Tick disk_delay); - - /** - * Delete the data buffer. - */ - ~IdeDisk(); - - /** - * Reset the device state - */ - void reset(int id); - - /** - * Register statistics. - */ - void regStats(); - - - /** - * Set the controller for this device - * @param c The IDE controller - */ - void setController(IdeController *c, DMAInterface<Bus> *dmaIntr) { - if (ctrl) panic("Cannot change the controller once set!\n"); - ctrl = c; - dmaInterface = dmaIntr; - } - - // Device register read/write - void read(const Addr &offset, IdeRegType regtype, uint8_t *data); - void write(const Addr &offset, IdeRegType regtype, const uint8_t *data); - - // Start/abort functions - void startDma(const uint32_t &prdTableBase); - void abortDma(); - - private: - void startCommand(); - - // Interrupt management - void intrPost(); - void intrClear(); - - // DMA stuff - void doDmaTransfer(); - friend class EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer>; - EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer> dmaTransferEvent; - - void doDmaRead(); - friend class EventWrapper<IdeDisk, &IdeDisk::doDmaRead>; - EventWrapper<IdeDisk, &IdeDisk::doDmaRead> dmaReadWaitEvent; - - void doDmaWrite(); - friend class EventWrapper<IdeDisk, &IdeDisk::doDmaWrite>; - EventWrapper<IdeDisk, &IdeDisk::doDmaWrite> dmaWriteWaitEvent; - - void dmaPrdReadDone(); - friend class EventWrapper<IdeDisk, &IdeDisk::dmaPrdReadDone>; - EventWrapper<IdeDisk, &IdeDisk::dmaPrdReadDone> dmaPrdReadEvent; - - void dmaReadDone(); - friend class EventWrapper<IdeDisk, &IdeDisk::dmaReadDone>; - EventWrapper<IdeDisk, &IdeDisk::dmaReadDone> dmaReadEvent; - - void dmaWriteDone(); - friend class EventWrapper<IdeDisk, &IdeDisk::dmaWriteDone>; - EventWrapper<IdeDisk, &IdeDisk::dmaWriteDone> dmaWriteEvent; - - // Disk image read/write - void readDisk(uint32_t sector, uint8_t *data); - void writeDisk(uint32_t sector, uint8_t *data); - - // State machine management - void updateState(DevAction_t action); - - // Utility functions - bool isBSYSet() { return (status & STATUS_BSY_BIT); } - bool isIENSet() { return nIENBit; } - bool isDEVSelect(); - - void setComplete() - { - // clear out the status byte - status = 0; - // set the DRDY bit - status |= STATUS_DRDY_BIT; - // set the SEEK bit - status |= STATUS_SEEK_BIT; - } - - uint32_t getLBABase() - { - return (Addr)(((cmdReg.head & 0xf) << 24) | (cmdReg.cyl_high << 16) | - (cmdReg.cyl_low << 8) | (cmdReg.sec_num)); - } - - inline Addr pciToDma(Addr pciAddr); - - uint32_t bytesInDmaPage(Addr curAddr, uint32_t bytesLeft); - - /** - * Serialize this object to the given output stream. - * @param os The stream to serialize to. - */ - void serialize(std::ostream &os); - - /** - * Reconstruct the state of this object from a checkpoint. - * @param cp The checkpoint to use. - * @param section The section name describing this object. - */ - void unserialize(Checkpoint *cp, const std::string §ion); -}; - - -#endif // __IDE_DISK_HH__ diff --git a/dev/io_device.cc b/dev/io_device.cc deleted file mode 100644 index 6ab876ab8..000000000 --- a/dev/io_device.cc +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "dev/io_device.hh" -#include "mem/bus/base_interface.hh" -#include "mem/bus/dma_interface.hh" -#include "sim/builder.hh" - -PioDevice::PioDevice(const std::string &name, Platform *p) - : FunctionalMemory(name), platform(p), pioInterface(NULL), pioLatency(0) -{} - -PioDevice::~PioDevice() -{ - if (pioInterface) - delete pioInterface; -} - -DEFINE_SIM_OBJECT_CLASS_NAME("PioDevice", PioDevice) - -DmaDevice::DmaDevice(const std::string &name, Platform *p) - : PioDevice(name, p), dmaInterface(NULL) -{} - -DmaDevice::~DmaDevice() -{ - if (dmaInterface) - delete dmaInterface; -} - -DEFINE_SIM_OBJECT_CLASS_NAME("DmaDevice", DmaDevice) - diff --git a/dev/io_device.hh b/dev/io_device.hh deleted file mode 100644 index bcfd062b9..000000000 --- a/dev/io_device.hh +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __DEV_IO_DEVICE_HH__ -#define __DEV_IO_DEVICE_HH__ - -#include "mem/functional/functional.hh" - -class BaseInterface; -class Bus; -class HierParams; -class Platform; -template <class BusType> class DMAInterface; - -class PioDevice : public FunctionalMemory -{ - protected: - Platform *platform; - BaseInterface *pioInterface; - Tick pioLatency; - - public: - PioDevice(const std::string &name, Platform *p); - virtual ~PioDevice(); -}; - -class DmaDevice : public PioDevice -{ - protected: - DMAInterface<Bus> *dmaInterface; - - public: - DmaDevice(const std::string &name, Platform *p); - virtual ~DmaDevice(); -}; - -#endif // __DEV_IO_DEVICE_HH__ diff --git a/dev/isa_fake.cc b/dev/isa_fake.cc deleted file mode 100644 index 2afebbded..000000000 --- a/dev/isa_fake.cc +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Isa Fake Device implementation - */ - -#include <deque> -#include <string> -#include <vector> - -#include "base/trace.hh" -#include "cpu/exec_context.hh" -#include "dev/isa_fake.hh" -#include "mem/bus/bus.hh" -#include "mem/bus/pio_interface.hh" -#include "mem/bus/pio_interface_impl.hh" -#include "mem/functional/memory_control.hh" -#include "sim/builder.hh" -#include "sim/system.hh" - -using namespace std; -using namespace TheISA; - -IsaFake::IsaFake(const string &name, Addr a, MemoryController *mmu, - HierParams *hier, Bus *pio_bus, Addr size) - : PioDevice(name, NULL), addr(a) -{ - mmu->add_child(this, RangeSize(addr, size)); - - if (pio_bus) { - pioInterface = newPioInterface(name + ".pio", hier, pio_bus, this, - &IsaFake::cacheAccess); - pioInterface->addAddrRange(RangeSize(addr, size)); - } -} - -Fault -IsaFake::read(MemReqPtr &req, uint8_t *data) -{ - DPRINTF(Tsunami, "read va=%#x size=%d\n", - req->vaddr, req->size); - -#if TRACING_ON - Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)) >> 6; -#endif - - switch (req->size) { - - case sizeof(uint64_t): - *(uint64_t*)data = 0xFFFFFFFFFFFFFFFFULL; - return NoFault; - case sizeof(uint32_t): - *(uint32_t*)data = 0xFFFFFFFF; - return NoFault; - case sizeof(uint16_t): - *(uint16_t*)data = 0xFFFF; - return NoFault; - case sizeof(uint8_t): - *(uint8_t*)data = 0xFF; - return NoFault; - - default: - panic("invalid access size(?) for PCI configspace!\n"); - } - DPRINTFN("Isa FakeSMC ERROR: read daddr=%#x size=%d\n", daddr, req->size); - - return NoFault; -} - -Fault -IsaFake::write(MemReqPtr &req, const uint8_t *data) -{ - DPRINTF(Tsunami, "write - va=%#x size=%d \n", - req->vaddr, req->size); - - //:Addr daddr = (req->paddr & addr_mask) >> 6; - - return NoFault; -} - -Tick -IsaFake::cacheAccess(MemReqPtr &req) -{ - return curTick; -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(IsaFake) - - SimObjectParam<MemoryController *> mmu; - Param<Addr> addr; - SimObjectParam<Bus*> pio_bus; - Param<Tick> pio_latency; - SimObjectParam<HierParams *> hier; - Param<Addr> size; - -END_DECLARE_SIM_OBJECT_PARAMS(IsaFake) - -BEGIN_INIT_SIM_OBJECT_PARAMS(IsaFake) - - INIT_PARAM(mmu, "Memory Controller"), - INIT_PARAM(addr, "Device Address"), - INIT_PARAM_DFLT(pio_bus, "The IO Bus to attach to", NULL), - INIT_PARAM_DFLT(pio_latency, "Programmed IO latency", 1000), - INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams), - INIT_PARAM_DFLT(size, "Size of address range", 0x8) - -END_INIT_SIM_OBJECT_PARAMS(IsaFake) - -CREATE_SIM_OBJECT(IsaFake) -{ - return new IsaFake(getInstanceName(), addr, mmu, hier, pio_bus, size); -} - -REGISTER_SIM_OBJECT("IsaFake", IsaFake) diff --git a/dev/isa_fake.hh b/dev/isa_fake.hh deleted file mode 100644 index 73e40c681..000000000 --- a/dev/isa_fake.hh +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Declaration of a fake device. - */ - -#ifndef __ISA_FAKE_HH__ -#define __ISA_FAKE_HH__ - -#include "dev/tsunami.hh" -#include "base/range.hh" -#include "dev/io_device.hh" - -class MemoryController; - -/** - * IsaFake is a device that returns -1 on all reads and - * accepts all writes. It is meant to be placed at an address range - * so that an mcheck doesn't occur when an os probes a piece of hw - * that doesn't exist (e.g. UARTs1-3). - */ -class IsaFake : public PioDevice -{ - private: - /** The address in memory that we respond to */ - Addr addr; - - public: - /** - * The constructor for Tsunmami Fake just registers itself with the MMU. - * @param name name of this device. - * @param a address to respond to. - * @param mmu the mmu we register with. - * @param size number of addresses to respond to - */ - IsaFake(const std::string &name, Addr a, MemoryController *mmu, - HierParams *hier, Bus *pio_bus, Addr size = 0x8); - - /** - * This read always returns -1. - * @param req The memory request. - * @param data Where to put the data. - */ - virtual Fault read(MemReqPtr &req, uint8_t *data); - - /** - * All writes are simply ignored. - * @param req The memory request. - * @param data the data to not write. - */ - virtual Fault write(MemReqPtr &req, const uint8_t *data); - - /** - * Return how long this access will take. - * @param req the memory request to calcuate - * @return Tick when the request is done - */ - Tick cacheAccess(MemReqPtr &req); -}; - -#endif // __ISA_FAKE_HH__ diff --git a/dev/ns_gige.cc b/dev/ns_gige.cc deleted file mode 100644 index ed8c794f9..000000000 --- a/dev/ns_gige.cc +++ /dev/null @@ -1,3105 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Device module for modelling the National Semiconductor - * DP83820 ethernet controller. Does not support priority queueing - */ -#include <cstdio> -#include <deque> -#include <string> - -#include "base/inet.hh" -#include "cpu/exec_context.hh" -#include "dev/etherlink.hh" -#include "dev/ns_gige.hh" -#include "dev/pciconfigall.hh" -#include "mem/bus/bus.hh" -#include "mem/bus/dma_interface.hh" -#include "mem/bus/pio_interface.hh" -#include "mem/bus/pio_interface_impl.hh" -#include "mem/functional/memory_control.hh" -#include "mem/functional/physical.hh" -#include "sim/builder.hh" -#include "sim/debug.hh" -#include "sim/host.hh" -#include "sim/stats.hh" -#include "arch/vtophys.hh" - -const char *NsRxStateStrings[] = -{ - "rxIdle", - "rxDescRefr", - "rxDescRead", - "rxFifoBlock", - "rxFragWrite", - "rxDescWrite", - "rxAdvance" -}; - -const char *NsTxStateStrings[] = -{ - "txIdle", - "txDescRefr", - "txDescRead", - "txFifoBlock", - "txFragRead", - "txDescWrite", - "txAdvance" -}; - -const char *NsDmaState[] = -{ - "dmaIdle", - "dmaReading", - "dmaWriting", - "dmaReadWaiting", - "dmaWriteWaiting" -}; - -using namespace std; -using namespace Net; -using namespace TheISA; - -/////////////////////////////////////////////////////////////////////// -// -// NSGigE PCI Device -// -NSGigE::NSGigE(Params *p) - : PciDev(p), ioEnable(false), - txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size), - txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL), - txXferLen(0), rxXferLen(0), clock(p->clock), - txState(txIdle), txEnable(false), CTDD(false), - txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle), - rxEnable(false), CRDD(false), rxPktBytes(0), - rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false), - eepromState(eepromStart), rxDmaReadEvent(this), rxDmaWriteEvent(this), - txDmaReadEvent(this), txDmaWriteEvent(this), - dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free), - txDelay(p->tx_delay), rxDelay(p->rx_delay), - rxKickTick(0), rxKickEvent(this), txKickTick(0), txKickEvent(this), - txEvent(this), rxFilterEnable(p->rx_filter), acceptBroadcast(false), - acceptMulticast(false), acceptUnicast(false), - acceptPerfect(false), acceptArp(false), multicastHashEnable(false), - physmem(p->pmem), intrTick(0), cpuPendingIntr(false), - intrEvent(0), interface(0) -{ - if (p->pio_bus) { - pioInterface = newPioInterface(name() + ".pio", p->hier, - p->pio_bus, this, - &NSGigE::cacheAccess); - pioLatency = p->pio_latency * p->pio_bus->clockRate; - } - - if (p->header_bus) { - if (p->payload_bus) - dmaInterface = new DMAInterface<Bus>(name() + ".dma", - p->header_bus, - p->payload_bus, 1, - p->dma_no_allocate); - else - dmaInterface = new DMAInterface<Bus>(name() + ".dma", - p->header_bus, - p->header_bus, 1, - p->dma_no_allocate); - } else if (p->payload_bus) - panic("Must define a header bus if defining a payload bus"); - - intrDelay = p->intr_delay; - dmaReadDelay = p->dma_read_delay; - dmaWriteDelay = p->dma_write_delay; - dmaReadFactor = p->dma_read_factor; - dmaWriteFactor = p->dma_write_factor; - - regsReset(); - memcpy(&rom.perfectMatch, p->eaddr.bytes(), ETH_ADDR_LEN); - - memset(&rxDesc32, 0, sizeof(rxDesc32)); - memset(&txDesc32, 0, sizeof(txDesc32)); - memset(&rxDesc64, 0, sizeof(rxDesc64)); - memset(&txDesc64, 0, sizeof(txDesc64)); -} - -NSGigE::~NSGigE() -{} - -void -NSGigE::regStats() -{ - txBytes - .name(name() + ".txBytes") - .desc("Bytes Transmitted") - .prereq(txBytes) - ; - - rxBytes - .name(name() + ".rxBytes") - .desc("Bytes Received") - .prereq(rxBytes) - ; - - txPackets - .name(name() + ".txPackets") - .desc("Number of Packets Transmitted") - .prereq(txBytes) - ; - - rxPackets - .name(name() + ".rxPackets") - .desc("Number of Packets Received") - .prereq(rxBytes) - ; - - txIpChecksums - .name(name() + ".txIpChecksums") - .desc("Number of tx IP Checksums done by device") - .precision(0) - .prereq(txBytes) - ; - - rxIpChecksums - .name(name() + ".rxIpChecksums") - .desc("Number of rx IP Checksums done by device") - .precision(0) - .prereq(rxBytes) - ; - - txTcpChecksums - .name(name() + ".txTcpChecksums") - .desc("Number of tx TCP Checksums done by device") - .precision(0) - .prereq(txBytes) - ; - - rxTcpChecksums - .name(name() + ".rxTcpChecksums") - .desc("Number of rx TCP Checksums done by device") - .precision(0) - .prereq(rxBytes) - ; - - txUdpChecksums - .name(name() + ".txUdpChecksums") - .desc("Number of tx UDP Checksums done by device") - .precision(0) - .prereq(txBytes) - ; - - rxUdpChecksums - .name(name() + ".rxUdpChecksums") - .desc("Number of rx UDP Checksums done by device") - .precision(0) - .prereq(rxBytes) - ; - - descDmaReads - .name(name() + ".descDMAReads") - .desc("Number of descriptors the device read w/ DMA") - .precision(0) - ; - - descDmaWrites - .name(name() + ".descDMAWrites") - .desc("Number of descriptors the device wrote w/ DMA") - .precision(0) - ; - - descDmaRdBytes - .name(name() + ".descDmaReadBytes") - .desc("number of descriptor bytes read w/ DMA") - .precision(0) - ; - - descDmaWrBytes - .name(name() + ".descDmaWriteBytes") - .desc("number of descriptor bytes write w/ DMA") - .precision(0) - ; - - txBandwidth - .name(name() + ".txBandwidth") - .desc("Transmit Bandwidth (bits/s)") - .precision(0) - .prereq(txBytes) - ; - - rxBandwidth - .name(name() + ".rxBandwidth") - .desc("Receive Bandwidth (bits/s)") - .precision(0) - .prereq(rxBytes) - ; - - totBandwidth - .name(name() + ".totBandwidth") - .desc("Total Bandwidth (bits/s)") - .precision(0) - .prereq(totBytes) - ; - - totPackets - .name(name() + ".totPackets") - .desc("Total Packets") - .precision(0) - .prereq(totBytes) - ; - - totBytes - .name(name() + ".totBytes") - .desc("Total Bytes") - .precision(0) - .prereq(totBytes) - ; - - totPacketRate - .name(name() + ".totPPS") - .desc("Total Tranmission Rate (packets/s)") - .precision(0) - .prereq(totBytes) - ; - - txPacketRate - .name(name() + ".txPPS") - .desc("Packet Tranmission Rate (packets/s)") - .precision(0) - .prereq(txBytes) - ; - - rxPacketRate - .name(name() + ".rxPPS") - .desc("Packet Reception Rate (packets/s)") - .precision(0) - .prereq(rxBytes) - ; - - postedSwi - .name(name() + ".postedSwi") - .desc("number of software interrupts posted to CPU") - .precision(0) - ; - - totalSwi - .name(name() + ".totalSwi") - .desc("total number of Swi written to ISR") - .precision(0) - ; - - coalescedSwi - .name(name() + ".coalescedSwi") - .desc("average number of Swi's coalesced into each post") - .precision(0) - ; - - postedRxIdle - .name(name() + ".postedRxIdle") - .desc("number of rxIdle interrupts posted to CPU") - .precision(0) - ; - - totalRxIdle - .name(name() + ".totalRxIdle") - .desc("total number of RxIdle written to ISR") - .precision(0) - ; - - coalescedRxIdle - .name(name() + ".coalescedRxIdle") - .desc("average number of RxIdle's coalesced into each post") - .precision(0) - ; - - postedRxOk - .name(name() + ".postedRxOk") - .desc("number of RxOk interrupts posted to CPU") - .precision(0) - ; - - totalRxOk - .name(name() + ".totalRxOk") - .desc("total number of RxOk written to ISR") - .precision(0) - ; - - coalescedRxOk - .name(name() + ".coalescedRxOk") - .desc("average number of RxOk's coalesced into each post") - .precision(0) - ; - - postedRxDesc - .name(name() + ".postedRxDesc") - .desc("number of RxDesc interrupts posted to CPU") - .precision(0) - ; - - totalRxDesc - .name(name() + ".totalRxDesc") - .desc("total number of RxDesc written to ISR") - .precision(0) - ; - - coalescedRxDesc - .name(name() + ".coalescedRxDesc") - .desc("average number of RxDesc's coalesced into each post") - .precision(0) - ; - - postedTxOk - .name(name() + ".postedTxOk") - .desc("number of TxOk interrupts posted to CPU") - .precision(0) - ; - - totalTxOk - .name(name() + ".totalTxOk") - .desc("total number of TxOk written to ISR") - .precision(0) - ; - - coalescedTxOk - .name(name() + ".coalescedTxOk") - .desc("average number of TxOk's coalesced into each post") - .precision(0) - ; - - postedTxIdle - .name(name() + ".postedTxIdle") - .desc("number of TxIdle interrupts posted to CPU") - .precision(0) - ; - - totalTxIdle - .name(name() + ".totalTxIdle") - .desc("total number of TxIdle written to ISR") - .precision(0) - ; - - coalescedTxIdle - .name(name() + ".coalescedTxIdle") - .desc("average number of TxIdle's coalesced into each post") - .precision(0) - ; - - postedTxDesc - .name(name() + ".postedTxDesc") - .desc("number of TxDesc interrupts posted to CPU") - .precision(0) - ; - - totalTxDesc - .name(name() + ".totalTxDesc") - .desc("total number of TxDesc written to ISR") - .precision(0) - ; - - coalescedTxDesc - .name(name() + ".coalescedTxDesc") - .desc("average number of TxDesc's coalesced into each post") - .precision(0) - ; - - postedRxOrn - .name(name() + ".postedRxOrn") - .desc("number of RxOrn posted to CPU") - .precision(0) - ; - - totalRxOrn - .name(name() + ".totalRxOrn") - .desc("total number of RxOrn written to ISR") - .precision(0) - ; - - coalescedRxOrn - .name(name() + ".coalescedRxOrn") - .desc("average number of RxOrn's coalesced into each post") - .precision(0) - ; - - coalescedTotal - .name(name() + ".coalescedTotal") - .desc("average number of interrupts coalesced into each post") - .precision(0) - ; - - postedInterrupts - .name(name() + ".postedInterrupts") - .desc("number of posts to CPU") - .precision(0) - ; - - droppedPackets - .name(name() + ".droppedPackets") - .desc("number of packets dropped") - .precision(0) - ; - - coalescedSwi = totalSwi / postedInterrupts; - coalescedRxIdle = totalRxIdle / postedInterrupts; - coalescedRxOk = totalRxOk / postedInterrupts; - coalescedRxDesc = totalRxDesc / postedInterrupts; - coalescedTxOk = totalTxOk / postedInterrupts; - coalescedTxIdle = totalTxIdle / postedInterrupts; - coalescedTxDesc = totalTxDesc / postedInterrupts; - coalescedRxOrn = totalRxOrn / postedInterrupts; - - coalescedTotal = (totalSwi + totalRxIdle + totalRxOk + totalRxDesc + - totalTxOk + totalTxIdle + totalTxDesc + - totalRxOrn) / postedInterrupts; - - txBandwidth = txBytes * Stats::constant(8) / simSeconds; - rxBandwidth = rxBytes * Stats::constant(8) / simSeconds; - totBandwidth = txBandwidth + rxBandwidth; - totBytes = txBytes + rxBytes; - totPackets = txPackets + rxPackets; - - txPacketRate = txPackets / simSeconds; - rxPacketRate = rxPackets / simSeconds; -} - -/** - * This is to read the PCI general configuration registers - */ -void -NSGigE::readConfig(int offset, int size, uint8_t *data) -{ - if (offset < PCI_DEVICE_SPECIFIC) - PciDev::readConfig(offset, size, data); - else - panic("Device specific PCI config space not implemented!\n"); -} - -/** - * This is to write to the PCI general configuration registers - */ -void -NSGigE::writeConfig(int offset, int size, const uint8_t* data) -{ - if (offset < PCI_DEVICE_SPECIFIC) - PciDev::writeConfig(offset, size, data); - else - panic("Device specific PCI config space not implemented!\n"); - - // Need to catch writes to BARs to update the PIO interface - switch (offset) { - // seems to work fine without all these PCI settings, but i - // put in the IO to double check, an assertion will fail if we - // need to properly implement it - case PCI_COMMAND: - if (config.data[offset] & PCI_CMD_IOSE) - ioEnable = true; - else - ioEnable = false; - -#if 0 - if (config.data[offset] & PCI_CMD_BME) { - bmEnabled = true; - } - else { - bmEnabled = false; - } - - if (config.data[offset] & PCI_CMD_MSE) { - memEnable = true; - } - else { - memEnable = false; - } -#endif - break; - - case PCI0_BASE_ADDR0: - if (BARAddrs[0] != 0) { - if (pioInterface) - pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0])); - - BARAddrs[0] &= EV5::PAddrUncachedMask; - } - break; - case PCI0_BASE_ADDR1: - if (BARAddrs[1] != 0) { - if (pioInterface) - pioInterface->addAddrRange(RangeSize(BARAddrs[1], BARSize[1])); - - BARAddrs[1] &= EV5::PAddrUncachedMask; - } - break; - } -} - -/** - * This reads the device registers, which are detailed in the NS83820 - * spec sheet - */ -Fault -NSGigE::read(MemReqPtr &req, uint8_t *data) -{ - assert(ioEnable); - - //The mask is to give you only the offset into the device register file - Addr daddr = req->paddr & 0xfff; - DPRINTF(EthernetPIO, "read da=%#x pa=%#x va=%#x size=%d\n", - daddr, req->paddr, req->vaddr, req->size); - - - // there are some reserved registers, you can see ns_gige_reg.h and - // the spec sheet for details - if (daddr > LAST && daddr <= RESERVED) { - panic("Accessing reserved register"); - } else if (daddr > RESERVED && daddr <= 0x3FC) { - readConfig(daddr & 0xff, req->size, data); - return NoFault; - } else if (daddr >= MIB_START && daddr <= MIB_END) { - // don't implement all the MIB's. hopefully the kernel - // doesn't actually DEPEND upon their values - // MIB are just hardware stats keepers - uint32_t ® = *(uint32_t *) data; - reg = 0; - return NoFault; - } else if (daddr > 0x3FC) - panic("Something is messed up!\n"); - - switch (req->size) { - case sizeof(uint32_t): - { - uint32_t ® = *(uint32_t *)data; - uint16_t rfaddr; - - switch (daddr) { - case CR: - reg = regs.command; - //these are supposed to be cleared on a read - reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR); - break; - - case CFGR: - reg = regs.config; - break; - - case MEAR: - reg = regs.mear; - break; - - case PTSCR: - reg = regs.ptscr; - break; - - case ISR: - reg = regs.isr; - devIntrClear(ISR_ALL); - break; - - case IMR: - reg = regs.imr; - break; - - case IER: - reg = regs.ier; - break; - - case IHR: - reg = regs.ihr; - break; - - case TXDP: - reg = regs.txdp; - break; - - case TXDP_HI: - reg = regs.txdp_hi; - break; - - case TX_CFG: - reg = regs.txcfg; - break; - - case GPIOR: - reg = regs.gpior; - break; - - case RXDP: - reg = regs.rxdp; - break; - - case RXDP_HI: - reg = regs.rxdp_hi; - break; - - case RX_CFG: - reg = regs.rxcfg; - break; - - case PQCR: - reg = regs.pqcr; - break; - - case WCSR: - reg = regs.wcsr; - break; - - case PCR: - reg = regs.pcr; - break; - - // see the spec sheet for how RFCR and RFDR work - // basically, you write to RFCR to tell the machine - // what you want to do next, then you act upon RFDR, - // and the device will be prepared b/c of what you - // wrote to RFCR - case RFCR: - reg = regs.rfcr; - break; - - case RFDR: - rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR); - switch (rfaddr) { - // Read from perfect match ROM octets - case 0x000: - reg = rom.perfectMatch[1]; - reg = reg << 8; - reg += rom.perfectMatch[0]; - break; - case 0x002: - reg = rom.perfectMatch[3] << 8; - reg += rom.perfectMatch[2]; - break; - case 0x004: - reg = rom.perfectMatch[5] << 8; - reg += rom.perfectMatch[4]; - break; - default: - // Read filter hash table - if (rfaddr >= FHASH_ADDR && - rfaddr < FHASH_ADDR + FHASH_SIZE) { - - // Only word-aligned reads supported - if (rfaddr % 2) - panic("unaligned read from filter hash table!"); - - reg = rom.filterHash[rfaddr - FHASH_ADDR + 1] << 8; - reg += rom.filterHash[rfaddr - FHASH_ADDR]; - break; - } - - panic("reading RFDR for something other than pattern" - " matching or hashing! %#x\n", rfaddr); - } - break; - - case SRR: - reg = regs.srr; - break; - - case MIBC: - reg = regs.mibc; - reg &= ~(MIBC_MIBS | MIBC_ACLR); - break; - - case VRCR: - reg = regs.vrcr; - break; - - case VTCR: - reg = regs.vtcr; - break; - - case VDR: - reg = regs.vdr; - break; - - case CCSR: - reg = regs.ccsr; - break; - - case TBICR: - reg = regs.tbicr; - break; - - case TBISR: - reg = regs.tbisr; - break; - - case TANAR: - reg = regs.tanar; - break; - - case TANLPAR: - reg = regs.tanlpar; - break; - - case TANER: - reg = regs.taner; - break; - - case TESR: - reg = regs.tesr; - break; - - case M5REG: - reg = 0; - if (params()->rx_thread) - reg |= M5REG_RX_THREAD; - if (params()->tx_thread) - reg |= M5REG_TX_THREAD; - if (params()->rss) - reg |= M5REG_RSS; - break; - - default: - panic("reading unimplemented register: addr=%#x", daddr); - } - - DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n", - daddr, reg, reg); - } - break; - - default: - panic("accessing register with invalid size: addr=%#x, size=%d", - daddr, req->size); - } - - return NoFault; -} - -Fault -NSGigE::write(MemReqPtr &req, const uint8_t *data) -{ - assert(ioEnable); - - Addr daddr = req->paddr & 0xfff; - DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n", - daddr, req->paddr, req->vaddr, req->size); - - if (daddr > LAST && daddr <= RESERVED) { - panic("Accessing reserved register"); - } else if (daddr > RESERVED && daddr <= 0x3FC) { - writeConfig(daddr & 0xff, req->size, data); - return NoFault; - } else if (daddr > 0x3FC) - panic("Something is messed up!\n"); - - if (req->size == sizeof(uint32_t)) { - uint32_t reg = *(uint32_t *)data; - uint16_t rfaddr; - - DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg); - - switch (daddr) { - case CR: - regs.command = reg; - if (reg & CR_TXD) { - txEnable = false; - } else if (reg & CR_TXE) { - txEnable = true; - - // the kernel is enabling the transmit machine - if (txState == txIdle) - txKick(); - } - - if (reg & CR_RXD) { - rxEnable = false; - } else if (reg & CR_RXE) { - rxEnable = true; - - if (rxState == rxIdle) - rxKick(); - } - - if (reg & CR_TXR) - txReset(); - - if (reg & CR_RXR) - rxReset(); - - if (reg & CR_SWI) - devIntrPost(ISR_SWI); - - if (reg & CR_RST) { - txReset(); - rxReset(); - - regsReset(); - } - break; - - case CFGR: - if (reg & CFGR_LNKSTS || - reg & CFGR_SPDSTS || - reg & CFGR_DUPSTS || - reg & CFGR_RESERVED || - reg & CFGR_T64ADDR || - reg & CFGR_PCI64_DET) - - // First clear all writable bits - regs.config &= CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS | - CFGR_RESERVED | CFGR_T64ADDR | - CFGR_PCI64_DET; - // Now set the appropriate writable bits - regs.config |= reg & ~(CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS | - CFGR_RESERVED | CFGR_T64ADDR | - CFGR_PCI64_DET); - -// all these #if 0's are because i don't THINK the kernel needs to -// have these implemented. if there is a problem relating to one of -// these, you may need to add functionality in. - if (reg & CFGR_TBI_EN) ; - if (reg & CFGR_MODE_1000) ; - - if (reg & CFGR_AUTO_1000) - panic("CFGR_AUTO_1000 not implemented!\n"); - - if (reg & CFGR_PINT_DUPSTS || - reg & CFGR_PINT_LNKSTS || - reg & CFGR_PINT_SPDSTS) - ; - - if (reg & CFGR_TMRTEST) ; - if (reg & CFGR_MRM_DIS) ; - if (reg & CFGR_MWI_DIS) ; - - if (reg & CFGR_T64ADDR) ; - // panic("CFGR_T64ADDR is read only register!\n"); - - if (reg & CFGR_PCI64_DET) - panic("CFGR_PCI64_DET is read only register!\n"); - - if (reg & CFGR_DATA64_EN) ; - if (reg & CFGR_M64ADDR) ; - if (reg & CFGR_PHY_RST) ; - if (reg & CFGR_PHY_DIS) ; - - if (reg & CFGR_EXTSTS_EN) - extstsEnable = true; - else - extstsEnable = false; - - if (reg & CFGR_REQALG) ; - if (reg & CFGR_SB) ; - if (reg & CFGR_POW) ; - if (reg & CFGR_EXD) ; - if (reg & CFGR_PESEL) ; - if (reg & CFGR_BROM_DIS) ; - if (reg & CFGR_EXT_125) ; - if (reg & CFGR_BEM) ; - break; - - case MEAR: - // Clear writable bits - regs.mear &= MEAR_EEDO; - // Set appropriate writable bits - regs.mear |= reg & ~MEAR_EEDO; - - // FreeBSD uses the EEPROM to read PMATCH (for the MAC address) - // even though it could get it through RFDR - if (reg & MEAR_EESEL) { - // Rising edge of clock - if (reg & MEAR_EECLK && !eepromClk) - eepromKick(); - } - else { - eepromState = eepromStart; - regs.mear &= ~MEAR_EEDI; - } - - eepromClk = reg & MEAR_EECLK; - - // since phy is completely faked, MEAR_MD* don't matter - if (reg & MEAR_MDIO) ; - if (reg & MEAR_MDDIR) ; - if (reg & MEAR_MDC) ; - break; - - case PTSCR: - regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY); - // these control BISTs for various parts of chip - we - // don't care or do just fake that the BIST is done - if (reg & PTSCR_RBIST_EN) - regs.ptscr |= PTSCR_RBIST_DONE; - if (reg & PTSCR_EEBIST_EN) - regs.ptscr &= ~PTSCR_EEBIST_EN; - if (reg & PTSCR_EELOAD_EN) - regs.ptscr &= ~PTSCR_EELOAD_EN; - break; - - case ISR: /* writing to the ISR has no effect */ - panic("ISR is a read only register!\n"); - - case IMR: - regs.imr = reg; - devIntrChangeMask(); - break; - - case IER: - regs.ier = reg; - break; - - case IHR: - regs.ihr = reg; - /* not going to implement real interrupt holdoff */ - break; - - case TXDP: - regs.txdp = (reg & 0xFFFFFFFC); - assert(txState == txIdle); - CTDD = false; - break; - - case TXDP_HI: - regs.txdp_hi = reg; - break; - - case TX_CFG: - regs.txcfg = reg; -#if 0 - if (reg & TX_CFG_CSI) ; - if (reg & TX_CFG_HBI) ; - if (reg & TX_CFG_MLB) ; - if (reg & TX_CFG_ATP) ; - if (reg & TX_CFG_ECRETRY) { - /* - * this could easily be implemented, but considering - * the network is just a fake pipe, wouldn't make - * sense to do this - */ - } - - if (reg & TX_CFG_BRST_DIS) ; -#endif - -#if 0 - /* we handle our own DMA, ignore the kernel's exhortations */ - if (reg & TX_CFG_MXDMA) ; -#endif - - // also, we currently don't care about fill/drain - // thresholds though this may change in the future with - // more realistic networks or a driver which changes it - // according to feedback - - break; - - case GPIOR: - // Only write writable bits - regs.gpior &= GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN - | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN; - regs.gpior |= reg & ~(GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN - | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN); - /* these just control general purpose i/o pins, don't matter */ - break; - - case RXDP: - regs.rxdp = reg; - CRDD = false; - break; - - case RXDP_HI: - regs.rxdp_hi = reg; - break; - - case RX_CFG: - regs.rxcfg = reg; -#if 0 - if (reg & RX_CFG_AEP) ; - if (reg & RX_CFG_ARP) ; - if (reg & RX_CFG_STRIPCRC) ; - if (reg & RX_CFG_RX_RD) ; - if (reg & RX_CFG_ALP) ; - if (reg & RX_CFG_AIRL) ; - - /* we handle our own DMA, ignore what kernel says about it */ - if (reg & RX_CFG_MXDMA) ; - - //also, we currently don't care about fill/drain thresholds - //though this may change in the future with more realistic - //networks or a driver which changes it according to feedback - if (reg & (RX_CFG_DRTH | RX_CFG_DRTH0)) ; -#endif - break; - - case PQCR: - /* there is no priority queueing used in the linux 2.6 driver */ - regs.pqcr = reg; - break; - - case WCSR: - /* not going to implement wake on LAN */ - regs.wcsr = reg; - break; - - case PCR: - /* not going to implement pause control */ - regs.pcr = reg; - break; - - case RFCR: - regs.rfcr = reg; - - rxFilterEnable = (reg & RFCR_RFEN) ? true : false; - acceptBroadcast = (reg & RFCR_AAB) ? true : false; - acceptMulticast = (reg & RFCR_AAM) ? true : false; - acceptUnicast = (reg & RFCR_AAU) ? true : false; - acceptPerfect = (reg & RFCR_APM) ? true : false; - acceptArp = (reg & RFCR_AARP) ? true : false; - multicastHashEnable = (reg & RFCR_MHEN) ? true : false; - -#if 0 - if (reg & RFCR_APAT) - panic("RFCR_APAT not implemented!\n"); -#endif - if (reg & RFCR_UHEN) - panic("Unicast hash filtering not used by drivers!\n"); - - if (reg & RFCR_ULM) - panic("RFCR_ULM not implemented!\n"); - - break; - - case RFDR: - rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR); - switch (rfaddr) { - case 0x000: - rom.perfectMatch[0] = (uint8_t)reg; - rom.perfectMatch[1] = (uint8_t)(reg >> 8); - break; - case 0x002: - rom.perfectMatch[2] = (uint8_t)reg; - rom.perfectMatch[3] = (uint8_t)(reg >> 8); - break; - case 0x004: - rom.perfectMatch[4] = (uint8_t)reg; - rom.perfectMatch[5] = (uint8_t)(reg >> 8); - break; - default: - - if (rfaddr >= FHASH_ADDR && - rfaddr < FHASH_ADDR + FHASH_SIZE) { - - // Only word-aligned writes supported - if (rfaddr % 2) - panic("unaligned write to filter hash table!"); - - rom.filterHash[rfaddr - FHASH_ADDR] = (uint8_t)reg; - rom.filterHash[rfaddr - FHASH_ADDR + 1] - = (uint8_t)(reg >> 8); - break; - } - panic("writing RFDR for something other than pattern matching\ - or hashing! %#x\n", rfaddr); - } - - case BRAR: - regs.brar = reg; - break; - - case BRDR: - panic("the driver never uses BRDR, something is wrong!\n"); - - case SRR: - panic("SRR is read only register!\n"); - - case MIBC: - panic("the driver never uses MIBC, something is wrong!\n"); - - case VRCR: - regs.vrcr = reg; - break; - - case VTCR: - regs.vtcr = reg; - break; - - case VDR: - panic("the driver never uses VDR, something is wrong!\n"); - - case CCSR: - /* not going to implement clockrun stuff */ - regs.ccsr = reg; - break; - - case TBICR: - regs.tbicr = reg; - if (reg & TBICR_MR_LOOPBACK) - panic("TBICR_MR_LOOPBACK never used, something wrong!\n"); - - if (reg & TBICR_MR_AN_ENABLE) { - regs.tanlpar = regs.tanar; - regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS); - } - -#if 0 - if (reg & TBICR_MR_RESTART_AN) ; -#endif - - break; - - case TBISR: - panic("TBISR is read only register!\n"); - - case TANAR: - // Only write the writable bits - regs.tanar &= TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED; - regs.tanar |= reg & ~(TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED); - - // Pause capability unimplemented -#if 0 - if (reg & TANAR_PS2) ; - if (reg & TANAR_PS1) ; -#endif - - break; - - case TANLPAR: - panic("this should only be written to by the fake phy!\n"); - - case TANER: - panic("TANER is read only register!\n"); - - case TESR: - regs.tesr = reg; - break; - - default: - panic("invalid register access daddr=%#x", daddr); - } - } else { - panic("Invalid Request Size"); - } - - return NoFault; -} - -void -NSGigE::devIntrPost(uint32_t interrupts) -{ - if (interrupts & ISR_RESERVE) - panic("Cannot set a reserved interrupt"); - - if (interrupts & ISR_NOIMPL) - warn("interrupt not implemented %#x\n", interrupts); - - interrupts &= ISR_IMPL; - regs.isr |= interrupts; - - if (interrupts & regs.imr) { - if (interrupts & ISR_SWI) { - totalSwi++; - } - if (interrupts & ISR_RXIDLE) { - totalRxIdle++; - } - if (interrupts & ISR_RXOK) { - totalRxOk++; - } - if (interrupts & ISR_RXDESC) { - totalRxDesc++; - } - if (interrupts & ISR_TXOK) { - totalTxOk++; - } - if (interrupts & ISR_TXIDLE) { - totalTxIdle++; - } - if (interrupts & ISR_TXDESC) { - totalTxDesc++; - } - if (interrupts & ISR_RXORN) { - totalRxOrn++; - } - } - - DPRINTF(EthernetIntr, - "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n", - interrupts, regs.isr, regs.imr); - - if ((regs.isr & regs.imr)) { - Tick when = curTick; - if ((regs.isr & regs.imr & ISR_NODELAY) == 0) - when += intrDelay; - cpuIntrPost(when); - } -} - -/* writing this interrupt counting stats inside this means that this function - is now limited to being used to clear all interrupts upon the kernel - reading isr and servicing. just telling you in case you were thinking - of expanding use. -*/ -void -NSGigE::devIntrClear(uint32_t interrupts) -{ - if (interrupts & ISR_RESERVE) - panic("Cannot clear a reserved interrupt"); - - if (regs.isr & regs.imr & ISR_SWI) { - postedSwi++; - } - if (regs.isr & regs.imr & ISR_RXIDLE) { - postedRxIdle++; - } - if (regs.isr & regs.imr & ISR_RXOK) { - postedRxOk++; - } - if (regs.isr & regs.imr & ISR_RXDESC) { - postedRxDesc++; - } - if (regs.isr & regs.imr & ISR_TXOK) { - postedTxOk++; - } - if (regs.isr & regs.imr & ISR_TXIDLE) { - postedTxIdle++; - } - if (regs.isr & regs.imr & ISR_TXDESC) { - postedTxDesc++; - } - if (regs.isr & regs.imr & ISR_RXORN) { - postedRxOrn++; - } - - if (regs.isr & regs.imr & ISR_IMPL) - postedInterrupts++; - - interrupts &= ~ISR_NOIMPL; - regs.isr &= ~interrupts; - - DPRINTF(EthernetIntr, - "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n", - interrupts, regs.isr, regs.imr); - - if (!(regs.isr & regs.imr)) - cpuIntrClear(); -} - -void -NSGigE::devIntrChangeMask() -{ - DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n", - regs.isr, regs.imr, regs.isr & regs.imr); - - if (regs.isr & regs.imr) - cpuIntrPost(curTick); - else - cpuIntrClear(); -} - -void -NSGigE::cpuIntrPost(Tick when) -{ - // If the interrupt you want to post is later than an interrupt - // already scheduled, just let it post in the coming one and don't - // schedule another. - // HOWEVER, must be sure that the scheduled intrTick is in the - // future (this was formerly the source of a bug) - /** - * @todo this warning should be removed and the intrTick code should - * be fixed. - */ - assert(when >= curTick); - assert(intrTick >= curTick || intrTick == 0); - if (when > intrTick && intrTick != 0) { - DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n", - intrTick); - return; - } - - intrTick = when; - if (intrTick < curTick) { - debug_break(); - intrTick = curTick; - } - - DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", - intrTick); - - if (intrEvent) - intrEvent->squash(); - intrEvent = new IntrEvent(this, true); - intrEvent->schedule(intrTick); -} - -void -NSGigE::cpuInterrupt() -{ - assert(intrTick == curTick); - - // Whether or not there's a pending interrupt, we don't care about - // it anymore - intrEvent = 0; - intrTick = 0; - - // Don't send an interrupt if there's already one - if (cpuPendingIntr) { - DPRINTF(EthernetIntr, - "would send an interrupt now, but there's already pending\n"); - } else { - // Send interrupt - cpuPendingIntr = true; - - DPRINTF(EthernetIntr, "posting interrupt\n"); - intrPost(); - } -} - -void -NSGigE::cpuIntrClear() -{ - if (!cpuPendingIntr) - return; - - if (intrEvent) { - intrEvent->squash(); - intrEvent = 0; - } - - intrTick = 0; - - cpuPendingIntr = false; - - DPRINTF(EthernetIntr, "clearing interrupt\n"); - intrClear(); -} - -bool -NSGigE::cpuIntrPending() const -{ return cpuPendingIntr; } - -void -NSGigE::txReset() -{ - - DPRINTF(Ethernet, "transmit reset\n"); - - CTDD = false; - txEnable = false;; - txFragPtr = 0; - assert(txDescCnt == 0); - txFifo.clear(); - txState = txIdle; - assert(txDmaState == dmaIdle); -} - -void -NSGigE::rxReset() -{ - DPRINTF(Ethernet, "receive reset\n"); - - CRDD = false; - assert(rxPktBytes == 0); - rxEnable = false; - rxFragPtr = 0; - assert(rxDescCnt == 0); - assert(rxDmaState == dmaIdle); - rxFifo.clear(); - rxState = rxIdle; -} - -void -NSGigE::regsReset() -{ - memset(®s, 0, sizeof(regs)); - regs.config = (CFGR_LNKSTS | CFGR_TBI_EN | CFGR_MODE_1000); - regs.mear = 0x12; - regs.txcfg = 0x120; // set drain threshold to 1024 bytes and - // fill threshold to 32 bytes - regs.rxcfg = 0x4; // set drain threshold to 16 bytes - regs.srr = 0x0103; // set the silicon revision to rev B or 0x103 - regs.mibc = MIBC_FRZ; - regs.vdr = 0x81; // set the vlan tag type to 802.1q - regs.tesr = 0xc000; // TBI capable of both full and half duplex - regs.brar = 0xffffffff; - - extstsEnable = false; - acceptBroadcast = false; - acceptMulticast = false; - acceptUnicast = false; - acceptPerfect = false; - acceptArp = false; -} - -void -NSGigE::rxDmaReadCopy() -{ - assert(rxDmaState == dmaReading); - - physmem->dma_read((uint8_t *)rxDmaData, rxDmaAddr, rxDmaLen); - rxDmaState = dmaIdle; - - DPRINTF(EthernetDMA, "rx dma read paddr=%#x len=%d\n", - rxDmaAddr, rxDmaLen); - DDUMP(EthernetDMA, rxDmaData, rxDmaLen); -} - -bool -NSGigE::doRxDmaRead() -{ - assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting); - rxDmaState = dmaReading; - - if (dmaInterface && !rxDmaFree) { - if (dmaInterface->busy()) - rxDmaState = dmaReadWaiting; - else - dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick, - &rxDmaReadEvent, true); - return true; - } - - if (dmaReadDelay == 0 && dmaReadFactor == 0) { - rxDmaReadCopy(); - return false; - } - - Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor; - Tick start = curTick + dmaReadDelay + factor; - rxDmaReadEvent.schedule(start); - return true; -} - -void -NSGigE::rxDmaReadDone() -{ - assert(rxDmaState == dmaReading); - rxDmaReadCopy(); - - // If the transmit state machine has a pending DMA, let it go first - if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) - txKick(); - - rxKick(); -} - -void -NSGigE::rxDmaWriteCopy() -{ - assert(rxDmaState == dmaWriting); - - physmem->dma_write(rxDmaAddr, (uint8_t *)rxDmaData, rxDmaLen); - rxDmaState = dmaIdle; - - DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n", - rxDmaAddr, rxDmaLen); - DDUMP(EthernetDMA, rxDmaData, rxDmaLen); -} - -bool -NSGigE::doRxDmaWrite() -{ - assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting); - rxDmaState = dmaWriting; - - if (dmaInterface && !rxDmaFree) { - if (dmaInterface->busy()) - rxDmaState = dmaWriteWaiting; - else - dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick, - &rxDmaWriteEvent, true); - return true; - } - - if (dmaWriteDelay == 0 && dmaWriteFactor == 0) { - rxDmaWriteCopy(); - return false; - } - - Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor; - Tick start = curTick + dmaWriteDelay + factor; - rxDmaWriteEvent.schedule(start); - return true; -} - -void -NSGigE::rxDmaWriteDone() -{ - assert(rxDmaState == dmaWriting); - rxDmaWriteCopy(); - - // If the transmit state machine has a pending DMA, let it go first - if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) - txKick(); - - rxKick(); -} - -void -NSGigE::rxKick() -{ - bool is64bit = (bool)(regs.config & CFGR_M64ADDR); - - DPRINTF(EthernetSM, - "receive kick rxState=%s (rxBuf.size=%d) %d-bit\n", - NsRxStateStrings[rxState], rxFifo.size(), is64bit ? 64 : 32); - - Addr link, bufptr; - uint32_t &cmdsts = is64bit ? rxDesc64.cmdsts : rxDesc32.cmdsts; - uint32_t &extsts = is64bit ? rxDesc64.extsts : rxDesc32.extsts; - - next: - if (clock) { - if (rxKickTick > curTick) { - DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n", - rxKickTick); - - goto exit; - } - - // Go to the next state machine clock tick. - rxKickTick = curTick + cycles(1); - } - - switch(rxDmaState) { - case dmaReadWaiting: - if (doRxDmaRead()) - goto exit; - break; - case dmaWriteWaiting: - if (doRxDmaWrite()) - goto exit; - break; - default: - break; - } - - link = is64bit ? (Addr)rxDesc64.link : (Addr)rxDesc32.link; - bufptr = is64bit ? (Addr)rxDesc64.bufptr : (Addr)rxDesc32.bufptr; - - // see state machine from spec for details - // the way this works is, if you finish work on one state and can - // go directly to another, you do that through jumping to the - // label "next". however, if you have intermediate work, like DMA - // so that you can't go to the next state yet, you go to exit and - // exit the loop. however, when the DMA is done it will trigger - // an event and come back to this loop. - switch (rxState) { - case rxIdle: - if (!rxEnable) { - DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n"); - goto exit; - } - - if (CRDD) { - rxState = rxDescRefr; - - rxDmaAddr = regs.rxdp & 0x3fffffff; - rxDmaData = - is64bit ? (void *)&rxDesc64.link : (void *)&rxDesc32.link; - rxDmaLen = is64bit ? sizeof(rxDesc64.link) : sizeof(rxDesc32.link); - rxDmaFree = dmaDescFree; - - descDmaReads++; - descDmaRdBytes += rxDmaLen; - - if (doRxDmaRead()) - goto exit; - } else { - rxState = rxDescRead; - - rxDmaAddr = regs.rxdp & 0x3fffffff; - rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32; - rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32); - rxDmaFree = dmaDescFree; - - descDmaReads++; - descDmaRdBytes += rxDmaLen; - - if (doRxDmaRead()) - goto exit; - } - break; - - case rxDescRefr: - if (rxDmaState != dmaIdle) - goto exit; - - rxState = rxAdvance; - break; - - case rxDescRead: - if (rxDmaState != dmaIdle) - goto exit; - - DPRINTF(EthernetDesc, "rxDesc: addr=%08x read descriptor\n", - regs.rxdp & 0x3fffffff); - DPRINTF(EthernetDesc, - "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n", - link, bufptr, cmdsts, extsts); - - if (cmdsts & CMDSTS_OWN) { - devIntrPost(ISR_RXIDLE); - rxState = rxIdle; - goto exit; - } else { - rxState = rxFifoBlock; - rxFragPtr = bufptr; - rxDescCnt = cmdsts & CMDSTS_LEN_MASK; - } - break; - - case rxFifoBlock: - if (!rxPacket) { - /** - * @todo in reality, we should be able to start processing - * the packet as it arrives, and not have to wait for the - * full packet ot be in the receive fifo. - */ - if (rxFifo.empty()) - goto exit; - - DPRINTF(EthernetSM, "****processing receive of new packet****\n"); - - // If we don't have a packet, grab a new one from the fifo. - rxPacket = rxFifo.front(); - rxPktBytes = rxPacket->length; - rxPacketBufPtr = rxPacket->data; - -#if TRACING_ON - if (DTRACE(Ethernet)) { - IpPtr ip(rxPacket); - if (ip) { - DPRINTF(Ethernet, "ID is %d\n", ip->id()); - TcpPtr tcp(ip); - if (tcp) { - DPRINTF(Ethernet, - "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", - tcp->sport(), tcp->dport(), tcp->seq(), - tcp->ack()); - } - } - } -#endif - - // sanity check - i think the driver behaves like this - assert(rxDescCnt >= rxPktBytes); - rxFifo.pop(); - } - - - // dont' need the && rxDescCnt > 0 if driver sanity check - // above holds - if (rxPktBytes > 0) { - rxState = rxFragWrite; - // don't need min<>(rxPktBytes,rxDescCnt) if above sanity - // check holds - rxXferLen = rxPktBytes; - - rxDmaAddr = rxFragPtr & 0x3fffffff; - rxDmaData = rxPacketBufPtr; - rxDmaLen = rxXferLen; - rxDmaFree = dmaDataFree; - - if (doRxDmaWrite()) - goto exit; - - } else { - rxState = rxDescWrite; - - //if (rxPktBytes == 0) { /* packet is done */ - assert(rxPktBytes == 0); - DPRINTF(EthernetSM, "done with receiving packet\n"); - - cmdsts |= CMDSTS_OWN; - cmdsts &= ~CMDSTS_MORE; - cmdsts |= CMDSTS_OK; - cmdsts &= 0xffff0000; - cmdsts += rxPacket->length; //i.e. set CMDSTS_SIZE - -#if 0 - /* - * all the driver uses these are for its own stats keeping - * which we don't care about, aren't necessary for - * functionality and doing this would just slow us down. - * if they end up using this in a later version for - * functional purposes, just undef - */ - if (rxFilterEnable) { - cmdsts &= ~CMDSTS_DEST_MASK; - const EthAddr &dst = rxFifoFront()->dst(); - if (dst->unicast()) - cmdsts |= CMDSTS_DEST_SELF; - if (dst->multicast()) - cmdsts |= CMDSTS_DEST_MULTI; - if (dst->broadcast()) - cmdsts |= CMDSTS_DEST_MASK; - } -#endif - - IpPtr ip(rxPacket); - if (extstsEnable && ip) { - extsts |= EXTSTS_IPPKT; - rxIpChecksums++; - if (cksum(ip) != 0) { - DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); - extsts |= EXTSTS_IPERR; - } - TcpPtr tcp(ip); - UdpPtr udp(ip); - if (tcp) { - extsts |= EXTSTS_TCPPKT; - rxTcpChecksums++; - if (cksum(tcp) != 0) { - DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); - extsts |= EXTSTS_TCPERR; - - } - } else if (udp) { - extsts |= EXTSTS_UDPPKT; - rxUdpChecksums++; - if (cksum(udp) != 0) { - DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); - extsts |= EXTSTS_UDPERR; - } - } - } - rxPacket = 0; - - /* - * the driver seems to always receive into desc buffers - * of size 1514, so you never have a pkt that is split - * into multiple descriptors on the receive side, so - * i don't implement that case, hence the assert above. - */ - - DPRINTF(EthernetDesc, - "rxDesc: addr=%08x writeback cmdsts extsts\n", - regs.rxdp & 0x3fffffff); - DPRINTF(EthernetDesc, - "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n", - link, bufptr, cmdsts, extsts); - - rxDmaAddr = regs.rxdp & 0x3fffffff; - rxDmaData = &cmdsts; - if (is64bit) { - rxDmaAddr += offsetof(ns_desc64, cmdsts); - rxDmaLen = sizeof(rxDesc64.cmdsts) + sizeof(rxDesc64.extsts); - } else { - rxDmaAddr += offsetof(ns_desc32, cmdsts); - rxDmaLen = sizeof(rxDesc32.cmdsts) + sizeof(rxDesc32.extsts); - } - rxDmaFree = dmaDescFree; - - descDmaWrites++; - descDmaWrBytes += rxDmaLen; - - if (doRxDmaWrite()) - goto exit; - } - break; - - case rxFragWrite: - if (rxDmaState != dmaIdle) - goto exit; - - rxPacketBufPtr += rxXferLen; - rxFragPtr += rxXferLen; - rxPktBytes -= rxXferLen; - - rxState = rxFifoBlock; - break; - - case rxDescWrite: - if (rxDmaState != dmaIdle) - goto exit; - - assert(cmdsts & CMDSTS_OWN); - - assert(rxPacket == 0); - devIntrPost(ISR_RXOK); - - if (cmdsts & CMDSTS_INTR) - devIntrPost(ISR_RXDESC); - - if (!rxEnable) { - DPRINTF(EthernetSM, "Halting the RX state machine\n"); - rxState = rxIdle; - goto exit; - } else - rxState = rxAdvance; - break; - - case rxAdvance: - if (link == 0) { - devIntrPost(ISR_RXIDLE); - rxState = rxIdle; - CRDD = true; - goto exit; - } else { - if (rxDmaState != dmaIdle) - goto exit; - rxState = rxDescRead; - regs.rxdp = link; - CRDD = false; - - rxDmaAddr = regs.rxdp & 0x3fffffff; - rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32; - rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32); - rxDmaFree = dmaDescFree; - - if (doRxDmaRead()) - goto exit; - } - break; - - default: - panic("Invalid rxState!"); - } - - DPRINTF(EthernetSM, "entering next rxState=%s\n", - NsRxStateStrings[rxState]); - goto next; - - exit: - /** - * @todo do we want to schedule a future kick? - */ - DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", - NsRxStateStrings[rxState]); - - if (clock && !rxKickEvent.scheduled()) - rxKickEvent.schedule(rxKickTick); -} - -void -NSGigE::transmit() -{ - if (txFifo.empty()) { - DPRINTF(Ethernet, "nothing to transmit\n"); - return; - } - - DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n", - txFifo.size()); - if (interface->sendPacket(txFifo.front())) { -#if TRACING_ON - if (DTRACE(Ethernet)) { - IpPtr ip(txFifo.front()); - if (ip) { - DPRINTF(Ethernet, "ID is %d\n", ip->id()); - TcpPtr tcp(ip); - if (tcp) { - DPRINTF(Ethernet, - "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", - tcp->sport(), tcp->dport(), tcp->seq(), - tcp->ack()); - } - } - } -#endif - - DDUMP(EthernetData, txFifo.front()->data, txFifo.front()->length); - txBytes += txFifo.front()->length; - txPackets++; - - DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n", - txFifo.avail()); - txFifo.pop(); - - /* - * normally do a writeback of the descriptor here, and ONLY - * after that is done, send this interrupt. but since our - * stuff never actually fails, just do this interrupt here, - * otherwise the code has to stray from this nice format. - * besides, it's functionally the same. - */ - devIntrPost(ISR_TXOK); - } - - if (!txFifo.empty() && !txEvent.scheduled()) { - DPRINTF(Ethernet, "reschedule transmit\n"); - txEvent.schedule(curTick + retryTime); - } -} - -void -NSGigE::txDmaReadCopy() -{ - assert(txDmaState == dmaReading); - - physmem->dma_read((uint8_t *)txDmaData, txDmaAddr, txDmaLen); - txDmaState = dmaIdle; - - DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", - txDmaAddr, txDmaLen); - DDUMP(EthernetDMA, txDmaData, txDmaLen); -} - -bool -NSGigE::doTxDmaRead() -{ - assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting); - txDmaState = dmaReading; - - if (dmaInterface && !txDmaFree) { - if (dmaInterface->busy()) - txDmaState = dmaReadWaiting; - else - dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, curTick, - &txDmaReadEvent, true); - return true; - } - - if (dmaReadDelay == 0 && dmaReadFactor == 0.0) { - txDmaReadCopy(); - return false; - } - - Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor; - Tick start = curTick + dmaReadDelay + factor; - txDmaReadEvent.schedule(start); - return true; -} - -void -NSGigE::txDmaReadDone() -{ - assert(txDmaState == dmaReading); - txDmaReadCopy(); - - // If the receive state machine has a pending DMA, let it go first - if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) - rxKick(); - - txKick(); -} - -void -NSGigE::txDmaWriteCopy() -{ - assert(txDmaState == dmaWriting); - - physmem->dma_write(txDmaAddr, (uint8_t *)txDmaData, txDmaLen); - txDmaState = dmaIdle; - - DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n", - txDmaAddr, txDmaLen); - DDUMP(EthernetDMA, txDmaData, txDmaLen); -} - -bool -NSGigE::doTxDmaWrite() -{ - assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting); - txDmaState = dmaWriting; - - if (dmaInterface && !txDmaFree) { - if (dmaInterface->busy()) - txDmaState = dmaWriteWaiting; - else - dmaInterface->doDMA(WriteInvalidate, txDmaAddr, txDmaLen, curTick, - &txDmaWriteEvent, true); - return true; - } - - if (dmaWriteDelay == 0 && dmaWriteFactor == 0.0) { - txDmaWriteCopy(); - return false; - } - - Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor; - Tick start = curTick + dmaWriteDelay + factor; - txDmaWriteEvent.schedule(start); - return true; -} - -void -NSGigE::txDmaWriteDone() -{ - assert(txDmaState == dmaWriting); - txDmaWriteCopy(); - - // If the receive state machine has a pending DMA, let it go first - if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) - rxKick(); - - txKick(); -} - -void -NSGigE::txKick() -{ - bool is64bit = (bool)(regs.config & CFGR_M64ADDR); - - DPRINTF(EthernetSM, "transmit kick txState=%s %d-bit\n", - NsTxStateStrings[txState], is64bit ? 64 : 32); - - Addr link, bufptr; - uint32_t &cmdsts = is64bit ? txDesc64.cmdsts : txDesc32.cmdsts; - uint32_t &extsts = is64bit ? txDesc64.extsts : txDesc32.extsts; - - next: - if (clock) { - if (txKickTick > curTick) { - DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n", - txKickTick); - goto exit; - } - - // Go to the next state machine clock tick. - txKickTick = curTick + cycles(1); - } - - switch(txDmaState) { - case dmaReadWaiting: - if (doTxDmaRead()) - goto exit; - break; - case dmaWriteWaiting: - if (doTxDmaWrite()) - goto exit; - break; - default: - break; - } - - link = is64bit ? (Addr)txDesc64.link : (Addr)txDesc32.link; - bufptr = is64bit ? (Addr)txDesc64.bufptr : (Addr)txDesc32.bufptr; - switch (txState) { - case txIdle: - if (!txEnable) { - DPRINTF(EthernetSM, "Transmit disabled. Nothing to do.\n"); - goto exit; - } - - if (CTDD) { - txState = txDescRefr; - - txDmaAddr = regs.txdp & 0x3fffffff; - txDmaData = - is64bit ? (void *)&txDesc64.link : (void *)&txDesc32.link; - txDmaLen = is64bit ? sizeof(txDesc64.link) : sizeof(txDesc32.link); - txDmaFree = dmaDescFree; - - descDmaReads++; - descDmaRdBytes += txDmaLen; - - if (doTxDmaRead()) - goto exit; - - } else { - txState = txDescRead; - - txDmaAddr = regs.txdp & 0x3fffffff; - txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32; - txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32); - txDmaFree = dmaDescFree; - - descDmaReads++; - descDmaRdBytes += txDmaLen; - - if (doTxDmaRead()) - goto exit; - } - break; - - case txDescRefr: - if (txDmaState != dmaIdle) - goto exit; - - txState = txAdvance; - break; - - case txDescRead: - if (txDmaState != dmaIdle) - goto exit; - - DPRINTF(EthernetDesc, "txDesc: addr=%08x read descriptor\n", - regs.txdp & 0x3fffffff); - DPRINTF(EthernetDesc, - "txDesc: link=%#x bufptr=%#x cmdsts=%#08x extsts=%#08x\n", - link, bufptr, cmdsts, extsts); - - if (cmdsts & CMDSTS_OWN) { - txState = txFifoBlock; - txFragPtr = bufptr; - txDescCnt = cmdsts & CMDSTS_LEN_MASK; - } else { - devIntrPost(ISR_TXIDLE); - txState = txIdle; - goto exit; - } - break; - - case txFifoBlock: - if (!txPacket) { - DPRINTF(EthernetSM, "****starting the tx of a new packet****\n"); - txPacket = new PacketData(16384); - txPacketBufPtr = txPacket->data; - } - - if (txDescCnt == 0) { - DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n"); - if (cmdsts & CMDSTS_MORE) { - DPRINTF(EthernetSM, "there are more descriptors to come\n"); - txState = txDescWrite; - - cmdsts &= ~CMDSTS_OWN; - - txDmaAddr = regs.txdp & 0x3fffffff; - txDmaData = &cmdsts; - if (is64bit) { - txDmaAddr += offsetof(ns_desc64, cmdsts); - txDmaLen = sizeof(txDesc64.cmdsts); - } else { - txDmaAddr += offsetof(ns_desc32, cmdsts); - txDmaLen = sizeof(txDesc32.cmdsts); - } - txDmaFree = dmaDescFree; - - if (doTxDmaWrite()) - goto exit; - - } else { /* this packet is totally done */ - DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n"); - /* deal with the the packet that just finished */ - if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) { - IpPtr ip(txPacket); - if (extsts & EXTSTS_UDPPKT) { - UdpPtr udp(ip); - udp->sum(0); - udp->sum(cksum(udp)); - txUdpChecksums++; - } else if (extsts & EXTSTS_TCPPKT) { - TcpPtr tcp(ip); - tcp->sum(0); - tcp->sum(cksum(tcp)); - txTcpChecksums++; - } - if (extsts & EXTSTS_IPPKT) { - ip->sum(0); - ip->sum(cksum(ip)); - txIpChecksums++; - } - } - - txPacket->length = txPacketBufPtr - txPacket->data; - // this is just because the receive can't handle a - // packet bigger want to make sure - if (txPacket->length > 1514) - panic("transmit packet too large, %s > 1514\n", - txPacket->length); - -#ifndef NDEBUG - bool success = -#endif - txFifo.push(txPacket); - assert(success); - - /* - * this following section is not tqo spec, but - * functionally shouldn't be any different. normally, - * the chip will wait til the transmit has occurred - * before writing back the descriptor because it has - * to wait to see that it was successfully transmitted - * to decide whether to set CMDSTS_OK or not. - * however, in the simulator since it is always - * successfully transmitted, and writing it exactly to - * spec would complicate the code, we just do it here - */ - - cmdsts &= ~CMDSTS_OWN; - cmdsts |= CMDSTS_OK; - - DPRINTF(EthernetDesc, - "txDesc writeback: cmdsts=%08x extsts=%08x\n", - cmdsts, extsts); - - txDmaFree = dmaDescFree; - txDmaAddr = regs.txdp & 0x3fffffff; - txDmaData = &cmdsts; - if (is64bit) { - txDmaAddr += offsetof(ns_desc64, cmdsts); - txDmaLen = - sizeof(txDesc64.cmdsts) + sizeof(txDesc64.extsts); - } else { - txDmaAddr += offsetof(ns_desc32, cmdsts); - txDmaLen = - sizeof(txDesc32.cmdsts) + sizeof(txDesc32.extsts); - } - - descDmaWrites++; - descDmaWrBytes += txDmaLen; - - transmit(); - txPacket = 0; - - if (!txEnable) { - DPRINTF(EthernetSM, "halting TX state machine\n"); - txState = txIdle; - goto exit; - } else - txState = txAdvance; - - if (doTxDmaWrite()) - goto exit; - } - } else { - DPRINTF(EthernetSM, "this descriptor isn't done yet\n"); - if (!txFifo.full()) { - txState = txFragRead; - - /* - * The number of bytes transferred is either whatever - * is left in the descriptor (txDescCnt), or if there - * is not enough room in the fifo, just whatever room - * is left in the fifo - */ - txXferLen = min<uint32_t>(txDescCnt, txFifo.avail()); - - txDmaAddr = txFragPtr & 0x3fffffff; - txDmaData = txPacketBufPtr; - txDmaLen = txXferLen; - txDmaFree = dmaDataFree; - - if (doTxDmaRead()) - goto exit; - } else { - txState = txFifoBlock; - transmit(); - - goto exit; - } - - } - break; - - case txFragRead: - if (txDmaState != dmaIdle) - goto exit; - - txPacketBufPtr += txXferLen; - txFragPtr += txXferLen; - txDescCnt -= txXferLen; - txFifo.reserve(txXferLen); - - txState = txFifoBlock; - break; - - case txDescWrite: - if (txDmaState != dmaIdle) - goto exit; - - if (cmdsts & CMDSTS_INTR) - devIntrPost(ISR_TXDESC); - - if (!txEnable) { - DPRINTF(EthernetSM, "halting TX state machine\n"); - txState = txIdle; - goto exit; - } else - txState = txAdvance; - break; - - case txAdvance: - if (link == 0) { - devIntrPost(ISR_TXIDLE); - txState = txIdle; - goto exit; - } else { - if (txDmaState != dmaIdle) - goto exit; - txState = txDescRead; - regs.txdp = link; - CTDD = false; - - txDmaAddr = link & 0x3fffffff; - txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32; - txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32); - txDmaFree = dmaDescFree; - - if (doTxDmaRead()) - goto exit; - } - break; - - default: - panic("invalid state"); - } - - DPRINTF(EthernetSM, "entering next txState=%s\n", - NsTxStateStrings[txState]); - goto next; - - exit: - /** - * @todo do we want to schedule a future kick? - */ - DPRINTF(EthernetSM, "tx state machine exited txState=%s\n", - NsTxStateStrings[txState]); - - if (clock && !txKickEvent.scheduled()) - txKickEvent.schedule(txKickTick); -} - -/** - * Advance the EEPROM state machine - * Called on rising edge of EEPROM clock bit in MEAR - */ -void -NSGigE::eepromKick() -{ - switch (eepromState) { - - case eepromStart: - - // Wait for start bit - if (regs.mear & MEAR_EEDI) { - // Set up to get 2 opcode bits - eepromState = eepromGetOpcode; - eepromBitsToRx = 2; - eepromOpcode = 0; - } - break; - - case eepromGetOpcode: - eepromOpcode <<= 1; - eepromOpcode += (regs.mear & MEAR_EEDI) ? 1 : 0; - --eepromBitsToRx; - - // Done getting opcode - if (eepromBitsToRx == 0) { - if (eepromOpcode != EEPROM_READ) - panic("only EEPROM reads are implemented!"); - - // Set up to get address - eepromState = eepromGetAddress; - eepromBitsToRx = 6; - eepromAddress = 0; - } - break; - - case eepromGetAddress: - eepromAddress <<= 1; - eepromAddress += (regs.mear & MEAR_EEDI) ? 1 : 0; - --eepromBitsToRx; - - // Done getting address - if (eepromBitsToRx == 0) { - - if (eepromAddress >= EEPROM_SIZE) - panic("EEPROM read access out of range!"); - - switch (eepromAddress) { - - case EEPROM_PMATCH2_ADDR: - eepromData = rom.perfectMatch[5]; - eepromData <<= 8; - eepromData += rom.perfectMatch[4]; - break; - - case EEPROM_PMATCH1_ADDR: - eepromData = rom.perfectMatch[3]; - eepromData <<= 8; - eepromData += rom.perfectMatch[2]; - break; - - case EEPROM_PMATCH0_ADDR: - eepromData = rom.perfectMatch[1]; - eepromData <<= 8; - eepromData += rom.perfectMatch[0]; - break; - - default: - panic("FreeBSD driver only uses EEPROM to read PMATCH!"); - } - // Set up to read data - eepromState = eepromRead; - eepromBitsToRx = 16; - - // Clear data in bit - regs.mear &= ~MEAR_EEDI; - } - break; - - case eepromRead: - // Clear Data Out bit - regs.mear &= ~MEAR_EEDO; - // Set bit to value of current EEPROM bit - regs.mear |= (eepromData & 0x8000) ? MEAR_EEDO : 0x0; - - eepromData <<= 1; - --eepromBitsToRx; - - // All done - if (eepromBitsToRx == 0) { - eepromState = eepromStart; - } - break; - - default: - panic("invalid EEPROM state"); - } - -} - -void -NSGigE::transferDone() -{ - if (txFifo.empty()) { - DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n"); - return; - } - - DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); - - if (txEvent.scheduled()) - txEvent.reschedule(curTick + cycles(1)); - else - txEvent.schedule(curTick + cycles(1)); -} - -bool -NSGigE::rxFilter(const PacketPtr &packet) -{ - EthPtr eth = packet; - bool drop = true; - string type; - - const EthAddr &dst = eth->dst(); - if (dst.unicast()) { - // If we're accepting all unicast addresses - if (acceptUnicast) - drop = false; - - // If we make a perfect match - if (acceptPerfect && dst == rom.perfectMatch) - drop = false; - - if (acceptArp && eth->type() == ETH_TYPE_ARP) - drop = false; - - } else if (dst.broadcast()) { - // if we're accepting broadcasts - if (acceptBroadcast) - drop = false; - - } else if (dst.multicast()) { - // if we're accepting all multicasts - if (acceptMulticast) - drop = false; - - // Multicast hashing faked - all packets accepted - if (multicastHashEnable) - drop = false; - } - - if (drop) { - DPRINTF(Ethernet, "rxFilter drop\n"); - DDUMP(EthernetData, packet->data, packet->length); - } - - return drop; -} - -bool -NSGigE::recvPacket(PacketPtr packet) -{ - rxBytes += packet->length; - rxPackets++; - - DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n", - rxFifo.avail()); - - if (!rxEnable) { - DPRINTF(Ethernet, "receive disabled...packet dropped\n"); - return true; - } - - if (!rxFilterEnable) { - DPRINTF(Ethernet, - "receive packet filtering disabled . . . packet dropped\n"); - return true; - } - - if (rxFilter(packet)) { - DPRINTF(Ethernet, "packet filtered...dropped\n"); - return true; - } - - if (rxFifo.avail() < packet->length) { -#if TRACING_ON - IpPtr ip(packet); - TcpPtr tcp(ip); - if (ip) { - DPRINTF(Ethernet, - "packet won't fit in receive buffer...pkt ID %d dropped\n", - ip->id()); - if (tcp) { - DPRINTF(Ethernet, "Seq=%d\n", tcp->seq()); - } - } -#endif - droppedPackets++; - devIntrPost(ISR_RXORN); - return false; - } - - rxFifo.push(packet); - - rxKick(); - return true; -} - -//===================================================================== -// -// -void -NSGigE::serialize(ostream &os) -{ - // Serialize the PciDev base class - PciDev::serialize(os); - - /* - * Finalize any DMA events now. - */ - if (rxDmaReadEvent.scheduled()) - rxDmaReadCopy(); - if (rxDmaWriteEvent.scheduled()) - rxDmaWriteCopy(); - if (txDmaReadEvent.scheduled()) - txDmaReadCopy(); - if (txDmaWriteEvent.scheduled()) - txDmaWriteCopy(); - - /* - * Serialize the device registers - */ - SERIALIZE_SCALAR(regs.command); - SERIALIZE_SCALAR(regs.config); - SERIALIZE_SCALAR(regs.mear); - SERIALIZE_SCALAR(regs.ptscr); - SERIALIZE_SCALAR(regs.isr); - SERIALIZE_SCALAR(regs.imr); - SERIALIZE_SCALAR(regs.ier); - SERIALIZE_SCALAR(regs.ihr); - SERIALIZE_SCALAR(regs.txdp); - SERIALIZE_SCALAR(regs.txdp_hi); - SERIALIZE_SCALAR(regs.txcfg); - SERIALIZE_SCALAR(regs.gpior); - SERIALIZE_SCALAR(regs.rxdp); - SERIALIZE_SCALAR(regs.rxdp_hi); - SERIALIZE_SCALAR(regs.rxcfg); - SERIALIZE_SCALAR(regs.pqcr); - SERIALIZE_SCALAR(regs.wcsr); - SERIALIZE_SCALAR(regs.pcr); - SERIALIZE_SCALAR(regs.rfcr); - SERIALIZE_SCALAR(regs.rfdr); - SERIALIZE_SCALAR(regs.brar); - SERIALIZE_SCALAR(regs.brdr); - SERIALIZE_SCALAR(regs.srr); - SERIALIZE_SCALAR(regs.mibc); - SERIALIZE_SCALAR(regs.vrcr); - SERIALIZE_SCALAR(regs.vtcr); - SERIALIZE_SCALAR(regs.vdr); - SERIALIZE_SCALAR(regs.ccsr); - SERIALIZE_SCALAR(regs.tbicr); - SERIALIZE_SCALAR(regs.tbisr); - SERIALIZE_SCALAR(regs.tanar); - SERIALIZE_SCALAR(regs.tanlpar); - SERIALIZE_SCALAR(regs.taner); - SERIALIZE_SCALAR(regs.tesr); - - SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); - SERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE); - - SERIALIZE_SCALAR(ioEnable); - - /* - * Serialize the data Fifos - */ - rxFifo.serialize("rxFifo", os); - txFifo.serialize("txFifo", os); - - /* - * Serialize the various helper variables - */ - bool txPacketExists = txPacket; - SERIALIZE_SCALAR(txPacketExists); - if (txPacketExists) { - txPacket->length = txPacketBufPtr - txPacket->data; - txPacket->serialize("txPacket", os); - uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data); - SERIALIZE_SCALAR(txPktBufPtr); - } - - bool rxPacketExists = rxPacket; - SERIALIZE_SCALAR(rxPacketExists); - if (rxPacketExists) { - rxPacket->serialize("rxPacket", os); - uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data); - SERIALIZE_SCALAR(rxPktBufPtr); - } - - SERIALIZE_SCALAR(txXferLen); - SERIALIZE_SCALAR(rxXferLen); - - /* - * Serialize Cached Descriptors - */ - SERIALIZE_SCALAR(rxDesc64.link); - SERIALIZE_SCALAR(rxDesc64.bufptr); - SERIALIZE_SCALAR(rxDesc64.cmdsts); - SERIALIZE_SCALAR(rxDesc64.extsts); - SERIALIZE_SCALAR(txDesc64.link); - SERIALIZE_SCALAR(txDesc64.bufptr); - SERIALIZE_SCALAR(txDesc64.cmdsts); - SERIALIZE_SCALAR(txDesc64.extsts); - SERIALIZE_SCALAR(rxDesc32.link); - SERIALIZE_SCALAR(rxDesc32.bufptr); - SERIALIZE_SCALAR(rxDesc32.cmdsts); - SERIALIZE_SCALAR(rxDesc32.extsts); - SERIALIZE_SCALAR(txDesc32.link); - SERIALIZE_SCALAR(txDesc32.bufptr); - SERIALIZE_SCALAR(txDesc32.cmdsts); - SERIALIZE_SCALAR(txDesc32.extsts); - SERIALIZE_SCALAR(extstsEnable); - - /* - * Serialize tx state machine - */ - int txState = this->txState; - SERIALIZE_SCALAR(txState); - SERIALIZE_SCALAR(txEnable); - SERIALIZE_SCALAR(CTDD); - SERIALIZE_SCALAR(txFragPtr); - SERIALIZE_SCALAR(txDescCnt); - int txDmaState = this->txDmaState; - SERIALIZE_SCALAR(txDmaState); - SERIALIZE_SCALAR(txKickTick); - - /* - * Serialize rx state machine - */ - int rxState = this->rxState; - SERIALIZE_SCALAR(rxState); - SERIALIZE_SCALAR(rxEnable); - SERIALIZE_SCALAR(CRDD); - SERIALIZE_SCALAR(rxPktBytes); - SERIALIZE_SCALAR(rxFragPtr); - SERIALIZE_SCALAR(rxDescCnt); - int rxDmaState = this->rxDmaState; - SERIALIZE_SCALAR(rxDmaState); - SERIALIZE_SCALAR(rxKickTick); - - /* - * Serialize EEPROM state machine - */ - int eepromState = this->eepromState; - SERIALIZE_SCALAR(eepromState); - SERIALIZE_SCALAR(eepromClk); - SERIALIZE_SCALAR(eepromBitsToRx); - SERIALIZE_SCALAR(eepromOpcode); - SERIALIZE_SCALAR(eepromAddress); - SERIALIZE_SCALAR(eepromData); - - /* - * If there's a pending transmit, store the time so we can - * reschedule it later - */ - Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0; - SERIALIZE_SCALAR(transmitTick); - - /* - * receive address filter settings - */ - SERIALIZE_SCALAR(rxFilterEnable); - SERIALIZE_SCALAR(acceptBroadcast); - SERIALIZE_SCALAR(acceptMulticast); - SERIALIZE_SCALAR(acceptUnicast); - SERIALIZE_SCALAR(acceptPerfect); - SERIALIZE_SCALAR(acceptArp); - SERIALIZE_SCALAR(multicastHashEnable); - - /* - * Keep track of pending interrupt status. - */ - SERIALIZE_SCALAR(intrTick); - SERIALIZE_SCALAR(cpuPendingIntr); - Tick intrEventTick = 0; - if (intrEvent) - intrEventTick = intrEvent->when(); - SERIALIZE_SCALAR(intrEventTick); - -} - -void -NSGigE::unserialize(Checkpoint *cp, const std::string §ion) -{ - // Unserialize the PciDev base class - PciDev::unserialize(cp, section); - - UNSERIALIZE_SCALAR(regs.command); - UNSERIALIZE_SCALAR(regs.config); - UNSERIALIZE_SCALAR(regs.mear); - UNSERIALIZE_SCALAR(regs.ptscr); - UNSERIALIZE_SCALAR(regs.isr); - UNSERIALIZE_SCALAR(regs.imr); - UNSERIALIZE_SCALAR(regs.ier); - UNSERIALIZE_SCALAR(regs.ihr); - UNSERIALIZE_SCALAR(regs.txdp); - UNSERIALIZE_SCALAR(regs.txdp_hi); - UNSERIALIZE_SCALAR(regs.txcfg); - UNSERIALIZE_SCALAR(regs.gpior); - UNSERIALIZE_SCALAR(regs.rxdp); - UNSERIALIZE_SCALAR(regs.rxdp_hi); - UNSERIALIZE_SCALAR(regs.rxcfg); - UNSERIALIZE_SCALAR(regs.pqcr); - UNSERIALIZE_SCALAR(regs.wcsr); - UNSERIALIZE_SCALAR(regs.pcr); - UNSERIALIZE_SCALAR(regs.rfcr); - UNSERIALIZE_SCALAR(regs.rfdr); - UNSERIALIZE_SCALAR(regs.brar); - UNSERIALIZE_SCALAR(regs.brdr); - UNSERIALIZE_SCALAR(regs.srr); - UNSERIALIZE_SCALAR(regs.mibc); - UNSERIALIZE_SCALAR(regs.vrcr); - UNSERIALIZE_SCALAR(regs.vtcr); - UNSERIALIZE_SCALAR(regs.vdr); - UNSERIALIZE_SCALAR(regs.ccsr); - UNSERIALIZE_SCALAR(regs.tbicr); - UNSERIALIZE_SCALAR(regs.tbisr); - UNSERIALIZE_SCALAR(regs.tanar); - UNSERIALIZE_SCALAR(regs.tanlpar); - UNSERIALIZE_SCALAR(regs.taner); - UNSERIALIZE_SCALAR(regs.tesr); - - UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); - UNSERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE); - - UNSERIALIZE_SCALAR(ioEnable); - - /* - * unserialize the data fifos - */ - rxFifo.unserialize("rxFifo", cp, section); - txFifo.unserialize("txFifo", cp, section); - - /* - * unserialize the various helper variables - */ - bool txPacketExists; - UNSERIALIZE_SCALAR(txPacketExists); - if (txPacketExists) { - txPacket = new PacketData(16384); - txPacket->unserialize("txPacket", cp, section); - uint32_t txPktBufPtr; - UNSERIALIZE_SCALAR(txPktBufPtr); - txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr; - } else - txPacket = 0; - - bool rxPacketExists; - UNSERIALIZE_SCALAR(rxPacketExists); - rxPacket = 0; - if (rxPacketExists) { - rxPacket = new PacketData(16384); - rxPacket->unserialize("rxPacket", cp, section); - uint32_t rxPktBufPtr; - UNSERIALIZE_SCALAR(rxPktBufPtr); - rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr; - } else - rxPacket = 0; - - UNSERIALIZE_SCALAR(txXferLen); - UNSERIALIZE_SCALAR(rxXferLen); - - /* - * Unserialize Cached Descriptors - */ - UNSERIALIZE_SCALAR(rxDesc64.link); - UNSERIALIZE_SCALAR(rxDesc64.bufptr); - UNSERIALIZE_SCALAR(rxDesc64.cmdsts); - UNSERIALIZE_SCALAR(rxDesc64.extsts); - UNSERIALIZE_SCALAR(txDesc64.link); - UNSERIALIZE_SCALAR(txDesc64.bufptr); - UNSERIALIZE_SCALAR(txDesc64.cmdsts); - UNSERIALIZE_SCALAR(txDesc64.extsts); - UNSERIALIZE_SCALAR(rxDesc32.link); - UNSERIALIZE_SCALAR(rxDesc32.bufptr); - UNSERIALIZE_SCALAR(rxDesc32.cmdsts); - UNSERIALIZE_SCALAR(rxDesc32.extsts); - UNSERIALIZE_SCALAR(txDesc32.link); - UNSERIALIZE_SCALAR(txDesc32.bufptr); - UNSERIALIZE_SCALAR(txDesc32.cmdsts); - UNSERIALIZE_SCALAR(txDesc32.extsts); - UNSERIALIZE_SCALAR(extstsEnable); - - /* - * unserialize tx state machine - */ - int txState; - UNSERIALIZE_SCALAR(txState); - this->txState = (TxState) txState; - UNSERIALIZE_SCALAR(txEnable); - UNSERIALIZE_SCALAR(CTDD); - UNSERIALIZE_SCALAR(txFragPtr); - UNSERIALIZE_SCALAR(txDescCnt); - int txDmaState; - UNSERIALIZE_SCALAR(txDmaState); - this->txDmaState = (DmaState) txDmaState; - UNSERIALIZE_SCALAR(txKickTick); - if (txKickTick) - txKickEvent.schedule(txKickTick); - - /* - * unserialize rx state machine - */ - int rxState; - UNSERIALIZE_SCALAR(rxState); - this->rxState = (RxState) rxState; - UNSERIALIZE_SCALAR(rxEnable); - UNSERIALIZE_SCALAR(CRDD); - UNSERIALIZE_SCALAR(rxPktBytes); - UNSERIALIZE_SCALAR(rxFragPtr); - UNSERIALIZE_SCALAR(rxDescCnt); - int rxDmaState; - UNSERIALIZE_SCALAR(rxDmaState); - this->rxDmaState = (DmaState) rxDmaState; - UNSERIALIZE_SCALAR(rxKickTick); - if (rxKickTick) - rxKickEvent.schedule(rxKickTick); - - /* - * Unserialize EEPROM state machine - */ - int eepromState; - UNSERIALIZE_SCALAR(eepromState); - this->eepromState = (EEPROMState) eepromState; - UNSERIALIZE_SCALAR(eepromClk); - UNSERIALIZE_SCALAR(eepromBitsToRx); - UNSERIALIZE_SCALAR(eepromOpcode); - UNSERIALIZE_SCALAR(eepromAddress); - UNSERIALIZE_SCALAR(eepromData); - - /* - * If there's a pending transmit, reschedule it now - */ - Tick transmitTick; - UNSERIALIZE_SCALAR(transmitTick); - if (transmitTick) - txEvent.schedule(curTick + transmitTick); - - /* - * unserialize receive address filter settings - */ - UNSERIALIZE_SCALAR(rxFilterEnable); - UNSERIALIZE_SCALAR(acceptBroadcast); - UNSERIALIZE_SCALAR(acceptMulticast); - UNSERIALIZE_SCALAR(acceptUnicast); - UNSERIALIZE_SCALAR(acceptPerfect); - UNSERIALIZE_SCALAR(acceptArp); - UNSERIALIZE_SCALAR(multicastHashEnable); - - /* - * Keep track of pending interrupt status. - */ - UNSERIALIZE_SCALAR(intrTick); - UNSERIALIZE_SCALAR(cpuPendingIntr); - Tick intrEventTick; - UNSERIALIZE_SCALAR(intrEventTick); - if (intrEventTick) { - intrEvent = new IntrEvent(this, true); - intrEvent->schedule(intrEventTick); - } - - /* - * re-add addrRanges to bus bridges - */ - if (pioInterface) { - pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0])); - pioInterface->addAddrRange(RangeSize(BARAddrs[1], BARSize[1])); - } -} - -Tick -NSGigE::cacheAccess(MemReqPtr &req) -{ - DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n", - req->paddr, req->paddr & 0xfff); - - return curTick + pioLatency; -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) - - SimObjectParam<EtherInt *> peer; - SimObjectParam<NSGigE *> device; - -END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) - -BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt) - - INIT_PARAM_DFLT(peer, "peer interface", NULL), - INIT_PARAM(device, "Ethernet device of this interface") - -END_INIT_SIM_OBJECT_PARAMS(NSGigEInt) - -CREATE_SIM_OBJECT(NSGigEInt) -{ - NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device); - - EtherInt *p = (EtherInt *)peer; - if (p) { - dev_int->setPeer(p); - p->setPeer(dev_int); - } - - return dev_int; -} - -REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt) - - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE) - - Param<Tick> clock; - - Param<Addr> addr; - SimObjectParam<MemoryController *> mmu; - SimObjectParam<PhysicalMemory *> physmem; - SimObjectParam<PciConfigAll *> configspace; - SimObjectParam<PciConfigData *> configdata; - SimObjectParam<Platform *> platform; - Param<uint32_t> pci_bus; - Param<uint32_t> pci_dev; - Param<uint32_t> pci_func; - - SimObjectParam<HierParams *> hier; - SimObjectParam<Bus*> pio_bus; - SimObjectParam<Bus*> dma_bus; - SimObjectParam<Bus*> payload_bus; - Param<bool> dma_desc_free; - Param<bool> dma_data_free; - Param<Tick> dma_read_delay; - Param<Tick> dma_write_delay; - Param<Tick> dma_read_factor; - Param<Tick> dma_write_factor; - Param<bool> dma_no_allocate; - Param<Tick> pio_latency; - Param<Tick> intr_delay; - - Param<Tick> rx_delay; - Param<Tick> tx_delay; - Param<uint32_t> rx_fifo_size; - Param<uint32_t> tx_fifo_size; - - Param<bool> rx_filter; - Param<string> hardware_address; - Param<bool> rx_thread; - Param<bool> tx_thread; - Param<bool> rss; - -END_DECLARE_SIM_OBJECT_PARAMS(NSGigE) - -BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE) - - INIT_PARAM(clock, "State machine processor frequency"), - - INIT_PARAM(addr, "Device Address"), - INIT_PARAM(mmu, "Memory Controller"), - INIT_PARAM(physmem, "Physical Memory"), - INIT_PARAM(configspace, "PCI Configspace"), - INIT_PARAM(configdata, "PCI Config data"), - INIT_PARAM(platform, "Platform"), - INIT_PARAM(pci_bus, "PCI bus"), - INIT_PARAM(pci_dev, "PCI device number"), - INIT_PARAM(pci_func, "PCI function code"), - - INIT_PARAM(hier, "Hierarchy global variables"), - INIT_PARAM(pio_bus, ""), - INIT_PARAM(dma_bus, ""), - INIT_PARAM(payload_bus, "The IO Bus to attach to for payload"), - INIT_PARAM(dma_desc_free, "DMA of Descriptors is free"), - INIT_PARAM(dma_data_free, "DMA of Data is free"), - INIT_PARAM(dma_read_delay, "fixed delay for dma reads"), - INIT_PARAM(dma_write_delay, "fixed delay for dma writes"), - INIT_PARAM(dma_read_factor, "multiplier for dma reads"), - INIT_PARAM(dma_write_factor, "multiplier for dma writes"), - INIT_PARAM(dma_no_allocate, "Should DMA reads allocate cache lines"), - INIT_PARAM(pio_latency, "Programmed IO latency in bus cycles"), - INIT_PARAM(intr_delay, "Interrupt Delay in microseconds"), - - INIT_PARAM(rx_delay, "Receive Delay"), - INIT_PARAM(tx_delay, "Transmit Delay"), - INIT_PARAM(rx_fifo_size, "max size in bytes of rxFifo"), - INIT_PARAM(tx_fifo_size, "max size in bytes of txFifo"), - - INIT_PARAM(rx_filter, "Enable Receive Filter"), - INIT_PARAM(hardware_address, "Ethernet Hardware Address"), - INIT_PARAM(rx_thread, ""), - INIT_PARAM(tx_thread, ""), - INIT_PARAM(rss, "") - -END_INIT_SIM_OBJECT_PARAMS(NSGigE) - - -CREATE_SIM_OBJECT(NSGigE) -{ - NSGigE::Params *params = new NSGigE::Params; - - params->name = getInstanceName(); - - params->clock = clock; - - params->mmu = mmu; - params->pmem = physmem; - params->configSpace = configspace; - params->configData = configdata; - params->plat = platform; - params->busNum = pci_bus; - params->deviceNum = pci_dev; - params->functionNum = pci_func; - - params->hier = hier; - params->pio_bus = pio_bus; - params->header_bus = dma_bus; - params->payload_bus = payload_bus; - params->dma_desc_free = dma_desc_free; - params->dma_data_free = dma_data_free; - params->dma_read_delay = dma_read_delay; - params->dma_write_delay = dma_write_delay; - params->dma_read_factor = dma_read_factor; - params->dma_write_factor = dma_write_factor; - params->dma_no_allocate = dma_no_allocate; - params->pio_latency = pio_latency; - params->intr_delay = intr_delay; - - params->rx_delay = rx_delay; - params->tx_delay = tx_delay; - params->rx_fifo_size = rx_fifo_size; - params->tx_fifo_size = tx_fifo_size; - - params->rx_filter = rx_filter; - params->eaddr = hardware_address; - params->rx_thread = rx_thread; - params->tx_thread = tx_thread; - params->rss = rss; - - return new NSGigE(params); -} - -REGISTER_SIM_OBJECT("NSGigE", NSGigE) diff --git a/dev/ns_gige.hh b/dev/ns_gige.hh deleted file mode 100644 index 59c55056e..000000000 --- a/dev/ns_gige.hh +++ /dev/null @@ -1,487 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Device module for modelling the National Semiconductor - * DP83820 ethernet controller - */ - -#ifndef __DEV_NS_GIGE_HH__ -#define __DEV_NS_GIGE_HH__ - -#include "base/inet.hh" -#include "base/statistics.hh" -#include "dev/etherint.hh" -#include "dev/etherpkt.hh" -#include "dev/io_device.hh" -#include "dev/ns_gige_reg.h" -#include "dev/pcidev.hh" -#include "dev/pktfifo.hh" -#include "mem/bus/bus.hh" -#include "sim/eventq.hh" - -// Hash filtering constants -const uint16_t FHASH_ADDR = 0x100; -const uint16_t FHASH_SIZE = 0x100; - -// EEPROM constants -const uint8_t EEPROM_READ = 0x2; -const uint8_t EEPROM_SIZE = 64; // Size in words of NSC93C46 EEPROM -const uint8_t EEPROM_PMATCH2_ADDR = 0xA; // EEPROM Address of PMATCH word 2 -const uint8_t EEPROM_PMATCH1_ADDR = 0xB; // EEPROM Address of PMATCH word 1 -const uint8_t EEPROM_PMATCH0_ADDR = 0xC; // EEPROM Address of PMATCH word 0 - -/** - * Ethernet device registers - */ -struct dp_regs { - uint32_t command; - uint32_t config; - uint32_t mear; - uint32_t ptscr; - uint32_t isr; - uint32_t imr; - uint32_t ier; - uint32_t ihr; - uint32_t txdp; - uint32_t txdp_hi; - uint32_t txcfg; - uint32_t gpior; - uint32_t rxdp; - uint32_t rxdp_hi; - uint32_t rxcfg; - uint32_t pqcr; - uint32_t wcsr; - uint32_t pcr; - uint32_t rfcr; - uint32_t rfdr; - uint32_t brar; - uint32_t brdr; - uint32_t srr; - uint32_t mibc; - uint32_t vrcr; - uint32_t vtcr; - uint32_t vdr; - uint32_t ccsr; - uint32_t tbicr; - uint32_t tbisr; - uint32_t tanar; - uint32_t tanlpar; - uint32_t taner; - uint32_t tesr; -}; - -struct dp_rom { - /** - * for perfect match memory. - * the linux driver doesn't use any other ROM - */ - uint8_t perfectMatch[ETH_ADDR_LEN]; - - /** - * for hash table memory. - * used by the freebsd driver - */ - uint8_t filterHash[FHASH_SIZE]; -}; - -class NSGigEInt; -class PhysicalMemory; -class BaseInterface; -class HierParams; -class Bus; -class PciConfigAll; - -/** - * NS DP83820 Ethernet device model - */ -class NSGigE : public PciDev -{ - public: - /** Transmit State Machine states */ - enum TxState - { - txIdle, - txDescRefr, - txDescRead, - txFifoBlock, - txFragRead, - txDescWrite, - txAdvance - }; - - /** Receive State Machine States */ - enum RxState - { - rxIdle, - rxDescRefr, - rxDescRead, - rxFifoBlock, - rxFragWrite, - rxDescWrite, - rxAdvance - }; - - enum DmaState - { - dmaIdle, - dmaReading, - dmaWriting, - dmaReadWaiting, - dmaWriteWaiting - }; - - /** EEPROM State Machine States */ - enum EEPROMState - { - eepromStart, - eepromGetOpcode, - eepromGetAddress, - eepromRead - }; - - private: - Addr addr; - static const Addr size = sizeof(dp_regs); - - protected: - /** device register file */ - dp_regs regs; - dp_rom rom; - - /** pci settings */ - bool ioEnable; -#if 0 - bool memEnable; - bool bmEnable; -#endif - - /*** BASIC STRUCTURES FOR TX/RX ***/ - /* Data FIFOs */ - PacketFifo txFifo; - PacketFifo rxFifo; - - /** various helper vars */ - PacketPtr txPacket; - PacketPtr rxPacket; - uint8_t *txPacketBufPtr; - uint8_t *rxPacketBufPtr; - uint32_t txXferLen; - uint32_t rxXferLen; - bool rxDmaFree; - bool txDmaFree; - - /** DescCaches */ - ns_desc32 txDesc32; - ns_desc32 rxDesc32; - ns_desc64 txDesc64; - ns_desc64 rxDesc64; - - /* state machine cycle time */ - Tick clock; - inline Tick cycles(int numCycles) const { return numCycles * clock; } - - /* tx State Machine */ - TxState txState; - bool txEnable; - - /** Current Transmit Descriptor Done */ - bool CTDD; - /** halt the tx state machine after next packet */ - bool txHalt; - /** ptr to the next byte in the current fragment */ - Addr txFragPtr; - /** count of bytes remaining in the current descriptor */ - uint32_t txDescCnt; - DmaState txDmaState; - - /** rx State Machine */ - RxState rxState; - bool rxEnable; - - /** Current Receive Descriptor Done */ - bool CRDD; - /** num of bytes in the current packet being drained from rxDataFifo */ - uint32_t rxPktBytes; - /** halt the rx state machine after current packet */ - bool rxHalt; - /** ptr to the next byte in current fragment */ - Addr rxFragPtr; - /** count of bytes remaining in the current descriptor */ - uint32_t rxDescCnt; - DmaState rxDmaState; - - bool extstsEnable; - - /** EEPROM State Machine */ - EEPROMState eepromState; - bool eepromClk; - uint8_t eepromBitsToRx; - uint8_t eepromOpcode; - uint8_t eepromAddress; - uint16_t eepromData; - - protected: - Tick dmaReadDelay; - Tick dmaWriteDelay; - - Tick dmaReadFactor; - Tick dmaWriteFactor; - - void *rxDmaData; - Addr rxDmaAddr; - int rxDmaLen; - bool doRxDmaRead(); - bool doRxDmaWrite(); - void rxDmaReadCopy(); - void rxDmaWriteCopy(); - - void *txDmaData; - Addr txDmaAddr; - int txDmaLen; - bool doTxDmaRead(); - bool doTxDmaWrite(); - void txDmaReadCopy(); - void txDmaWriteCopy(); - - void rxDmaReadDone(); - friend class EventWrapper<NSGigE, &NSGigE::rxDmaReadDone>; - EventWrapper<NSGigE, &NSGigE::rxDmaReadDone> rxDmaReadEvent; - - void rxDmaWriteDone(); - friend class EventWrapper<NSGigE, &NSGigE::rxDmaWriteDone>; - EventWrapper<NSGigE, &NSGigE::rxDmaWriteDone> rxDmaWriteEvent; - - void txDmaReadDone(); - friend class EventWrapper<NSGigE, &NSGigE::txDmaReadDone>; - EventWrapper<NSGigE, &NSGigE::txDmaReadDone> txDmaReadEvent; - - void txDmaWriteDone(); - friend class EventWrapper<NSGigE, &NSGigE::txDmaWriteDone>; - EventWrapper<NSGigE, &NSGigE::txDmaWriteDone> txDmaWriteEvent; - - bool dmaDescFree; - bool dmaDataFree; - - protected: - Tick txDelay; - Tick rxDelay; - - void txReset(); - void rxReset(); - void regsReset(); - - void rxKick(); - Tick rxKickTick; - typedef EventWrapper<NSGigE, &NSGigE::rxKick> RxKickEvent; - friend void RxKickEvent::process(); - RxKickEvent rxKickEvent; - - void txKick(); - Tick txKickTick; - typedef EventWrapper<NSGigE, &NSGigE::txKick> TxKickEvent; - friend void TxKickEvent::process(); - TxKickEvent txKickEvent; - - void eepromKick(); - - /** - * Retransmit event - */ - void transmit(); - void txEventTransmit() - { - transmit(); - if (txState == txFifoBlock) - txKick(); - } - typedef EventWrapper<NSGigE, &NSGigE::txEventTransmit> TxEvent; - friend void TxEvent::process(); - TxEvent txEvent; - - void txDump() const; - void rxDump() const; - - /** - * receive address filter - */ - bool rxFilterEnable; - bool rxFilter(const PacketPtr &packet); - bool acceptBroadcast; - bool acceptMulticast; - bool acceptUnicast; - bool acceptPerfect; - bool acceptArp; - bool multicastHashEnable; - - PhysicalMemory *physmem; - - /** - * Interrupt management - */ - void devIntrPost(uint32_t interrupts); - void devIntrClear(uint32_t interrupts); - void devIntrChangeMask(); - - Tick intrDelay; - Tick intrTick; - bool cpuPendingIntr; - void cpuIntrPost(Tick when); - void cpuInterrupt(); - void cpuIntrClear(); - - typedef EventWrapper<NSGigE, &NSGigE::cpuInterrupt> IntrEvent; - friend void IntrEvent::process(); - IntrEvent *intrEvent; - NSGigEInt *interface; - - public: - struct Params : public PciDev::Params - { - PhysicalMemory *pmem; - HierParams *hier; - Bus *pio_bus; - Bus *header_bus; - Bus *payload_bus; - Tick clock; - Tick intr_delay; - Tick tx_delay; - Tick rx_delay; - Tick pio_latency; - bool dma_desc_free; - bool dma_data_free; - Tick dma_read_delay; - Tick dma_write_delay; - Tick dma_read_factor; - Tick dma_write_factor; - bool rx_filter; - Net::EthAddr eaddr; - uint32_t tx_fifo_size; - uint32_t rx_fifo_size; - bool rx_thread; - bool tx_thread; - bool rss; - bool dma_no_allocate; - }; - - NSGigE(Params *params); - ~NSGigE(); - const Params *params() const { return (const Params *)_params; } - - virtual void writeConfig(int offset, int size, const uint8_t *data); - virtual void readConfig(int offset, int size, uint8_t *data); - - virtual Fault read(MemReqPtr &req, uint8_t *data); - virtual Fault write(MemReqPtr &req, const uint8_t *data); - - bool cpuIntrPending() const; - void cpuIntrAck() { cpuIntrClear(); } - - bool recvPacket(PacketPtr packet); - void transferDone(); - - void setInterface(NSGigEInt *i) { assert(!interface); interface = i; } - - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); - - public: - void regStats(); - - private: - Stats::Scalar<> txBytes; - Stats::Scalar<> rxBytes; - Stats::Scalar<> txPackets; - Stats::Scalar<> rxPackets; - Stats::Scalar<> txIpChecksums; - Stats::Scalar<> rxIpChecksums; - Stats::Scalar<> txTcpChecksums; - Stats::Scalar<> rxTcpChecksums; - Stats::Scalar<> txUdpChecksums; - Stats::Scalar<> rxUdpChecksums; - Stats::Scalar<> descDmaReads; - Stats::Scalar<> descDmaWrites; - Stats::Scalar<> descDmaRdBytes; - Stats::Scalar<> descDmaWrBytes; - Stats::Formula totBandwidth; - Stats::Formula totPackets; - Stats::Formula totBytes; - Stats::Formula totPacketRate; - Stats::Formula txBandwidth; - Stats::Formula rxBandwidth; - Stats::Formula txPacketRate; - Stats::Formula rxPacketRate; - Stats::Scalar<> postedSwi; - Stats::Formula coalescedSwi; - Stats::Scalar<> totalSwi; - Stats::Scalar<> postedRxIdle; - Stats::Formula coalescedRxIdle; - Stats::Scalar<> totalRxIdle; - Stats::Scalar<> postedRxOk; - Stats::Formula coalescedRxOk; - Stats::Scalar<> totalRxOk; - Stats::Scalar<> postedRxDesc; - Stats::Formula coalescedRxDesc; - Stats::Scalar<> totalRxDesc; - Stats::Scalar<> postedTxOk; - Stats::Formula coalescedTxOk; - Stats::Scalar<> totalTxOk; - Stats::Scalar<> postedTxIdle; - Stats::Formula coalescedTxIdle; - Stats::Scalar<> totalTxIdle; - Stats::Scalar<> postedTxDesc; - Stats::Formula coalescedTxDesc; - Stats::Scalar<> totalTxDesc; - Stats::Scalar<> postedRxOrn; - Stats::Formula coalescedRxOrn; - Stats::Scalar<> totalRxOrn; - Stats::Formula coalescedTotal; - Stats::Scalar<> postedInterrupts; - Stats::Scalar<> droppedPackets; - - public: - Tick cacheAccess(MemReqPtr &req); -}; - -/* - * Ethernet Interface for an Ethernet Device - */ -class NSGigEInt : public EtherInt -{ - private: - NSGigE *dev; - - public: - NSGigEInt(const std::string &name, NSGigE *d) - : EtherInt(name), dev(d) { dev->setInterface(this); } - - virtual bool recvPacket(PacketPtr pkt) { return dev->recvPacket(pkt); } - virtual void sendDone() { dev->transferDone(); } -}; - -#endif // __DEV_NS_GIGE_HH__ diff --git a/dev/ns_gige_reg.h b/dev/ns_gige_reg.h deleted file mode 100644 index 5f6fa2cc5..000000000 --- a/dev/ns_gige_reg.h +++ /dev/null @@ -1,351 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Ethernet device register definitions for the National - * Semiconductor DP83820 Ethernet controller - */ - -#ifndef __DEV_NS_GIGE_REG_H__ -#define __DEV_NS_GIGE_REG_H__ - -/* Device Register Address Map */ -#define CR 0x00 -#define CFGR 0x04 -#define MEAR 0x08 -#define PTSCR 0x0c -#define ISR 0x10 -#define IMR 0x14 -#define IER 0x18 -#define IHR 0x1c -#define TXDP 0x20 -#define TXDP_HI 0x24 -#define TX_CFG 0x28 -#define GPIOR 0x2c -#define RXDP 0x30 -#define RXDP_HI 0x34 -#define RX_CFG 0x38 -#define PQCR 0x3c -#define WCSR 0x40 -#define PCR 0x44 -#define RFCR 0x48 -#define RFDR 0x4c -#define BRAR 0x50 -#define BRDR 0x54 -#define SRR 0x58 -#define MIBC 0x5c -#define MIB_START 0x60 -#define MIB_END 0x88 -#define VRCR 0xbc -#define VTCR 0xc0 -#define VDR 0xc4 -#define CCSR 0xcc -#define TBICR 0xe0 -#define TBISR 0xe4 -#define TANAR 0xe8 -#define TANLPAR 0xec -#define TANER 0xf0 -#define TESR 0xf4 -#define M5REG 0xf8 -#define LAST 0xf8 -#define RESERVED 0xfc - -/* Chip Command Register */ -#define CR_TXE 0x00000001 -#define CR_TXD 0x00000002 -#define CR_RXE 0x00000004 -#define CR_RXD 0x00000008 -#define CR_TXR 0x00000010 -#define CR_RXR 0x00000020 -#define CR_SWI 0x00000080 -#define CR_RST 0x00000100 - -/* configuration register */ -#define CFGR_LNKSTS 0x80000000 -#define CFGR_SPDSTS 0x60000000 -#define CFGR_SPDSTS1 0x40000000 -#define CFGR_SPDSTS0 0x20000000 -#define CFGR_DUPSTS 0x10000000 -#define CFGR_TBI_EN 0x01000000 -#define CFGR_RESERVED 0x0e000000 -#define CFGR_MODE_1000 0x00400000 -#define CFGR_AUTO_1000 0x00200000 -#define CFGR_PINT_CTL 0x001c0000 -#define CFGR_PINT_DUPSTS 0x00100000 -#define CFGR_PINT_LNKSTS 0x00080000 -#define CFGR_PINT_SPDSTS 0x00040000 -#define CFGR_TMRTEST 0x00020000 -#define CFGR_MRM_DIS 0x00010000 -#define CFGR_MWI_DIS 0x00008000 -#define CFGR_T64ADDR 0x00004000 -#define CFGR_PCI64_DET 0x00002000 -#define CFGR_DATA64_EN 0x00001000 -#define CFGR_M64ADDR 0x00000800 -#define CFGR_PHY_RST 0x00000400 -#define CFGR_PHY_DIS 0x00000200 -#define CFGR_EXTSTS_EN 0x00000100 -#define CFGR_REQALG 0x00000080 -#define CFGR_SB 0x00000040 -#define CFGR_POW 0x00000020 -#define CFGR_EXD 0x00000010 -#define CFGR_PESEL 0x00000008 -#define CFGR_BROM_DIS 0x00000004 -#define CFGR_EXT_125 0x00000002 -#define CFGR_BEM 0x00000001 - -/* EEPROM access register */ -#define MEAR_EEDI 0x00000001 -#define MEAR_EEDO 0x00000002 -#define MEAR_EECLK 0x00000004 -#define MEAR_EESEL 0x00000008 -#define MEAR_MDIO 0x00000010 -#define MEAR_MDDIR 0x00000020 -#define MEAR_MDC 0x00000040 - -/* PCI test control register */ -#define PTSCR_EEBIST_FAIL 0x00000001 -#define PTSCR_EEBIST_EN 0x00000002 -#define PTSCR_EELOAD_EN 0x00000004 -#define PTSCR_RBIST_FAIL 0x000001b8 -#define PTSCR_RBIST_DONE 0x00000200 -#define PTSCR_RBIST_EN 0x00000400 -#define PTSCR_RBIST_RST 0x00002000 -#define PTSCR_RBIST_RDONLY 0x000003f9 - -/* interrupt status register */ -#define ISR_RESERVE 0x80000000 -#define ISR_TXDESC3 0x40000000 -#define ISR_TXDESC2 0x20000000 -#define ISR_TXDESC1 0x10000000 -#define ISR_TXDESC0 0x08000000 -#define ISR_RXDESC3 0x04000000 -#define ISR_RXDESC2 0x02000000 -#define ISR_RXDESC1 0x01000000 -#define ISR_RXDESC0 0x00800000 -#define ISR_TXRCMP 0x00400000 -#define ISR_RXRCMP 0x00200000 -#define ISR_DPERR 0x00100000 -#define ISR_SSERR 0x00080000 -#define ISR_RMABT 0x00040000 -#define ISR_RTABT 0x00020000 -#define ISR_RXSOVR 0x00010000 -#define ISR_HIBINT 0x00008000 -#define ISR_PHY 0x00004000 -#define ISR_PME 0x00002000 -#define ISR_SWI 0x00001000 -#define ISR_MIB 0x00000800 -#define ISR_TXURN 0x00000400 -#define ISR_TXIDLE 0x00000200 -#define ISR_TXERR 0x00000100 -#define ISR_TXDESC 0x00000080 -#define ISR_TXOK 0x00000040 -#define ISR_RXORN 0x00000020 -#define ISR_RXIDLE 0x00000010 -#define ISR_RXEARLY 0x00000008 -#define ISR_RXERR 0x00000004 -#define ISR_RXDESC 0x00000002 -#define ISR_RXOK 0x00000001 -#define ISR_ALL 0x7FFFFFFF -#define ISR_DELAY (ISR_TXIDLE|ISR_TXDESC|ISR_TXOK| \ - ISR_RXIDLE|ISR_RXDESC|ISR_RXOK) -#define ISR_NODELAY (ISR_ALL & ~ISR_DELAY) -#define ISR_IMPL (ISR_SWI|ISR_TXIDLE|ISR_TXDESC|ISR_TXOK|ISR_RXORN| \ - ISR_RXIDLE|ISR_RXDESC|ISR_RXOK) -#define ISR_NOIMPL (ISR_ALL & ~ISR_IMPL) - -/* transmit configuration register */ -#define TX_CFG_CSI 0x80000000 -#define TX_CFG_HBI 0x40000000 -#define TX_CFG_MLB 0x20000000 -#define TX_CFG_ATP 0x10000000 -#define TX_CFG_ECRETRY 0x00800000 -#define TX_CFG_BRST_DIS 0x00080000 -#define TX_CFG_MXDMA1024 0x00000000 -#define TX_CFG_MXDMA512 0x00700000 -#define TX_CFG_MXDMA256 0x00600000 -#define TX_CFG_MXDMA128 0x00500000 -#define TX_CFG_MXDMA64 0x00400000 -#define TX_CFG_MXDMA32 0x00300000 -#define TX_CFG_MXDMA16 0x00200000 -#define TX_CFG_MXDMA8 0x00100000 -#define TX_CFG_MXDMA 0x00700000 - -#define TX_CFG_FLTH_MASK 0x0000ff00 -#define TX_CFG_DRTH_MASK 0x000000ff - -/*general purpose I/O control register */ -#define GPIOR_UNUSED 0xffff8000 -#define GPIOR_GP5_IN 0x00004000 -#define GPIOR_GP4_IN 0x00002000 -#define GPIOR_GP3_IN 0x00001000 -#define GPIOR_GP2_IN 0x00000800 -#define GPIOR_GP1_IN 0x00000400 -#define GPIOR_GP5_OE 0x00000200 -#define GPIOR_GP4_OE 0x00000100 -#define GPIOR_GP3_OE 0x00000080 -#define GPIOR_GP2_OE 0x00000040 -#define GPIOR_GP1_OE 0x00000020 -#define GPIOR_GP5_OUT 0x00000010 -#define GPIOR_GP4_OUT 0x00000008 -#define GPIOR_GP3_OUT 0x00000004 -#define GPIOR_GP2_OUT 0x00000002 -#define GPIOR_GP1_OUT 0x00000001 - -/* receive configuration register */ -#define RX_CFG_AEP 0x80000000 -#define RX_CFG_ARP 0x40000000 -#define RX_CFG_STRIPCRC 0x20000000 -#define RX_CFG_RX_FD 0x10000000 -#define RX_CFG_ALP 0x08000000 -#define RX_CFG_AIRL 0x04000000 -#define RX_CFG_MXDMA512 0x00700000 -#define RX_CFG_MXDMA 0x00700000 -#define RX_CFG_DRTH 0x0000003e -#define RX_CFG_DRTH0 0x00000002 - -/* pause control status register */ -#define PCR_PSEN (1 << 31) -#define PCR_PS_MCAST (1 << 30) -#define PCR_PS_DA (1 << 29) -#define PCR_STHI_8 (3 << 23) -#define PCR_STLO_4 (1 << 23) -#define PCR_FFHI_8K (3 << 21) -#define PCR_FFLO_4K (1 << 21) -#define PCR_PAUSE_CNT 0xFFFE - -/*receive filter/match control register */ -#define RFCR_RFEN 0x80000000 -#define RFCR_AAB 0x40000000 -#define RFCR_AAM 0x20000000 -#define RFCR_AAU 0x10000000 -#define RFCR_APM 0x08000000 -#define RFCR_APAT 0x07800000 -#define RFCR_APAT3 0x04000000 -#define RFCR_APAT2 0x02000000 -#define RFCR_APAT1 0x01000000 -#define RFCR_APAT0 0x00800000 -#define RFCR_AARP 0x00400000 -#define RFCR_MHEN 0x00200000 -#define RFCR_UHEN 0x00100000 -#define RFCR_ULM 0x00080000 -#define RFCR_RFADDR 0x000003ff - -/* receive filter/match data register */ -#define RFDR_BMASK 0x00030000 -#define RFDR_RFDATA0 0x000000ff -#define RFDR_RFDATA1 0x0000ff00 - -/* management information base control register */ -#define MIBC_MIBS 0x00000008 -#define MIBC_ACLR 0x00000004 -#define MIBC_FRZ 0x00000002 -#define MIBC_WRN 0x00000001 - -/* VLAN/IP receive control register */ -#define VRCR_RUDPE 0x00000080 -#define VRCR_RTCPE 0x00000040 -#define VRCR_RIPE 0x00000020 -#define VRCR_IPEN 0x00000010 -#define VRCR_DUTF 0x00000008 -#define VRCR_DVTF 0x00000004 -#define VRCR_VTREN 0x00000002 -#define VRCR_VTDEN 0x00000001 - -/* VLAN/IP transmit control register */ -#define VTCR_PPCHK 0x00000008 -#define VTCR_GCHK 0x00000004 -#define VTCR_VPPTI 0x00000002 -#define VTCR_VGTI 0x00000001 - -/* Clockrun Control/Status Register */ -#define CCSR_CLKRUN_EN 0x00000001 - -/* TBI control register */ -#define TBICR_MR_LOOPBACK 0x00004000 -#define TBICR_MR_AN_ENABLE 0x00001000 -#define TBICR_MR_RESTART_AN 0x00000200 - -/* TBI status register */ -#define TBISR_MR_LINK_STATUS 0x00000020 -#define TBISR_MR_AN_COMPLETE 0x00000004 - -/* TBI auto-negotiation advertisement register */ -#define TANAR_NP 0x00008000 -#define TANAR_RF2 0x00002000 -#define TANAR_RF1 0x00001000 -#define TANAR_PS2 0x00000100 -#define TANAR_PS1 0x00000080 -#define TANAR_HALF_DUP 0x00000040 -#define TANAR_FULL_DUP 0x00000020 -#define TANAR_UNUSED 0x00000E1F - -/* M5 control register */ -#define M5REG_RESERVED 0xfffffffc -#define M5REG_RSS 0x00000004 -#define M5REG_RX_THREAD 0x00000002 -#define M5REG_TX_THREAD 0x00000001 - -struct ns_desc32 { - uint32_t link; /* link field to next descriptor in linked list */ - uint32_t bufptr; /* pointer to the first fragment or buffer */ - uint32_t cmdsts; /* command/status field */ - uint32_t extsts; /* extended status field for VLAN and IP info */ -}; - -struct ns_desc64 { - uint64_t link; /* link field to next descriptor in linked list */ - uint64_t bufptr; /* pointer to the first fragment or buffer */ - uint32_t cmdsts; /* command/status field */ - uint32_t extsts; /* extended status field for VLAN and IP info */ -}; - -/* cmdsts flags for descriptors */ -#define CMDSTS_OWN 0x80000000 -#define CMDSTS_MORE 0x40000000 -#define CMDSTS_INTR 0x20000000 -#define CMDSTS_ERR 0x10000000 -#define CMDSTS_OK 0x08000000 -#define CMDSTS_LEN_MASK 0x0000ffff - -#define CMDSTS_DEST_MASK 0x01800000 -#define CMDSTS_DEST_SELF 0x00800000 -#define CMDSTS_DEST_MULTI 0x01000000 - -/* extended flags for descriptors */ -#define EXTSTS_UDPERR 0x00400000 -#define EXTSTS_UDPPKT 0x00200000 -#define EXTSTS_TCPERR 0x00100000 -#define EXTSTS_TCPPKT 0x00080000 -#define EXTSTS_IPERR 0x00040000 -#define EXTSTS_IPPKT 0x00020000 - - -/* speed status */ -#define SPDSTS_POLARITY (CFGR_SPDSTS1 | CFGR_SPDSTS0 | CFGR_DUPSTS | (lnksts ? CFGR_LNKSTS : 0)) - -#endif /* __DEV_NS_GIGE_REG_H__ */ diff --git a/dev/pciconfigall.cc b/dev/pciconfigall.cc deleted file mode 100644 index d55084fa5..000000000 --- a/dev/pciconfigall.cc +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* @file - * PCI Configspace implementation - */ - -#include <deque> -#include <string> -#include <vector> -#include <bitset> - -#include "base/trace.hh" -#include "dev/pciconfigall.hh" -#include "dev/pcidev.hh" -#include "dev/pcireg.h" -#include "mem/bus/bus.hh" -#include "mem/bus/pio_interface.hh" -#include "mem/bus/pio_interface_impl.hh" -#include "mem/functional/memory_control.hh" -#include "sim/builder.hh" -#include "sim/system.hh" - -using namespace std; -using namespace TheISA; - -PciConfigAll::PciConfigAll(const string &name, - Addr a, MemoryController *mmu, - HierParams *hier, Bus *pio_bus, Tick pio_latency) - : PioDevice(name, NULL), addr(a) -{ - mmu->add_child(this, RangeSize(addr, size)); - - if (pio_bus) { - pioInterface = newPioInterface(name + ".pio", hier, pio_bus, this, - &PciConfigAll::cacheAccess); - pioInterface->addAddrRange(RangeSize(addr, size)); - pioLatency = pio_latency * pio_bus->clockRate; - } - - // Make all the pointers to devices null - for(int x=0; x < MAX_PCI_DEV; x++) - for(int y=0; y < MAX_PCI_FUNC; y++) - devices[x][y] = NULL; -} - -// If two interrupts share the same line largely bad things will happen. -// Since we don't track how many times an interrupt was set and correspondingly -// cleared two devices on the same interrupt line and assert and deassert each -// others interrupt "line". Interrupts will not work correctly. -void -PciConfigAll::startup() -{ - bitset<256> intLines; - PciDev *tempDev; - uint8_t intline; - - for (int x = 0; x < MAX_PCI_DEV; x++) { - for (int y = 0; y < MAX_PCI_FUNC; y++) { - if (devices[x][y] != NULL) { - tempDev = devices[x][y]; - intline = tempDev->interruptLine(); - if (intLines.test(intline)) - warn("Interrupt line %#X is used multiple times" - "(You probably want to fix this).\n", (uint32_t)intline); - else - intLines.set(intline); - } // devices != NULL - } // PCI_FUNC - } // PCI_DEV - -} - -Fault -PciConfigAll::read(MemReqPtr &req, uint8_t *data) -{ - - Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)); - - DPRINTF(PciConfigAll, "read va=%#x da=%#x size=%d\n", - req->vaddr, daddr, req->size); - - int device = (daddr >> 11) & 0x1F; - int func = (daddr >> 8) & 0x7; - int reg = daddr & 0xFF; - - if (devices[device][func] == NULL) { - switch (req->size) { - // case sizeof(uint64_t): - // *(uint64_t*)data = 0xFFFFFFFFFFFFFFFF; - // return NoFault; - case sizeof(uint32_t): - *(uint32_t*)data = 0xFFFFFFFF; - return NoFault; - case sizeof(uint16_t): - *(uint16_t*)data = 0xFFFF; - return NoFault; - case sizeof(uint8_t): - *(uint8_t*)data = 0xFF; - return NoFault; - default: - panic("invalid access size(?) for PCI configspace!\n"); - } - } else { - switch (req->size) { - case sizeof(uint32_t): - case sizeof(uint16_t): - case sizeof(uint8_t): - devices[device][func]->readConfig(reg, req->size, data); - return NoFault; - default: - panic("invalid access size(?) for PCI configspace!\n"); - } - } - - DPRINTFN("PCI Configspace ERROR: read daddr=%#x size=%d\n", - daddr, req->size); - - return NoFault; -} - -Fault -PciConfigAll::write(MemReqPtr &req, const uint8_t *data) -{ - Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)); - - int device = (daddr >> 11) & 0x1F; - int func = (daddr >> 8) & 0x7; - int reg = daddr & 0xFF; - - if (devices[device][func] == NULL) - panic("Attempting to write to config space on non-existant device\n"); - else if (req->size != sizeof(uint8_t) && - req->size != sizeof(uint16_t) && - req->size != sizeof(uint32_t)) - panic("invalid access size(?) for PCI configspace!\n"); - - DPRINTF(PciConfigAll, "write - va=%#x size=%d data=%#x\n", - req->vaddr, req->size, *(uint32_t*)data); - - devices[device][func]->writeConfig(reg, req->size, data); - - return NoFault; -} - -void -PciConfigAll::serialize(std::ostream &os) -{ - /* - * There is no state associated with this object that requires - * serialization. The only real state are the device pointers - * which are all setup by the constructor of the PciDev class - */ -} - -void -PciConfigAll::unserialize(Checkpoint *cp, const std::string §ion) -{ - /* - * There is no state associated with this object that requires - * serialization. The only real state are the device pointers - * which are all setup by the constructor of the PciDev class - */ -} - -Tick -PciConfigAll::cacheAccess(MemReqPtr &req) -{ - return curTick + pioLatency; -} - -#ifndef DOXYGEN_SHOULD_SKIP_THIS - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(PciConfigAll) - - SimObjectParam<MemoryController *> mmu; - Param<Addr> addr; - Param<Addr> mask; - SimObjectParam<Bus*> pio_bus; - Param<Tick> pio_latency; - SimObjectParam<HierParams *> hier; - -END_DECLARE_SIM_OBJECT_PARAMS(PciConfigAll) - -BEGIN_INIT_SIM_OBJECT_PARAMS(PciConfigAll) - - INIT_PARAM(mmu, "Memory Controller"), - INIT_PARAM(addr, "Device Address"), - INIT_PARAM(mask, "Address Mask"), - INIT_PARAM_DFLT(pio_bus, "The IO Bus to attach to", NULL), - INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), - INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams) - -END_INIT_SIM_OBJECT_PARAMS(PciConfigAll) - -CREATE_SIM_OBJECT(PciConfigAll) -{ - return new PciConfigAll(getInstanceName(), addr, mmu, hier, pio_bus, - pio_latency); -} - -REGISTER_SIM_OBJECT("PciConfigAll", PciConfigAll) - -#endif // DOXYGEN_SHOULD_SKIP_THIS diff --git a/dev/pciconfigall.hh b/dev/pciconfigall.hh deleted file mode 100644 index c6a0241d8..000000000 --- a/dev/pciconfigall.hh +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * @file - * PCI Config space implementation. - */ - -#ifndef __PCICONFIGALL_HH__ -#define __PCICONFIGALL_HH__ - -#include "dev/pcireg.h" -#include "base/range.hh" -#include "dev/io_device.hh" - - -static const uint32_t MAX_PCI_DEV = 32; -static const uint32_t MAX_PCI_FUNC = 8; - -class PciDev; -class MemoryController; - -/** - * PCI Config Space - * All of PCI config space needs to return -1 on Tsunami, except - * the devices that exist. This device maps the entire bus config - * space and passes the requests on to TsunamiPCIDev devices as - * appropriate. - */ -class PciConfigAll : public PioDevice -{ - private: - Addr addr; - static const Addr size = 0xffffff; - - /** - * Pointers to all the devices that are registered with this - * particular config space. - */ - PciDev* devices[MAX_PCI_DEV][MAX_PCI_FUNC]; - - public: - /** - * Constructor for PCIConfigAll - * @param name name of the object - * @param a base address of the write - * @param mmu the memory controller - * @param hier object to store parameters universal the device hierarchy - * @param bus The bus that this device is attached to - */ - PciConfigAll(const std::string &name, Addr a, MemoryController *mmu, - HierParams *hier, Bus *pio_bus, Tick pio_latency); - - - /** - * Check if a device exists. - * @param pcidev PCI device to check - * @param pcifunc PCI function to check - * @return true if device exists, false otherwise - */ - bool deviceExists(uint32_t pcidev, uint32_t pcifunc) - { return devices[pcidev][pcifunc] != NULL ? true : false; } - - /** - * Registers a device with the config space object. - * @param pcidev PCI device to register - * @param pcifunc PCI function to register - * @param device device to register - */ - void registerDevice(uint8_t pcidev, uint8_t pcifunc, PciDev *device) - { devices[pcidev][pcifunc] = device; } - - /** - * Read something in PCI config space. If the device does not exist - * -1 is returned, if the device does exist its PciDev::ReadConfig (or the - * virtual function that overrides) it is called. - * @param req Contains the address of the field to read. - * @param data Return the field read. - * @return The fault condition of the access. - */ - virtual Fault read(MemReqPtr &req, uint8_t *data); - - /** - * Write to PCI config spcae. If the device does not exit the simulator - * panics. If it does it is passed on the PciDev::WriteConfig (or the virtual - * function that overrides it). - * @param req Contains the address to write to. - * @param data The data to write. - * @return The fault condition of the access. - */ - - virtual Fault write(MemReqPtr &req, const uint8_t *data); - - /** - * Start up function to check if more than one person is using an interrupt line - * and print a warning if such a case exists - */ - virtual void startup(); - - /** - * Serialize this object to the given output stream. - * @param os The stream to serialize to. - */ - virtual void serialize(std::ostream &os); - - /** - * Reconstruct the state of this object from a checkpoint. - * @param cp The checkpoint use. - * @param section The section name of this object - */ - virtual void unserialize(Checkpoint *cp, const std::string §ion); - - /** - * Return how long this access will take. - * @param req the memory request to calcuate - * @return Tick when the request is done - */ - Tick cacheAccess(MemReqPtr &req); - -}; - -#endif // __PCICONFIGALL_HH__ diff --git a/dev/pcidev.cc b/dev/pcidev.cc deleted file mode 100644 index a05ee3803..000000000 --- a/dev/pcidev.cc +++ /dev/null @@ -1,427 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* @file - * A single PCI device configuration space entry. - */ - -#include <list> -#include <sstream> -#include <string> -#include <vector> - -#include "base/inifile.hh" -#include "base/misc.hh" -#include "base/str.hh" // for to_number -#include "base/trace.hh" -#include "dev/pcidev.hh" -#include "dev/pciconfigall.hh" -#include "mem/bus/bus.hh" -#include "mem/functional/memory_control.hh" -#include "sim/builder.hh" -#include "sim/param.hh" -#include "sim/root.hh" -#include "dev/tsunamireg.h" - -using namespace std; - -PciDev::PciDev(Params *p) - : DmaDevice(p->name, p->plat), _params(p), plat(p->plat), - configData(p->configData) -{ - // copy the config data from the PciConfigData object - if (configData) { - memcpy(config.data, configData->config.data, sizeof(config.data)); - memcpy(BARSize, configData->BARSize, sizeof(BARSize)); - memcpy(BARAddrs, configData->BARAddrs, sizeof(BARAddrs)); - } else - panic("NULL pointer to configuration data"); - - // Setup pointer in config space to point to this entry - if (p->configSpace->deviceExists(p->deviceNum, p->functionNum)) - panic("Two PCI devices occuping same dev: %#x func: %#x", - p->deviceNum, p->functionNum); - else - p->configSpace->registerDevice(p->deviceNum, p->functionNum, this); -} - -Fault -PciDev::read(MemReqPtr &req, uint8_t *data) -{ return NoFault; } - -Fault -PciDev::write(MemReqPtr &req, const uint8_t *data) -{ return NoFault; } - -Fault -PciDev::readBar0(MemReqPtr &req, Addr daddr, uint8_t *data) -{ panic("not implemented"); } - -Fault -PciDev::readBar1(MemReqPtr &req, Addr daddr, uint8_t *data) -{ panic("not implemented"); } - -Fault -PciDev::readBar2(MemReqPtr &req, Addr daddr, uint8_t *data) -{ panic("not implemented"); } - -Fault -PciDev::readBar3(MemReqPtr &req, Addr daddr, uint8_t *data) -{ panic("not implemented"); } - -Fault -PciDev::readBar4(MemReqPtr &req, Addr daddr, uint8_t *data) -{ panic("not implemented"); } - -Fault -PciDev::readBar5(MemReqPtr &req, Addr daddr, uint8_t *data) -{ panic("not implemented"); } - -Fault -PciDev::writeBar0(MemReqPtr &req, Addr daddr, const uint8_t *data) -{ panic("not implemented"); } - -Fault -PciDev::writeBar1(MemReqPtr &req, Addr daddr, const uint8_t *data) -{ panic("not implemented"); } - -Fault -PciDev::writeBar2(MemReqPtr &req, Addr daddr, const uint8_t *data) -{ panic("not implemented"); } - -Fault -PciDev::writeBar3(MemReqPtr &req, Addr daddr, const uint8_t *data) -{ panic("not implemented"); } - -Fault -PciDev::writeBar4(MemReqPtr &req, Addr daddr, const uint8_t *data) -{ panic("not implemented"); } - -Fault -PciDev::writeBar5(MemReqPtr &req, Addr daddr, const uint8_t *data) -{ panic("not implemented"); } - -void -PciDev::readConfig(int offset, int size, uint8_t *data) -{ - if (offset >= PCI_DEVICE_SPECIFIC) - panic("Device specific PCI config space not implemented!\n"); - - switch(size) { - case sizeof(uint8_t): - *data = config.data[offset]; - break; - case sizeof(uint16_t): - *(uint16_t*)data = *(uint16_t*)&config.data[offset]; - break; - case sizeof(uint32_t): - *(uint32_t*)data = *(uint32_t*)&config.data[offset]; - break; - default: - panic("Invalid PCI configuration read size!\n"); - } - - DPRINTF(PCIDEV, - "read device: %#x function: %#x register: %#x %d bytes: data: %#x\n", - params()->deviceNum, params()->functionNum, offset, size, - *(uint32_t*)data); -} - -void -PciDev::writeConfig(int offset, int size, const uint8_t *data) -{ - if (offset >= PCI_DEVICE_SPECIFIC) - panic("Device specific PCI config space not implemented!\n"); - - uint8_t &data8 = *(uint8_t*)data; - uint16_t &data16 = *(uint16_t*)data; - uint32_t &data32 = *(uint32_t*)data; - - DPRINTF(PCIDEV, - "write device: %#x function: %#x reg: %#x size: %d data: %#x\n", - params()->deviceNum, params()->functionNum, offset, size, data32); - - switch (size) { - case sizeof(uint8_t): // 1-byte access - switch (offset) { - case PCI0_INTERRUPT_LINE: - config.interruptLine = data8; - case PCI_CACHE_LINE_SIZE: - config.cacheLineSize = data8; - case PCI_LATENCY_TIMER: - config.latencyTimer = data8; - break; - /* Do nothing for these read-only registers */ - case PCI0_INTERRUPT_PIN: - case PCI0_MINIMUM_GRANT: - case PCI0_MAXIMUM_LATENCY: - case PCI_CLASS_CODE: - case PCI_REVISION_ID: - break; - default: - panic("writing to a read only register"); - } - break; - - case sizeof(uint16_t): // 2-byte access - switch (offset) { - case PCI_COMMAND: - config.command = data16; - case PCI_STATUS: - config.status = data16; - case PCI_CACHE_LINE_SIZE: - config.cacheLineSize = data16; - break; - default: - panic("writing to a read only register"); - } - break; - - case sizeof(uint32_t): // 4-byte access - switch (offset) { - case PCI0_BASE_ADDR0: - case PCI0_BASE_ADDR1: - case PCI0_BASE_ADDR2: - case PCI0_BASE_ADDR3: - case PCI0_BASE_ADDR4: - case PCI0_BASE_ADDR5: - - uint32_t barnum, bar_mask; - Addr base_addr, base_size, space_base; - - barnum = BAR_NUMBER(offset); - - if (BAR_IO_SPACE(letoh(config.baseAddr[barnum]))) { - bar_mask = BAR_IO_MASK; - space_base = TSUNAMI_PCI0_IO; - } else { - bar_mask = BAR_MEM_MASK; - space_base = TSUNAMI_PCI0_MEMORY; - } - - // Writing 0xffffffff to a BAR tells the card to set the - // value of the bar to size of memory it needs - if (letoh(data32) == 0xffffffff) { - // This is I/O Space, bottom two bits are read only - - config.baseAddr[barnum] = letoh( - (~(BARSize[barnum] - 1) & ~bar_mask) | - (letoh(config.baseAddr[barnum]) & bar_mask)); - } else { - MemoryController *mmu = params()->mmu; - - config.baseAddr[barnum] = letoh( - (letoh(data32) & ~bar_mask) | - (letoh(config.baseAddr[barnum]) & bar_mask)); - - if (letoh(config.baseAddr[barnum]) & ~bar_mask) { - base_addr = (letoh(data32) & ~bar_mask) + space_base; - base_size = BARSize[barnum]; - - // It's never been set - if (BARAddrs[barnum] == 0) - mmu->add_child((FunctionalMemory *)this, - RangeSize(base_addr, base_size)); - else - mmu->update_child((FunctionalMemory *)this, - RangeSize(BARAddrs[barnum], base_size), - RangeSize(base_addr, base_size)); - - BARAddrs[barnum] = base_addr; - } - } - break; - - case PCI0_ROM_BASE_ADDR: - if (letoh(data32) == 0xfffffffe) - config.expansionROM = htole((uint32_t)0xffffffff); - else - config.expansionROM = data32; - break; - - case PCI_COMMAND: - // This could also clear some of the error bits in the Status - // register. However they should never get set, so lets ignore - // it for now - config.command = data16; - break; - - default: - DPRINTF(PCIDEV, "Writing to a read only register"); - } - break; - - default: - panic("invalid access size"); - } -} - -void -PciDev::serialize(ostream &os) -{ - SERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0])); - SERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0])); - SERIALIZE_ARRAY(config.data, sizeof(config.data) / sizeof(config.data[0])); -} - -void -PciDev::unserialize(Checkpoint *cp, const std::string §ion) -{ - UNSERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0])); - UNSERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0])); - UNSERIALIZE_ARRAY(config.data, - sizeof(config.data) / sizeof(config.data[0])); - - // Add the MMU mappings for the BARs - for (int i=0; i < 6; i++) { - if (BARAddrs[i] != 0) - params()->mmu->add_child(this, RangeSize(BARAddrs[i], BARSize[i])); - } -} - -#ifndef DOXYGEN_SHOULD_SKIP_THIS - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(PciConfigData) - - Param<uint16_t> VendorID; - Param<uint16_t> DeviceID; - Param<uint16_t> Command; - Param<uint16_t> Status; - Param<uint8_t> Revision; - Param<uint8_t> ProgIF; - Param<uint8_t> SubClassCode; - Param<uint8_t> ClassCode; - Param<uint8_t> CacheLineSize; - Param<uint8_t> LatencyTimer; - Param<uint8_t> HeaderType; - Param<uint8_t> BIST; - Param<uint32_t> BAR0; - Param<uint32_t> BAR1; - Param<uint32_t> BAR2; - Param<uint32_t> BAR3; - Param<uint32_t> BAR4; - Param<uint32_t> BAR5; - Param<uint32_t> CardbusCIS; - Param<uint16_t> SubsystemVendorID; - Param<uint16_t> SubsystemID; - Param<uint32_t> ExpansionROM; - Param<uint8_t> InterruptLine; - Param<uint8_t> InterruptPin; - Param<uint8_t> MinimumGrant; - Param<uint8_t> MaximumLatency; - Param<uint32_t> BAR0Size; - Param<uint32_t> BAR1Size; - Param<uint32_t> BAR2Size; - Param<uint32_t> BAR3Size; - Param<uint32_t> BAR4Size; - Param<uint32_t> BAR5Size; - -END_DECLARE_SIM_OBJECT_PARAMS(PciConfigData) - -BEGIN_INIT_SIM_OBJECT_PARAMS(PciConfigData) - - INIT_PARAM(VendorID, "Vendor ID"), - INIT_PARAM(DeviceID, "Device ID"), - INIT_PARAM_DFLT(Command, "Command Register", 0x00), - INIT_PARAM_DFLT(Status, "Status Register", 0x00), - INIT_PARAM_DFLT(Revision, "Device Revision", 0x00), - INIT_PARAM_DFLT(ProgIF, "Programming Interface", 0x00), - INIT_PARAM(SubClassCode, "Sub-Class Code"), - INIT_PARAM(ClassCode, "Class Code"), - INIT_PARAM_DFLT(CacheLineSize, "System Cacheline Size", 0x00), - INIT_PARAM_DFLT(LatencyTimer, "PCI Latency Timer", 0x00), - INIT_PARAM_DFLT(HeaderType, "PCI Header Type", 0x00), - INIT_PARAM_DFLT(BIST, "Built In Self Test", 0x00), - INIT_PARAM_DFLT(BAR0, "Base Address Register 0", 0x00), - INIT_PARAM_DFLT(BAR1, "Base Address Register 1", 0x00), - INIT_PARAM_DFLT(BAR2, "Base Address Register 2", 0x00), - INIT_PARAM_DFLT(BAR3, "Base Address Register 3", 0x00), - INIT_PARAM_DFLT(BAR4, "Base Address Register 4", 0x00), - INIT_PARAM_DFLT(BAR5, "Base Address Register 5", 0x00), - INIT_PARAM_DFLT(CardbusCIS, "Cardbus Card Information Structure", 0x00), - INIT_PARAM_DFLT(SubsystemVendorID, "Subsystem Vendor ID", 0x00), - INIT_PARAM_DFLT(SubsystemID, "Subsystem ID", 0x00), - INIT_PARAM_DFLT(ExpansionROM, "Expansion ROM Base Address Register", 0x00), - INIT_PARAM(InterruptLine, "Interrupt Line Register"), - INIT_PARAM(InterruptPin, "Interrupt Pin Register"), - INIT_PARAM_DFLT(MinimumGrant, "Minimum Grant", 0x00), - INIT_PARAM_DFLT(MaximumLatency, "Maximum Latency", 0x00), - INIT_PARAM_DFLT(BAR0Size, "Base Address Register 0 Size", 0x00), - INIT_PARAM_DFLT(BAR1Size, "Base Address Register 1 Size", 0x00), - INIT_PARAM_DFLT(BAR2Size, "Base Address Register 2 Size", 0x00), - INIT_PARAM_DFLT(BAR3Size, "Base Address Register 3 Size", 0x00), - INIT_PARAM_DFLT(BAR4Size, "Base Address Register 4 Size", 0x00), - INIT_PARAM_DFLT(BAR5Size, "Base Address Register 5 Size", 0x00) - -END_INIT_SIM_OBJECT_PARAMS(PciConfigData) - -CREATE_SIM_OBJECT(PciConfigData) -{ - PciConfigData *data = new PciConfigData(getInstanceName()); - - data->config.vendor = htole(VendorID); - data->config.device = htole(DeviceID); - data->config.command = htole(Command); - data->config.status = htole(Status); - data->config.revision = htole(Revision); - data->config.progIF = htole(ProgIF); - data->config.subClassCode = htole(SubClassCode); - data->config.classCode = htole(ClassCode); - data->config.cacheLineSize = htole(CacheLineSize); - data->config.latencyTimer = htole(LatencyTimer); - data->config.headerType = htole(HeaderType); - data->config.bist = htole(BIST); - - data->config.baseAddr0 = htole(BAR0); - data->config.baseAddr1 = htole(BAR1); - data->config.baseAddr2 = htole(BAR2); - data->config.baseAddr3 = htole(BAR3); - data->config.baseAddr4 = htole(BAR4); - data->config.baseAddr5 = htole(BAR5); - data->config.cardbusCIS = htole(CardbusCIS); - data->config.subsystemVendorID = htole(SubsystemVendorID); - data->config.subsystemID = htole(SubsystemVendorID); - data->config.expansionROM = htole(ExpansionROM); - data->config.interruptLine = htole(InterruptLine); - data->config.interruptPin = htole(InterruptPin); - data->config.minimumGrant = htole(MinimumGrant); - data->config.maximumLatency = htole(MaximumLatency); - - data->BARSize[0] = BAR0Size; - data->BARSize[1] = BAR1Size; - data->BARSize[2] = BAR2Size; - data->BARSize[3] = BAR3Size; - data->BARSize[4] = BAR4Size; - data->BARSize[5] = BAR5Size; - - return data; -} - -REGISTER_SIM_OBJECT("PciConfigData", PciConfigData) - -#endif // DOXYGEN_SHOULD_SKIP_THIS diff --git a/dev/pcidev.hh b/dev/pcidev.hh deleted file mode 100644 index bdfc6b932..000000000 --- a/dev/pcidev.hh +++ /dev/null @@ -1,298 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* @file - * Interface for devices using PCI configuration - */ - -#ifndef __DEV_PCIDEV_HH__ -#define __DEV_PCIDEV_HH__ - -#include "dev/io_device.hh" -#include "dev/pcireg.h" -#include "dev/platform.hh" - -#define BAR_IO_MASK 0x3 -#define BAR_MEM_MASK 0xF -#define BAR_IO_SPACE_BIT 0x1 -#define BAR_IO_SPACE(x) ((x) & BAR_IO_SPACE_BIT) -#define BAR_NUMBER(x) (((x) - PCI0_BASE_ADDR0) >> 0x2); - -class PciConfigAll; -class MemoryController; - - -/** - * This class encapulates the first 64 bytes of a singles PCI - * devices config space that in configured by the configuration file. - */ -class PciConfigData : public SimObject -{ - public: - /** - * Constructor to initialize the devices config space to 0. - */ - PciConfigData(const std::string &name) - : SimObject(name) - { - memset(config.data, 0, sizeof(config.data)); - memset(BARAddrs, 0, sizeof(BARAddrs)); - memset(BARSize, 0, sizeof(BARSize)); - } - - /** The first 64 bytes */ - PCIConfig config; - - /** The size of the BARs */ - uint32_t BARSize[6]; - - /** The addresses of the BARs */ - Addr BARAddrs[6]; -}; - -/** - * PCI device, base implemnation is only config space. - * Each device is connected to a PCIConfigSpace device - * which returns -1 for everything but the pcidevs that - * register with it. This object registers with the PCIConfig space - * object. - */ -class PciDev : public DmaDevice -{ - public: - struct Params - { - std::string name; - Platform *plat; - MemoryController *mmu; - - /** - * A pointer to the configspace all object that calls us when - * a read comes to this particular device/function. - */ - PciConfigAll *configSpace; - - /** - * A pointer to the object that contains the first 64 bytes of - * config space - */ - PciConfigData *configData; - - /** The bus number we are on */ - uint32_t busNum; - - /** The device number we have */ - uint32_t deviceNum; - - /** The function number */ - uint32_t functionNum; - }; - - protected: - Params *_params; - - public: - const Params *params() const { return _params; } - - protected: - /** The current config space. Unlike the PciConfigData this is - * updated during simulation while continues to reflect what was - * in the config file. - */ - PCIConfig config; - - /** The size of the BARs */ - uint32_t BARSize[6]; - - /** The current address mapping of the BARs */ - Addr BARAddrs[6]; - - bool - isBAR(Addr addr, int bar) const - { - assert(bar >= 0 && bar < 6); - return BARAddrs[bar] <= addr && addr < BARAddrs[bar] + BARSize[bar]; - } - - int - getBAR(Addr addr) - { - for (int i = 0; i <= 5; ++i) - if (isBAR(addr, i)) - return i; - - return -1; - } - - bool - getBAR(Addr paddr, Addr &daddr, int &bar) - { - int b = getBAR(paddr); - if (b < 0) - return false; - - daddr = paddr - BARAddrs[b]; - bar = b; - return true; - } - - protected: - Platform *plat; - PciConfigData *configData; - - public: - Addr pciToDma(Addr pciAddr) const - { return plat->pciToDma(pciAddr); } - - void - intrPost() - { plat->postPciInt(configData->config.interruptLine); } - - void - intrClear() - { plat->clearPciInt(configData->config.interruptLine); } - - uint8_t - interruptLine() - { return configData->config.interruptLine; } - - public: - /** - * Constructor for PCI Dev. This function copies data from the - * config file object PCIConfigData and registers the device with - * a PciConfigAll object. - */ - PciDev(Params *params); - - virtual Fault read(MemReqPtr &req, uint8_t *data); - virtual Fault write(MemReqPtr &req, const uint8_t *data); - - public: - /** - * Implement the read/write as BAR accesses - */ - Fault readBar(MemReqPtr &req, uint8_t *data); - Fault writeBar(MemReqPtr &req, const uint8_t *data); - - public: - /** - * Read from a specific BAR - */ - virtual Fault readBar0(MemReqPtr &req, Addr daddr, uint8_t *data); - virtual Fault readBar1(MemReqPtr &req, Addr daddr, uint8_t *data); - virtual Fault readBar2(MemReqPtr &req, Addr daddr, uint8_t *data); - virtual Fault readBar3(MemReqPtr &req, Addr daddr, uint8_t *data); - virtual Fault readBar4(MemReqPtr &req, Addr daddr, uint8_t *data); - virtual Fault readBar5(MemReqPtr &req, Addr daddr, uint8_t *data); - - public: - /** - * Write to a specific BAR - */ - virtual Fault writeBar0(MemReqPtr &req, Addr daddr, const uint8_t *data); - virtual Fault writeBar1(MemReqPtr &req, Addr daddr, const uint8_t *data); - virtual Fault writeBar2(MemReqPtr &req, Addr daddr, const uint8_t *data); - virtual Fault writeBar3(MemReqPtr &req, Addr daddr, const uint8_t *data); - virtual Fault writeBar4(MemReqPtr &req, Addr daddr, const uint8_t *data); - virtual Fault writeBar5(MemReqPtr &req, Addr daddr, const uint8_t *data); - - public: - /** - * Write to the PCI config space data that is stored locally. This may be - * overridden by the device but at some point it will eventually call this - * for normal operations that it does not need to override. - * @param offset the offset into config space - * @param size the size of the write - * @param data the data to write - */ - virtual void writeConfig(int offset, int size, const uint8_t* data); - - - /** - * Read from the PCI config space data that is stored locally. This may be - * overridden by the device but at some point it will eventually call this - * for normal operations that it does not need to override. - * @param offset the offset into config space - * @param size the size of the read - * @param data pointer to the location where the read value should be stored - */ - virtual void readConfig(int offset, int size, uint8_t *data); - - /** - * Serialize this object to the given output stream. - * @param os The stream to serialize to. - */ - virtual void serialize(std::ostream &os); - - /** - * Reconstruct the state of this object from a checkpoint. - * @param cp The checkpoint use. - * @param section The section name of this object - */ - virtual void unserialize(Checkpoint *cp, const std::string §ion); -}; - -inline Fault -PciDev::readBar(MemReqPtr &req, uint8_t *data) -{ - using namespace TheISA; - if (isBAR(req->paddr, 0)) - return readBar0(req, req->paddr - BARAddrs[0], data); - if (isBAR(req->paddr, 1)) - return readBar1(req, req->paddr - BARAddrs[1], data); - if (isBAR(req->paddr, 2)) - return readBar2(req, req->paddr - BARAddrs[2], data); - if (isBAR(req->paddr, 3)) - return readBar3(req, req->paddr - BARAddrs[3], data); - if (isBAR(req->paddr, 4)) - return readBar4(req, req->paddr - BARAddrs[4], data); - if (isBAR(req->paddr, 5)) - return readBar5(req, req->paddr - BARAddrs[5], data); - return genMachineCheckFault(); -} - -inline Fault -PciDev::writeBar(MemReqPtr &req, const uint8_t *data) -{ - using namespace TheISA; - if (isBAR(req->paddr, 0)) - return writeBar0(req, req->paddr - BARAddrs[0], data); - if (isBAR(req->paddr, 1)) - return writeBar1(req, req->paddr - BARAddrs[1], data); - if (isBAR(req->paddr, 2)) - return writeBar2(req, req->paddr - BARAddrs[2], data); - if (isBAR(req->paddr, 3)) - return writeBar3(req, req->paddr - BARAddrs[3], data); - if (isBAR(req->paddr, 4)) - return writeBar4(req, req->paddr - BARAddrs[4], data); - if (isBAR(req->paddr, 5)) - return writeBar5(req, req->paddr - BARAddrs[5], data); - return genMachineCheckFault(); -} - -#endif // __DEV_PCIDEV_HH__ diff --git a/dev/pcireg.h b/dev/pcireg.h deleted file mode 100644 index 9d2737c20..000000000 --- a/dev/pcireg.h +++ /dev/null @@ -1,156 +0,0 @@ -/* - * 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. - */ - -/* @file - * Device register definitions for a device's PCI config space - */ - -#ifndef __PCIREG_H__ -#define __PCIREG_H__ - -#include <sys/types.h> - -union PCIConfig { - uint8_t data[64]; - - struct { - uint16_t vendor; - uint16_t device; - uint16_t command; - uint16_t status; - uint8_t revision; - uint8_t progIF; - uint8_t subClassCode; - uint8_t classCode; - uint8_t cacheLineSize; - uint8_t latencyTimer; - uint8_t headerType; - uint8_t bist; - union { - uint32_t baseAddr[6]; - - struct { - uint32_t baseAddr0; - uint32_t baseAddr1; - uint32_t baseAddr2; - uint32_t baseAddr3; - uint32_t baseAddr4; - uint32_t baseAddr5; - }; - }; - uint32_t cardbusCIS; - uint16_t subsystemVendorID; - uint16_t subsystemID; - uint32_t expansionROM; - uint32_t reserved0; - uint32_t reserved1; - uint8_t interruptLine; - uint8_t interruptPin; - uint8_t minimumGrant; - uint8_t maximumLatency; - }; -}; - -// Common PCI offsets -#define PCI_VENDOR_ID 0x00 // Vendor ID ro -#define PCI_DEVICE_ID 0x02 // Device ID ro -#define PCI_COMMAND 0x04 // Command rw -#define PCI_STATUS 0x06 // Status rw -#define PCI_REVISION_ID 0x08 // Revision ID ro -#define PCI_CLASS_CODE 0x09 // Class Code ro -#define PCI_SUB_CLASS_CODE 0x0A // Sub Class Code ro -#define PCI_BASE_CLASS_CODE 0x0B // Base Class Code ro -#define PCI_CACHE_LINE_SIZE 0x0C // Cache Line Size ro+ -#define PCI_LATENCY_TIMER 0x0D // Latency Timer ro+ -#define PCI_HEADER_TYPE 0x0E // Header Type ro -#define PCI_BIST 0x0F // Built in self test rw - -// some pci command reg bitfields -#define PCI_CMD_BME 0x04 // Bus master function enable -#define PCI_CMD_MSE 0x02 // Memory Space Access enable -#define PCI_CMD_IOSE 0x01 // I/O space enable - -// Type 0 PCI offsets -#define PCI0_BASE_ADDR0 0x10 // Base Address 0 rw -#define PCI0_BASE_ADDR1 0x14 // Base Address 1 rw -#define PCI0_BASE_ADDR2 0x18 // Base Address 2 rw -#define PCI0_BASE_ADDR3 0x1C // Base Address 3 rw -#define PCI0_BASE_ADDR4 0x20 // Base Address 4 rw -#define PCI0_BASE_ADDR5 0x24 // Base Address 5 rw -#define PCI0_CIS 0x28 // CardBus CIS Pointer ro -#define PCI0_SUB_VENDOR_ID 0x2C // Sub-Vendor ID ro -#define PCI0_SUB_SYSTEM_ID 0x2E // Sub-System ID ro -#define PCI0_ROM_BASE_ADDR 0x30 // Expansion ROM Base Address rw -#define PCI0_RESERVED0 0x34 -#define PCI0_RESERVED1 0x38 -#define PCI0_INTERRUPT_LINE 0x3C // Interrupt Line rw -#define PCI0_INTERRUPT_PIN 0x3D // Interrupt Pin ro -#define PCI0_MINIMUM_GRANT 0x3E // Maximum Grant ro -#define PCI0_MAXIMUM_LATENCY 0x3F // Maximum Latency ro - -// Type 1 PCI offsets -#define PCI1_BASE_ADDR0 0x10 // Base Address 0 rw -#define PCI1_BASE_ADDR1 0x14 // Base Address 1 rw -#define PCI1_PRI_BUS_NUM 0x18 // Primary Bus Number rw -#define PCI1_SEC_BUS_NUM 0x19 // Secondary Bus Number rw -#define PCI1_SUB_BUS_NUM 0x1A // Subordinate Bus Number rw -#define PCI1_SEC_LAT_TIMER 0x1B // Secondary Latency Timer ro+ -#define PCI1_IO_BASE 0x1C // I/O Base rw -#define PCI1_IO_LIMIT 0x1D // I/O Limit rw -#define PCI1_SECONDARY_STATUS 0x1E // Secondary Status rw -#define PCI1_MEM_BASE 0x20 // Memory Base rw -#define PCI1_MEM_LIMIT 0x22 // Memory Limit rw -#define PCI1_PRF_MEM_BASE 0x24 // Prefetchable Memory Base rw -#define PCI1_PRF_MEM_LIMIT 0x26 // Prefetchable Memory Limit rw -#define PCI1_PRF_BASE_UPPER 0x28 // Prefetchable Base Upper 32 rw -#define PCI1_PRF_LIMIT_UPPER 0x2C // Prefetchable Limit Upper 32 rw -#define PCI1_IO_BASE_UPPER 0x30 // I/O Base Upper 16 bits rw -#define PCI1_IO_LIMIT_UPPER 0x32 // I/O Limit Upper 16 bits rw -#define PCI1_RESERVED 0x34 // Reserved ro -#define PCI1_ROM_BASE_ADDR 0x38 // Expansion ROM Base Address rw -#define PCI1_INTR_LINE 0x3C // Interrupt Line rw -#define PCI1_INTR_PIN 0x3D // Interrupt Pin ro -#define PCI1_BRIDGE_CTRL 0x3E // Bridge Control rw - -// Device specific offsets -#define PCI_DEVICE_SPECIFIC 0x40 // 192 bytes - -// Some Vendor IDs -#define PCI_VENDOR_DEC 0x1011 -#define PCI_VENDOR_NCR 0x101A -#define PCI_VENDOR_QLOGIC 0x1077 -#define PCI_VENDOR_SIMOS 0x1291 - -// Some Product IDs -#define PCI_PRODUCT_DEC_PZA 0x0008 -#define PCI_PRODUCT_NCR_810 0x0001 -#define PCI_PRODUCT_QLOGIC_ISP1020 0x1020 -#define PCI_PRODUCT_SIMOS_SIMOS 0x1291 -#define PCI_PRODUCT_SIMOS_ETHER 0x1292 - -#endif // __PCIREG_H__ diff --git a/dev/pitreg.h b/dev/pitreg.h deleted file mode 100644 index 5fe1cf03f..000000000 --- a/dev/pitreg.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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. - */ - -/* @file - * Device register definitions for a device's PCI config space - */ - -#ifndef __PITREG_H__ -#define __PITREG_H__ - -#include <sys/types.h> - -// Control Word Format - -#define PIT_SEL_SHFT 0x6 -#define PIT_RW_SHFT 0x4 -#define PIT_MODE_SHFT 0x1 -#define PIT_BCD_SHFT 0x0 - -#define PIT_SEL_MASK 0x3 -#define PIT_RW_MASK 0x3 -#define PIT_MODE_MASK 0x7 -#define PIT_BCD_MASK 0x1 - -#define GET_CTRL_FIELD(x, s, m) (((x) >> s) & m) -#define GET_CTRL_SEL(x) GET_CTRL_FIELD(x, PIT_SEL_SHFT, PIT_SEL_MASK) -#define GET_CTRL_RW(x) GET_CTRL_FIELD(x, PIT_RW_SHFT, PIT_RW_MASK) -#define GET_CTRL_MODE(x) GET_CTRL_FIELD(x, PIT_MODE_SHFT, PIT_MODE_MASK) -#define GET_CTRL_BCD(x) GET_CTRL_FIELD(x, PIT_BCD_SHFT, PIT_BCD_MASK) - -#define PIT_READ_BACK 0x3 - -#define PIT_RW_LATCH_COMMAND 0x0 -#define PIT_RW_LSB_ONLY 0x1 -#define PIT_RW_MSB_ONLY 0x2 -#define PIT_RW_16BIT 0x3 - -#define PIT_MODE_INTTC 0x0 -#define PIT_MODE_ONESHOT 0x1 -#define PIT_MODE_RATEGEN 0x2 -#define PIT_MODE_SQWAVE 0x3 -#define PIT_MODE_SWSTROBE 0x4 -#define PIT_MODE_HWSTROBE 0x5 - -#define PIT_BCD_FALSE 0x0 -#define PIT_BCD_TRUE 0x1 - -#endif // __PITREG_H__ diff --git a/dev/pktfifo.cc b/dev/pktfifo.cc deleted file mode 100644 index 639009be9..000000000 --- a/dev/pktfifo.cc +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "base/misc.hh" -#include "dev/pktfifo.hh" - -using namespace std; - -bool -PacketFifo::copyout(void *dest, int offset, int len) -{ - char *data = (char *)dest; - if (offset + len >= size()) - return false; - - list<PacketPtr>::iterator p = fifo.begin(); - list<PacketPtr>::iterator end = fifo.end(); - while (len > 0) { - while (offset >= (*p)->length) { - offset -= (*p)->length; - ++p; - } - - if (p == end) - panic("invalid fifo"); - - int size = min((*p)->length - offset, len); - memcpy(data, (*p)->data, size); - offset = 0; - len -= size; - data += size; - ++p; - } - - return true; -} - - -void -PacketFifo::serialize(const string &base, ostream &os) -{ - paramOut(os, base + ".size", _size); - paramOut(os, base + ".maxsize", _maxsize); - paramOut(os, base + ".reserved", _reserved); - paramOut(os, base + ".packets", fifo.size()); - - int i = 0; - list<PacketPtr>::iterator p = fifo.begin(); - list<PacketPtr>::iterator end = fifo.end(); - while (p != end) { - (*p)->serialize(csprintf("%s.packet%d", base, i), os); - ++p; - ++i; - } -} - -void -PacketFifo::unserialize(const string &base, Checkpoint *cp, - const string §ion) -{ - paramIn(cp, section, base + ".size", _size); -// paramIn(cp, section, base + ".maxsize", _maxsize); - paramIn(cp, section, base + ".reserved", _reserved); - int fifosize; - paramIn(cp, section, base + ".packets", fifosize); - - fifo.clear(); - - for (int i = 0; i < fifosize; ++i) { - PacketPtr p = new PacketData(16384); - p->unserialize(csprintf("%s.packet%d", base, i), cp, section); - fifo.push_back(p); - } -} diff --git a/dev/pktfifo.hh b/dev/pktfifo.hh deleted file mode 100644 index e245840a8..000000000 --- a/dev/pktfifo.hh +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __DEV_PKTFIFO_HH__ -#define __DEV_PKTFIFO_HH__ - -#include <iosfwd> -#include <list> -#include <string> - -#include "dev/etherpkt.hh" -#include "sim/serialize.hh" - -class Checkpoint; -class PacketFifo -{ - public: - typedef std::list<PacketPtr> fifo_list; - typedef fifo_list::iterator iterator; - - protected: - std::list<PacketPtr> fifo; - int _maxsize; - int _size; - int _reserved; - - public: - explicit PacketFifo(int max) : _maxsize(max), _size(0), _reserved(0) {} - virtual ~PacketFifo() {} - - int packets() const { return fifo.size(); } - int maxsize() const { return _maxsize; } - int size() const { return _size; } - int reserved() const { return _reserved; } - int avail() const { return _maxsize - _size - _reserved; } - bool empty() const { return size() <= 0; } - bool full() const { return avail() <= 0; } - - int reserve(int len = 0) - { - _reserved += len; - assert(avail() >= 0); - return _reserved; - } - - iterator begin() { return fifo.begin(); } - iterator end() { return fifo.end(); } - - PacketPtr front() { return fifo.front(); } - - bool push(PacketPtr ptr) - { - assert(ptr->length); - assert(_reserved <= ptr->length); - assert(ptr->slack == 0); - if (avail() < ptr->length - _reserved) - return false; - - _size += ptr->length; - fifo.push_back(ptr); - _reserved = 0; - return true; - } - - void pop() - { - if (empty()) - return; - - PacketPtr &packet = fifo.front(); - _size -= packet->length; - _size -= packet->slack; - packet->slack = 0; - packet = NULL; - fifo.pop_front(); - } - - void clear() - { - for (iterator i = begin(); i != end(); ++i) - (*i)->slack = 0; - fifo.clear(); - _size = 0; - _reserved = 0; - } - - void remove(iterator i) - { - PacketPtr &packet = *i; - if (i != fifo.begin()) { - iterator prev = i; - --prev; - assert(prev != fifo.end()); - (*prev)->slack += packet->length; - } else { - _size -= packet->length; - _size -= packet->slack; - } - - packet->slack = 0; - packet = NULL; - fifo.erase(i); - } - - bool copyout(void *dest, int offset, int len); - - int countPacketsBefore(iterator end) - { - iterator i = fifo.begin(); - int count = 0; - - while (i != end) { - ++count; - ++i; - } - - return count; - } - - int countPacketsAfter(iterator i) - { - iterator end = fifo.end(); - int count = 0; - - while (i != end) { - ++count; - ++i; - } - - return count; - } - - -/** - * Serialization stuff - */ - public: - void serialize(const std::string &base, std::ostream &os); - void unserialize(const std::string &base, - Checkpoint *cp, const std::string §ion); -}; - -#endif // __DEV_PKTFIFO_HH__ diff --git a/dev/platform.cc b/dev/platform.cc deleted file mode 100644 index 5b667b12c..000000000 --- a/dev/platform.cc +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "dev/platform.hh" -#include "sim/builder.hh" -#include "sim/sim_exit.hh" - -using namespace std; -using namespace TheISA; - -Platform::Platform(const string &name, IntrControl *intctrl, PciConfigAll *pci) - : SimObject(name), intrctrl(intctrl), pciconfig(pci) -{ -} - -Platform::~Platform() -{ -} - -void -Platform::postPciInt(int line) -{ - panic("No PCI interrupt support in platform."); -} - -void -Platform::clearPciInt(int line) -{ - panic("No PCI interrupt support in platform."); -} - -Addr -Platform::pciToDma(Addr pciAddr) const -{ - panic("No PCI dma support in platform."); -} - -DEFINE_SIM_OBJECT_CLASS_NAME("Platform", Platform) - diff --git a/dev/platform.hh b/dev/platform.hh deleted file mode 100644 index 1ee645454..000000000 --- a/dev/platform.hh +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * Generic interface for platforms - */ - -#ifndef __DEV_PLATFORM_HH__ -#define __DEV_PLATFORM_HH__ - -#include "sim/sim_object.hh" -#include "arch/isa_traits.hh" - -class PciConfigAll; -class IntrControl; -class SimConsole; -class Uart; - -class Platform : public SimObject -{ - public: - /** Pointer to the interrupt controller */ - IntrControl *intrctrl; - - /** Pointer to the PCI configuration space */ - PciConfigAll *pciconfig; - - /** Pointer to the UART, set by the uart */ - Uart *uart; - - public: - Platform(const std::string &name, IntrControl *intctrl, PciConfigAll *pci); - virtual ~Platform(); - virtual void postConsoleInt() = 0; - virtual void clearConsoleInt() = 0; - virtual Tick intrFrequency() = 0; - virtual void postPciInt(int line); - virtual void clearPciInt(int line); - virtual Addr pciToDma(Addr pciAddr) const; -}; - -#endif // __DEV_PLATFORM_HH__ diff --git a/dev/rtcreg.h b/dev/rtcreg.h deleted file mode 100644 index 5025a0e95..000000000 --- a/dev/rtcreg.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#define RTC_SEC 0x00 -#define RTC_SEC_ALRM 0x01 -#define RTC_MIN 0x02 -#define RTC_MIN_ALRM 0x03 -#define RTC_HR 0x04 -#define RTC_HR_ALRM 0x05 -#define RTC_DOW 0x06 -#define RTC_DOM 0x07 -#define RTC_MON 0x08 -#define RTC_YEAR 0x09 - -#define RTC_STAT_REGA 0x0A -#define RTCA_1024HZ 0x06 /* 1024Hz periodic interrupt frequency */ -#define RTCA_32768HZ 0x20 /* 22-stage divider, 32.768KHz timebase */ -#define RTCA_UIP 0x80 /* 1 = date and time update in progress */ - -#define RTC_STAT_REGB 0x0B -#define RTCB_DST 0x01 /* USA Daylight Savings Time enable */ -#define RTCB_24HR 0x02 /* 0 = 12 hours, 1 = 24 hours */ -#define RTCB_BIN 0x04 /* 0 = BCD, 1 = Binary coded time */ -#define RTCB_SQWE 0x08 /* 1 = output sqare wave at SQW pin */ -#define RTCB_UPDT_IE 0x10 /* 1 = enable update-ended interrupt */ -#define RTCB_ALRM_IE 0x20 /* 1 = enable alarm interrupt */ -#define RTCB_PRDC_IE 0x40 /* 1 = enable periodic clock interrupt */ -#define RTCB_NO_UPDT 0x80 /* stop clock updates */ - -#define RTC_STAT_REGC 0x0C -#define RTC_STAT_REGD 0x0D - diff --git a/dev/simconsole.cc b/dev/simconsole.cc deleted file mode 100644 index b818e61f4..000000000 --- a/dev/simconsole.cc +++ /dev/null @@ -1,415 +0,0 @@ -/* - * 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. - */ - -/* @file - * Implements the user interface to a serial console - */ - -#include <sys/ioctl.h> -#include <sys/termios.h> -#include <sys/types.h> -#include <errno.h> -#include <poll.h> -#include <unistd.h> - -#include <iostream> -#include <fstream> -#include <sstream> -#include <string> - -#include "base/misc.hh" -#include "base/output.hh" -#include "base/socket.hh" -#include "base/trace.hh" -#include "dev/platform.hh" -#include "dev/simconsole.hh" -#include "dev/uart.hh" -#include "mem/functional/memory_control.hh" -#include "sim/builder.hh" - -using namespace std; - -//////////////////////////////////////////////////////////////////////// -// -// - -SimConsole::Event::Event(SimConsole *c, int fd, int e) - : PollEvent(fd, e), cons(c) -{ -} - -void -SimConsole::Event::process(int revent) -{ - if (revent & POLLIN) - cons->data(); - else if (revent & POLLNVAL) - cons->detach(); -} - -SimConsole::SimConsole(const string &name, ostream *os, int num) - : SimObject(name), event(NULL), number(num), in_fd(-1), out_fd(-1), - listener(NULL), txbuf(16384), rxbuf(16384), outfile(os) -#if TRACING_ON == 1 - , linebuf(16384) -#endif -{ - if (outfile) - outfile->setf(ios::unitbuf); -} - -SimConsole::~SimConsole() -{ - close(); -} - -void -SimConsole::close() -{ - if (in_fd != -1) - ::close(in_fd); - - if (out_fd != in_fd && out_fd != -1) - ::close(out_fd); -} - -void -SimConsole::attach(int in, int out, ConsoleListener *l) -{ - in_fd = in; - out_fd = out; - listener = l; - - event = new Event(this, in, POLLIN); - pollQueue.schedule(event); - - stringstream stream; - ccprintf(stream, "==== m5 slave console: Console %d ====", number); - - // we need an actual carriage return followed by a newline for the - // terminal - stream << "\r\n"; - - write((const uint8_t *)stream.str().c_str(), stream.str().size()); - - - DPRINTFN("attach console %d\n", number); - - txbuf.readall(out); -} - -void -SimConsole::detach() -{ - close(); - in_fd = -1; - out_fd = -1; - - pollQueue.remove(event); - - if (listener) { - listener->add(this); - listener = NULL; - } - - DPRINTFN("detach console %d\n", number); -} - -void -SimConsole::data() -{ - uint8_t buf[1024]; - int len; - - len = read(buf, sizeof(buf)); - if (len) { - rxbuf.write((char *)buf, len); - // Inform the UART there is data available - uart->dataAvailable(); - } -} - -size_t -SimConsole::read(uint8_t *buf, size_t len) -{ - if (in_fd < 0) - panic("Console not properly attached.\n"); - - size_t ret; - do { - ret = ::read(in_fd, buf, len); - } while (ret == -1 && errno == EINTR); - - - if (ret < 0) - DPRINTFN("Read failed.\n"); - - if (ret <= 0) { - detach(); - return 0; - } - - return ret; -} - -// Console output. -size_t -SimConsole::write(const uint8_t *buf, size_t len) -{ - if (out_fd < 0) - panic("Console not properly attached.\n"); - - size_t ret; - for (;;) { - ret = ::write(out_fd, buf, len); - - if (ret >= 0) - break; - - if (errno != EINTR) - detach(); - } - - return ret; -} - -#define MORE_PENDING (ULL(1) << 61) -#define RECEIVE_SUCCESS (ULL(0) << 62) -#define RECEIVE_NONE (ULL(2) << 62) -#define RECEIVE_ERROR (ULL(3) << 62) - -bool -SimConsole::in(uint8_t &c) -{ - bool empty, ret; - - empty = rxbuf.empty(); - ret = !empty; - if (!empty) { - rxbuf.read((char *)&c, 1); - empty = rxbuf.empty(); - } - - DPRINTF(ConsoleVerbose, "in: \'%c\' %#02x more: %d, return: %d\n", - isprint(c) ? c : ' ', c, !empty, ret); - - return ret; -} - -uint64_t -SimConsole::console_in() -{ - uint8_t c; - uint64_t value; - - if (in(c)) { - value = RECEIVE_SUCCESS | c; - if (!rxbuf.empty()) - value |= MORE_PENDING; - } else { - value = RECEIVE_NONE; - } - - DPRINTF(ConsoleVerbose, "console_in: return: %#x\n", value); - - return value; -} - -void -SimConsole::out(char c) -{ -#if TRACING_ON == 1 - if (DTRACE(Console)) { - static char last = '\0'; - - if (c != '\n' && c != '\r' || - last != '\n' && last != '\r') { - if (c == '\n' || c == '\r') { - int size = linebuf.size(); - char *buffer = new char[size + 1]; - linebuf.read(buffer, size); - buffer[size] = '\0'; - DPRINTF(Console, "%s\n", buffer); - delete [] buffer; - } else { - linebuf.write(c); - } - } - - last = c; - } -#endif - - txbuf.write(c); - - if (out_fd >= 0) - write(c); - - if (outfile) - outfile->write(&c, 1); - - DPRINTF(ConsoleVerbose, "out: \'%c\' %#02x\n", - isprint(c) ? c : ' ', (int)c); - -} - - -void -SimConsole::serialize(ostream &os) -{ -} - -void -SimConsole::unserialize(Checkpoint *cp, const std::string §ion) -{ -} - - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimConsole) - - SimObjectParam<ConsoleListener *> listener; - SimObjectParam<IntrControl *> intr_control; - Param<string> output; - Param<bool> append_name; - Param<int> number; - -END_DECLARE_SIM_OBJECT_PARAMS(SimConsole) - -BEGIN_INIT_SIM_OBJECT_PARAMS(SimConsole) - - INIT_PARAM(listener, "console listener"), - INIT_PARAM(intr_control, "interrupt controller"), - INIT_PARAM(output, "file to dump output to"), - INIT_PARAM_DFLT(append_name, "append name() to filename", true), - INIT_PARAM_DFLT(number, "console number", 0) - -END_INIT_SIM_OBJECT_PARAMS(SimConsole) - -CREATE_SIM_OBJECT(SimConsole) -{ - string filename = output; - ostream *stream = NULL; - - if (!filename.empty()) { - if (append_name) - filename += "." + getInstanceName(); - stream = simout.find(filename); - } - - SimConsole *console = new SimConsole(getInstanceName(), stream, number); - ((ConsoleListener *)listener)->add(console); - - return console; -} - -REGISTER_SIM_OBJECT("SimConsole", SimConsole) - -//////////////////////////////////////////////////////////////////////// -// -// - -ConsoleListener::ConsoleListener(const string &name) - : SimObject(name), event(NULL) -{} - -ConsoleListener::~ConsoleListener() -{ - if (event) - delete event; -} - -void -ConsoleListener::Event::process(int revent) -{ - listener->accept(); -} - -/////////////////////////////////////////////////////////////////////// -// socket creation and console attach -// - -void -ConsoleListener::listen(int port) -{ - while (!listener.listen(port, true)) { - DPRINTF(Console, - ": can't bind address console port %d inuse PID %d\n", - port, getpid()); - port++; - } - - ccprintf(cerr, "Listening for console connection on port %d\n", port); - - event = new Event(this, listener.getfd(), POLLIN); - pollQueue.schedule(event); -} - -void -ConsoleListener::add(SimConsole *cons) -{ ConsoleList.push_back(cons);} - -void -ConsoleListener::accept() -{ - if (!listener.islistening()) - panic("%s: cannot accept a connection if not listening!", name()); - - int sfd = listener.accept(true); - if (sfd != -1) { - iter_t i = ConsoleList.begin(); - iter_t end = ConsoleList.end(); - if (i == end) { - close(sfd); - } else { - (*i)->attach(sfd, this); - i = ConsoleList.erase(i); - } - } -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(ConsoleListener) - - Param<int> port; - -END_DECLARE_SIM_OBJECT_PARAMS(ConsoleListener) - -BEGIN_INIT_SIM_OBJECT_PARAMS(ConsoleListener) - - INIT_PARAM_DFLT(port, "listen port", 3456) - -END_INIT_SIM_OBJECT_PARAMS(ConsoleListener) - -CREATE_SIM_OBJECT(ConsoleListener) -{ - ConsoleListener *listener = new ConsoleListener(getInstanceName()); - listener->listen(port); - - return listener; -} - -REGISTER_SIM_OBJECT("ConsoleListener", ConsoleListener) diff --git a/dev/simconsole.hh b/dev/simconsole.hh deleted file mode 100644 index cf0641f9e..000000000 --- a/dev/simconsole.hh +++ /dev/null @@ -1,165 +0,0 @@ -/* - * 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. - */ - -/* @file - * User Console Interface - */ - -#ifndef __CONSOLE_HH__ -#define __CONSOLE_HH__ - -#include <iostream> - -#include "base/circlebuf.hh" -#include "cpu/intr_control.hh" -#include "base/pollevent.hh" -#include "base/socket.hh" -#include "sim/sim_object.hh" - -class ConsoleListener; -class Uart; - -class SimConsole : public SimObject -{ - public: - Uart *uart; - - protected: - class Event : public PollEvent - { - protected: - SimConsole *cons; - - public: - Event(SimConsole *c, int fd, int e); - void process(int revent); - }; - - friend class Event; - Event *event; - - protected: - int number; - int in_fd; - int out_fd; - ConsoleListener *listener; - - public: - SimConsole(const std::string &name, std::ostream *os, int num); - ~SimConsole(); - - protected: - CircleBuf txbuf; - CircleBuf rxbuf; - std::ostream *outfile; -#if TRACING_ON == 1 - CircleBuf linebuf; -#endif - - public: - /////////////////////// - // Terminal Interface - - void attach(int fd, ConsoleListener *l = NULL) { attach(fd, fd, l); } - void attach(int in, int out, ConsoleListener *l = NULL); - void detach(); - - void data(); - - void close(); - void read(uint8_t &c) { read(&c, 1); } - size_t read(uint8_t *buf, size_t len); - void write(uint8_t c) { write(&c, 1); } - size_t write(const uint8_t *buf, size_t len); - - public: - ///////////////// - // OS interface - - // Get a character from the console. - bool in(uint8_t &value); - - // get a character from the console in the console specific format - // corresponds to GETC: - // retval<63:61> - // 000: success: character received - // 001: success: character received, more pending - // 100: failure: no character ready - // 110: failure: character received with error - // 111: failure: character received with error, more pending - // retval<31:0> - // character read from console - // - // Interrupts are cleared when the buffer is empty. - uint64_t console_in(); - - // Send a character to the console - void out(char c); - - //Ask the console if data is available - bool dataAvailable() { return !rxbuf.empty(); } - - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); -}; - -class ConsoleListener : public SimObject -{ - protected: - class Event : public PollEvent - { - protected: - ConsoleListener *listener; - - public: - Event(ConsoleListener *l, int fd, int e) - : PollEvent(fd, e), listener(l) {} - void process(int revent); - }; - - friend class Event; - Event *event; - - typedef std::list<SimConsole *> list_t; - typedef list_t::iterator iter_t; - list_t ConsoleList; - - protected: - ListenSocket listener; - - public: - ConsoleListener(const std::string &name); - ~ConsoleListener(); - - void add(SimConsole *cons); - - void accept(); - void listen(int port); -}; - -#endif // __CONSOLE_HH__ diff --git a/dev/simple_disk.cc b/dev/simple_disk.cc deleted file mode 100644 index b8c5d44ab..000000000 --- a/dev/simple_disk.cc +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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. - */ - -/* @file - * Simple disk interface for the system console - */ - -#include <sys/types.h> -#include <sys/uio.h> -#include <fcntl.h> -#include <unistd.h> - -#include <cstring> -#include <string> - -#include "base/misc.hh" -#include "base/trace.hh" -#include "dev/disk_image.hh" -#include "dev/simple_disk.hh" -#include "mem/functional/physical.hh" -#include "sim/builder.hh" - -using namespace std; - -SimpleDisk::SimpleDisk(const string &name, PhysicalMemory *pmem, - DiskImage *img) - : SimObject(name), physmem(pmem), image(img) -{} - -SimpleDisk::~SimpleDisk() -{} - - -void -SimpleDisk::read(Addr addr, baddr_t block, int count) const -{ - uint8_t *data = physmem->dma_addr(addr, count); - if (!data) - panic("dma out of range! read addr=%#x count=%d\n", addr, count); - - if (count & (SectorSize - 1)) - panic("Not reading a multiple of a sector (count = %d)", count); - - for (int i = 0, j = 0; i < count; i += SectorSize, j++) - image->read(data + i, block + j); - - DPRINTF(SimpleDisk, "read block=%#x len=%d\n", (uint64_t)block, count); - DDUMP(SimpleDiskData, data, count); -} - -void -SimpleDisk::write(Addr addr, baddr_t block, int count) -{ - panic("unimplemented!\n"); - -#if 0 - uint8_t *data = physmem->dma_addr(addr, count); - if (!data) - panic("dma out of range! write addr=%#x count=%d\n", addr, count); - - image->write(data, block, count); -#endif -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleDisk) - - SimObjectParam<PhysicalMemory *> physmem; - SimObjectParam<DiskImage *> disk; - -END_DECLARE_SIM_OBJECT_PARAMS(SimpleDisk) - -BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleDisk) - - INIT_PARAM(physmem, "Physical Memory"), - INIT_PARAM(disk, "Disk Image") - -END_INIT_SIM_OBJECT_PARAMS(SimpleDisk) - -CREATE_SIM_OBJECT(SimpleDisk) -{ - return new SimpleDisk(getInstanceName(), physmem, disk); -} - -REGISTER_SIM_OBJECT("SimpleDisk", SimpleDisk) diff --git a/dev/simple_disk.hh b/dev/simple_disk.hh deleted file mode 100644 index 57f81c5a9..000000000 --- a/dev/simple_disk.hh +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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. - */ - -/* @file - * Simple disk interface for the system console - */ - -#ifndef __DEV_SIMPLE_DISK_HH__ -#define __DEV_SIMPLE_DISK_HH__ - -#include "sim/sim_object.hh" -#include "arch/isa_traits.hh" - -class DiskImage; -class PhysicalMemory; - -/* - * Trivial interface to a disk image used by the System Console - */ -class SimpleDisk : public SimObject -{ - public: - typedef uint64_t baddr_t; - - protected: - PhysicalMemory *physmem; - DiskImage *image; - - public: - SimpleDisk(const std::string &name, PhysicalMemory *pmem, DiskImage *img); - ~SimpleDisk(); - - void read(Addr addr, baddr_t block, int count) const; - void write(Addr addr, baddr_t block, int count); -}; - -#endif // __DEV_SIMPLE_DISK_HH__ diff --git a/dev/sinic.cc b/dev/sinic.cc deleted file mode 100644 index 0853717ba..000000000 --- a/dev/sinic.cc +++ /dev/null @@ -1,1905 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <cstdio> -#include <deque> -#include <string> - -#include "base/inet.hh" -#include "cpu/exec_context.hh" -#include "cpu/intr_control.hh" -#include "dev/etherlink.hh" -#include "dev/sinic.hh" -#include "dev/pciconfigall.hh" -#include "mem/bus/bus.hh" -#include "mem/bus/dma_interface.hh" -#include "mem/bus/pio_interface.hh" -#include "mem/bus/pio_interface_impl.hh" -#include "mem/functional/memory_control.hh" -#include "mem/functional/physical.hh" -#include "sim/builder.hh" -#include "sim/debug.hh" -#include "sim/eventq.hh" -#include "sim/host.hh" -#include "sim/stats.hh" -#include "arch/vtophys.hh" - -using namespace Net; -using namespace TheISA; - -namespace Sinic { - -const char *RxStateStrings[] = -{ - "rxIdle", - "rxFifoBlock", - "rxBeginCopy", - "rxCopy", - "rxCopyDone" -}; - -const char *TxStateStrings[] = -{ - "txIdle", - "txFifoBlock", - "txBeginCopy", - "txCopy", - "txCopyDone" -}; - - -/////////////////////////////////////////////////////////////////////// -// -// Sinic PCI Device -// -Base::Base(Params *p) - : PciDev(p), rxEnable(false), txEnable(false), clock(p->clock), - intrDelay(p->intr_delay), intrTick(0), cpuIntrEnable(false), - cpuPendingIntr(false), intrEvent(0), interface(NULL) -{ -} - -Device::Device(Params *p) - : Base(p), plat(p->plat), physmem(p->physmem), rxUnique(0), txUnique(0), - virtualRegs(p->virtual_count < 1 ? 1 : p->virtual_count), - rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), - rxKickTick(0), txKickTick(0), - txEvent(this), rxDmaEvent(this), txDmaEvent(this), - dmaReadDelay(p->dma_read_delay), dmaReadFactor(p->dma_read_factor), - dmaWriteDelay(p->dma_write_delay), dmaWriteFactor(p->dma_write_factor) -{ - reset(); - - if (p->pio_bus) { - pioInterface = newPioInterface(p->name + ".pio", p->hier, p->pio_bus, - this, &Device::cacheAccess); - pioLatency = p->pio_latency * p->pio_bus->clockRate; - } - - if (p->header_bus) { - if (p->payload_bus) - dmaInterface = new DMAInterface<Bus>(p->name + ".dma", - p->header_bus, - p->payload_bus, 1, - p->dma_no_allocate); - else - dmaInterface = new DMAInterface<Bus>(p->name + ".dma", - p->header_bus, - p->header_bus, 1, - p->dma_no_allocate); - } else if (p->payload_bus) - panic("must define a header bus if defining a payload bus"); -} - -Device::~Device() -{} - -void -Device::regStats() -{ - rxBytes - .name(name() + ".rxBytes") - .desc("Bytes Received") - .prereq(rxBytes) - ; - - rxBandwidth - .name(name() + ".rxBandwidth") - .desc("Receive Bandwidth (bits/s)") - .precision(0) - .prereq(rxBytes) - ; - - rxPackets - .name(name() + ".rxPackets") - .desc("Number of Packets Received") - .prereq(rxBytes) - ; - - rxPacketRate - .name(name() + ".rxPPS") - .desc("Packet Reception Rate (packets/s)") - .precision(0) - .prereq(rxBytes) - ; - - rxIpPackets - .name(name() + ".rxIpPackets") - .desc("Number of IP Packets Received") - .prereq(rxBytes) - ; - - rxTcpPackets - .name(name() + ".rxTcpPackets") - .desc("Number of Packets Received") - .prereq(rxBytes) - ; - - rxUdpPackets - .name(name() + ".rxUdpPackets") - .desc("Number of UDP Packets Received") - .prereq(rxBytes) - ; - - rxIpChecksums - .name(name() + ".rxIpChecksums") - .desc("Number of rx IP Checksums done by device") - .precision(0) - .prereq(rxBytes) - ; - - rxTcpChecksums - .name(name() + ".rxTcpChecksums") - .desc("Number of rx TCP Checksums done by device") - .precision(0) - .prereq(rxBytes) - ; - - rxUdpChecksums - .name(name() + ".rxUdpChecksums") - .desc("Number of rx UDP Checksums done by device") - .precision(0) - .prereq(rxBytes) - ; - - totBandwidth - .name(name() + ".totBandwidth") - .desc("Total Bandwidth (bits/s)") - .precision(0) - .prereq(totBytes) - ; - - totPackets - .name(name() + ".totPackets") - .desc("Total Packets") - .precision(0) - .prereq(totBytes) - ; - - totBytes - .name(name() + ".totBytes") - .desc("Total Bytes") - .precision(0) - .prereq(totBytes) - ; - - totPacketRate - .name(name() + ".totPPS") - .desc("Total Tranmission Rate (packets/s)") - .precision(0) - .prereq(totBytes) - ; - - txBytes - .name(name() + ".txBytes") - .desc("Bytes Transmitted") - .prereq(txBytes) - ; - - txBandwidth - .name(name() + ".txBandwidth") - .desc("Transmit Bandwidth (bits/s)") - .precision(0) - .prereq(txBytes) - ; - - txPackets - .name(name() + ".txPackets") - .desc("Number of Packets Transmitted") - .prereq(txBytes) - ; - - txPacketRate - .name(name() + ".txPPS") - .desc("Packet Tranmission Rate (packets/s)") - .precision(0) - .prereq(txBytes) - ; - - txIpPackets - .name(name() + ".txIpPackets") - .desc("Number of IP Packets Transmitted") - .prereq(txBytes) - ; - - txTcpPackets - .name(name() + ".txTcpPackets") - .desc("Number of TCP Packets Transmitted") - .prereq(txBytes) - ; - - txUdpPackets - .name(name() + ".txUdpPackets") - .desc("Number of Packets Transmitted") - .prereq(txBytes) - ; - - txIpChecksums - .name(name() + ".txIpChecksums") - .desc("Number of tx IP Checksums done by device") - .precision(0) - .prereq(txBytes) - ; - - txTcpChecksums - .name(name() + ".txTcpChecksums") - .desc("Number of tx TCP Checksums done by device") - .precision(0) - .prereq(txBytes) - ; - - txUdpChecksums - .name(name() + ".txUdpChecksums") - .desc("Number of tx UDP Checksums done by device") - .precision(0) - .prereq(txBytes) - ; - - txBandwidth = txBytes * Stats::constant(8) / simSeconds; - rxBandwidth = rxBytes * Stats::constant(8) / simSeconds; - totBandwidth = txBandwidth + rxBandwidth; - totBytes = txBytes + rxBytes; - totPackets = txPackets + rxPackets; - txPacketRate = txPackets / simSeconds; - rxPacketRate = rxPackets / simSeconds; -} - -/** - * This is to write to the PCI general configuration registers - */ -void -Device::writeConfig(int offset, int size, const uint8_t *data) -{ - switch (offset) { - case PCI0_BASE_ADDR0: - // Need to catch writes to BARs to update the PIO interface - PciDev::writeConfig(offset, size, data); - if (BARAddrs[0] != 0) { - if (pioInterface) - pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0])); - - BARAddrs[0] &= EV5::PAddrUncachedMask; - } - break; - - default: - PciDev::writeConfig(offset, size, data); - } -} - -void -Device::prepareIO(int cpu, int index) -{ - int size = virtualRegs.size(); - if (index > size) - panic("Trying to access a vnic that doesn't exist %d > %d\n", - index, size); -} - -void -Device::prepareRead(int cpu, int index) -{ - using namespace Regs; - prepareIO(cpu, index); - - VirtualReg &vnic = virtualRegs[index]; - - // update rx registers - uint64_t rxdone = vnic.RxDone; - rxdone = set_RxDone_Packets(rxdone, rxFifo.countPacketsAfter(rxFifoPtr)); - rxdone = set_RxDone_Empty(rxdone, rxFifo.empty()); - rxdone = set_RxDone_High(rxdone, rxFifo.size() > regs.RxFifoMark); - rxdone = set_RxDone_NotHigh(rxdone, rxLow); - regs.RxData = vnic.RxData; - regs.RxDone = rxdone; - regs.RxWait = rxdone; - - // update tx regsiters - uint64_t txdone = vnic.TxDone; - txdone = set_TxDone_Packets(txdone, txFifo.packets()); - txdone = set_TxDone_Full(txdone, txFifo.avail() < regs.TxMaxCopy); - txdone = set_TxDone_Low(txdone, txFifo.size() < regs.TxFifoMark); - regs.TxData = vnic.TxData; - regs.TxDone = txdone; - regs.TxWait = txdone; -} - -void -Device::prepareWrite(int cpu, int index) -{ - prepareIO(cpu, index); -} - -/** - * I/O read of device register - */ -Fault -Device::read(MemReqPtr &req, uint8_t *data) -{ - assert(config.command & PCI_CMD_MSE); - Fault fault = readBar(req, data); - - if (fault && fault->isMachineCheckFault()) { - panic("address does not map to a BAR pa=%#x va=%#x size=%d", - req->paddr, req->vaddr, req->size); - - return genMachineCheckFault(); - } - - return fault; -} - -Fault -Device::readBar0(MemReqPtr &req, Addr daddr, uint8_t *data) -{ - int cpu = (req->xc->readMiscReg(TheISA::IPR_PALtemp16) >> 8) & 0xff; - Addr index = daddr >> Regs::VirtualShift; - Addr raddr = daddr & Regs::VirtualMask; - - if (!regValid(raddr)) - panic("invalid register: cpu=%d vnic=%d da=%#x pa=%#x va=%#x size=%d", - cpu, index, daddr, req->paddr, req->vaddr, req->size); - - const Regs::Info &info = regInfo(raddr); - if (!info.read) - panic("read %s (write only): " - "cpu=%d vnic=%d da=%#x pa=%#x va=%#x size=%d", - info.name, cpu, index, daddr, req->paddr, req->vaddr, req->size); - - if (req->size != info.size) - panic("read %s (invalid size): " - "cpu=%d vnic=%d da=%#x pa=%#x va=%#x size=%d", - info.name, cpu, index, daddr, req->paddr, req->vaddr, req->size); - - prepareRead(cpu, index); - - uint64_t value = 0; - if (req->size == 4) { - uint32_t ® = *(uint32_t *)data; - reg = regData32(raddr); - value = reg; - } - - if (req->size == 8) { - uint64_t ® = *(uint64_t *)data; - reg = regData64(raddr); - value = reg; - } - - DPRINTF(EthernetPIO, - "read %s: cpu=%d vnic=%d da=%#x pa=%#x va=%#x size=%d val=%#x\n", - info.name, cpu, index, daddr, req->paddr, req->vaddr, req->size, - value); - - // reading the interrupt status register has the side effect of - // clearing it - if (raddr == Regs::IntrStatus) - devIntrClear(); - - return NoFault; -} - -/** - * IPR read of device register - */ -Fault -Device::iprRead(Addr daddr, int cpu, uint64_t &result) -{ - if (!regValid(daddr)) - panic("invalid address: da=%#x", daddr); - - const Regs::Info &info = regInfo(daddr); - if (!info.read) - panic("reading %s (write only): cpu=%d da=%#x", info.name, cpu, daddr); - - DPRINTF(EthernetPIO, "IPR read %s: cpu=%d da=%#x\n", - info.name, cpu, daddr); - - prepareRead(cpu, 0); - - if (info.size == 4) - result = regData32(daddr); - - if (info.size == 8) - result = regData64(daddr); - - DPRINTF(EthernetPIO, "IPR read %s: cpu=%s da=%#x val=%#x\n", - info.name, cpu, result); - - return NoFault; -} - -/** - * I/O write of device register - */ -Fault -Device::write(MemReqPtr &req, const uint8_t *data) -{ - assert(config.command & PCI_CMD_MSE); - Fault fault = writeBar(req, data); - - if (fault && fault->isMachineCheckFault()) { - panic("address does not map to a BAR pa=%#x va=%#x size=%d", - req->paddr, req->vaddr, req->size); - - return genMachineCheckFault(); - } - - return fault; -} - -Fault -Device::writeBar0(MemReqPtr &req, Addr daddr, const uint8_t *data) -{ - int cpu = (req->xc->readMiscReg(TheISA::IPR_PALtemp16) >> 8) & 0xff; - Addr index = daddr >> Regs::VirtualShift; - Addr raddr = daddr & Regs::VirtualMask; - - if (!regValid(raddr)) - panic("invalid address: cpu=%d da=%#x pa=%#x va=%#x size=%d", - cpu, daddr, req->paddr, req->vaddr, req->size); - - const Regs::Info &info = regInfo(raddr); - if (!info.write) - panic("write %s (read only): " - "cpu=%d vnic=%d da=%#x pa=%#x va=%#x size=%d", - info.name, cpu, index, daddr, req->paddr, req->vaddr, req->size); - - if (req->size != info.size) - panic("write %s (invalid size): " - "cpu=%d vnic=%d da=%#x pa=%#x va=%#x size=%d", - info.name, cpu, index, daddr, req->paddr, req->vaddr, req->size); - - uint32_t reg32 = *(uint32_t *)data; - uint64_t reg64 = *(uint64_t *)data; - VirtualReg &vnic = virtualRegs[index]; - - DPRINTF(EthernetPIO, - "write %s vnic %d: cpu=%d val=%#x da=%#x pa=%#x va=%#x size=%d\n", - info.name, index, cpu, info.size == 4 ? reg32 : reg64, daddr, - req->paddr, req->vaddr, req->size); - - prepareWrite(cpu, index); - - switch (raddr) { - case Regs::Config: - changeConfig(reg32); - break; - - case Regs::Command: - command(reg32); - break; - - case Regs::IntrStatus: - devIntrClear(regs.IntrStatus & reg32); - break; - - case Regs::IntrMask: - devIntrChangeMask(reg32); - break; - - case Regs::RxData: - if (Regs::get_RxDone_Busy(vnic.RxDone)) - panic("receive machine busy with another request! rxState=%s", - RxStateStrings[rxState]); - - vnic.rxUnique = rxUnique++; - vnic.RxDone = Regs::RxDone_Busy; - vnic.RxData = reg64; - - if (Regs::get_RxData_Vaddr(reg64)) { - Addr vaddr = Regs::get_RxData_Addr(reg64); - Addr paddr = vtophys(req->xc, vaddr); - DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d): " - "vaddr=%#x, paddr=%#x\n", - index, vnic.rxUnique, vaddr, paddr); - - vnic.RxData = Regs::set_RxData_Addr(vnic.RxData, paddr); - } else { - DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d)\n", - index, vnic.rxUnique); - } - - if (vnic.rxPacket == rxFifo.end()) { - DPRINTF(EthernetPIO, "request new packet...appending to rxList\n"); - rxList.push_back(index); - } else { - DPRINTF(EthernetPIO, "packet exists...appending to rxBusy\n"); - rxBusy.push_back(index); - } - - if (rxEnable && (rxState == rxIdle || rxState == rxFifoBlock)) { - rxState = rxFifoBlock; - rxKick(); - } - break; - - case Regs::TxData: - if (Regs::get_TxDone_Busy(vnic.TxDone)) - panic("transmit machine busy with another request! txState=%s", - TxStateStrings[txState]); - - vnic.txUnique = txUnique++; - vnic.TxDone = Regs::TxDone_Busy; - vnic.TxData = reg64; - - if (Regs::get_TxData_Vaddr(reg64)) { - Addr vaddr = Regs::get_TxData_Addr(reg64); - Addr paddr = vtophys(req->xc, vaddr); - DPRINTF(EthernetPIO, "write TxData vnic %d (rxunique %d): " - "vaddr=%#x, paddr=%#x\n", - index, vnic.txUnique, vaddr, paddr); - - vnic.TxData = Regs::set_TxData_Addr(vnic.TxData, paddr); - } else { - DPRINTF(EthernetPIO, "write TxData vnic %d (rxunique %d)\n", - index, vnic.txUnique); - } - - if (txList.empty() || txList.front() != index) - txList.push_back(index); - if (txEnable && txState == txIdle && txList.front() == index) { - txState = txFifoBlock; - txKick(); - } - break; - } - - return NoFault; -} - -void -Device::devIntrPost(uint32_t interrupts) -{ - if ((interrupts & Regs::Intr_Res)) - panic("Cannot set a reserved interrupt"); - - regs.IntrStatus |= interrupts; - - DPRINTF(EthernetIntr, - "interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n", - interrupts, regs.IntrStatus, regs.IntrMask); - - interrupts = regs.IntrStatus & regs.IntrMask; - - // Intr_RxHigh is special, we only signal it if we've emptied the fifo - // and then filled it above the high watermark - if (rxEmpty) - rxEmpty = false; - else - interrupts &= ~Regs::Intr_RxHigh; - - // Intr_TxLow is special, we only signal it if we've filled up the fifo - // and then dropped below the low watermark - if (txFull) - txFull = false; - else - interrupts &= ~Regs::Intr_TxLow; - - if (interrupts) { - Tick when = curTick; - if ((interrupts & Regs::Intr_NoDelay) == 0) - when += intrDelay; - cpuIntrPost(when); - } -} - -void -Device::devIntrClear(uint32_t interrupts) -{ - if ((interrupts & Regs::Intr_Res)) - panic("Cannot clear a reserved interrupt"); - - regs.IntrStatus &= ~interrupts; - - DPRINTF(EthernetIntr, - "interrupt cleared from intStatus: intr=%x status=%x mask=%x\n", - interrupts, regs.IntrStatus, regs.IntrMask); - - if (!(regs.IntrStatus & regs.IntrMask)) - cpuIntrClear(); -} - -void -Device::devIntrChangeMask(uint32_t newmask) -{ - if (regs.IntrMask == newmask) - return; - - regs.IntrMask = newmask; - - DPRINTF(EthernetIntr, - "interrupt mask changed: intStatus=%x intMask=%x masked=%x\n", - regs.IntrStatus, regs.IntrMask, regs.IntrStatus & regs.IntrMask); - - if (regs.IntrStatus & regs.IntrMask) - cpuIntrPost(curTick); - else - cpuIntrClear(); -} - -void -Base::cpuIntrPost(Tick when) -{ - // If the interrupt you want to post is later than an interrupt - // already scheduled, just let it post in the coming one and don't - // schedule another. - // HOWEVER, must be sure that the scheduled intrTick is in the - // future (this was formerly the source of a bug) - /** - * @todo this warning should be removed and the intrTick code should - * be fixed. - */ - assert(when >= curTick); - assert(intrTick >= curTick || intrTick == 0); - if (!cpuIntrEnable) { - DPRINTF(EthernetIntr, "interrupts not enabled.\n", - intrTick); - return; - } - - if (when > intrTick && intrTick != 0) { - DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n", - intrTick); - return; - } - - intrTick = when; - if (intrTick < curTick) { - debug_break(); - intrTick = curTick; - } - - DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", - intrTick); - - if (intrEvent) - intrEvent->squash(); - intrEvent = new IntrEvent(this, true); - intrEvent->schedule(intrTick); -} - -void -Base::cpuInterrupt() -{ - assert(intrTick == curTick); - - // Whether or not there's a pending interrupt, we don't care about - // it anymore - intrEvent = 0; - intrTick = 0; - - // Don't send an interrupt if there's already one - if (cpuPendingIntr) { - DPRINTF(EthernetIntr, - "would send an interrupt now, but there's already pending\n"); - } else { - // Send interrupt - cpuPendingIntr = true; - - DPRINTF(EthernetIntr, "posting interrupt\n"); - intrPost(); - } -} - -void -Base::cpuIntrClear() -{ - if (!cpuPendingIntr) - return; - - if (intrEvent) { - intrEvent->squash(); - intrEvent = 0; - } - - intrTick = 0; - - cpuPendingIntr = false; - - DPRINTF(EthernetIntr, "clearing cchip interrupt\n"); - intrClear(); -} - -bool -Base::cpuIntrPending() const -{ return cpuPendingIntr; } - -void -Device::changeConfig(uint32_t newconf) -{ - uint32_t changed = regs.Config ^ newconf; - if (!changed) - return; - - regs.Config = newconf; - - if ((changed & Regs::Config_IntEn)) { - cpuIntrEnable = regs.Config & Regs::Config_IntEn; - if (cpuIntrEnable) { - if (regs.IntrStatus & regs.IntrMask) - cpuIntrPost(curTick); - } else { - cpuIntrClear(); - } - } - - if ((changed & Regs::Config_TxEn)) { - txEnable = regs.Config & Regs::Config_TxEn; - if (txEnable) - txKick(); - } - - if ((changed & Regs::Config_RxEn)) { - rxEnable = regs.Config & Regs::Config_RxEn; - if (rxEnable) - rxKick(); - } -} - -void -Device::command(uint32_t command) -{ - if (command & Regs::Command_Intr) - devIntrPost(Regs::Intr_Soft); - - if (command & Regs::Command_Reset) - reset(); -} - -void -Device::reset() -{ - using namespace Regs; - - memset(®s, 0, sizeof(regs)); - - regs.Config = 0; - if (params()->rx_thread) - regs.Config |= Config_RxThread; - if (params()->tx_thread) - regs.Config |= Config_TxThread; - if (params()->rss) - regs.Config |= Config_RSS; - if (params()->zero_copy) - regs.Config |= Config_ZeroCopy; - if (params()->delay_copy) - regs.Config |= Config_DelayCopy; - if (params()->virtual_addr) - regs.Config |= Config_Vaddr; - - if (params()->delay_copy && params()->zero_copy) - panic("Can't delay copy and zero copy"); - - regs.IntrMask = Intr_Soft | Intr_RxHigh | Intr_RxPacket | Intr_TxLow; - regs.RxMaxCopy = params()->rx_max_copy; - regs.TxMaxCopy = params()->tx_max_copy; - regs.RxMaxIntr = params()->rx_max_intr; - regs.VirtualCount = params()->virtual_count; - regs.RxFifoSize = params()->rx_fifo_size; - regs.TxFifoSize = params()->tx_fifo_size; - regs.RxFifoMark = params()->rx_fifo_threshold; - regs.TxFifoMark = params()->tx_fifo_threshold; - regs.HwAddr = params()->eaddr; - - rxList.clear(); - rxBusy.clear(); - rxActive = -1; - txList.clear(); - - rxState = rxIdle; - txState = txIdle; - - rxFifo.clear(); - rxFifoPtr = rxFifo.end(); - txFifo.clear(); - rxEmpty = false; - rxLow = true; - txFull = false; - - int size = virtualRegs.size(); - virtualRegs.clear(); - virtualRegs.resize(size); - for (int i = 0; i < size; ++i) - virtualRegs[i].rxPacket = rxFifo.end(); -} - -void -Device::rxDmaCopy() -{ - assert(rxState == rxCopy); - rxState = rxCopyDone; - DPRINTF(EthernetDMA, "begin rx dma write paddr=%#x len=%d\n", - rxDmaAddr, rxDmaLen); - physmem->dma_write(rxDmaAddr, (uint8_t *)rxDmaData, rxDmaLen); - DPRINTF(EthernetDMA, "end rx dma write paddr=%#x len=%d\n", - rxDmaAddr, rxDmaLen); - DDUMP(EthernetData, rxDmaData, rxDmaLen); -} - -void -Device::rxDmaDone() -{ - rxDmaCopy(); - - // If the transmit state machine has a pending DMA, let it go first - if (txState == txBeginCopy) - txKick(); - - rxKick(); -} - -void -Device::rxKick() -{ - VirtualReg *vnic = NULL; - - DPRINTF(EthernetSM, "rxKick: rxState=%s (rxFifo.size=%d)\n", - RxStateStrings[rxState], rxFifo.size()); - - if (rxKickTick > curTick) { - DPRINTF(EthernetSM, "rxKick: exiting, can't run till %d\n", - rxKickTick); - return; - } - - next: - if (rxState == rxIdle) - goto exit; - - if (rxActive == -1) { - if (rxState != rxFifoBlock) - panic("no active vnic while in state %s", RxStateStrings[rxState]); - - DPRINTF(EthernetSM, "processing rxState=%s\n", - RxStateStrings[rxState]); - } else { - vnic = &virtualRegs[rxActive]; - DPRINTF(EthernetSM, - "processing rxState=%s for vnic %d (rxunique %d)\n", - RxStateStrings[rxState], rxActive, vnic->rxUnique); - } - - switch (rxState) { - case rxFifoBlock: - if (DTRACE(EthernetSM)) { - PacketFifo::iterator end = rxFifo.end(); - int size = virtualRegs.size(); - for (int i = 0; i < size; ++i) { - VirtualReg *vn = &virtualRegs[i]; - if (vn->rxPacket != end && - !Regs::get_RxDone_Busy(vn->RxDone)) { - DPRINTF(EthernetSM, - "vnic %d (rxunique %d), has outstanding packet %d\n", - i, vn->rxUnique, - rxFifo.countPacketsBefore(vn->rxPacket)); - } - } - } - - if (!rxBusy.empty()) { - rxActive = rxBusy.front(); - rxBusy.pop_front(); - vnic = &virtualRegs[rxActive]; - - if (vnic->rxPacket == rxFifo.end()) - panic("continuing vnic without packet\n"); - - DPRINTF(EthernetSM, - "continue processing for vnic %d (rxunique %d)\n", - rxActive, vnic->rxUnique); - - rxState = rxBeginCopy; - - break; - } - - if (rxFifoPtr == rxFifo.end()) { - DPRINTF(EthernetSM, "receive waiting for data. Nothing to do.\n"); - goto exit; - } - - if (rxList.empty()) - panic("Not idle, but nothing to do!"); - - assert(!rxFifo.empty()); - - rxActive = rxList.front(); - rxList.pop_front(); - vnic = &virtualRegs[rxActive]; - - DPRINTF(EthernetSM, - "processing new packet for vnic %d (rxunique %d)\n", - rxActive, vnic->rxUnique); - - // Grab a new packet from the fifo. - vnic->rxPacket = rxFifoPtr++; - vnic->rxPacketOffset = 0; - vnic->rxPacketBytes = (*vnic->rxPacket)->length; - assert(vnic->rxPacketBytes); - - vnic->rxDoneData = 0; - /* scope for variables */ { - IpPtr ip(*vnic->rxPacket); - if (ip) { - DPRINTF(Ethernet, "ID is %d\n", ip->id()); - vnic->rxDoneData |= Regs::RxDone_IpPacket; - rxIpChecksums++; - if (cksum(ip) != 0) { - DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); - vnic->rxDoneData |= Regs::RxDone_IpError; - } - TcpPtr tcp(ip); - UdpPtr udp(ip); - if (tcp) { - DPRINTF(Ethernet, - "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", - tcp->sport(), tcp->dport(), tcp->seq(), - tcp->ack()); - vnic->rxDoneData |= Regs::RxDone_TcpPacket; - rxTcpChecksums++; - if (cksum(tcp) != 0) { - DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); - vnic->rxDoneData |= Regs::RxDone_TcpError; - } - } else if (udp) { - vnic->rxDoneData |= Regs::RxDone_UdpPacket; - rxUdpChecksums++; - if (cksum(udp) != 0) { - DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); - vnic->rxDoneData |= Regs::RxDone_UdpError; - } - } - } - } - rxState = rxBeginCopy; - break; - - case rxBeginCopy: - if (dmaInterface && dmaInterface->busy()) - goto exit; - - rxDmaAddr = plat->pciToDma(Regs::get_RxData_Addr(vnic->RxData)); - rxDmaLen = min<int>(Regs::get_RxData_Len(vnic->RxData), - vnic->rxPacketBytes); - rxDmaData = (*vnic->rxPacket)->data + vnic->rxPacketOffset; - rxState = rxCopy; - - if (rxDmaAddr == 1LL) { - rxState = rxCopyDone; - break; - } - - if (dmaInterface) { - dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, - curTick, &rxDmaEvent, true); - goto exit; - } - - if (dmaWriteDelay != 0 || dmaWriteFactor != 0) { - Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor; - Tick start = curTick + dmaWriteDelay + factor; - rxDmaEvent.schedule(start); - goto exit; - } - - rxDmaCopy(); - break; - - case rxCopy: - DPRINTF(EthernetSM, "receive machine still copying\n"); - goto exit; - - case rxCopyDone: - vnic->RxDone = vnic->rxDoneData; - vnic->RxDone |= Regs::RxDone_Complete; - - if (vnic->rxPacketBytes == rxDmaLen) { - // Packet is complete. Indicate how many bytes were copied - vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, rxDmaLen); - - DPRINTF(EthernetSM, - "rxKick: packet complete on vnic %d (rxunique %d)\n", - rxActive, vnic->rxUnique); - rxFifo.remove(vnic->rxPacket); - vnic->rxPacket = rxFifo.end(); - } else { - vnic->rxPacketBytes -= rxDmaLen; - vnic->rxPacketOffset += rxDmaLen; - vnic->RxDone |= Regs::RxDone_More; - vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, - vnic->rxPacketBytes); - DPRINTF(EthernetSM, - "rxKick: packet not complete on vnic %d (rxunique %d): " - "%d bytes left\n", - rxActive, vnic->rxUnique, vnic->rxPacketBytes); - } - - rxActive = -1; - rxState = rxBusy.empty() && rxList.empty() ? rxIdle : rxFifoBlock; - - if (rxFifo.empty()) { - devIntrPost(Regs::Intr_RxEmpty); - rxEmpty = true; - } - - if (rxFifo.size() < params()->rx_fifo_low_mark) - rxLow = true; - - if (rxFifo.size() > params()->rx_fifo_threshold) - rxLow = false; - - devIntrPost(Regs::Intr_RxDMA); - break; - - default: - panic("Invalid rxState!"); - } - - DPRINTF(EthernetSM, "entering next rxState=%s\n", - RxStateStrings[rxState]); - - goto next; - - exit: - /** - * @todo do we want to schedule a future kick? - */ - DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", - RxStateStrings[rxState]); -} - -void -Device::txDmaCopy() -{ - assert(txState == txCopy); - txState = txCopyDone; - physmem->dma_read((uint8_t *)txDmaData, txDmaAddr, txDmaLen); - DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", - txDmaAddr, txDmaLen); - DDUMP(EthernetData, txDmaData, txDmaLen); -} - -void -Device::txDmaDone() -{ - txDmaCopy(); - - // If the receive state machine has a pending DMA, let it go first - if (rxState == rxBeginCopy) - rxKick(); - - txKick(); -} - -void -Device::transmit() -{ - if (txFifo.empty()) { - DPRINTF(Ethernet, "nothing to transmit\n"); - return; - } - - uint32_t interrupts; - PacketPtr packet = txFifo.front(); - if (!interface->sendPacket(packet)) { - DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n", - txFifo.avail()); - goto reschedule; - } - - txFifo.pop(); -#if TRACING_ON - if (DTRACE(Ethernet)) { - IpPtr ip(packet); - if (ip) { - DPRINTF(Ethernet, "ID is %d\n", ip->id()); - TcpPtr tcp(ip); - if (tcp) { - DPRINTF(Ethernet, - "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", - tcp->sport(), tcp->dport(), tcp->seq(), - tcp->ack()); - } - } - } -#endif - - DDUMP(EthernetData, packet->data, packet->length); - txBytes += packet->length; - txPackets++; - - DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n", - txFifo.avail()); - - interrupts = Regs::Intr_TxPacket; - if (txFifo.size() < regs.TxFifoMark) - interrupts |= Regs::Intr_TxLow; - devIntrPost(interrupts); - - reschedule: - if (!txFifo.empty() && !txEvent.scheduled()) { - DPRINTF(Ethernet, "reschedule transmit\n"); - txEvent.schedule(curTick + retryTime); - } -} - -void -Device::txKick() -{ - VirtualReg *vnic; - DPRINTF(EthernetSM, "txKick: txState=%s (txFifo.size=%d)\n", - TxStateStrings[txState], txFifo.size()); - - if (txKickTick > curTick) { - DPRINTF(EthernetSM, "txKick: exiting, can't run till %d\n", - txKickTick); - return; - } - - next: - if (txState == txIdle) - goto exit; - - assert(!txList.empty()); - vnic = &virtualRegs[txList.front()]; - - switch (txState) { - case txFifoBlock: - assert(Regs::get_TxDone_Busy(vnic->TxDone)); - if (!txPacket) { - // Grab a new packet from the fifo. - txPacket = new PacketData(16384); - txPacketOffset = 0; - } - - if (txFifo.avail() - txPacket->length < - Regs::get_TxData_Len(vnic->TxData)) { - DPRINTF(EthernetSM, "transmit fifo full. Nothing to do.\n"); - goto exit; - } - - txState = txBeginCopy; - break; - - case txBeginCopy: - if (dmaInterface && dmaInterface->busy()) - goto exit; - - txDmaAddr = plat->pciToDma(Regs::get_TxData_Addr(vnic->TxData)); - txDmaLen = Regs::get_TxData_Len(vnic->TxData); - txDmaData = txPacket->data + txPacketOffset; - txState = txCopy; - - if (dmaInterface) { - dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, - curTick, &txDmaEvent, true); - goto exit; - } - - if (dmaReadDelay != 0 || dmaReadFactor != 0) { - Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor; - Tick start = curTick + dmaReadDelay + factor; - txDmaEvent.schedule(start); - goto exit; - } - - txDmaCopy(); - break; - - case txCopy: - DPRINTF(EthernetSM, "transmit machine still copying\n"); - goto exit; - - case txCopyDone: - vnic->TxDone = txDmaLen | Regs::TxDone_Complete; - txPacket->length += txDmaLen; - if ((vnic->TxData & Regs::TxData_More)) { - txPacketOffset += txDmaLen; - txState = txIdle; - devIntrPost(Regs::Intr_TxDMA); - break; - } - - assert(txPacket->length <= txFifo.avail()); - if ((vnic->TxData & Regs::TxData_Checksum)) { - IpPtr ip(txPacket); - if (ip) { - TcpPtr tcp(ip); - if (tcp) { - tcp->sum(0); - tcp->sum(cksum(tcp)); - txTcpChecksums++; - } - - UdpPtr udp(ip); - if (udp) { - udp->sum(0); - udp->sum(cksum(udp)); - txUdpChecksums++; - } - - ip->sum(0); - ip->sum(cksum(ip)); - txIpChecksums++; - } - } - - txFifo.push(txPacket); - if (txFifo.avail() < regs.TxMaxCopy) { - devIntrPost(Regs::Intr_TxFull); - txFull = true; - } - txPacket = 0; - transmit(); - txList.pop_front(); - txState = txList.empty() ? txIdle : txFifoBlock; - devIntrPost(Regs::Intr_TxDMA); - break; - - default: - panic("Invalid txState!"); - } - - DPRINTF(EthernetSM, "entering next txState=%s\n", - TxStateStrings[txState]); - - goto next; - - exit: - /** - * @todo do we want to schedule a future kick? - */ - DPRINTF(EthernetSM, "tx state machine exited txState=%s\n", - TxStateStrings[txState]); -} - -void -Device::transferDone() -{ - if (txFifo.empty()) { - DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n"); - return; - } - - DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); - - if (txEvent.scheduled()) - txEvent.reschedule(curTick + cycles(1)); - else - txEvent.schedule(curTick + cycles(1)); -} - -bool -Device::rxFilter(const PacketPtr &packet) -{ - if (!Regs::get_Config_Filter(regs.Config)) - return false; - - panic("receive filter not implemented\n"); - bool drop = true; - -#if 0 - string type; - - EthHdr *eth = packet->eth(); - if (eth->unicast()) { - // If we're accepting all unicast addresses - if (acceptUnicast) - drop = false; - - // If we make a perfect match - if (acceptPerfect && params->eaddr == eth.dst()) - drop = false; - - if (acceptArp && eth->type() == ETH_TYPE_ARP) - drop = false; - - } else if (eth->broadcast()) { - // if we're accepting broadcasts - if (acceptBroadcast) - drop = false; - - } else if (eth->multicast()) { - // if we're accepting all multicasts - if (acceptMulticast) - drop = false; - - } - - if (drop) { - DPRINTF(Ethernet, "rxFilter drop\n"); - DDUMP(EthernetData, packet->data, packet->length); - } -#endif - return drop; -} - -bool -Device::recvPacket(PacketPtr packet) -{ - rxBytes += packet->length; - rxPackets++; - - DPRINTF(Ethernet, "Receiving packet from wire, rxFifo Available is %d\n", - rxFifo.avail()); - - if (!rxEnable) { - DPRINTF(Ethernet, "receive disabled...packet dropped\n"); - return true; - } - - if (rxFilter(packet)) { - DPRINTF(Ethernet, "packet filtered...dropped\n"); - return true; - } - - if (rxFifo.size() >= regs.RxFifoMark) - devIntrPost(Regs::Intr_RxHigh); - - if (!rxFifo.push(packet)) { - DPRINTF(Ethernet, - "packet will not fit in receive buffer...packet dropped\n"); - return false; - } - - // If we were at the last element, back up one ot go to the new - // last element of the list. - if (rxFifoPtr == rxFifo.end()) - --rxFifoPtr; - - devIntrPost(Regs::Intr_RxPacket); - rxKick(); - return true; -} - -//===================================================================== -// -// -void -Base::serialize(ostream &os) -{ - // Serialize the PciDev base class - PciDev::serialize(os); - - SERIALIZE_SCALAR(rxEnable); - SERIALIZE_SCALAR(txEnable); - SERIALIZE_SCALAR(cpuIntrEnable); - - /* - * Keep track of pending interrupt status. - */ - SERIALIZE_SCALAR(intrTick); - SERIALIZE_SCALAR(cpuPendingIntr); - Tick intrEventTick = 0; - if (intrEvent) - intrEventTick = intrEvent->when(); - SERIALIZE_SCALAR(intrEventTick); -} - -void -Base::unserialize(Checkpoint *cp, const std::string §ion) -{ - // Unserialize the PciDev base class - PciDev::unserialize(cp, section); - - UNSERIALIZE_SCALAR(rxEnable); - UNSERIALIZE_SCALAR(txEnable); - UNSERIALIZE_SCALAR(cpuIntrEnable); - - /* - * Keep track of pending interrupt status. - */ - UNSERIALIZE_SCALAR(intrTick); - UNSERIALIZE_SCALAR(cpuPendingIntr); - Tick intrEventTick; - UNSERIALIZE_SCALAR(intrEventTick); - if (intrEventTick) { - intrEvent = new IntrEvent(this, true); - intrEvent->schedule(intrEventTick); - } -} - -void -Device::serialize(ostream &os) -{ - int count; - - // Serialize the PciDev base class - Base::serialize(os); - - if (rxState == rxCopy) - panic("can't serialize with an in flight dma request rxState=%s", - RxStateStrings[rxState]); - - if (txState == txCopy) - panic("can't serialize with an in flight dma request txState=%s", - TxStateStrings[txState]); - - /* - * Serialize the device registers - */ - SERIALIZE_SCALAR(regs.Config); - SERIALIZE_SCALAR(regs.IntrStatus); - SERIALIZE_SCALAR(regs.IntrMask); - SERIALIZE_SCALAR(regs.RxMaxCopy); - SERIALIZE_SCALAR(regs.TxMaxCopy); - SERIALIZE_SCALAR(regs.RxMaxIntr); - SERIALIZE_SCALAR(regs.VirtualCount); - SERIALIZE_SCALAR(regs.RxData); - SERIALIZE_SCALAR(regs.RxDone); - SERIALIZE_SCALAR(regs.TxData); - SERIALIZE_SCALAR(regs.TxDone); - - /* - * Serialize the virtual nic state - */ - int virtualRegsSize = virtualRegs.size(); - SERIALIZE_SCALAR(virtualRegsSize); - for (int i = 0; i < virtualRegsSize; ++i) { - VirtualReg *vnic = &virtualRegs[i]; - - string reg = csprintf("vnic%d", i); - paramOut(os, reg + ".RxData", vnic->RxData); - paramOut(os, reg + ".RxDone", vnic->RxDone); - paramOut(os, reg + ".TxData", vnic->TxData); - paramOut(os, reg + ".TxDone", vnic->TxDone); - - bool rxPacketExists = vnic->rxPacket != rxFifo.end(); - paramOut(os, reg + ".rxPacketExists", rxPacketExists); - if (rxPacketExists) { - int rxPacket = 0; - PacketFifo::iterator i = rxFifo.begin(); - while (i != vnic->rxPacket) { - assert(i != rxFifo.end()); - ++i; - ++rxPacket; - } - - paramOut(os, reg + ".rxPacket", rxPacket); - paramOut(os, reg + ".rxPacketOffset", vnic->rxPacketOffset); - paramOut(os, reg + ".rxPacketBytes", vnic->rxPacketBytes); - } - paramOut(os, reg + ".rxDoneData", vnic->rxDoneData); - } - - int rxFifoPtr = rxFifo.countPacketsBefore(this->rxFifoPtr); - SERIALIZE_SCALAR(rxFifoPtr); - - SERIALIZE_SCALAR(rxActive); - - VirtualList::iterator i, end; - for (count = 0, i = rxList.begin(), end = rxList.end(); i != end; ++i) - paramOut(os, csprintf("rxList%d", count++), *i); - int rxListSize = count; - SERIALIZE_SCALAR(rxListSize); - - for (count = 0, i = rxBusy.begin(), end = rxBusy.end(); i != end; ++i) - paramOut(os, csprintf("rxBusy%d", count++), *i); - int rxBusySize = count; - SERIALIZE_SCALAR(rxBusySize); - - for (count = 0, i = txList.begin(), end = txList.end(); i != end; ++i) - paramOut(os, csprintf("txList%d", count++), *i); - int txListSize = count; - SERIALIZE_SCALAR(txListSize); - - /* - * Serialize rx state machine - */ - int rxState = this->rxState; - SERIALIZE_SCALAR(rxState); - SERIALIZE_SCALAR(rxEmpty); - SERIALIZE_SCALAR(rxLow); - rxFifo.serialize("rxFifo", os); - - /* - * Serialize tx state machine - */ - int txState = this->txState; - SERIALIZE_SCALAR(txState); - SERIALIZE_SCALAR(txFull); - txFifo.serialize("txFifo", os); - bool txPacketExists = txPacket; - SERIALIZE_SCALAR(txPacketExists); - if (txPacketExists) { - txPacket->serialize("txPacket", os); - SERIALIZE_SCALAR(txPacketOffset); - SERIALIZE_SCALAR(txPacketBytes); - } - - /* - * If there's a pending transmit, store the time so we can - * reschedule it later - */ - Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0; - SERIALIZE_SCALAR(transmitTick); -} - -void -Device::unserialize(Checkpoint *cp, const std::string §ion) -{ - // Unserialize the PciDev base class - Base::unserialize(cp, section); - - /* - * Unserialize the device registers - */ - UNSERIALIZE_SCALAR(regs.Config); - UNSERIALIZE_SCALAR(regs.IntrStatus); - UNSERIALIZE_SCALAR(regs.IntrMask); - UNSERIALIZE_SCALAR(regs.RxMaxCopy); - UNSERIALIZE_SCALAR(regs.TxMaxCopy); - UNSERIALIZE_SCALAR(regs.RxMaxIntr); - UNSERIALIZE_SCALAR(regs.VirtualCount); - UNSERIALIZE_SCALAR(regs.RxData); - UNSERIALIZE_SCALAR(regs.RxDone); - UNSERIALIZE_SCALAR(regs.TxData); - UNSERIALIZE_SCALAR(regs.TxDone); - - UNSERIALIZE_SCALAR(rxActive); - - int rxListSize; - UNSERIALIZE_SCALAR(rxListSize); - rxList.clear(); - for (int i = 0; i < rxListSize; ++i) { - int value; - paramIn(cp, section, csprintf("rxList%d", i), value); - rxList.push_back(value); - } - - int rxBusySize; - UNSERIALIZE_SCALAR(rxBusySize); - rxBusy.clear(); - for (int i = 0; i < rxBusySize; ++i) { - int value; - paramIn(cp, section, csprintf("rxBusy%d", i), value); - rxBusy.push_back(value); - } - - int txListSize; - UNSERIALIZE_SCALAR(txListSize); - txList.clear(); - for (int i = 0; i < txListSize; ++i) { - int value; - paramIn(cp, section, csprintf("txList%d", i), value); - txList.push_back(value); - } - - /* - * Unserialize rx state machine - */ - int rxState; - UNSERIALIZE_SCALAR(rxState); - UNSERIALIZE_SCALAR(rxEmpty); - UNSERIALIZE_SCALAR(rxLow); - this->rxState = (RxState) rxState; - rxFifo.unserialize("rxFifo", cp, section); - - int rxFifoPtr; - UNSERIALIZE_SCALAR(rxFifoPtr); - this->rxFifoPtr = rxFifo.begin(); - for (int i = 0; i < rxFifoPtr; ++i) - ++this->rxFifoPtr; - - /* - * Unserialize tx state machine - */ - int txState; - UNSERIALIZE_SCALAR(txState); - UNSERIALIZE_SCALAR(txFull); - this->txState = (TxState) txState; - txFifo.unserialize("txFifo", cp, section); - bool txPacketExists; - UNSERIALIZE_SCALAR(txPacketExists); - txPacket = 0; - if (txPacketExists) { - txPacket = new PacketData(16384); - txPacket->unserialize("txPacket", cp, section); - UNSERIALIZE_SCALAR(txPacketOffset); - UNSERIALIZE_SCALAR(txPacketBytes); - } - - /* - * unserialize the virtual nic registers/state - * - * this must be done after the unserialization of the rxFifo - * because the packet iterators depend on the fifo being populated - */ - int virtualRegsSize; - UNSERIALIZE_SCALAR(virtualRegsSize); - virtualRegs.clear(); - virtualRegs.resize(virtualRegsSize); - for (int i = 0; i < virtualRegsSize; ++i) { - VirtualReg *vnic = &virtualRegs[i]; - string reg = csprintf("vnic%d", i); - - paramIn(cp, section, reg + ".RxData", vnic->RxData); - paramIn(cp, section, reg + ".RxDone", vnic->RxDone); - paramIn(cp, section, reg + ".TxData", vnic->TxData); - paramIn(cp, section, reg + ".TxDone", vnic->TxDone); - - vnic->rxUnique = rxUnique++; - vnic->txUnique = txUnique++; - - bool rxPacketExists; - paramIn(cp, section, reg + ".rxPacketExists", rxPacketExists); - if (rxPacketExists) { - int rxPacket; - paramIn(cp, section, reg + ".rxPacket", rxPacket); - vnic->rxPacket = rxFifo.begin(); - while (rxPacket--) - ++vnic->rxPacket; - - paramIn(cp, section, reg + ".rxPacketOffset", - vnic->rxPacketOffset); - paramIn(cp, section, reg + ".rxPacketBytes", vnic->rxPacketBytes); - } else { - vnic->rxPacket = rxFifo.end(); - } - paramIn(cp, section, reg + ".rxDoneData", vnic->rxDoneData); - } - - /* - * If there's a pending transmit, reschedule it now - */ - Tick transmitTick; - UNSERIALIZE_SCALAR(transmitTick); - if (transmitTick) - txEvent.schedule(curTick + transmitTick); - - /* - * re-add addrRanges to bus bridges - */ - if (pioInterface) - pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0])); -} - -Tick -Device::cacheAccess(MemReqPtr &req) -{ - Addr daddr; - int bar; - if (!getBAR(req->paddr, daddr, bar)) - panic("address does not map to a BAR pa=%#x va=%#x size=%d", - req->paddr, req->vaddr, req->size); - - DPRINTF(EthernetPIO, "timing %s to paddr=%#x bar=%d daddr=%#x\n", - req->cmd.toString(), req->paddr, bar, daddr); - - return curTick + pioLatency; -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(Interface) - - SimObjectParam<EtherInt *> peer; - SimObjectParam<Device *> device; - -END_DECLARE_SIM_OBJECT_PARAMS(Interface) - -BEGIN_INIT_SIM_OBJECT_PARAMS(Interface) - - INIT_PARAM_DFLT(peer, "peer interface", NULL), - INIT_PARAM(device, "Ethernet device of this interface") - -END_INIT_SIM_OBJECT_PARAMS(Interface) - -CREATE_SIM_OBJECT(Interface) -{ - Interface *dev_int = new Interface(getInstanceName(), device); - - EtherInt *p = (EtherInt *)peer; - if (p) { - dev_int->setPeer(p); - p->setPeer(dev_int); - } - - return dev_int; -} - -REGISTER_SIM_OBJECT("SinicInt", Interface) - - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(Device) - - Param<Tick> clock; - - Param<Addr> addr; - SimObjectParam<MemoryController *> mmu; - SimObjectParam<PhysicalMemory *> physmem; - SimObjectParam<PciConfigAll *> configspace; - SimObjectParam<PciConfigData *> configdata; - SimObjectParam<Platform *> platform; - Param<uint32_t> pci_bus; - Param<uint32_t> pci_dev; - Param<uint32_t> pci_func; - - SimObjectParam<HierParams *> hier; - SimObjectParam<Bus*> pio_bus; - SimObjectParam<Bus*> dma_bus; - SimObjectParam<Bus*> payload_bus; - Param<Tick> dma_read_delay; - Param<Tick> dma_read_factor; - Param<Tick> dma_write_delay; - Param<Tick> dma_write_factor; - Param<bool> dma_no_allocate; - Param<Tick> pio_latency; - Param<Tick> intr_delay; - - Param<Tick> rx_delay; - Param<Tick> tx_delay; - Param<uint32_t> rx_max_copy; - Param<uint32_t> tx_max_copy; - Param<uint32_t> rx_max_intr; - Param<uint32_t> rx_fifo_size; - Param<uint32_t> tx_fifo_size; - Param<uint32_t> rx_fifo_threshold; - Param<uint32_t> rx_fifo_low_mark; - Param<uint32_t> tx_fifo_high_mark; - Param<uint32_t> tx_fifo_threshold; - - Param<bool> rx_filter; - Param<string> hardware_address; - Param<bool> rx_thread; - Param<bool> tx_thread; - Param<bool> rss; - Param<uint32_t> virtual_count; - Param<bool> zero_copy; - Param<bool> delay_copy; - Param<bool> virtual_addr; - -END_DECLARE_SIM_OBJECT_PARAMS(Device) - -BEGIN_INIT_SIM_OBJECT_PARAMS(Device) - - INIT_PARAM(clock, "State machine cycle time"), - - INIT_PARAM(addr, "Device Address"), - INIT_PARAM(mmu, "Memory Controller"), - INIT_PARAM(physmem, "Physical Memory"), - INIT_PARAM(configspace, "PCI Configspace"), - INIT_PARAM(configdata, "PCI Config data"), - INIT_PARAM(platform, "Platform"), - INIT_PARAM(pci_bus, "PCI bus"), - INIT_PARAM(pci_dev, "PCI device number"), - INIT_PARAM(pci_func, "PCI function code"), - - INIT_PARAM(hier, "Hierarchy global variables"), - INIT_PARAM(pio_bus, ""), - INIT_PARAM(dma_bus, ""), - INIT_PARAM(payload_bus, "The IO Bus to attach to for payload"), - INIT_PARAM(dma_read_delay, "fixed delay for dma reads"), - INIT_PARAM(dma_read_factor, "multiplier for dma reads"), - INIT_PARAM(dma_write_delay, "fixed delay for dma writes"), - INIT_PARAM(dma_write_factor, "multiplier for dma writes"), - INIT_PARAM(dma_no_allocate, "Should we allocat on read in cache"), - INIT_PARAM(pio_latency, "Programmed IO latency in bus cycles"), - INIT_PARAM(intr_delay, "Interrupt Delay"), - - INIT_PARAM(rx_delay, "Receive Delay"), - INIT_PARAM(tx_delay, "Transmit Delay"), - INIT_PARAM(rx_max_copy, "rx max copy"), - INIT_PARAM(tx_max_copy, "rx max copy"), - INIT_PARAM(rx_max_intr, "rx max intr"), - INIT_PARAM(rx_fifo_size, "max size in bytes of rxFifo"), - INIT_PARAM(tx_fifo_size, "max size in bytes of txFifo"), - INIT_PARAM(rx_fifo_threshold, "max size in bytes of rxFifo"), - INIT_PARAM(rx_fifo_low_mark, "max size in bytes of rxFifo"), - INIT_PARAM(tx_fifo_high_mark, "max size in bytes of txFifo"), - INIT_PARAM(tx_fifo_threshold, "max size in bytes of txFifo"), - - INIT_PARAM(rx_filter, "Enable Receive Filter"), - INIT_PARAM(hardware_address, "Ethernet Hardware Address"), - INIT_PARAM(rx_thread, ""), - INIT_PARAM(tx_thread, ""), - INIT_PARAM(rss, ""), - INIT_PARAM(virtual_count, ""), - INIT_PARAM(zero_copy, ""), - INIT_PARAM(delay_copy, ""), - INIT_PARAM(virtual_addr, "") - -END_INIT_SIM_OBJECT_PARAMS(Device) - - -CREATE_SIM_OBJECT(Device) -{ - Device::Params *params = new Device::Params; - - params->name = getInstanceName(); - - params->clock = clock; - - params->mmu = mmu; - params->physmem = physmem; - params->configSpace = configspace; - params->configData = configdata; - params->plat = platform; - params->busNum = pci_bus; - params->deviceNum = pci_dev; - params->functionNum = pci_func; - - params->hier = hier; - params->pio_bus = pio_bus; - params->header_bus = dma_bus; - params->payload_bus = payload_bus; - params->dma_read_delay = dma_read_delay; - params->dma_read_factor = dma_read_factor; - params->dma_write_delay = dma_write_delay; - params->dma_write_factor = dma_write_factor; - params->dma_no_allocate = dma_no_allocate; - params->pio_latency = pio_latency; - params->intr_delay = intr_delay; - - params->tx_delay = tx_delay; - params->rx_delay = rx_delay; - params->rx_max_copy = rx_max_copy; - params->tx_max_copy = tx_max_copy; - params->rx_max_intr = rx_max_intr; - params->rx_fifo_size = rx_fifo_size; - params->tx_fifo_size = tx_fifo_size; - params->rx_fifo_threshold = rx_fifo_threshold; - params->rx_fifo_low_mark = rx_fifo_low_mark; - params->tx_fifo_high_mark = tx_fifo_high_mark; - params->tx_fifo_threshold = tx_fifo_threshold; - - params->rx_filter = rx_filter; - params->eaddr = hardware_address; - params->rx_thread = rx_thread; - params->tx_thread = tx_thread; - params->rss = rss; - params->virtual_count = virtual_count; - params->zero_copy = zero_copy; - params->delay_copy = delay_copy; - params->virtual_addr = virtual_addr; - - return new Device(params); -} - -REGISTER_SIM_OBJECT("Sinic", Device) - -/* namespace Sinic */ } diff --git a/dev/sinic.hh b/dev/sinic.hh deleted file mode 100644 index 892b3ab69..000000000 --- a/dev/sinic.hh +++ /dev/null @@ -1,401 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __DEV_SINIC_HH__ -#define __DEV_SINIC_HH__ - -#include "base/inet.hh" -#include "base/statistics.hh" -#include "dev/etherint.hh" -#include "dev/etherpkt.hh" -#include "dev/io_device.hh" -#include "dev/pcidev.hh" -#include "dev/pktfifo.hh" -#include "dev/sinicreg.hh" -#include "mem/bus/bus.hh" -#include "sim/eventq.hh" - -namespace Sinic { - -class Interface; -class Base : public PciDev -{ - protected: - bool rxEnable; - bool txEnable; - Tick clock; - inline Tick cycles(int numCycles) const { return numCycles * clock; } - - protected: - Tick intrDelay; - Tick intrTick; - bool cpuIntrEnable; - bool cpuPendingIntr; - void cpuIntrPost(Tick when); - void cpuInterrupt(); - void cpuIntrClear(); - - typedef EventWrapper<Base, &Base::cpuInterrupt> IntrEvent; - friend void IntrEvent::process(); - IntrEvent *intrEvent; - Interface *interface; - - bool cpuIntrPending() const; - void cpuIntrAck() { cpuIntrClear(); } - -/** - * Serialization stuff - */ - public: - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); - -/** - * Construction/Destruction/Parameters - */ - public: - struct Params : public PciDev::Params - { - Tick clock; - Tick intr_delay; - }; - - Base(Params *p); -}; - -class Device : public Base -{ - protected: - Platform *plat; - PhysicalMemory *physmem; - - protected: - /** Receive State Machine States */ - enum RxState { - rxIdle, - rxFifoBlock, - rxBeginCopy, - rxCopy, - rxCopyDone - }; - - /** Transmit State Machine states */ - enum TxState { - txIdle, - txFifoBlock, - txBeginCopy, - txCopy, - txCopyDone - }; - - /** device register file */ - struct { - uint32_t Config; // 0x00 - uint32_t Command; // 0x04 - uint32_t IntrStatus; // 0x08 - uint32_t IntrMask; // 0x0c - uint32_t RxMaxCopy; // 0x10 - uint32_t TxMaxCopy; // 0x14 - uint32_t RxMaxIntr; // 0x18 - uint32_t VirtualCount; // 0x1c - uint32_t RxFifoSize; // 0x20 - uint32_t TxFifoSize; // 0x24 - uint32_t RxFifoMark; // 0x28 - uint32_t TxFifoMark; // 0x2c - uint64_t RxData; // 0x30 - uint64_t RxDone; // 0x38 - uint64_t RxWait; // 0x40 - uint64_t TxData; // 0x48 - uint64_t TxDone; // 0x50 - uint64_t TxWait; // 0x58 - uint64_t HwAddr; // 0x60 - } regs; - - struct VirtualReg { - uint64_t RxData; - uint64_t RxDone; - uint64_t TxData; - uint64_t TxDone; - - PacketFifo::iterator rxPacket; - int rxPacketOffset; - int rxPacketBytes; - uint64_t rxDoneData; - - Counter rxUnique; - Counter txUnique; - - VirtualReg() - : RxData(0), RxDone(0), TxData(0), TxDone(0), - rxPacketOffset(0), rxPacketBytes(0), rxDoneData(0) - { } - }; - typedef std::vector<VirtualReg> VirtualRegs; - typedef std::list<int> VirtualList; - Counter rxUnique; - Counter txUnique; - VirtualRegs virtualRegs; - VirtualList rxList; - VirtualList rxBusy; - int rxActive; - VirtualList txList; - - uint8_t ®Data8(Addr daddr) { return *((uint8_t *)®s + daddr); } - uint32_t ®Data32(Addr daddr) { return *(uint32_t *)®Data8(daddr); } - uint64_t ®Data64(Addr daddr) { return *(uint64_t *)®Data8(daddr); } - - private: - Addr addr; - static const Addr size = Regs::Size; - - protected: - RxState rxState; - PacketFifo rxFifo; - PacketFifo::iterator rxFifoPtr; - bool rxEmpty; - bool rxLow; - Addr rxDmaAddr; - uint8_t *rxDmaData; - int rxDmaLen; - - TxState txState; - PacketFifo txFifo; - bool txFull; - PacketPtr txPacket; - int txPacketOffset; - int txPacketBytes; - Addr txDmaAddr; - uint8_t *txDmaData; - int txDmaLen; - - protected: - void reset(); - - void rxKick(); - Tick rxKickTick; - typedef EventWrapper<Device, &Device::rxKick> RxKickEvent; - friend void RxKickEvent::process(); - - void txKick(); - Tick txKickTick; - typedef EventWrapper<Device, &Device::txKick> TxKickEvent; - friend void TxKickEvent::process(); - - /** - * Retransmit event - */ - void transmit(); - void txEventTransmit() - { - transmit(); - if (txState == txFifoBlock) - txKick(); - } - typedef EventWrapper<Device, &Device::txEventTransmit> TxEvent; - friend void TxEvent::process(); - TxEvent txEvent; - - void txDump() const; - void rxDump() const; - - /** - * receive address filter - */ - bool rxFilter(const PacketPtr &packet); - -/** - * device configuration - */ - void changeConfig(uint32_t newconfig); - void command(uint32_t command); - -/** - * device ethernet interface - */ - public: - bool recvPacket(PacketPtr packet); - void transferDone(); - void setInterface(Interface *i) { assert(!interface); interface = i; } - -/** - * DMA parameters - */ - protected: - void rxDmaCopy(); - void rxDmaDone(); - friend class EventWrapper<Device, &Device::rxDmaDone>; - EventWrapper<Device, &Device::rxDmaDone> rxDmaEvent; - - void txDmaCopy(); - void txDmaDone(); - friend class EventWrapper<Device, &Device::txDmaDone>; - EventWrapper<Device, &Device::txDmaDone> txDmaEvent; - - Tick dmaReadDelay; - Tick dmaReadFactor; - Tick dmaWriteDelay; - Tick dmaWriteFactor; - -/** - * Interrupt management - */ - protected: - void devIntrPost(uint32_t interrupts); - void devIntrClear(uint32_t interrupts = Regs::Intr_All); - void devIntrChangeMask(uint32_t newmask); - -/** - * PCI Configuration interface - */ - public: - virtual void writeConfig(int offset, int size, const uint8_t *data); - -/** - * Memory Interface - */ - public: - virtual Fault read(MemReqPtr &req, uint8_t *data); - virtual Fault write(MemReqPtr &req, const uint8_t *data); - - void prepareIO(int cpu, int index); - void prepareRead(int cpu, int index); - void prepareWrite(int cpu, int index); - Fault iprRead(Addr daddr, int cpu, uint64_t &result); - Fault readBar0(MemReqPtr &req, Addr daddr, uint8_t *data); - Fault writeBar0(MemReqPtr &req, Addr daddr, const uint8_t *data); - Tick cacheAccess(MemReqPtr &req); - -/** - * Statistics - */ - private: - Stats::Scalar<> rxBytes; - Stats::Formula rxBandwidth; - Stats::Scalar<> rxPackets; - Stats::Formula rxPacketRate; - Stats::Scalar<> rxIpPackets; - Stats::Scalar<> rxTcpPackets; - Stats::Scalar<> rxUdpPackets; - Stats::Scalar<> rxIpChecksums; - Stats::Scalar<> rxTcpChecksums; - Stats::Scalar<> rxUdpChecksums; - - Stats::Scalar<> txBytes; - Stats::Formula txBandwidth; - Stats::Formula totBandwidth; - Stats::Formula totPackets; - Stats::Formula totBytes; - Stats::Formula totPacketRate; - Stats::Scalar<> txPackets; - Stats::Formula txPacketRate; - Stats::Scalar<> txIpPackets; - Stats::Scalar<> txTcpPackets; - Stats::Scalar<> txUdpPackets; - Stats::Scalar<> txIpChecksums; - Stats::Scalar<> txTcpChecksums; - Stats::Scalar<> txUdpChecksums; - - public: - virtual void regStats(); - -/** - * Serialization stuff - */ - public: - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); - -/** - * Construction/Destruction/Parameters - */ - public: - struct Params : public Base::Params - { - IntrControl *i; - PhysicalMemory *pmem; - Tick tx_delay; - Tick rx_delay; - HierParams *hier; - Bus *pio_bus; - Bus *header_bus; - Bus *payload_bus; - Tick pio_latency; - PhysicalMemory *physmem; - IntrControl *intctrl; - bool rx_filter; - Net::EthAddr eaddr; - uint32_t rx_max_copy; - uint32_t tx_max_copy; - uint32_t rx_max_intr; - uint32_t rx_fifo_size; - uint32_t tx_fifo_size; - uint32_t rx_fifo_threshold; - uint32_t rx_fifo_low_mark; - uint32_t tx_fifo_high_mark; - uint32_t tx_fifo_threshold; - Tick dma_read_delay; - Tick dma_read_factor; - Tick dma_write_delay; - Tick dma_write_factor; - bool dma_no_allocate; - bool rx_thread; - bool tx_thread; - bool rss; - uint32_t virtual_count; - bool zero_copy; - bool delay_copy; - bool virtual_addr; - }; - - protected: - const Params *params() const { return (const Params *)_params; } - - public: - Device(Params *params); - ~Device(); -}; - -/* - * Ethernet Interface for an Ethernet Device - */ -class Interface : public EtherInt -{ - private: - Device *dev; - - public: - Interface(const std::string &name, Device *d) - : EtherInt(name), dev(d) { dev->setInterface(this); } - - virtual bool recvPacket(PacketPtr pkt) { return dev->recvPacket(pkt); } - virtual void sendDone() { dev->transferDone(); } -}; - -/* namespace Sinic */ } - -#endif // __DEV_SINIC_HH__ diff --git a/dev/sinicreg.hh b/dev/sinicreg.hh deleted file mode 100644 index d41eb5b16..000000000 --- a/dev/sinicreg.hh +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __DEV_SINICREG_HH__ -#define __DEV_SINICREG_HH__ - -#define __SINIC_REG32(NAME, VAL) static const uint32_t NAME = (VAL) -#define __SINIC_REG64(NAME, VAL) static const uint64_t NAME = (VAL) - -#define __SINIC_VAL32(NAME, OFFSET, WIDTH) \ - static const uint32_t NAME##_width = WIDTH; \ - static const uint32_t NAME##_offset = OFFSET; \ - static const uint32_t NAME##_mask = (1 << WIDTH) - 1; \ - static const uint32_t NAME = ((1 << WIDTH) - 1) << OFFSET; \ - static inline uint32_t get_##NAME(uint32_t reg) \ - { return (reg & NAME) >> OFFSET; } \ - static inline uint32_t set_##NAME(uint32_t reg, uint32_t val) \ - { return (reg & ~NAME) | ((val << OFFSET) & NAME); } - -#define __SINIC_VAL64(NAME, OFFSET, WIDTH) \ - static const uint64_t NAME##_width = WIDTH; \ - static const uint64_t NAME##_offset = OFFSET; \ - static const uint64_t NAME##_mask = (ULL(1) << WIDTH) - 1; \ - static const uint64_t NAME = ((ULL(1) << WIDTH) - 1) << OFFSET; \ - static inline uint64_t get_##NAME(uint64_t reg) \ - { return (reg & NAME) >> OFFSET; } \ - static inline uint64_t set_##NAME(uint64_t reg, uint64_t val) \ - { return (reg & ~NAME) | ((val << OFFSET) & NAME); } - -namespace Sinic { -namespace Regs { - -static const int VirtualShift = 8; -static const int VirtualMask = 0xff; - -// Registers -__SINIC_REG32(Config, 0x00); // 32: configuration register -__SINIC_REG32(Command, 0x04); // 32: command register -__SINIC_REG32(IntrStatus, 0x08); // 32: interrupt status -__SINIC_REG32(IntrMask, 0x0c); // 32: interrupt mask -__SINIC_REG32(RxMaxCopy, 0x10); // 32: max bytes per rx copy -__SINIC_REG32(TxMaxCopy, 0x14); // 32: max bytes per tx copy -__SINIC_REG32(RxMaxIntr, 0x18); // 32: max receives per interrupt -__SINIC_REG32(VirtualCount, 0x1c); // 32: number of virutal NICs -__SINIC_REG32(RxFifoSize, 0x20); // 32: rx fifo capacity in bytes -__SINIC_REG32(TxFifoSize, 0x24); // 32: tx fifo capacity in bytes -__SINIC_REG32(RxFifoMark, 0x28); // 32: rx fifo high watermark -__SINIC_REG32(TxFifoMark, 0x2c); // 32: tx fifo low watermark -__SINIC_REG32(RxData, 0x30); // 64: receive data -__SINIC_REG32(RxDone, 0x38); // 64: receive done -__SINIC_REG32(RxWait, 0x40); // 64: receive done (busy wait) -__SINIC_REG32(TxData, 0x48); // 64: transmit data -__SINIC_REG32(TxDone, 0x50); // 64: transmit done -__SINIC_REG32(TxWait, 0x58); // 64: transmit done (busy wait) -__SINIC_REG32(HwAddr, 0x60); // 64: mac address -__SINIC_REG32(Size, 0x68); // register addres space size - -// Config register bits -__SINIC_VAL32(Config_ZeroCopy, 12, 1); // enable zero copy -__SINIC_VAL32(Config_DelayCopy,11, 1); // enable delayed copy -__SINIC_VAL32(Config_RSS, 10, 1); // enable receive side scaling -__SINIC_VAL32(Config_RxThread, 9, 1); // enable receive threads -__SINIC_VAL32(Config_TxThread, 8, 1); // enable transmit thread -__SINIC_VAL32(Config_Filter, 7, 1); // enable receive filter -__SINIC_VAL32(Config_Vlan, 6, 1); // enable vlan tagging -__SINIC_VAL32(Config_Vaddr, 5, 1); // enable virtual addressing -__SINIC_VAL32(Config_Desc, 4, 1); // enable tx/rx descriptors -__SINIC_VAL32(Config_Poll, 3, 1); // enable polling -__SINIC_VAL32(Config_IntEn, 2, 1); // enable interrupts -__SINIC_VAL32(Config_TxEn, 1, 1); // enable transmit -__SINIC_VAL32(Config_RxEn, 0, 1); // enable receive - -// Command register bits -__SINIC_VAL32(Command_Intr, 1, 1); // software interrupt -__SINIC_VAL32(Command_Reset, 0, 1); // reset chip - -// Interrupt register bits -__SINIC_VAL32(Intr_Soft, 8, 1); // software interrupt -__SINIC_VAL32(Intr_TxLow, 7, 1); // tx fifo dropped below watermark -__SINIC_VAL32(Intr_TxFull, 6, 1); // tx fifo full -__SINIC_VAL32(Intr_TxDMA, 5, 1); // tx dma completed w/ interrupt -__SINIC_VAL32(Intr_TxPacket, 4, 1); // packet transmitted -__SINIC_VAL32(Intr_RxHigh, 3, 1); // rx fifo above high watermark -__SINIC_VAL32(Intr_RxEmpty, 2, 1); // rx fifo empty -__SINIC_VAL32(Intr_RxDMA, 1, 1); // rx dma completed w/ interrupt -__SINIC_VAL32(Intr_RxPacket, 0, 1); // packet received -__SINIC_REG32(Intr_All, 0x01ff); // all valid interrupts -__SINIC_REG32(Intr_NoDelay, 0x01cc); // interrupts that aren't coalesced -__SINIC_REG32(Intr_Res, ~0x01ff); // reserved interrupt bits - -// RX Data Description -__SINIC_VAL64(RxData_Vaddr, 60, 1); // Addr is virtual -__SINIC_VAL64(RxData_Len, 40, 20); // 0 - 256k -__SINIC_VAL64(RxData_Addr, 0, 40); // Address 1TB - -// TX Data Description -__SINIC_VAL64(TxData_More, 63, 1); // Packet not complete (will dma more) -__SINIC_VAL64(TxData_Checksum, 62, 1); // do checksum -__SINIC_VAL64(TxData_Vaddr, 60, 1); // Addr is virtual -__SINIC_VAL64(TxData_Len, 40, 20); // 0 - 256k -__SINIC_VAL64(TxData_Addr, 0, 40); // Address 1TB - -// RX Done/Busy Information -__SINIC_VAL64(RxDone_Packets, 32, 16); // number of packets in rx fifo -__SINIC_VAL64(RxDone_Busy, 31, 1); // receive dma busy copying -__SINIC_VAL64(RxDone_Complete, 30, 1); // valid data (packet complete) -__SINIC_VAL64(RxDone_More, 29, 1); // Packet has more data (dma again) -__SINIC_VAL64(RxDone_Empty, 28, 1); // rx fifo is empty -__SINIC_VAL64(RxDone_High, 27, 1); // rx fifo is above the watermark -__SINIC_VAL64(RxDone_NotHigh, 26, 1); // rxfifo never hit the high watermark -__SINIC_VAL64(RxDone_TcpError, 25, 1); // TCP packet error (bad checksum) -__SINIC_VAL64(RxDone_UdpError, 24, 1); // UDP packet error (bad checksum) -__SINIC_VAL64(RxDone_IpError, 23, 1); // IP packet error (bad checksum) -__SINIC_VAL64(RxDone_TcpPacket, 22, 1); // this is a TCP packet -__SINIC_VAL64(RxDone_UdpPacket, 21, 1); // this is a UDP packet -__SINIC_VAL64(RxDone_IpPacket, 20, 1); // this is an IP packet -__SINIC_VAL64(RxDone_CopyLen, 0, 20); // up to 256k - -// TX Done/Busy Information -__SINIC_VAL64(TxDone_Packets, 32, 16); // number of packets in tx fifo -__SINIC_VAL64(TxDone_Busy, 31, 1); // transmit dma busy copying -__SINIC_VAL64(TxDone_Complete, 30, 1); // valid data (packet complete) -__SINIC_VAL64(TxDone_Full, 29, 1); // tx fifo is full -__SINIC_VAL64(TxDone_Low, 28, 1); // tx fifo is below the watermark -__SINIC_VAL64(TxDone_Res0, 27, 1); // reserved -__SINIC_VAL64(TxDone_Res1, 26, 1); // reserved -__SINIC_VAL64(TxDone_Res2, 25, 1); // reserved -__SINIC_VAL64(TxDone_Res3, 24, 1); // reserved -__SINIC_VAL64(TxDone_Res4, 23, 1); // reserved -__SINIC_VAL64(TxDone_Res5, 22, 1); // reserved -__SINIC_VAL64(TxDone_Res6, 21, 1); // reserved -__SINIC_VAL64(TxDone_Res7, 20, 1); // reserved -__SINIC_VAL64(TxDone_CopyLen, 0, 20); // up to 256k - -struct Info -{ - uint8_t size; - bool read; - bool write; - const char *name; -}; - -/* namespace Regs */ } - -inline const Regs::Info& -regInfo(Addr daddr) -{ - static Regs::Info invalid = { 0, false, false, "invalid" }; - static Regs::Info info [] = { - { 4, true, true, "Config" }, - { 4, false, true, "Command" }, - { 4, true, true, "IntrStatus" }, - { 4, true, true, "IntrMask" }, - { 4, true, false, "RxMaxCopy" }, - { 4, true, false, "TxMaxCopy" }, - { 4, true, false, "RxMaxIntr" }, - { 4, true, false, "VirtualCount" }, - { 4, true, false, "RxFifoSize" }, - { 4, true, false, "TxFifoSize" }, - { 4, true, false, "RxFifoMark" }, - { 4, true, false, "TxFifoMark" }, - { 8, true, true, "RxData" }, - invalid, - { 8, true, false, "RxDone" }, - invalid, - { 8, true, false, "RxWait" }, - invalid, - { 8, true, true, "TxData" }, - invalid, - { 8, true, false, "TxDone" }, - invalid, - { 8, true, false, "TxWait" }, - invalid, - { 8, true, false, "HwAddr" }, - invalid, - }; - - return info[daddr / 4]; -} - -inline bool -regValid(Addr daddr) -{ - if (daddr > Regs::Size) - return false; - - if (regInfo(daddr).size == 0) - return false; - - return true; -} - -/* namespace Sinic */ } - -#endif // __DEV_SINICREG_HH__ diff --git a/dev/tsunami.cc b/dev/tsunami.cc deleted file mode 100644 index 58fc7434e..000000000 --- a/dev/tsunami.cc +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Implementation of Tsunami platform. - */ - -#include <deque> -#include <string> -#include <vector> - -#include "cpu/intr_control.hh" -#include "dev/simconsole.hh" -#include "dev/ide_ctrl.hh" -#include "dev/tsunami_cchip.hh" -#include "dev/tsunami_pchip.hh" -#include "dev/tsunami_io.hh" -#include "dev/tsunami.hh" -#include "dev/pciconfigall.hh" -#include "sim/builder.hh" -#include "sim/system.hh" - -using namespace std; -//Should this be AlphaISA? -using namespace TheISA; - -Tsunami::Tsunami(const string &name, System *s, IntrControl *ic, - PciConfigAll *pci) - : Platform(name, ic, pci), system(s) -{ - // set the back pointer from the system to myself - system->platform = this; - - for (int i = 0; i < Tsunami::Max_CPUs; i++) - intr_sum_type[i] = 0; -} - -Tick -Tsunami::intrFrequency() -{ - return io->frequency(); -} - -void -Tsunami::postConsoleInt() -{ - io->postPIC(0x10); -} - -void -Tsunami::clearConsoleInt() -{ - io->clearPIC(0x10); -} - -void -Tsunami::postPciInt(int line) -{ - cchip->postDRIR(line); -} - -void -Tsunami::clearPciInt(int line) -{ - cchip->clearDRIR(line); -} - -Addr -Tsunami::pciToDma(Addr pciAddr) const -{ - return pchip->translatePciToDma(pciAddr); -} - -void -Tsunami::serialize(std::ostream &os) -{ - SERIALIZE_ARRAY(intr_sum_type, Tsunami::Max_CPUs); -} - -void -Tsunami::unserialize(Checkpoint *cp, const std::string §ion) -{ - UNSERIALIZE_ARRAY(intr_sum_type, Tsunami::Max_CPUs); -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(Tsunami) - - SimObjectParam<System *> system; - SimObjectParam<IntrControl *> intrctrl; - SimObjectParam<PciConfigAll *> pciconfig; - -END_DECLARE_SIM_OBJECT_PARAMS(Tsunami) - -BEGIN_INIT_SIM_OBJECT_PARAMS(Tsunami) - - INIT_PARAM(system, "system"), - INIT_PARAM(intrctrl, "interrupt controller"), - INIT_PARAM(pciconfig, "PCI configuration") - -END_INIT_SIM_OBJECT_PARAMS(Tsunami) - -CREATE_SIM_OBJECT(Tsunami) -{ - return new Tsunami(getInstanceName(), system, intrctrl, pciconfig); -} - -REGISTER_SIM_OBJECT("Tsunami", Tsunami) diff --git a/dev/tsunami.hh b/dev/tsunami.hh deleted file mode 100644 index 7fd91d5b2..000000000 --- a/dev/tsunami.hh +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * Declaration of top level class for the Tsunami chipset. This class just - * retains pointers to all its children so the children can communicate. - */ - -#ifndef __DEV_TSUNAMI_HH__ -#define __DEV_TSUNAMI_HH__ - -#include "dev/platform.hh" - -class IdeController; -class TlaserClock; -class NSGigE; -class TsunamiCChip; -class TsunamiPChip; -class TsunamiIO; -class PciConfigAll; -class System; - -/** - * Top level class for Tsunami Chipset emulation. - * This structure just contains pointers to all the - * children so the children can commnicate to do the - * read work - */ - -class Tsunami : public Platform -{ - public: - /** Max number of CPUs in a Tsunami */ - static const int Max_CPUs = 64; - - /** Pointer to the system */ - System *system; - - /** Pointer to the TsunamiIO device which has the RTC */ - TsunamiIO *io; - - /** Pointer to the Tsunami CChip. - * The chip contains some configuration information and - * all the interrupt mask and status registers - */ - TsunamiCChip *cchip; - - /** Pointer to the Tsunami PChip. - * The pchip is the interface to the PCI bus, in our case - * it does not have to do much. - */ - TsunamiPChip *pchip; - - int intr_sum_type[Tsunami::Max_CPUs]; - int ipi_pending[Tsunami::Max_CPUs]; - - public: - /** - * Constructor for the Tsunami Class. - * @param name name of the object - * @param intrctrl pointer to the interrupt controller - */ - Tsunami(const std::string &name, System *s, IntrControl *intctrl, - PciConfigAll *pci); - - /** - * Return the interrupting frequency to AlphaAccess - * @return frequency of RTC interrupts - */ - virtual Tick intrFrequency(); - - /** - * Cause the cpu to post a serial interrupt to the CPU. - */ - virtual void postConsoleInt(); - - /** - * Clear a posted CPU interrupt (id=55) - */ - virtual void clearConsoleInt(); - - /** - * Cause the chipset to post a cpi interrupt to the CPU. - */ - virtual void postPciInt(int line); - - /** - * Clear a posted PCI->CPU interrupt - */ - virtual void clearPciInt(int line); - - virtual Addr pciToDma(Addr pciAddr) const; - - /** - * Serialize this object to the given output stream. - * @param os The stream to serialize to. - */ - virtual void serialize(std::ostream &os); - - /** - * Reconstruct the state of this object from a checkpoint. - * @param cp The checkpoint use. - * @param section The section name of this object - */ - virtual void unserialize(Checkpoint *cp, const std::string §ion); -}; - -#endif // __DEV_TSUNAMI_HH__ diff --git a/dev/tsunami_cchip.cc b/dev/tsunami_cchip.cc deleted file mode 100644 index 2649fe27a..000000000 --- a/dev/tsunami_cchip.cc +++ /dev/null @@ -1,580 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Emulation of the Tsunami CChip CSRs - */ - -#include <deque> -#include <string> -#include <vector> - -#include "base/trace.hh" -#include "dev/tsunami_cchip.hh" -#include "dev/tsunamireg.h" -#include "dev/tsunami.hh" -#include "mem/bus/bus.hh" -#include "mem/bus/pio_interface.hh" -#include "mem/bus/pio_interface_impl.hh" -#include "mem/functional/memory_control.hh" -#include "cpu/exec_context.hh" -#include "cpu/intr_control.hh" -#include "sim/builder.hh" -#include "sim/system.hh" - -using namespace std; -//Should this be AlphaISA? -using namespace TheISA; - -TsunamiCChip::TsunamiCChip(const string &name, Tsunami *t, Addr a, - MemoryController *mmu, HierParams *hier, - Bus* pio_bus, Tick pio_latency) - : PioDevice(name, t), addr(a), tsunami(t) -{ - mmu->add_child(this, RangeSize(addr, size)); - - if (pio_bus) { - pioInterface = newPioInterface(name + ".pio", hier, pio_bus, this, - &TsunamiCChip::cacheAccess); - pioInterface->addAddrRange(RangeSize(addr, size)); - pioLatency = pio_latency * pio_bus->clockRate; - } - - drir = 0; - ipint = 0; - itint = 0; - - for (int x = 0; x < Tsunami::Max_CPUs; x++) - { - dim[x] = 0; - dir[x] = 0; - } - - //Put back pointer in tsunami - tsunami->cchip = this; -} - -Fault -TsunamiCChip::read(MemReqPtr &req, uint8_t *data) -{ - DPRINTF(Tsunami, "read va=%#x size=%d\n", req->vaddr, req->size); - - Addr regnum = (req->paddr - (addr & EV5::PAddrImplMask)) >> 6; - Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)); - - ExecContext *xc = req->xc; - - switch (req->size) { - - case sizeof(uint64_t): - if (daddr & TSDEV_CC_BDIMS) - { - *(uint64_t*)data = dim[(daddr >> 4) & 0x3F]; - return NoFault; - } - - if (daddr & TSDEV_CC_BDIRS) - { - *(uint64_t*)data = dir[(daddr >> 4) & 0x3F]; - return NoFault; - } - - switch(regnum) { - case TSDEV_CC_CSR: - *(uint64_t*)data = 0x0; - return NoFault; - case TSDEV_CC_MTR: - panic("TSDEV_CC_MTR not implemeted\n"); - return NoFault; - case TSDEV_CC_MISC: - *(uint64_t*)data = (ipint << 8) & 0xF | - (itint << 4) & 0xF | - (xc->readCpuId() & 0x3); - return NoFault; - case TSDEV_CC_AAR0: - case TSDEV_CC_AAR1: - case TSDEV_CC_AAR2: - case TSDEV_CC_AAR3: - *(uint64_t*)data = 0; - return NoFault; - case TSDEV_CC_DIM0: - *(uint64_t*)data = dim[0]; - return NoFault; - case TSDEV_CC_DIM1: - *(uint64_t*)data = dim[1]; - return NoFault; - case TSDEV_CC_DIM2: - *(uint64_t*)data = dim[2]; - return NoFault; - case TSDEV_CC_DIM3: - *(uint64_t*)data = dim[3]; - return NoFault; - case TSDEV_CC_DIR0: - *(uint64_t*)data = dir[0]; - return NoFault; - case TSDEV_CC_DIR1: - *(uint64_t*)data = dir[1]; - return NoFault; - case TSDEV_CC_DIR2: - *(uint64_t*)data = dir[2]; - return NoFault; - case TSDEV_CC_DIR3: - *(uint64_t*)data = dir[3]; - return NoFault; - case TSDEV_CC_DRIR: - *(uint64_t*)data = drir; - return NoFault; - case TSDEV_CC_PRBEN: - panic("TSDEV_CC_PRBEN not implemented\n"); - return NoFault; - case TSDEV_CC_IIC0: - case TSDEV_CC_IIC1: - case TSDEV_CC_IIC2: - case TSDEV_CC_IIC3: - panic("TSDEV_CC_IICx not implemented\n"); - return NoFault; - case TSDEV_CC_MPR0: - case TSDEV_CC_MPR1: - case TSDEV_CC_MPR2: - case TSDEV_CC_MPR3: - panic("TSDEV_CC_MPRx not implemented\n"); - return NoFault; - case TSDEV_CC_IPIR: - *(uint64_t*)data = ipint; - return NoFault; - case TSDEV_CC_ITIR: - *(uint64_t*)data = itint; - return NoFault; - default: - panic("default in cchip read reached, accessing 0x%x\n"); - } // uint64_t - - break; - case sizeof(uint32_t): - if (regnum == TSDEV_CC_DRIR) { - warn("accessing DRIR with 32 bit read, " - "hopefully your just reading this for timing"); - *(uint32_t*)data = drir; - } else - panic("invalid access size(?) for tsunami register!\n"); - return NoFault; - case sizeof(uint16_t): - case sizeof(uint8_t): - default: - panic("invalid access size(?) for tsunami register!\n"); - } - DPRINTFN("Tsunami CChip ERROR: read regnum=%#x size=%d\n", regnum, req->size); - - return NoFault; -} - -Fault -TsunamiCChip::write(MemReqPtr &req, const uint8_t *data) -{ - DPRINTF(Tsunami, "write - va=%#x value=%#x size=%d \n", - req->vaddr, *(uint64_t*)data, req->size); - - Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)); - Addr regnum = (req->paddr - (addr & EV5::PAddrImplMask)) >> 6; - - bool supportedWrite = false; - - switch (req->size) { - - case sizeof(uint64_t): - if (daddr & TSDEV_CC_BDIMS) - { - int number = (daddr >> 4) & 0x3F; - - uint64_t bitvector; - uint64_t olddim; - uint64_t olddir; - - olddim = dim[number]; - olddir = dir[number]; - dim[number] = *(uint64_t*)data; - dir[number] = dim[number] & drir; - for(int x = 0; x < Tsunami::Max_CPUs; x++) - { - bitvector = ULL(1) << x; - // Figure out which bits have changed - if ((dim[number] & bitvector) != (olddim & bitvector)) - { - // The bit is now set and it wasn't before (set) - if((dim[number] & bitvector) && (dir[number] & bitvector)) - { - tsunami->intrctrl->post(number, TheISA::INTLEVEL_IRQ1, x); - DPRINTF(Tsunami, "dim write resulting in posting dir" - " interrupt to cpu %d\n", number); - } - else if ((olddir & bitvector) && - !(dir[number] & bitvector)) - { - // The bit was set and now its now clear and - // we were interrupting on that bit before - tsunami->intrctrl->clear(number, TheISA::INTLEVEL_IRQ1, x); - DPRINTF(Tsunami, "dim write resulting in clear" - " dir interrupt to cpu %d\n", number); - - } - - - } - } - return NoFault; - } - - switch(regnum) { - case TSDEV_CC_CSR: - panic("TSDEV_CC_CSR write\n"); - return NoFault; - case TSDEV_CC_MTR: - panic("TSDEV_CC_MTR write not implemented\n"); - return NoFault; - case TSDEV_CC_MISC: - uint64_t ipreq; - ipreq = (*(uint64_t*)data >> 12) & 0xF; - //If it is bit 12-15, this is an IPI post - if (ipreq) { - reqIPI(ipreq); - supportedWrite = true; - } - - //If it is bit 8-11, this is an IPI clear - uint64_t ipintr; - ipintr = (*(uint64_t*)data >> 8) & 0xF; - if (ipintr) { - clearIPI(ipintr); - supportedWrite = true; - } - - //If it is the 4-7th bit, clear the RTC interrupt - uint64_t itintr; - itintr = (*(uint64_t*)data >> 4) & 0xF; - if (itintr) { - clearITI(itintr); - supportedWrite = true; - } - - // ignore NXMs - if (*(uint64_t*)data & 0x10000000) - supportedWrite = true; - - if(!supportedWrite) - panic("TSDEV_CC_MISC write not implemented\n"); - - return NoFault; - case TSDEV_CC_AAR0: - case TSDEV_CC_AAR1: - case TSDEV_CC_AAR2: - case TSDEV_CC_AAR3: - panic("TSDEV_CC_AARx write not implemeted\n"); - return NoFault; - case TSDEV_CC_DIM0: - case TSDEV_CC_DIM1: - case TSDEV_CC_DIM2: - case TSDEV_CC_DIM3: - int number; - if(regnum == TSDEV_CC_DIM0) - number = 0; - else if(regnum == TSDEV_CC_DIM1) - number = 1; - else if(regnum == TSDEV_CC_DIM2) - number = 2; - else - number = 3; - - uint64_t bitvector; - uint64_t olddim; - uint64_t olddir; - - olddim = dim[number]; - olddir = dir[number]; - dim[number] = *(uint64_t*)data; - dir[number] = dim[number] & drir; - for(int x = 0; x < 64; x++) - { - bitvector = ULL(1) << x; - // Figure out which bits have changed - if ((dim[number] & bitvector) != (olddim & bitvector)) - { - // The bit is now set and it wasn't before (set) - if((dim[number] & bitvector) && (dir[number] & bitvector)) - { - tsunami->intrctrl->post(number, TheISA::INTLEVEL_IRQ1, x); - DPRINTF(Tsunami, "posting dir interrupt to cpu 0\n"); - } - else if ((olddir & bitvector) && - !(dir[number] & bitvector)) - { - // The bit was set and now its now clear and - // we were interrupting on that bit before - tsunami->intrctrl->clear(number, TheISA::INTLEVEL_IRQ1, x); - DPRINTF(Tsunami, "dim write resulting in clear" - " dir interrupt to cpu %d\n", - x); - - } - - - } - } - return NoFault; - case TSDEV_CC_DIR0: - case TSDEV_CC_DIR1: - case TSDEV_CC_DIR2: - case TSDEV_CC_DIR3: - panic("TSDEV_CC_DIR write not implemented\n"); - case TSDEV_CC_DRIR: - panic("TSDEV_CC_DRIR write not implemented\n"); - case TSDEV_CC_PRBEN: - panic("TSDEV_CC_PRBEN write not implemented\n"); - case TSDEV_CC_IIC0: - case TSDEV_CC_IIC1: - case TSDEV_CC_IIC2: - case TSDEV_CC_IIC3: - panic("TSDEV_CC_IICx write not implemented\n"); - case TSDEV_CC_MPR0: - case TSDEV_CC_MPR1: - case TSDEV_CC_MPR2: - case TSDEV_CC_MPR3: - panic("TSDEV_CC_MPRx write not implemented\n"); - case TSDEV_CC_IPIR: - clearIPI(*(uint64_t*)data); - return NoFault; - case TSDEV_CC_ITIR: - clearITI(*(uint64_t*)data); - return NoFault; - case TSDEV_CC_IPIQ: - reqIPI(*(uint64_t*)data); - return NoFault; - default: - panic("default in cchip read reached, accessing 0x%x\n"); - } - - break; - case sizeof(uint32_t): - case sizeof(uint16_t): - case sizeof(uint8_t): - default: - panic("invalid access size(?) for tsunami register!\n"); - } - - DPRINTFN("Tsunami ERROR: write daddr=%#x size=%d\n", daddr, req->size); - - return NoFault; -} - -void -TsunamiCChip::clearIPI(uint64_t ipintr) -{ - int numcpus = tsunami->intrctrl->cpu->system->execContexts.size(); - assert(numcpus <= Tsunami::Max_CPUs); - - if (ipintr) { - for (int cpunum=0; cpunum < numcpus; cpunum++) { - // Check each cpu bit - uint64_t cpumask = ULL(1) << cpunum; - if (ipintr & cpumask) { - // Check if there is a pending ipi - if (ipint & cpumask) { - ipint &= ~cpumask; - tsunami->intrctrl->clear(cpunum, TheISA::INTLEVEL_IRQ3, 0); - DPRINTF(IPI, "clear IPI IPI cpu=%d\n", cpunum); - } - else - warn("clear IPI for CPU=%d, but NO IPI\n", cpunum); - } - } - } - else - panic("Big IPI Clear, but not processors indicated\n"); -} - -void -TsunamiCChip::clearITI(uint64_t itintr) -{ - int numcpus = tsunami->intrctrl->cpu->system->execContexts.size(); - assert(numcpus <= Tsunami::Max_CPUs); - - if (itintr) { - for (int i=0; i < numcpus; i++) { - uint64_t cpumask = ULL(1) << i; - if (itintr & cpumask & itint) { - tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ2, 0); - itint &= ~cpumask; - DPRINTF(Tsunami, "clearing rtc interrupt to cpu=%d\n", i); - } - } - } - else - panic("Big ITI Clear, but not processors indicated\n"); -} - -void -TsunamiCChip::reqIPI(uint64_t ipreq) -{ - int numcpus = tsunami->intrctrl->cpu->system->execContexts.size(); - assert(numcpus <= Tsunami::Max_CPUs); - - if (ipreq) { - for (int cpunum=0; cpunum < numcpus; cpunum++) { - // Check each cpu bit - uint64_t cpumask = ULL(1) << cpunum; - if (ipreq & cpumask) { - // Check if there is already an ipi (bits 8:11) - if (!(ipint & cpumask)) { - ipint |= cpumask; - tsunami->intrctrl->post(cpunum, TheISA::INTLEVEL_IRQ3, 0); - DPRINTF(IPI, "send IPI cpu=%d\n", cpunum); - } - else - warn("post IPI for CPU=%d, but IPI already\n", cpunum); - } - } - } - else - panic("Big IPI Request, but not processors indicated\n"); -} - - -void -TsunamiCChip::postRTC() -{ - int size = tsunami->intrctrl->cpu->system->execContexts.size(); - assert(size <= Tsunami::Max_CPUs); - - for (int i = 0; i < size; i++) { - uint64_t cpumask = ULL(1) << i; - if (!(cpumask & itint)) { - itint |= cpumask; - tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ2, 0); - DPRINTF(Tsunami, "Posting RTC interrupt to cpu=%d", i); - } - } - -} - -void -TsunamiCChip::postDRIR(uint32_t interrupt) -{ - uint64_t bitvector = ULL(1) << interrupt; - uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size(); - assert(size <= Tsunami::Max_CPUs); - drir |= bitvector; - - for(int i=0; i < size; i++) { - dir[i] = dim[i] & drir; - if (dim[i] & bitvector) { - tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ1, interrupt); - DPRINTF(Tsunami, "posting dir interrupt to cpu %d," - "interrupt %d\n",i, interrupt); - } - } -} - -void -TsunamiCChip::clearDRIR(uint32_t interrupt) -{ - uint64_t bitvector = ULL(1) << interrupt; - uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size(); - assert(size <= Tsunami::Max_CPUs); - - if (drir & bitvector) - { - drir &= ~bitvector; - for(int i=0; i < size; i++) { - if (dir[i] & bitvector) { - tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ1, interrupt); - DPRINTF(Tsunami, "clearing dir interrupt to cpu %d," - "interrupt %d\n",i, interrupt); - - } - dir[i] = dim[i] & drir; - } - } - else - DPRINTF(Tsunami, "Spurrious clear? interrupt %d\n", interrupt); -} - -Tick -TsunamiCChip::cacheAccess(MemReqPtr &req) -{ - return curTick + pioLatency; -} - - -void -TsunamiCChip::serialize(std::ostream &os) -{ - SERIALIZE_ARRAY(dim, Tsunami::Max_CPUs); - SERIALIZE_ARRAY(dir, Tsunami::Max_CPUs); - SERIALIZE_SCALAR(ipint); - SERIALIZE_SCALAR(itint); - SERIALIZE_SCALAR(drir); -} - -void -TsunamiCChip::unserialize(Checkpoint *cp, const std::string §ion) -{ - UNSERIALIZE_ARRAY(dim, Tsunami::Max_CPUs); - UNSERIALIZE_ARRAY(dir, Tsunami::Max_CPUs); - UNSERIALIZE_SCALAR(ipint); - UNSERIALIZE_SCALAR(itint); - UNSERIALIZE_SCALAR(drir); -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip) - - SimObjectParam<Tsunami *> tsunami; - SimObjectParam<MemoryController *> mmu; - Param<Addr> addr; - SimObjectParam<Bus*> pio_bus; - Param<Tick> pio_latency; - SimObjectParam<HierParams *> hier; - -END_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip) - -BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiCChip) - - INIT_PARAM(tsunami, "Tsunami"), - INIT_PARAM(mmu, "Memory Controller"), - INIT_PARAM(addr, "Device Address"), - INIT_PARAM_DFLT(pio_bus, "The IO Bus to attach to", NULL), - INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), - INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams) - -END_INIT_SIM_OBJECT_PARAMS(TsunamiCChip) - -CREATE_SIM_OBJECT(TsunamiCChip) -{ - return new TsunamiCChip(getInstanceName(), tsunami, addr, mmu, hier, - pio_bus, pio_latency); -} - -REGISTER_SIM_OBJECT("TsunamiCChip", TsunamiCChip) diff --git a/dev/tsunami_cchip.hh b/dev/tsunami_cchip.hh deleted file mode 100644 index d88ad375f..000000000 --- a/dev/tsunami_cchip.hh +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Emulation of the Tsunami CChip CSRs - */ - -#ifndef __TSUNAMI_CCHIP_HH__ -#define __TSUNAMI_CCHIP_HH__ - -#include "dev/tsunami.hh" -#include "base/range.hh" -#include "dev/io_device.hh" - -class MemoryController; - -/** - * Tsunami CChip CSR Emulation. This device includes all the interrupt - * handling code for the chipset. - */ -class TsunamiCChip : public PioDevice -{ - private: - /** The base address of this device */ - Addr addr; - - /** The size of mappad from the above address */ - static const Addr size = 0xfffffff; - - protected: - /** - * pointer to the tsunami object. - * This is our access to all the other tsunami - * devices. - */ - Tsunami *tsunami; - - /** - * The dims are device interrupt mask registers. - * One exists for each CPU, the DRIR X DIM = DIR - */ - uint64_t dim[Tsunami::Max_CPUs]; - - /** - * The dirs are device interrupt registers. - * One exists for each CPU, the DRIR X DIM = DIR - */ - uint64_t dir[Tsunami::Max_CPUs]; - - /** - * This register contains bits for each PCI interrupt - * that can occur. - */ - uint64_t drir; - - /** Indicator of which CPUs have an IPI interrupt */ - uint64_t ipint; - - /** Indicator of which CPUs have an RTC interrupt */ - uint64_t itint; - - public: - /** - * Initialize the Tsunami CChip by setting all of the - * device register to 0. - * @param name name of this device. - * @param t pointer back to the Tsunami object that we belong to. - * @param a address we are mapped at. - * @param mmu pointer to the memory controller that sends us events. - * @param hier object to store parameters universal the device hierarchy - * @param bus The bus that this device is attached to - */ - TsunamiCChip(const std::string &name, Tsunami *t, Addr a, - MemoryController *mmu, HierParams *hier, Bus *pio_bus, - Tick pio_latency); - - /** - * Process a read to the CChip. - * @param req Contains the address to read from. - * @param data A pointer to write the read data to. - * @return The fault condition of the access. - */ - virtual Fault read(MemReqPtr &req, uint8_t *data); - - - /** - * Process a write to the CChip. - * @param req Contains the address to write to. - * @param data The data to write. - * @return The fault condition of the access. - */ - virtual Fault write(MemReqPtr &req, const uint8_t *data); - - /** - * post an RTC interrupt to the CPU - */ - void postRTC(); - - /** - * post an interrupt to the CPU. - * @param interrupt the interrupt number to post (0-64) - */ - void postDRIR(uint32_t interrupt); - - /** - * clear an interrupt previously posted to the CPU. - * @param interrupt the interrupt number to post (0-64) - */ - void clearDRIR(uint32_t interrupt); - - /** - * post an ipi interrupt to the CPU. - * @param ipintr the cpu number to clear(bitvector) - */ - void clearIPI(uint64_t ipintr); - - /** - * clear a timer interrupt previously posted to the CPU. - * @param itintr the cpu number to clear(bitvector) - */ - void clearITI(uint64_t itintr); - - /** - * request an interrupt be posted to the CPU. - * @param ipreq the cpu number to interrupt(bitvector) - */ - void reqIPI(uint64_t ipreq); - - - /** - * Serialize this object to the given output stream. - * @param os The stream to serialize to. - */ - virtual void serialize(std::ostream &os); - - /** - * Reconstruct the state of this object from a checkpoint. - * @param cp The checkpoint use. - * @param section The section name of this object - */ - virtual void unserialize(Checkpoint *cp, const std::string §ion); - - /** - * Return how long this access will take. - * @param req the memory request to calcuate - * @return Tick when the request is done - */ - Tick cacheAccess(MemReqPtr &req); -}; - -#endif // __TSUNAMI_CCHIP_HH__ diff --git a/dev/tsunami_io.cc b/dev/tsunami_io.cc deleted file mode 100644 index e66d6653b..000000000 --- a/dev/tsunami_io.cc +++ /dev/null @@ -1,719 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Tsunami I/O including PIC, PIT, RTC, DMA - */ - -#include <sys/time.h> - -#include <deque> -#include <string> -#include <vector> - -#include "base/trace.hh" -#include "dev/tsunami_io.hh" -#include "dev/tsunami.hh" -#include "dev/pitreg.h" -#include "mem/bus/bus.hh" -#include "mem/bus/pio_interface.hh" -#include "mem/bus/pio_interface_impl.hh" -#include "sim/builder.hh" -#include "dev/tsunami_cchip.hh" -#include "dev/tsunamireg.h" -#include "dev/rtcreg.h" -#include "mem/functional/memory_control.hh" - -using namespace std; -//Should this be AlphaISA? -using namespace TheISA; - -TsunamiIO::RTC::RTC(const string &name, Tsunami* t, Tick i) - : _name(name), event(t, i), addr(0) -{ - memset(clock_data, 0, sizeof(clock_data)); - stat_regA = RTCA_32768HZ | RTCA_1024HZ; - stat_regB = RTCB_PRDC_IE |RTCB_BIN | RTCB_24HR; -} - -void -TsunamiIO::RTC::set_time(time_t t) -{ - struct tm tm; - gmtime_r(&t, &tm); - - sec = tm.tm_sec; - min = tm.tm_min; - hour = tm.tm_hour; - wday = tm.tm_wday + 1; - mday = tm.tm_mday; - mon = tm.tm_mon + 1; - year = tm.tm_year; - - DPRINTFN("Real-time clock set to %s", asctime(&tm)); -} - -void -TsunamiIO::RTC::writeAddr(const uint8_t *data) -{ - if (*data <= RTC_STAT_REGD) - addr = *data; - else - panic("RTC addresses over 0xD are not implemented.\n"); -} - -void -TsunamiIO::RTC::writeData(const uint8_t *data) -{ - if (addr < RTC_STAT_REGA) - clock_data[addr] = *data; - else { - switch (addr) { - case RTC_STAT_REGA: - if (*data != (RTCA_32768HZ | RTCA_1024HZ)) - panic("Unimplemented RTC register A value write!\n"); - stat_regA = *data; - break; - case RTC_STAT_REGB: - if ((*data & ~(RTCB_PRDC_IE | RTCB_SQWE)) != (RTCB_BIN | RTCB_24HR)) - panic("Write to RTC reg B bits that are not implemented!\n"); - - if (*data & RTCB_PRDC_IE) { - if (!event.scheduled()) - event.scheduleIntr(); - } else { - if (event.scheduled()) - event.deschedule(); - } - stat_regB = *data; - break; - case RTC_STAT_REGC: - case RTC_STAT_REGD: - panic("RTC status registers C and D are not implemented.\n"); - break; - } - } -} - -void -TsunamiIO::RTC::readData(uint8_t *data) -{ - if (addr < RTC_STAT_REGA) - *data = clock_data[addr]; - else { - switch (addr) { - case RTC_STAT_REGA: - // toggle UIP bit for linux - stat_regA ^= RTCA_UIP; - *data = stat_regA; - break; - case RTC_STAT_REGB: - *data = stat_regB; - break; - case RTC_STAT_REGC: - case RTC_STAT_REGD: - *data = 0x00; - break; - } - } -} - -void -TsunamiIO::RTC::serialize(const string &base, ostream &os) -{ - paramOut(os, base + ".addr", addr); - arrayParamOut(os, base + ".clock_data", clock_data, sizeof(clock_data)); - paramOut(os, base + ".stat_regA", stat_regA); - paramOut(os, base + ".stat_regB", stat_regB); -} - -void -TsunamiIO::RTC::unserialize(const string &base, Checkpoint *cp, - const string §ion) -{ - paramIn(cp, section, base + ".addr", addr); - arrayParamIn(cp, section, base + ".clock_data", clock_data, - sizeof(clock_data)); - paramIn(cp, section, base + ".stat_regA", stat_regA); - paramIn(cp, section, base + ".stat_regB", stat_regB); - - // We're not unserializing the event here, but we need to - // rescehedule the event since curTick was moved forward by the - // checkpoint - event.reschedule(curTick + event.interval); -} - -TsunamiIO::RTC::RTCEvent::RTCEvent(Tsunami*t, Tick i) - : Event(&mainEventQueue), tsunami(t), interval(i) -{ - DPRINTF(MC146818, "RTC Event Initilizing\n"); - schedule(curTick + interval); -} - -void -TsunamiIO::RTC::RTCEvent::scheduleIntr() -{ - schedule(curTick + interval); -} - -void -TsunamiIO::RTC::RTCEvent::process() -{ - DPRINTF(MC146818, "RTC Timer Interrupt\n"); - schedule(curTick + interval); - //Actually interrupt the processor here - tsunami->cchip->postRTC(); -} - -const char * -TsunamiIO::RTC::RTCEvent::description() -{ - return "tsunami RTC interrupt"; -} - -TsunamiIO::PITimer::PITimer(const string &name) - : _name(name), counter0(name + ".counter0"), counter1(name + ".counter1"), - counter2(name + ".counter2") -{ - counter[0] = &counter0; - counter[1] = &counter0; - counter[2] = &counter0; -} - -void -TsunamiIO::PITimer::writeControl(const uint8_t *data) -{ - int rw; - int sel; - - sel = GET_CTRL_SEL(*data); - - if (sel == PIT_READ_BACK) - panic("PITimer Read-Back Command is not implemented.\n"); - - rw = GET_CTRL_RW(*data); - - if (rw == PIT_RW_LATCH_COMMAND) - counter[sel]->latchCount(); - else { - counter[sel]->setRW(rw); - counter[sel]->setMode(GET_CTRL_MODE(*data)); - counter[sel]->setBCD(GET_CTRL_BCD(*data)); - } -} - -void -TsunamiIO::PITimer::serialize(const string &base, ostream &os) -{ - // serialize the counters - counter0.serialize(base + ".counter0", os); - counter1.serialize(base + ".counter1", os); - counter2.serialize(base + ".counter2", os); -} - -void -TsunamiIO::PITimer::unserialize(const string &base, Checkpoint *cp, - const string §ion) -{ - // unserialze the counters - counter0.unserialize(base + ".counter0", cp, section); - counter1.unserialize(base + ".counter1", cp, section); - counter2.unserialize(base + ".counter2", cp, section); -} - -TsunamiIO::PITimer::Counter::Counter(const string &name) - : _name(name), event(this), count(0), latched_count(0), period(0), - mode(0), output_high(false), latch_on(false), read_byte(LSB), - write_byte(LSB) -{ - -} - -void -TsunamiIO::PITimer::Counter::latchCount() -{ - // behave like a real latch - if(!latch_on) { - latch_on = true; - read_byte = LSB; - latched_count = count; - } -} - -void -TsunamiIO::PITimer::Counter::read(uint8_t *data) -{ - if (latch_on) { - switch (read_byte) { - case LSB: - read_byte = MSB; - *data = (uint8_t)latched_count; - break; - case MSB: - read_byte = LSB; - latch_on = false; - *data = latched_count >> 8; - break; - } - } else { - switch (read_byte) { - case LSB: - read_byte = MSB; - *data = (uint8_t)count; - break; - case MSB: - read_byte = LSB; - *data = count >> 8; - break; - } - } -} - -void -TsunamiIO::PITimer::Counter::write(const uint8_t *data) -{ - switch (write_byte) { - case LSB: - count = (count & 0xFF00) | *data; - - if (event.scheduled()) - event.deschedule(); - output_high = false; - write_byte = MSB; - break; - - case MSB: - count = (count & 0x00FF) | (*data << 8); - period = count; - - if (period > 0) { - DPRINTF(Tsunami, "Timer set to curTick + %d\n", - count * event.interval); - event.schedule(curTick + count * event.interval); - } - write_byte = LSB; - break; - } -} - -void -TsunamiIO::PITimer::Counter::setRW(int rw_val) -{ - if (rw_val != PIT_RW_16BIT) - panic("Only LSB/MSB read/write is implemented.\n"); -} - -void -TsunamiIO::PITimer::Counter::setMode(int mode_val) -{ - if(mode_val != PIT_MODE_INTTC && mode_val != PIT_MODE_RATEGEN && - mode_val != PIT_MODE_SQWAVE) - panic("PIT mode %#x is not implemented: \n", mode_val); - - mode = mode_val; -} - -void -TsunamiIO::PITimer::Counter::setBCD(int bcd_val) -{ - if (bcd_val != PIT_BCD_FALSE) - panic("PITimer does not implement BCD counts.\n"); -} - -bool -TsunamiIO::PITimer::Counter::outputHigh() -{ - return output_high; -} - -void -TsunamiIO::PITimer::Counter::serialize(const string &base, ostream &os) -{ - paramOut(os, base + ".count", count); - paramOut(os, base + ".latched_count", latched_count); - paramOut(os, base + ".period", period); - paramOut(os, base + ".mode", mode); - paramOut(os, base + ".output_high", output_high); - paramOut(os, base + ".latch_on", latch_on); - paramOut(os, base + ".read_byte", read_byte); - paramOut(os, base + ".write_byte", write_byte); - - Tick event_tick = 0; - if (event.scheduled()) - event_tick = event.when(); - paramOut(os, base + ".event_tick", event_tick); -} - -void -TsunamiIO::PITimer::Counter::unserialize(const string &base, Checkpoint *cp, - const string §ion) -{ - paramIn(cp, section, base + ".count", count); - paramIn(cp, section, base + ".latched_count", latched_count); - paramIn(cp, section, base + ".period", period); - paramIn(cp, section, base + ".mode", mode); - paramIn(cp, section, base + ".output_high", output_high); - paramIn(cp, section, base + ".latch_on", latch_on); - paramIn(cp, section, base + ".read_byte", read_byte); - paramIn(cp, section, base + ".write_byte", write_byte); - - Tick event_tick; - paramIn(cp, section, base + ".event_tick", event_tick); - if (event_tick) - event.schedule(event_tick); -} - -TsunamiIO::PITimer::Counter::CounterEvent::CounterEvent(Counter* c_ptr) - : Event(&mainEventQueue) -{ - interval = (Tick)(Clock::Float::s / 1193180.0); - counter = c_ptr; -} - -void -TsunamiIO::PITimer::Counter::CounterEvent::process() -{ - DPRINTF(Tsunami, "Timer Interrupt\n"); - switch (counter->mode) { - case PIT_MODE_INTTC: - counter->output_high = true; - case PIT_MODE_RATEGEN: - case PIT_MODE_SQWAVE: - break; - default: - panic("Unimplemented PITimer mode.\n"); - } -} - -const char * -TsunamiIO::PITimer::Counter::CounterEvent::description() -{ - return "tsunami 8254 Interval timer"; -} - -TsunamiIO::TsunamiIO(const string &name, Tsunami *t, time_t init_time, - Addr a, MemoryController *mmu, HierParams *hier, - Bus *pio_bus, Tick pio_latency, Tick ci) - : PioDevice(name, t), addr(a), clockInterval(ci), tsunami(t), - pitimer(name + "pitimer"), rtc(name + ".rtc", t, ci) -{ - mmu->add_child(this, RangeSize(addr, size)); - - if (pio_bus) { - pioInterface = newPioInterface(name + ".pio", hier, pio_bus, this, - &TsunamiIO::cacheAccess); - pioInterface->addAddrRange(RangeSize(addr, size)); - pioLatency = pio_latency * pio_bus->clockRate; - } - - // set the back pointer from tsunami to myself - tsunami->io = this; - - timerData = 0; - rtc.set_time(init_time == 0 ? time(NULL) : init_time); - picr = 0; - picInterrupting = false; -} - -Tick -TsunamiIO::frequency() const -{ - return Clock::Frequency / clockInterval; -} - -Fault -TsunamiIO::read(MemReqPtr &req, uint8_t *data) -{ - DPRINTF(Tsunami, "io read va=%#x size=%d IOPorrt=%#x\n", - req->vaddr, req->size, req->vaddr & 0xfff); - - Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)); - - - switch(req->size) { - case sizeof(uint8_t): - switch(daddr) { - // PIC1 mask read - case TSDEV_PIC1_MASK: - *(uint8_t*)data = ~mask1; - return NoFault; - case TSDEV_PIC2_MASK: - *(uint8_t*)data = ~mask2; - return NoFault; - case TSDEV_PIC1_ISR: - // !!! If this is modified 64bit case needs to be too - // Pal code has to do a 64 bit physical read because there is - // no load physical byte instruction - *(uint8_t*)data = picr; - return NoFault; - case TSDEV_PIC2_ISR: - // PIC2 not implemnted... just return 0 - *(uint8_t*)data = 0x00; - return NoFault; - case TSDEV_TMR0_DATA: - pitimer.counter0.read(data); - return NoFault; - case TSDEV_TMR1_DATA: - pitimer.counter1.read(data); - return NoFault; - case TSDEV_TMR2_DATA: - pitimer.counter2.read(data); - return NoFault; - case TSDEV_RTC_DATA: - rtc.readData(data); - return NoFault; - case TSDEV_CTRL_PORTB: - if (pitimer.counter2.outputHigh()) - *data = PORTB_SPKR_HIGH; - else - *data = 0x00; - return NoFault; - default: - panic("I/O Read - va%#x size %d\n", req->vaddr, req->size); - } - case sizeof(uint16_t): - case sizeof(uint32_t): - panic("I/O Read - invalid size - va %#x size %d\n", - req->vaddr, req->size); - - case sizeof(uint64_t): - switch(daddr) { - case TSDEV_PIC1_ISR: - // !!! If this is modified 8bit case needs to be too - // Pal code has to do a 64 bit physical read because there is - // no load physical byte instruction - *(uint64_t*)data = (uint64_t)picr; - return NoFault; - default: - panic("I/O Read - invalid size - va %#x size %d\n", - req->vaddr, req->size); - } - - default: - panic("I/O Read - invalid size - va %#x size %d\n", - req->vaddr, req->size); - } - panic("I/O Read - va%#x size %d\n", req->vaddr, req->size); - - return NoFault; -} - -Fault -TsunamiIO::write(MemReqPtr &req, const uint8_t *data) -{ - -#if TRACING_ON - uint8_t dt = *(uint8_t*)data; - uint64_t dt64 = dt; -#endif - - DPRINTF(Tsunami, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n", - req->vaddr, req->size, req->vaddr & 0xfff, dt64); - - Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)); - - switch(req->size) { - case sizeof(uint8_t): - switch(daddr) { - case TSDEV_PIC1_MASK: - mask1 = ~(*(uint8_t*)data); - if ((picr & mask1) && !picInterrupting) { - picInterrupting = true; - tsunami->cchip->postDRIR(55); - DPRINTF(Tsunami, "posting pic interrupt to cchip\n"); - } - if ((!(picr & mask1)) && picInterrupting) { - picInterrupting = false; - tsunami->cchip->clearDRIR(55); - DPRINTF(Tsunami, "clearing pic interrupt\n"); - } - return NoFault; - case TSDEV_PIC2_MASK: - mask2 = *(uint8_t*)data; - //PIC2 Not implemented to interrupt - return NoFault; - case TSDEV_PIC1_ACK: - // clear the interrupt on the PIC - picr &= ~(1 << (*(uint8_t*)data & 0xF)); - if (!(picr & mask1)) - tsunami->cchip->clearDRIR(55); - return NoFault; - case TSDEV_DMA1_CMND: - return NoFault; - case TSDEV_DMA2_CMND: - return NoFault; - case TSDEV_DMA1_MMASK: - return NoFault; - case TSDEV_DMA2_MMASK: - return NoFault; - case TSDEV_PIC2_ACK: - return NoFault; - case TSDEV_DMA1_RESET: - return NoFault; - case TSDEV_DMA2_RESET: - return NoFault; - case TSDEV_DMA1_MODE: - mode1 = *(uint8_t*)data; - return NoFault; - case TSDEV_DMA2_MODE: - mode2 = *(uint8_t*)data; - return NoFault; - case TSDEV_DMA1_MASK: - case TSDEV_DMA2_MASK: - return NoFault; - case TSDEV_TMR0_DATA: - pitimer.counter0.write(data); - return NoFault; - case TSDEV_TMR1_DATA: - pitimer.counter1.write(data); - return NoFault; - case TSDEV_TMR2_DATA: - pitimer.counter2.write(data); - return NoFault; - case TSDEV_TMR_CTRL: - pitimer.writeControl(data); - return NoFault; - case TSDEV_RTC_ADDR: - rtc.writeAddr(data); - return NoFault; - case TSDEV_KBD: - return NoFault; - case TSDEV_RTC_DATA: - rtc.writeData(data); - return NoFault; - case TSDEV_CTRL_PORTB: - // System Control Port B not implemented - return NoFault; - default: - panic("I/O Write - va%#x size %d data %#x\n", req->vaddr, req->size, (int)*data); - } - case sizeof(uint16_t): - case sizeof(uint32_t): - case sizeof(uint64_t): - default: - panic("I/O Write - invalid size - va %#x size %d\n", - req->vaddr, req->size); - } - - - return NoFault; -} - -void -TsunamiIO::postPIC(uint8_t bitvector) -{ - //PIC2 Is not implemented, because nothing of interest there - picr |= bitvector; - if (picr & mask1) { - tsunami->cchip->postDRIR(55); - DPRINTF(Tsunami, "posting pic interrupt to cchip\n"); - } -} - -void -TsunamiIO::clearPIC(uint8_t bitvector) -{ - //PIC2 Is not implemented, because nothing of interest there - picr &= ~bitvector; - if (!(picr & mask1)) { - tsunami->cchip->clearDRIR(55); - DPRINTF(Tsunami, "clearing pic interrupt to cchip\n"); - } -} - -Tick -TsunamiIO::cacheAccess(MemReqPtr &req) -{ - return curTick + pioLatency; -} - -void -TsunamiIO::serialize(ostream &os) -{ - SERIALIZE_SCALAR(timerData); - SERIALIZE_SCALAR(mask1); - SERIALIZE_SCALAR(mask2); - SERIALIZE_SCALAR(mode1); - SERIALIZE_SCALAR(mode2); - SERIALIZE_SCALAR(picr); - SERIALIZE_SCALAR(picInterrupting); - - // Serialize the timers - pitimer.serialize("pitimer", os); - rtc.serialize("rtc", os); -} - -void -TsunamiIO::unserialize(Checkpoint *cp, const string §ion) -{ - UNSERIALIZE_SCALAR(timerData); - UNSERIALIZE_SCALAR(mask1); - UNSERIALIZE_SCALAR(mask2); - UNSERIALIZE_SCALAR(mode1); - UNSERIALIZE_SCALAR(mode2); - UNSERIALIZE_SCALAR(picr); - UNSERIALIZE_SCALAR(picInterrupting); - - // Unserialize the timers - pitimer.unserialize("pitimer", cp, section); - rtc.unserialize("rtc", cp, section); -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO) - - SimObjectParam<Tsunami *> tsunami; - Param<time_t> time; - SimObjectParam<MemoryController *> mmu; - Param<Addr> addr; - SimObjectParam<Bus*> pio_bus; - Param<Tick> pio_latency; - SimObjectParam<HierParams *> hier; - Param<Tick> frequency; - -END_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO) - -BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiIO) - - INIT_PARAM(tsunami, "Tsunami"), - INIT_PARAM(time, "System time to use (0 for actual time"), - INIT_PARAM(mmu, "Memory Controller"), - INIT_PARAM(addr, "Device Address"), - INIT_PARAM(pio_bus, "The IO Bus to attach to"), - INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), - INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams), - INIT_PARAM(frequency, "clock interrupt frequency") - -END_INIT_SIM_OBJECT_PARAMS(TsunamiIO) - -CREATE_SIM_OBJECT(TsunamiIO) -{ - return new TsunamiIO(getInstanceName(), tsunami, time, addr, mmu, hier, - pio_bus, pio_latency, frequency); -} - -REGISTER_SIM_OBJECT("TsunamiIO", TsunamiIO) diff --git a/dev/tsunami_io.hh b/dev/tsunami_io.hh deleted file mode 100644 index b024ecd14..000000000 --- a/dev/tsunami_io.hh +++ /dev/null @@ -1,371 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Tsunami I/O Space mapping including RTC/timer interrupts - */ - -#ifndef __DEV_TSUNAMI_IO_HH__ -#define __DEV_TSUNAMI_IO_HH__ - -#include "dev/io_device.hh" -#include "base/range.hh" -#include "dev/tsunami.hh" -#include "sim/eventq.hh" - -class MemoryController; - -/** - * Tsunami I/O device is a catch all for all the south bridge stuff we care - * to implement. - */ -class TsunamiIO : public PioDevice -{ - private: - /** The base address of this device */ - Addr addr; - - /** The size of mappad from the above address */ - static const Addr size = 0xff; - - struct tm tm; - - protected: - /** Real-Time Clock (MC146818) */ - class RTC - { - private: - /** Event for RTC periodic interrupt */ - struct RTCEvent : public Event - { - /** A pointer back to tsunami to create interrupt the processor. */ - Tsunami* tsunami; - Tick interval; - - RTCEvent(Tsunami* t, Tick i); - - /** Schedule the RTC periodic interrupt */ - void scheduleIntr(); - - /** Event process to occur at interrupt*/ - virtual void process(); - - /** Event description */ - virtual const char *description(); - }; - - private: - std::string _name; - const std::string &name() const { return _name; } - - /** RTC periodic interrupt event */ - RTCEvent event; - - /** Current RTC register address/index */ - int addr; - - /** Data for real-time clock function */ - union { - uint8_t clock_data[10]; - - struct { - uint8_t sec; - uint8_t sec_alrm; - uint8_t min; - uint8_t min_alrm; - uint8_t hour; - uint8_t hour_alrm; - uint8_t wday; - uint8_t mday; - uint8_t mon; - uint8_t year; - }; - }; - - /** RTC status register A */ - uint8_t stat_regA; - - /** RTC status register B */ - uint8_t stat_regB; - - public: - RTC(const std::string &name, Tsunami* t, Tick i); - - /** Set the initial RTC time/date */ - void set_time(time_t t); - - /** RTC address port: write address of RTC RAM data to access */ - void writeAddr(const uint8_t *data); - - /** RTC write data */ - void writeData(const uint8_t *data); - - /** RTC read data */ - void readData(uint8_t *data); - - /** - * Serialize this object to the given output stream. - * @param os The stream to serialize to. - */ - void serialize(const std::string &base, 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 - */ - void unserialize(const std::string &base, Checkpoint *cp, - const std::string §ion); - }; - - /** Programmable Interval Timer (Intel 8254) */ - class PITimer - { - /** Counter element for PIT */ - class Counter - { - /** Event for counter interrupt */ - class CounterEvent : public Event - { - private: - /** Pointer back to Counter */ - Counter* counter; - Tick interval; - - public: - CounterEvent(Counter*); - - /** Event process */ - virtual void process(); - - /** Event description */ - virtual const char *description(); - - friend class Counter; - }; - - private: - std::string _name; - const std::string &name() const { return _name; } - - CounterEvent event; - - /** Current count value */ - uint16_t count; - - /** Latched count */ - uint16_t latched_count; - - /** Interrupt period */ - uint16_t period; - - /** Current mode of operation */ - uint8_t mode; - - /** Output goes high when the counter reaches zero */ - bool output_high; - - /** State of the count latch */ - bool latch_on; - - /** Set of values for read_byte and write_byte */ - enum {LSB, MSB}; - - /** Determine which byte of a 16-bit count value to read/write */ - uint8_t read_byte, write_byte; - - public: - Counter(const std::string &name); - - /** Latch the current count (if one is not already latched) */ - void latchCount(); - - /** Set the read/write mode */ - void setRW(int rw_val); - - /** Set operational mode */ - void setMode(int mode_val); - - /** Set count encoding */ - void setBCD(int bcd_val); - - /** Read a count byte */ - void read(uint8_t *data); - - /** Write a count byte */ - void write(const uint8_t *data); - - /** Is the output high? */ - bool outputHigh(); - - /** - * Serialize this object to the given output stream. - * @param os The stream to serialize to. - */ - void serialize(const std::string &base, 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 - */ - void unserialize(const std::string &base, Checkpoint *cp, - const std::string §ion); - }; - - private: - std::string _name; - const std::string &name() const { return _name; } - - /** PIT has three seperate counters */ - Counter *counter[3]; - - public: - /** Public way to access individual counters (avoid array accesses) */ - Counter counter0; - Counter counter1; - Counter counter2; - - PITimer(const std::string &name); - - /** Write control word */ - void writeControl(const uint8_t* data); - - /** - * Serialize this object to the given output stream. - * @param os The stream to serialize to. - */ - void serialize(const std::string &base, 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 - */ - void unserialize(const std::string &base, Checkpoint *cp, - const std::string §ion); - }; - - /** Mask of the PIC1 */ - uint8_t mask1; - - /** Mask of the PIC2 */ - uint8_t mask2; - - /** Mode of PIC1. Not used for anything */ - uint8_t mode1; - - /** Mode of PIC2. Not used for anything */ - uint8_t mode2; - - /** Raw PIC interrupt register before masking */ - uint8_t picr; //Raw PIC interrput register - - /** Is the pic interrupting right now or not. */ - bool picInterrupting; - - Tick clockInterval; - - /** A pointer to the Tsunami device which be belong to */ - Tsunami *tsunami; - - /** Intel 8253 Periodic Interval Timer */ - PITimer pitimer; - - RTC rtc; - - /** The interval is set via two writes to the PIT. - * This variable contains a flag as to how many writes have happened, and - * the time so far. - */ - uint16_t timerData; - - public: - /** - * Return the freqency of the RTC - * @return interrupt rate of the RTC - */ - Tick frequency() const; - - /** - * Initialize all the data for devices supported by Tsunami I/O. - * @param name name of this device. - * @param t pointer back to the Tsunami object that we belong to. - * @param init_time Time (as in seconds since 1970) to set RTC to. - * @param a address we are mapped at. - * @param mmu pointer to the memory controller that sends us events. - */ - TsunamiIO(const std::string &name, Tsunami *t, time_t init_time, - Addr a, MemoryController *mmu, HierParams *hier, Bus *pio_bus, - Tick pio_latency, Tick ci); - - /** - * Process a read to one of the devices we are emulating. - * @param req Contains the address to read from. - * @param data A pointer to write the read data to. - * @return The fault condition of the access. - */ - virtual Fault read(MemReqPtr &req, uint8_t *data); - - /** - * Process a write to one of the devices we emulate. - * @param req Contains the address to write to. - * @param data The data to write. - * @return The fault condition of the access. - */ - virtual Fault write(MemReqPtr &req, const uint8_t *data); - - /** - * Post an PIC interrupt to the CPU via the CChip - * @param bitvector interrupt to post. - */ - void postPIC(uint8_t bitvector); - - /** - * Clear a posted interrupt - * @param bitvector interrupt to clear - */ - void clearPIC(uint8_t bitvector); - - /** - * Serialize this object to the given output stream. - * @param os The stream to serialize to. - */ - virtual void serialize(std::ostream &os); - - /** - * Reconstruct the state of this object from a checkpoint. - * @param cp The checkpoint use. - * @param section The section name of this object - */ - virtual void unserialize(Checkpoint *cp, const std::string §ion); - - Tick cacheAccess(MemReqPtr &req); -}; - -#endif // __DEV_TSUNAMI_IO_HH__ diff --git a/dev/tsunami_pchip.cc b/dev/tsunami_pchip.cc deleted file mode 100644 index 46efc3dfe..000000000 --- a/dev/tsunami_pchip.cc +++ /dev/null @@ -1,388 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Tsunami PChip (pci) - */ - -#include <deque> -#include <string> -#include <vector> - -#include "base/trace.hh" -#include "dev/tsunami_pchip.hh" -#include "dev/tsunamireg.h" -#include "dev/tsunami.hh" -#include "mem/bus/bus.hh" -#include "mem/bus/pio_interface.hh" -#include "mem/bus/pio_interface_impl.hh" -#include "mem/functional/memory_control.hh" -#include "mem/functional/physical.hh" -#include "sim/builder.hh" -#include "sim/system.hh" - -using namespace std; -//Should this be AlphaISA? -using namespace TheISA; - -TsunamiPChip::TsunamiPChip(const string &name, Tsunami *t, Addr a, - MemoryController *mmu, HierParams *hier, - Bus *pio_bus, Tick pio_latency) - : PioDevice(name, t), addr(a), tsunami(t) -{ - mmu->add_child(this, RangeSize(addr, size)); - - for (int i = 0; i < 4; i++) { - wsba[i] = 0; - wsm[i] = 0; - tba[i] = 0; - } - - if (pio_bus) { - pioInterface = newPioInterface(name + ".pio", hier, pio_bus, this, - &TsunamiPChip::cacheAccess); - pioInterface->addAddrRange(RangeSize(addr, size)); - pioLatency = pio_latency * pio_bus->clockRate; - } - - - // initialize pchip control register - pctl = (ULL(0x1) << 20) | (ULL(0x1) << 32) | (ULL(0x2) << 36); - - //Set back pointer in tsunami - tsunami->pchip = this; -} - -Fault -TsunamiPChip::read(MemReqPtr &req, uint8_t *data) -{ - DPRINTF(Tsunami, "read va=%#x size=%d\n", - req->vaddr, req->size); - - Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)) >> 6; - - switch (req->size) { - - case sizeof(uint64_t): - switch(daddr) { - case TSDEV_PC_WSBA0: - *(uint64_t*)data = wsba[0]; - return NoFault; - case TSDEV_PC_WSBA1: - *(uint64_t*)data = wsba[1]; - return NoFault; - case TSDEV_PC_WSBA2: - *(uint64_t*)data = wsba[2]; - return NoFault; - case TSDEV_PC_WSBA3: - *(uint64_t*)data = wsba[3]; - return NoFault; - case TSDEV_PC_WSM0: - *(uint64_t*)data = wsm[0]; - return NoFault; - case TSDEV_PC_WSM1: - *(uint64_t*)data = wsm[1]; - return NoFault; - case TSDEV_PC_WSM2: - *(uint64_t*)data = wsm[2]; - return NoFault; - case TSDEV_PC_WSM3: - *(uint64_t*)data = wsm[3]; - return NoFault; - case TSDEV_PC_TBA0: - *(uint64_t*)data = tba[0]; - return NoFault; - case TSDEV_PC_TBA1: - *(uint64_t*)data = tba[1]; - return NoFault; - case TSDEV_PC_TBA2: - *(uint64_t*)data = tba[2]; - return NoFault; - case TSDEV_PC_TBA3: - *(uint64_t*)data = tba[3]; - return NoFault; - case TSDEV_PC_PCTL: - *(uint64_t*)data = pctl; - return NoFault; - case TSDEV_PC_PLAT: - panic("PC_PLAT not implemented\n"); - case TSDEV_PC_RES: - panic("PC_RES not implemented\n"); - case TSDEV_PC_PERROR: - *(uint64_t*)data = 0x00; - return NoFault; - case TSDEV_PC_PERRMASK: - *(uint64_t*)data = 0x00; - return NoFault; - case TSDEV_PC_PERRSET: - panic("PC_PERRSET not implemented\n"); - case TSDEV_PC_TLBIV: - panic("PC_TLBIV not implemented\n"); - case TSDEV_PC_TLBIA: - *(uint64_t*)data = 0x00; // shouldn't be readable, but linux - return NoFault; - case TSDEV_PC_PMONCTL: - panic("PC_PMONCTL not implemented\n"); - case TSDEV_PC_PMONCNT: - panic("PC_PMONCTN not implemented\n"); - default: - panic("Default in PChip Read reached reading 0x%x\n", daddr); - - } // uint64_t - - break; - case sizeof(uint32_t): - case sizeof(uint16_t): - case sizeof(uint8_t): - default: - panic("invalid access size(?) for tsunami register!\n\n"); - } - DPRINTFN("Tsunami PChip ERROR: read daddr=%#x size=%d\n", daddr, req->size); - - return NoFault; -} - -Fault -TsunamiPChip::write(MemReqPtr &req, const uint8_t *data) -{ - DPRINTF(Tsunami, "write - va=%#x size=%d \n", - req->vaddr, req->size); - - Addr daddr = (req->paddr - (addr & EV5::PAddrImplMask)) >> 6; - - switch (req->size) { - - case sizeof(uint64_t): - switch(daddr) { - case TSDEV_PC_WSBA0: - wsba[0] = *(uint64_t*)data; - return NoFault; - case TSDEV_PC_WSBA1: - wsba[1] = *(uint64_t*)data; - return NoFault; - case TSDEV_PC_WSBA2: - wsba[2] = *(uint64_t*)data; - return NoFault; - case TSDEV_PC_WSBA3: - wsba[3] = *(uint64_t*)data; - return NoFault; - case TSDEV_PC_WSM0: - wsm[0] = *(uint64_t*)data; - return NoFault; - case TSDEV_PC_WSM1: - wsm[1] = *(uint64_t*)data; - return NoFault; - case TSDEV_PC_WSM2: - wsm[2] = *(uint64_t*)data; - return NoFault; - case TSDEV_PC_WSM3: - wsm[3] = *(uint64_t*)data; - return NoFault; - case TSDEV_PC_TBA0: - tba[0] = *(uint64_t*)data; - return NoFault; - case TSDEV_PC_TBA1: - tba[1] = *(uint64_t*)data; - return NoFault; - case TSDEV_PC_TBA2: - tba[2] = *(uint64_t*)data; - return NoFault; - case TSDEV_PC_TBA3: - tba[3] = *(uint64_t*)data; - return NoFault; - case TSDEV_PC_PCTL: - pctl = *(uint64_t*)data; - return NoFault; - case TSDEV_PC_PLAT: - panic("PC_PLAT not implemented\n"); - case TSDEV_PC_RES: - panic("PC_RES not implemented\n"); - case TSDEV_PC_PERROR: - return NoFault; - case TSDEV_PC_PERRMASK: - panic("PC_PERRMASK not implemented\n"); - case TSDEV_PC_PERRSET: - panic("PC_PERRSET not implemented\n"); - case TSDEV_PC_TLBIV: - panic("PC_TLBIV not implemented\n"); - case TSDEV_PC_TLBIA: - return NoFault; // value ignored, supposted to invalidate SG TLB - case TSDEV_PC_PMONCTL: - panic("PC_PMONCTL not implemented\n"); - case TSDEV_PC_PMONCNT: - panic("PC_PMONCTN not implemented\n"); - default: - panic("Default in PChip Read reached reading 0x%x\n", daddr); - - } // uint64_t - - break; - case sizeof(uint32_t): - case sizeof(uint16_t): - case sizeof(uint8_t): - default: - panic("invalid access size(?) for tsunami register!\n\n"); - } - - DPRINTFN("Tsunami ERROR: write daddr=%#x size=%d\n", daddr, req->size); - - return NoFault; -} - -#define DMA_ADDR_MASK ULL(0x3ffffffff) - -Addr -TsunamiPChip::translatePciToDma(Addr busAddr) -{ - // compare the address to the window base registers - uint64_t tbaMask = 0; - uint64_t baMask = 0; - - uint64_t windowMask = 0; - uint64_t windowBase = 0; - - uint64_t pteEntry = 0; - - Addr pteAddr; - Addr dmaAddr; - -#if 0 - DPRINTF(IdeDisk, "Translation for bus address: %#x\n", busAddr); - for (int i = 0; i < 4; i++) { - DPRINTF(IdeDisk, "(%d) base:%#x mask:%#x\n", - i, wsba[i], wsm[i]); - - windowBase = wsba[i]; - windowMask = ~wsm[i] & (ULL(0xfff) << 20); - - if ((busAddr & windowMask) == (windowBase & windowMask)) { - DPRINTF(IdeDisk, "Would have matched %d (wb:%#x wm:%#x --> ba&wm:%#x wb&wm:%#x)\n", - i, windowBase, windowMask, (busAddr & windowMask), - (windowBase & windowMask)); - } - } -#endif - - for (int i = 0; i < 4; i++) { - - windowBase = wsba[i]; - windowMask = ~wsm[i] & (ULL(0xfff) << 20); - - if ((busAddr & windowMask) == (windowBase & windowMask)) { - - if (wsba[i] & 0x1) { // see if enabled - if (wsba[i] & 0x2) { // see if SG bit is set - /** @todo - This currently is faked by just doing a direct - read from memory, however, to be realistic, this - needs to actually do a bus transaction. The process - is explained in the tsunami documentation on page - 10-12 and basically munges the address to look up a - PTE from a table in memory and then uses that mapping - to create an address for the SG page - */ - - tbaMask = ~(((wsm[i] & (ULL(0xfff) << 20)) >> 10) | ULL(0x3ff)); - baMask = (wsm[i] & (ULL(0xfff) << 20)) | (ULL(0x7f) << 13); - pteAddr = (tba[i] & tbaMask) | ((busAddr & baMask) >> 10); - - memcpy((void *)&pteEntry, - tsunami->system-> - physmem->dma_addr(pteAddr, sizeof(uint64_t)), - sizeof(uint64_t)); - - dmaAddr = ((pteEntry & ~ULL(0x1)) << 12) | (busAddr & ULL(0x1fff)); - - } else { - baMask = (wsm[i] & (ULL(0xfff) << 20)) | ULL(0xfffff); - tbaMask = ~baMask; - dmaAddr = (tba[i] & tbaMask) | (busAddr & baMask); - } - - return (dmaAddr & DMA_ADDR_MASK); - } - } - } - - // if no match was found, then return the original address - return busAddr; -} - -void -TsunamiPChip::serialize(std::ostream &os) -{ - SERIALIZE_SCALAR(pctl); - SERIALIZE_ARRAY(wsba, 4); - SERIALIZE_ARRAY(wsm, 4); - SERIALIZE_ARRAY(tba, 4); -} - -void -TsunamiPChip::unserialize(Checkpoint *cp, const std::string §ion) -{ - UNSERIALIZE_SCALAR(pctl); - UNSERIALIZE_ARRAY(wsba, 4); - UNSERIALIZE_ARRAY(wsm, 4); - UNSERIALIZE_ARRAY(tba, 4); -} - -Tick -TsunamiPChip::cacheAccess(MemReqPtr &req) -{ - return curTick + pioLatency; -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiPChip) - - SimObjectParam<Tsunami *> tsunami; - SimObjectParam<MemoryController *> mmu; - Param<Addr> addr; - SimObjectParam<Bus*> pio_bus; - Param<Tick> pio_latency; - SimObjectParam<HierParams *> hier; - -END_DECLARE_SIM_OBJECT_PARAMS(TsunamiPChip) - -BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiPChip) - - INIT_PARAM(tsunami, "Tsunami"), - INIT_PARAM(mmu, "Memory Controller"), - INIT_PARAM(addr, "Device Address"), - INIT_PARAM_DFLT(pio_bus, "The IO Bus to attach to", NULL), - INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), - INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams) - -END_INIT_SIM_OBJECT_PARAMS(TsunamiPChip) - -CREATE_SIM_OBJECT(TsunamiPChip) -{ - return new TsunamiPChip(getInstanceName(), tsunami, addr, mmu, hier, - pio_bus, pio_latency); -} - -REGISTER_SIM_OBJECT("TsunamiPChip", TsunamiPChip) diff --git a/dev/tsunami_pchip.hh b/dev/tsunami_pchip.hh deleted file mode 100644 index c1d95431b..000000000 --- a/dev/tsunami_pchip.hh +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Tsunami PCI interface CSRs - */ - -#ifndef __TSUNAMI_PCHIP_HH__ -#define __TSUNAMI_PCHIP_HH__ - -#include "dev/tsunami.hh" -#include "base/range.hh" -#include "dev/io_device.hh" - -class MemoryController; - -/** - * A very simple implementation of the Tsunami PCI interface chips. - */ -class TsunamiPChip : public PioDevice -{ - private: - /** The base address of this device */ - Addr addr; - - /** The size of mappad from the above address */ - static const Addr size = 0xfff; - - protected: - /** - * pointer to the tsunami object. - * This is our access to all the other tsunami - * devices. - */ - Tsunami *tsunami; - - /** Pchip control register */ - uint64_t pctl; - - /** Window Base addresses */ - uint64_t wsba[4]; - - /** Window masks */ - uint64_t wsm[4]; - - /** Translated Base Addresses */ - uint64_t tba[4]; - - public: - /** - * Register the PChip with the mmu and init all wsba, wsm, and tba to 0 - * @param name the name of thes device - * @param t a pointer to the tsunami device - * @param a the address which we respond to - * @param mmu the mmu we are to register with - * @param hier object to store parameters universal the device hierarchy - * @param bus The bus that this device is attached to - */ - TsunamiPChip(const std::string &name, Tsunami *t, Addr a, - MemoryController *mmu, HierParams *hier, Bus *pio_bus, - Tick pio_latency); - - /** - * Translate a PCI bus address to a memory address for DMA. - * @todo Andrew says this needs to be fixed. What's wrong with it? - * @param busAddr PCI address to translate. - * @return memory system address - */ - Addr translatePciToDma(Addr busAddr); - - /** - * Process a read to the PChip. - * @param req Contains the address to read from. - * @param data A pointer to write the read data to. - * @return The fault condition of the access. - */ - virtual Fault read(MemReqPtr &req, uint8_t *data); - - /** - * Process a write to the PChip. - * @param req Contains the address to write to. - * @param data The data to write. - * @return The fault condition of the access. - */ - virtual Fault write(MemReqPtr &req, const uint8_t *data); - - /** - * Serialize this object to the given output stream. - * @param os The stream to serialize to. - */ - virtual void serialize(std::ostream &os); - - /** - * Reconstruct the state of this object from a checkpoint. - * @param cp The checkpoint use. - * @param section The section name of this object - */ - virtual void unserialize(Checkpoint *cp, const std::string §ion); - - /** - * Return how long this access will take. - * @param req the memory request to calcuate - * @return Tick when the request is done - */ - Tick cacheAccess(MemReqPtr &req); -}; - -#endif // __TSUNAMI_PCHIP_HH__ diff --git a/dev/tsunamireg.h b/dev/tsunamireg.h deleted file mode 100644 index a10259900..000000000 --- a/dev/tsunamireg.h +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * List of Tsunami CSRs - */ - -#ifndef __TSUNAMIREG_H__ -#define __TSUNAMIREG_H__ - -#define ALPHA_K0SEG_BASE ULL(0xfffffc0000000000) - -// CChip Registers -#define TSDEV_CC_CSR 0x00 -#define TSDEV_CC_MTR 0x01 -#define TSDEV_CC_MISC 0x02 - -#define TSDEV_CC_AAR0 0x04 -#define TSDEV_CC_AAR1 0x05 -#define TSDEV_CC_AAR2 0x06 -#define TSDEV_CC_AAR3 0x07 -#define TSDEV_CC_DIM0 0x08 -#define TSDEV_CC_DIM1 0x09 -#define TSDEV_CC_DIR0 0x0A -#define TSDEV_CC_DIR1 0x0B -#define TSDEV_CC_DRIR 0x0C -#define TSDEV_CC_PRBEN 0x0D -#define TSDEV_CC_IIC0 0x0E -#define TSDEV_CC_IIC1 0x0F -#define TSDEV_CC_MPR0 0x10 -#define TSDEV_CC_MPR1 0x11 -#define TSDEV_CC_MPR2 0x12 -#define TSDEV_CC_MPR3 0x13 - -#define TSDEV_CC_DIM2 0x18 -#define TSDEV_CC_DIM3 0x19 -#define TSDEV_CC_DIR2 0x1A -#define TSDEV_CC_DIR3 0x1B -#define TSDEV_CC_IIC2 0x1C -#define TSDEV_CC_IIC3 0x1D - -// BigTsunami Registers -#define TSDEV_CC_BDIMS 0x1000000 -#define TSDEV_CC_BDIRS 0x2000000 -#define TSDEV_CC_IPIQ 0x20 //0xf01a000800 -#define TSDEV_CC_IPIR 0x21 //0xf01a000840 -#define TSDEV_CC_ITIR 0x22 //0xf01a000880 - - -// PChip Registers -#define TSDEV_PC_WSBA0 0x00 -#define TSDEV_PC_WSBA1 0x01 -#define TSDEV_PC_WSBA2 0x02 -#define TSDEV_PC_WSBA3 0x03 -#define TSDEV_PC_WSM0 0x04 -#define TSDEV_PC_WSM1 0x05 -#define TSDEV_PC_WSM2 0x06 -#define TSDEV_PC_WSM3 0x07 -#define TSDEV_PC_TBA0 0x08 -#define TSDEV_PC_TBA1 0x09 -#define TSDEV_PC_TBA2 0x0A -#define TSDEV_PC_TBA3 0x0B -#define TSDEV_PC_PCTL 0x0C -#define TSDEV_PC_PLAT 0x0D -#define TSDEV_PC_RES 0x0E -#define TSDEV_PC_PERROR 0x0F -#define TSDEV_PC_PERRMASK 0x10 -#define TSDEV_PC_PERRSET 0x11 -#define TSDEV_PC_TLBIV 0x12 -#define TSDEV_PC_TLBIA 0x13 -#define TSDEV_PC_PMONCTL 0x14 -#define TSDEV_PC_PMONCNT 0x15 - -#define TSDEV_PC_SPST 0x20 - - -// DChip Registers -#define TSDEV_DC_DSC 0x20 -#define TSDEV_DC_STR 0x21 -#define TSDEV_DC_DREV 0x22 -#define TSDEV_DC_DSC2 0x23 - -// I/O Ports -#define TSDEV_PIC1_MASK 0x21 -#define TSDEV_PIC2_MASK 0xA1 -#define TSDEV_PIC1_ISR 0x20 -#define TSDEV_PIC2_ISR 0xA0 -#define TSDEV_PIC1_ACK 0x20 -#define TSDEV_PIC2_ACK 0xA0 -#define TSDEV_DMA1_RESET 0x0D -#define TSDEV_DMA2_RESET 0xDA -#define TSDEV_DMA1_MODE 0x0B -#define TSDEV_DMA2_MODE 0xD6 -#define TSDEV_DMA1_MASK 0x0A -#define TSDEV_DMA2_MASK 0xD4 -#define TSDEV_CTRL_PORTB 0x61 -#define TSDEV_TMR0_DATA 0x40 -#define TSDEV_TMR1_DATA 0x41 -#define TSDEV_TMR2_DATA 0x42 -#define TSDEV_TMR_CTRL 0x43 -#define TSDEV_KBD 0x64 -#define TSDEV_DMA1_CMND 0x08 -#define TSDEV_DMA1_STAT TSDEV_DMA1_CMND -#define TSDEV_DMA2_CMND 0xD0 -#define TSDEV_DMA2_STAT TSDEV_DMA2_CMND -#define TSDEV_DMA1_MMASK 0x0F -#define TSDEV_DMA2_MMASK 0xDE - -/* Added for keyboard accesses */ -#define TSDEV_KBD 0x64 - -/* Added for ATA PCI DMA */ -#define ATA_PCI_DMA 0x00 -#define ATA_PCI_DMA2 0x02 -#define ATA_PCI_DMA3 0x16 -#define ATA_PCI_DMA4 0x17 -#define ATA_PCI_DMA5 0x1a -#define ATA_PCI_DMA6 0x11 -#define ATA_PCI_DMA7 0x14 - -#define TSDEV_RTC_ADDR 0x70 -#define TSDEV_RTC_DATA 0x71 - -#define PCHIP_PCI0_MEMORY ULL(0x00000000000) -#define PCHIP_PCI0_IO ULL(0x001FC000000) -#define TSUNAMI_UNCACHABLE_BIT ULL(0x80000000000) -#define TSUNAMI_PCI0_MEMORY TSUNAMI_UNCACHABLE_BIT + PCHIP_PCI0_MEMORY -#define TSUNAMI_PCI0_IO TSUNAMI_UNCACHABLE_BIT + PCHIP_PCI0_IO - - -// UART Defines -#define UART_IER_RDI 0x01 -#define UART_IER_THRI 0x02 -#define UART_IER_RLSI 0x04 - - -#define UART_LSR_TEMT 0x40 -#define UART_LSR_THRE 0x20 -#define UART_LSR_DR 0x01 - -#define UART_MCR_LOOP 0x10 - -// System Control PortB Status Bits -#define PORTB_SPKR_HIGH 0x20 - -#endif // __TSUNAMIREG_H__ diff --git a/dev/uart.cc b/dev/uart.cc deleted file mode 100644 index b2eeb8e9f..000000000 --- a/dev/uart.cc +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Implements a 8250 UART - */ - -#include <string> -#include <vector> - -#include "base/inifile.hh" -#include "base/str.hh" // for to_number -#include "base/trace.hh" -#include "dev/simconsole.hh" -#include "dev/uart.hh" -#include "dev/platform.hh" -#include "mem/bus/bus.hh" -#include "mem/bus/pio_interface.hh" -#include "mem/bus/pio_interface_impl.hh" -#include "mem/functional/memory_control.hh" -#include "sim/builder.hh" - -using namespace std; - -Uart::Uart(const string &name, SimConsole *c, MemoryController *mmu, Addr a, - Addr s, HierParams *hier, Bus *bus, Tick pio_latency, Platform *p) - : PioDevice(name, p), addr(a), size(s), cons(c) -{ - mmu->add_child(this, RangeSize(addr, size)); - - - if (bus) { - pioInterface = newPioInterface(name, hier, bus, this, - &Uart::cacheAccess); - pioInterface->addAddrRange(RangeSize(addr, size)); - pioLatency = pio_latency * bus->clockRate; - } - - status = 0; - - // set back pointers - cons->uart = this; - platform->uart = this; -} - -Tick -Uart::cacheAccess(MemReqPtr &req) -{ - return curTick + pioLatency; -} - -DEFINE_SIM_OBJECT_CLASS_NAME("Uart", Uart) - diff --git a/dev/uart.hh b/dev/uart.hh deleted file mode 100644 index 78b1dc68e..000000000 --- a/dev/uart.hh +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** @file - * Base class for UART - */ - -#ifndef __UART_HH__ -#define __UART_HH__ - -#include "base/range.hh" -#include "dev/io_device.hh" - -class SimConsole; -class MemoryController; -class Platform; - -const int RX_INT = 0x1; -const int TX_INT = 0x2; - - -class Uart : public PioDevice -{ - - protected: - int status; - Addr addr; - Addr size; - SimConsole *cons; - - public: - Uart(const std::string &name, SimConsole *c, MemoryController *mmu, - Addr a, Addr s, HierParams *hier, Bus *bus, Tick pio_latency, - Platform *p); - - virtual Fault read(MemReqPtr &req, uint8_t *data) = 0; - virtual Fault write(MemReqPtr &req, const uint8_t *data) = 0; - - - /** - * Inform the uart that there is data available. - */ - virtual void dataAvailable() = 0; - - - /** - * Return if we have an interrupt pending - * @return interrupt status - */ - bool intStatus() { return status ? true : false; } - - /** - * Return how long this access will take. - * @param req the memory request to calcuate - * @return Tick when the request is done - */ - Tick cacheAccess(MemReqPtr &req); -}; - -#endif // __UART_HH__ diff --git a/dev/uart8250.cc b/dev/uart8250.cc deleted file mode 100644 index 65bccee86..000000000 --- a/dev/uart8250.cc +++ /dev/null @@ -1,349 +0,0 @@ -/* - * Copyright (c) 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. - */ - -/** @file - * Implements a 8250 UART - */ - -#include <string> -#include <vector> - -#include "base/inifile.hh" -#include "base/str.hh" // for to_number -#include "base/trace.hh" -#include "dev/simconsole.hh" -#include "dev/uart8250.hh" -#include "dev/platform.hh" -#include "mem/bus/bus.hh" -#include "mem/bus/pio_interface.hh" -#include "mem/bus/pio_interface_impl.hh" -#include "mem/functional/memory_control.hh" -#include "sim/builder.hh" - -using namespace std; -using namespace TheISA; - -Uart8250::IntrEvent::IntrEvent(Uart8250 *u, int bit) - : Event(&mainEventQueue), uart(u) -{ - DPRINTF(Uart, "UART Interrupt Event Initilizing\n"); - intrBit = bit; -} - -const char * -Uart8250::IntrEvent::description() -{ - return "uart interrupt delay event"; -} - -void -Uart8250::IntrEvent::process() -{ - if (intrBit & uart->IER) { - DPRINTF(Uart, "UART InterEvent, interrupting\n"); - uart->platform->postConsoleInt(); - uart->status |= intrBit; - } - else - DPRINTF(Uart, "UART InterEvent, not interrupting\n"); - -} - -/* The linux serial driver (8250.c about line 1182) loops reading from - * the device until the device reports it has no more data to - * read. After a maximum of 255 iterations the code prints "serial8250 - * too much work for irq X," and breaks out of the loop. Since the - * simulated system is so much slower than the actual system, if a - * user is typing on the keyboard it is very easy for them to provide - * input at a fast enough rate to not allow the loop to exit and thus - * the error to be printed. This magic number provides a delay between - * the time the UART receives a character to send to the simulated - * system and the time it actually notifies the system it has a - * character to send to alleviate this problem. --Ali - */ -void -Uart8250::IntrEvent::scheduleIntr() -{ - static const Tick interval = (Tick)((Clock::Float::s / 2e9) * 450); - DPRINTF(Uart, "Scheduling IER interrupt for %#x, at cycle %lld\n", intrBit, - curTick + interval); - if (!scheduled()) - schedule(curTick + interval); - else - reschedule(curTick + interval); -} - - -Uart8250::Uart8250(const string &name, SimConsole *c, MemoryController *mmu, - Addr a, Addr s, HierParams *hier, Bus *pio_bus, - Tick pio_latency, Platform *p) - : Uart(name, c, mmu, a, s, hier, pio_bus, pio_latency, p), - txIntrEvent(this, TX_INT), rxIntrEvent(this, RX_INT) -{ - IER = 0; - DLAB = 0; - LCR = 0; - MCR = 0; - -} - -Fault -Uart8250::read(MemReqPtr &req, uint8_t *data) -{ - Addr daddr = req->paddr - (addr & EV5::PAddrImplMask); - DPRINTF(Uart, " read register %#x\n", daddr); - - assert(req->size == 1); - - switch (daddr) { - case 0x0: - if (!(LCR & 0x80)) { // read byte - if (cons->dataAvailable()) - cons->in(*data); - else { - *(uint8_t*)data = 0; - // A limited amount of these are ok. - DPRINTF(Uart, "empty read of RX register\n"); - } - status &= ~RX_INT; - platform->clearConsoleInt(); - - if (cons->dataAvailable() && (IER & UART_IER_RDI)) - rxIntrEvent.scheduleIntr(); - } else { // dll divisor latch - ; - } - break; - case 0x1: - if (!(LCR & 0x80)) { // Intr Enable Register(IER) - *(uint8_t*)data = IER; - } else { // DLM divisor latch MSB - ; - } - break; - case 0x2: // Intr Identification Register (IIR) - DPRINTF(Uart, "IIR Read, status = %#x\n", (uint32_t)status); - - if (status & RX_INT) /* Rx data interrupt has a higher priority */ - *(uint8_t*)data = IIR_RXID; - else if (status & TX_INT) - *(uint8_t*)data = IIR_TXID; - else - *(uint8_t*)data = IIR_NOPEND; - - //Tx interrupts are cleared on IIR reads - status &= ~TX_INT; - break; - case 0x3: // Line Control Register (LCR) - *(uint8_t*)data = LCR; - break; - case 0x4: // Modem Control Register (MCR) - break; - case 0x5: // Line Status Register (LSR) - uint8_t lsr; - lsr = 0; - // check if there are any bytes to be read - if (cons->dataAvailable()) - lsr = UART_LSR_DR; - lsr |= UART_LSR_TEMT | UART_LSR_THRE; - *(uint8_t*)data = lsr; - break; - case 0x6: // Modem Status Register (MSR) - *(uint8_t*)data = 0; - break; - case 0x7: // Scratch Register (SCR) - *(uint8_t*)data = 0; // doesn't exist with at 8250. - break; - default: - panic("Tried to access a UART port that doesn't exist\n"); - break; - } - - return NoFault; - -} - -Fault -Uart8250::write(MemReqPtr &req, const uint8_t *data) -{ - Addr daddr = req->paddr - (addr & EV5::PAddrImplMask); - - DPRINTF(Uart, " write register %#x value %#x\n", daddr, *(uint8_t*)data); - - switch (daddr) { - case 0x0: - if (!(LCR & 0x80)) { // write byte - cons->out(*(uint8_t *)data); - platform->clearConsoleInt(); - status &= ~TX_INT; - if (UART_IER_THRI & IER) - txIntrEvent.scheduleIntr(); - } else { // dll divisor latch - ; - } - break; - case 0x1: - if (!(LCR & 0x80)) { // Intr Enable Register(IER) - IER = *(uint8_t*)data; - if (UART_IER_THRI & IER) - { - DPRINTF(Uart, "IER: IER_THRI set, scheduling TX intrrupt\n"); - txIntrEvent.scheduleIntr(); - } - else - { - DPRINTF(Uart, "IER: IER_THRI cleared, descheduling TX intrrupt\n"); - if (txIntrEvent.scheduled()) - txIntrEvent.deschedule(); - if (status & TX_INT) - platform->clearConsoleInt(); - status &= ~TX_INT; - } - - if ((UART_IER_RDI & IER) && cons->dataAvailable()) { - DPRINTF(Uart, "IER: IER_RDI set, scheduling RX intrrupt\n"); - rxIntrEvent.scheduleIntr(); - } else { - DPRINTF(Uart, "IER: IER_RDI cleared, descheduling RX intrrupt\n"); - if (rxIntrEvent.scheduled()) - rxIntrEvent.deschedule(); - if (status & RX_INT) - platform->clearConsoleInt(); - status &= ~RX_INT; - } - } else { // DLM divisor latch MSB - ; - } - break; - case 0x2: // FIFO Control Register (FCR) - break; - case 0x3: // Line Control Register (LCR) - LCR = *(uint8_t*)data; - break; - case 0x4: // Modem Control Register (MCR) - if (*(uint8_t*)data == (UART_MCR_LOOP | 0x0A)) - MCR = 0x9A; - break; - case 0x7: // Scratch Register (SCR) - // We are emulating a 8250 so we don't have a scratch reg - break; - default: - panic("Tried to access a UART port that doesn't exist\n"); - break; - } - return NoFault; -} - -void -Uart8250::dataAvailable() -{ - // if the kernel wants an interrupt when we have data - if (IER & UART_IER_RDI) - { - platform->postConsoleInt(); - status |= RX_INT; - } - -} - - - -void -Uart8250::serialize(ostream &os) -{ - SERIALIZE_SCALAR(status); - SERIALIZE_SCALAR(IER); - SERIALIZE_SCALAR(DLAB); - SERIALIZE_SCALAR(LCR); - SERIALIZE_SCALAR(MCR); - Tick rxintrwhen; - if (rxIntrEvent.scheduled()) - rxintrwhen = rxIntrEvent.when(); - else - rxintrwhen = 0; - Tick txintrwhen; - if (txIntrEvent.scheduled()) - txintrwhen = txIntrEvent.when(); - else - txintrwhen = 0; - SERIALIZE_SCALAR(rxintrwhen); - SERIALIZE_SCALAR(txintrwhen); -} - -void -Uart8250::unserialize(Checkpoint *cp, const std::string §ion) -{ - UNSERIALIZE_SCALAR(status); - UNSERIALIZE_SCALAR(IER); - UNSERIALIZE_SCALAR(DLAB); - UNSERIALIZE_SCALAR(LCR); - UNSERIALIZE_SCALAR(MCR); - Tick rxintrwhen; - Tick txintrwhen; - UNSERIALIZE_SCALAR(rxintrwhen); - UNSERIALIZE_SCALAR(txintrwhen); - if (rxintrwhen != 0) - rxIntrEvent.schedule(rxintrwhen); - if (txintrwhen != 0) - txIntrEvent.schedule(txintrwhen); -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(Uart8250) - - SimObjectParam<SimConsole *> console; - SimObjectParam<MemoryController *> mmu; - SimObjectParam<Platform *> platform; - Param<Addr> addr; - Param<Addr> size; - SimObjectParam<Bus*> pio_bus; - Param<Tick> pio_latency; - SimObjectParam<HierParams *> hier; - - -END_DECLARE_SIM_OBJECT_PARAMS(Uart8250) - -BEGIN_INIT_SIM_OBJECT_PARAMS(Uart8250) - - INIT_PARAM(console, "The console"), - INIT_PARAM(mmu, "Memory Controller"), - INIT_PARAM(platform, "Pointer to platfrom"), - INIT_PARAM(addr, "Device Address"), - INIT_PARAM_DFLT(size, "Device size", 0x8), - INIT_PARAM(pio_bus, ""), - INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), - INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams) - -END_INIT_SIM_OBJECT_PARAMS(Uart8250) - -CREATE_SIM_OBJECT(Uart8250) -{ - return new Uart8250(getInstanceName(), console, mmu, addr, size, hier, - pio_bus, pio_latency, platform); -} - -REGISTER_SIM_OBJECT("Uart8250", Uart8250) diff --git a/dev/uart8250.hh b/dev/uart8250.hh deleted file mode 100644 index 63d1da3cf..000000000 --- a/dev/uart8250.hh +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 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. - */ - -/** @file - * Defines a 8250 UART - */ - -#ifndef __TSUNAMI_UART_HH__ -#define __TSUNAMI_UART_HH__ - -#include "dev/tsunamireg.h" -#include "base/range.hh" -#include "dev/io_device.hh" -#include "dev/uart.hh" - - -/* UART8250 Interrupt ID Register - * bit 0 Interrupt Pending 0 = true, 1 = false - * bit 2:1 ID of highest priority interrupt - * bit 7:3 zeroes - */ -#define IIR_NOPEND 0x1 - -// Interrupt IDs -#define IIR_MODEM 0x00 /* Modem Status (lowest priority) */ -#define IIR_TXID 0x02 /* Tx Data */ -#define IIR_RXID 0x04 /* Rx Data */ -#define IIR_LINE 0x06 /* Rx Line Status (highest priority)*/ - -class SimConsole; -class MemoryController; -class Platform; - -class Uart8250 : public Uart -{ - - - protected: - uint8_t IER, DLAB, LCR, MCR; - - class IntrEvent : public Event - { - protected: - Uart8250 *uart; - int intrBit; - public: - IntrEvent(Uart8250 *u, int bit); - virtual void process(); - virtual const char *description(); - void scheduleIntr(); - }; - - IntrEvent txIntrEvent; - IntrEvent rxIntrEvent; - - public: - Uart8250(const std::string &name, SimConsole *c, MemoryController *mmu, - Addr a, Addr s, HierParams *hier, Bus *pio_bus, Tick pio_latency, - Platform *p); - - virtual Fault read(MemReqPtr &req, uint8_t *data); - virtual Fault write(MemReqPtr &req, const uint8_t *data); - - - /** - * Inform the uart that there is data available. - */ - virtual void dataAvailable(); - - - /** - * Return if we have an interrupt pending - * @return interrupt status - */ - virtual bool intStatus() { return status ? true : false; } - - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); - -}; - -#endif // __TSUNAMI_UART_HH__ diff --git a/docs/stl.hh b/docs/stl.hh index bf537efd4..fd9f68140 100644 --- a/docs/stl.hh +++ b/docs/stl.hh @@ -24,6 +24,9 @@ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Erik Hallnor + * Nathan Binkert */ /** diff --git a/encumbered/cpu/full/op_class.hh b/encumbered/cpu/full/op_class.hh deleted file mode 100644 index ff53b58d2..000000000 --- a/encumbered/cpu/full/op_class.hh +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __ENCUMBERED_CPU_FULL_OP_CLASS_HH__ -#define __ENCUMBERED_CPU_FULL_OP_CLASS_HH__ - -/** - * @file - * Definition of operation classes. - */ - -/** - * Instruction operation classes. These classes are used for - * assigning instructions to functional units. - */ -enum OpClass { - No_OpClass = 0, /* inst does not use a functional unit */ - IntAluOp, /* integer ALU */ - IntMultOp, /* integer multiplier */ - IntDivOp, /* integer divider */ - FloatAddOp, /* floating point adder/subtractor */ - FloatCmpOp, /* floating point comparator */ - FloatCvtOp, /* floating point<->integer converter */ - FloatMultOp, /* floating point multiplier */ - FloatDivOp, /* floating point divider */ - FloatSqrtOp, /* floating point square root */ - MemReadOp, /* memory read port */ - MemWriteOp, /* memory write port */ - IprAccessOp, /* Internal Processor Register read/write port */ - InstPrefetchOp, /* instruction prefetch port (on I-cache) */ - Num_OpClasses /* total functional unit classes */ -}; - -/** - * Array mapping OpClass enum values to strings. Defined in fu_pool.cc. - */ -extern const char *opClassStrings[]; - -#endif // __ENCUMBERED_CPU_FULL_OP_CLASS_HH__ diff --git a/ext/dnet/LICENSE b/ext/dnet/LICENSE new file mode 100644 index 000000000..95ecd51e6 --- /dev/null +++ b/ext/dnet/LICENSE @@ -0,0 +1,28 @@ + + Copyright (c) 2000-2004 Dug Song <dugsong@monkey.org> + All rights reserved, all wrongs reversed. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The names of the authors and copyright holders may not be used to + endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/ext/dnet/dnet/addr.h b/ext/dnet/dnet/addr.h new file mode 100644 index 000000000..584e3aba3 --- /dev/null +++ b/ext/dnet/dnet/addr.h @@ -0,0 +1,67 @@ +/* + * addr.h + * + * Network address operations. + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * + * $Id: addr.h,v 1.12 2003/02/27 03:44:55 dugsong Exp $ + */ + +#ifndef DNET_ADDR_H +#define DNET_ADDR_H + +#define ADDR_TYPE_NONE 0 /* No address set */ +#define ADDR_TYPE_ETH 1 /* Ethernet */ +#define ADDR_TYPE_IP 2 /* Internet Protocol v4 */ +#define ADDR_TYPE_IP6 3 /* Internet Protocol v6 */ + +struct addr { + uint16_t addr_type; + uint16_t addr_bits; + union { + eth_addr_t __eth; + ip_addr_t __ip; + ip6_addr_t __ip6; + + uint8_t __data8[16]; + uint16_t __data16[8]; + uint32_t __data32[4]; + } __addr_u; +}; +#define addr_eth __addr_u.__eth +#define addr_ip __addr_u.__ip +#define addr_ip6 __addr_u.__ip6 +#define addr_data8 __addr_u.__data8 +#define addr_data16 __addr_u.__data16 +#define addr_data32 __addr_u.__data32 + +#define addr_pack(addr, type, bits, data, len) do { \ + (addr)->addr_type = type; \ + (addr)->addr_bits = bits; \ + memmove((addr)->addr_data8, (char *)data, len); \ +} while (0) + +__BEGIN_DECLS +int addr_cmp(const struct addr *a, const struct addr *b); + +int addr_bcast(const struct addr *a, struct addr *b); +int addr_net(const struct addr *a, struct addr *b); + +char *addr_ntop(const struct addr *src, char *dst, size_t size); +int addr_pton(const char *src, struct addr *dst); + +char *addr_ntoa(const struct addr *a); +#define addr_aton addr_pton + +int addr_ntos(const struct addr *a, struct sockaddr *sa); +int addr_ston(const struct sockaddr *sa, struct addr *a); + +int addr_btos(uint16_t bits, struct sockaddr *sa); +int addr_stob(const struct sockaddr *sa, uint16_t *bits); + +int addr_btom(uint16_t bits, void *mask, size_t size); +int addr_mtob(const void *mask, size_t size, uint16_t *bits); +__END_DECLS + +#endif /* DNET_ADDR_H */ diff --git a/ext/dnet/dnet/arp.h b/ext/dnet/dnet/arp.h new file mode 100644 index 000000000..d3c162410 --- /dev/null +++ b/ext/dnet/dnet/arp.h @@ -0,0 +1,103 @@ +/* + * arp.h + * + * Address Resolution Protocol. + * RFC 826 + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * + * $Id: arp.h,v 1.12 2003/03/16 17:39:17 dugsong Exp $ + */ + +#ifndef DNET_ARP_H +#define DNET_ARP_H + +#define ARP_HDR_LEN 8 /* base ARP header length */ +#define ARP_ETHIP_LEN 20 /* base ARP message length */ + +#ifndef __GNUC__ +# define __attribute__(x) +# pragma pack(1) +#endif + +/* + * ARP header + */ +struct arp_hdr { + uint16_t ar_hrd; /* format of hardware address */ + uint16_t ar_pro; /* format of protocol address */ + uint8_t ar_hln; /* length of hardware address (ETH_ADDR_LEN) */ + uint8_t ar_pln; /* length of protocol address (IP_ADDR_LEN) */ + uint16_t ar_op; /* operation */ +}; + +/* + * Hardware address format + */ +#define ARP_HRD_ETH 0x0001 /* ethernet hardware */ +#define ARP_HRD_IEEE802 0x0006 /* IEEE 802 hardware */ + +/* + * Protocol address format + */ +#define ARP_PRO_IP 0x0800 /* IP protocol */ + +/* + * ARP operation + */ +#define ARP_OP_REQUEST 1 /* request to resolve ha given pa */ +#define ARP_OP_REPLY 2 /* response giving hardware address */ +#define ARP_OP_REVREQUEST 3 /* request to resolve pa given ha */ +#define ARP_OP_REVREPLY 4 /* response giving protocol address */ + +/* + * Ethernet/IP ARP message + */ +struct arp_ethip { + uint8_t ar_sha[ETH_ADDR_LEN]; /* sender hardware address */ + uint8_t ar_spa[IP_ADDR_LEN]; /* sender protocol address */ + uint8_t ar_tha[ETH_ADDR_LEN]; /* target hardware address */ + uint8_t ar_tpa[IP_ADDR_LEN]; /* target protocol address */ +}; + +/* + * ARP cache entry + */ +struct arp_entry { + struct addr arp_pa; /* protocol address */ + struct addr arp_ha; /* hardware address */ +}; + +#ifndef __GNUC__ +# pragma pack() +#endif + +#define arp_pack_hdr_ethip(hdr, op, sha, spa, tha, tpa) do { \ + struct arp_hdr *pack_arp_p = (struct arp_hdr *)(hdr); \ + struct arp_ethip *pack_ethip_p = (struct arp_ethip *) \ + ((uint8_t *)(hdr) + ARP_HDR_LEN); \ + pack_arp_p->ar_hrd = htons(ARP_HRD_ETH); \ + pack_arp_p->ar_pro = htons(ARP_PRO_IP); \ + pack_arp_p->ar_hln = ETH_ADDR_LEN; \ + pack_arp_p->ar_pln = IP_ADDR_LEN; \ + pack_arp_p->ar_op = htons(op); \ + memmove(pack_ethip_p->ar_sha, &(sha), ETH_ADDR_LEN); \ + memmove(pack_ethip_p->ar_spa, &(spa), IP_ADDR_LEN); \ + memmove(pack_ethip_p->ar_tha, &(tha), ETH_ADDR_LEN); \ + memmove(pack_ethip_p->ar_tpa, &(tpa), IP_ADDR_LEN); \ +} while (0) + +typedef struct arp_handle arp_t; + +typedef int (*arp_handler)(const struct arp_entry *entry, void *arg); + +__BEGIN_DECLS +arp_t *arp_open(void); +int arp_add(arp_t *arp, const struct arp_entry *entry); +int arp_delete(arp_t *arp, const struct arp_entry *entry); +int arp_get(arp_t *arp, struct arp_entry *entry); +int arp_loop(arp_t *arp, arp_handler callback, void *arg); +arp_t *arp_close(arp_t *arp); +__END_DECLS + +#endif /* DNET_ARP_H */ diff --git a/ext/dnet/dnet/blob.h b/ext/dnet/dnet/blob.h new file mode 100644 index 000000000..a3be7897d --- /dev/null +++ b/ext/dnet/dnet/blob.h @@ -0,0 +1,56 @@ +/* + * blob.h + * + * Binary blob handling. + * + * Copyright (c) 2002 Dug Song <dugsong@monkey.org> + * + * $Id: blob.h,v 1.2 2002/04/05 03:06:44 dugsong Exp $ + */ + +#ifndef DNET_BLOB_H +#define DNET_BLOB_H + +typedef struct blob { + u_char *base; /* start of data */ + int off; /* offset into data */ + int end; /* end of data */ + int size; /* size of allocation */ +} blob_t; + +__BEGIN_DECLS +blob_t *blob_new(void); + +int blob_read(blob_t *b, void *buf, int len); +int blob_write(blob_t *b, const void *buf, int len); + +int blob_seek(blob_t *b, int off, int whence); +#define blob_skip(b, l) blob_seek(b, l, SEEK_CUR) +#define blob_rewind(b) blob_seek(b, 0, SEEK_SET) + +#define blob_offset(b) ((b)->off) +#define blob_left(b) ((b)->end - (b)->off) + +int blob_index(blob_t *b, const void *buf, int len); +int blob_rindex(blob_t *b, const void *buf, int len); + +int blob_pack(blob_t *b, const char *fmt, ...); +int blob_unpack(blob_t *b, const char *fmt, ...); + +int blob_insert(blob_t *b, const void *buf, int len); +int blob_delete(blob_t *b, void *buf, int len); + +int blob_print(blob_t *b, char *style, int len); + +blob_t *blob_free(blob_t *b); + +int blob_register_alloc(size_t size, void *(*bmalloc)(size_t), + void (*bfree)(void *), void *(*brealloc)(void *, size_t)); +#ifdef va_start +typedef int (*blob_fmt_cb)(int pack, int len, blob_t *b, va_list *arg); + +int blob_register_pack(char c, blob_fmt_cb fmt_cb); +#endif +__END_DECLS + +#endif /* DNET_BLOB_H */ diff --git a/ext/dnet/dnet/eth.h b/ext/dnet/dnet/eth.h new file mode 100644 index 000000000..da3033066 --- /dev/null +++ b/ext/dnet/dnet/eth.h @@ -0,0 +1,77 @@ +/* + * eth.h + * + * Ethernet. + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * + * $Id: eth.h,v 1.15 2004/01/03 08:47:23 dugsong Exp $ + */ + +#ifndef DNET_ETH_H +#define DNET_ETH_H + +#define ETH_ADDR_LEN 6 +#define ETH_ADDR_BITS 48 +#define ETH_TYPE_LEN 2 +#define ETH_CRC_LEN 4 +#define ETH_HDR_LEN 14 + +#define ETH_LEN_MIN 64 /* minimum frame length with CRC */ +#define ETH_LEN_MAX 1518 /* maximum frame length with CRC */ + +#define ETH_MTU (ETH_LEN_MAX - ETH_HDR_LEN - ETH_CRC_LEN) +#define ETH_MIN (ETH_LEN_MIN - ETH_HDR_LEN - ETH_CRC_LEN) + +typedef struct eth_addr { + uint8_t data[ETH_ADDR_LEN]; +} eth_addr_t; + +struct eth_hdr { + eth_addr_t eth_dst; /* destination address */ + eth_addr_t eth_src; /* source address */ + uint16_t eth_type; /* payload type */ +}; + +/* + * Ethernet payload types - http://standards.ieee.org/regauth/ethertype + */ +#define ETH_TYPE_PUP 0x0200 /* PUP protocol */ +#define ETH_TYPE_IP 0x0800 /* IP protocol */ +#define ETH_TYPE_ARP 0x0806 /* address resolution protocol */ +#define ETH_TYPE_REVARP 0x8035 /* reverse addr resolution protocol */ +#define ETH_TYPE_8021Q 0x8100 /* IEEE 802.1Q VLAN tagging */ +#define ETH_TYPE_IPV6 0x86DD /* IPv6 protocol */ +#define ETH_TYPE_MPLS 0x8847 /* MPLS */ +#define ETH_TYPE_MPLS_MCAST 0x8848 /* MPLS Multicast */ +#define ETH_TYPE_PPPOEDISC 0x8863 /* PPP Over Ethernet Discovery Stage */ +#define ETH_TYPE_PPPOE 0x8864 /* PPP Over Ethernet Session Stage */ +#define ETH_TYPE_LOOPBACK 0x9000 /* used to test interfaces */ + +#define ETH_IS_MULTICAST(ea) (*(ea) & 0x01) /* is address mcast/bcast? */ + +#define ETH_ADDR_BROADCAST "\xff\xff\xff\xff\xff\xff" + +#define eth_pack_hdr(h, dst, src, type) do { \ + struct eth_hdr *eth_pack_p = (struct eth_hdr *)(h); \ + memmove(ð_pack_p->eth_dst, &(dst), ETH_ADDR_LEN); \ + memmove(ð_pack_p->eth_src, &(src), ETH_ADDR_LEN); \ + eth_pack_p->eth_type = htons(type); \ +} while (0) + +typedef struct eth_handle eth_t; + +__BEGIN_DECLS +eth_t *eth_open(const char *device); +int eth_get(eth_t *e, eth_addr_t *ea); +int eth_set(eth_t *e, const eth_addr_t *ea); +size_t eth_send(eth_t *e, const void *buf, size_t len); +eth_t *eth_close(eth_t *e); + +char *eth_ntop(const eth_addr_t *eth, char *dst, size_t len); +int eth_pton(const char *src, eth_addr_t *dst); +char *eth_ntoa(const eth_addr_t *eth); +#define eth_aton eth_pton +__END_DECLS + +#endif /* DNET_ETH_H */ diff --git a/ext/dnet/dnet/fw.h b/ext/dnet/dnet/fw.h new file mode 100644 index 000000000..ebda8e7eb --- /dev/null +++ b/ext/dnet/dnet/fw.h @@ -0,0 +1,54 @@ +/* + * fw.h + * + * Network firewalling operations. + * + * Copyright (c) 2001 Dug Song <dugsong@monkey.org> + * + * $Id: fw.h,v 1.13 2002/12/14 04:02:36 dugsong Exp $ + */ + +#ifndef DNET_FW_H +#define DNET_FW_H + +struct fw_rule { + char fw_device[INTF_NAME_LEN]; /* interface name */ + uint8_t fw_op; /* operation */ + uint8_t fw_dir; /* direction */ + uint8_t fw_proto; /* IP protocol */ + struct addr fw_src; /* src address / net */ + struct addr fw_dst; /* dst address / net */ + uint16_t fw_sport[2]; /* range / ICMP type */ + uint16_t fw_dport[2]; /* range / ICMP code */ +}; + +#define FW_OP_ALLOW 1 +#define FW_OP_BLOCK 2 + +#define FW_DIR_IN 1 +#define FW_DIR_OUT 2 + +#define fw_pack_rule(rule, dev, op, dir, p, s, d, sp1, sp2, dp1, dp2) \ +do { \ + strlcpy((rule)->fw_device, dev, sizeof((rule)->fw_device)); \ + (rule)->fw_op = op; (rule)->fw_dir = dir; \ + (rule)->fw_proto = p; \ + memmove(&(rule)->fw_src, &(s), sizeof((rule)->fw_src)); \ + memmove(&(rule)->fw_dst, &(d), sizeof((rule)->fw_dst)); \ + (rule)->fw_sport[0] = sp1; (rule)->fw_sport[1] = sp2; \ + (rule)->fw_dport[0] = dp1; (rule)->fw_dport[1] = dp2; \ +} while (0) + +typedef struct fw_handle fw_t; + +typedef int (*fw_handler)(const struct fw_rule *rule, void *arg); + +__BEGIN_DECLS +fw_t *fw_open(void); +int fw_add(fw_t *f, const struct fw_rule *rule); +int fw_delete(fw_t *f, const struct fw_rule *rule); +int fw_loop(fw_t *f, fw_handler callback, void *arg); +fw_t *fw_close(fw_t *f); +__END_DECLS + +#endif /* DNET_FW_H */ diff --git a/ext/dnet/dnet/icmp.h b/ext/dnet/dnet/icmp.h new file mode 100644 index 000000000..e997d5887 --- /dev/null +++ b/ext/dnet/dnet/icmp.h @@ -0,0 +1,265 @@ +/* + * icmp.h + * + * Internet Control Message Protocol. + * RFC 792, 950, 1256, 1393, 1475, 2002, 2521 + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * + * $Id: icmp.h,v 1.14 2003/03/16 17:39:17 dugsong Exp $ + */ + +#ifndef DNET_ICMP_H +#define DNET_ICMP_H + +#define ICMP_HDR_LEN 4 /* base ICMP header length */ +#define ICMP_LEN_MIN 8 /* minimum ICMP message size, with header */ + +#ifndef __GNUC__ +# define __attribute__(x) +# pragma pack(1) +#endif + +/* + * ICMP header + */ +struct icmp_hdr { + uint8_t icmp_type; /* type of message, see below */ + uint8_t icmp_code; /* type sub code */ + uint16_t icmp_cksum; /* ones complement cksum of struct */ +}; + +/* + * Types (icmp_type) and codes (icmp_code) - + * http://www.iana.org/assignments/icmp-parameters + */ +#define ICMP_CODE_NONE 0 /* for types without codes */ +#define ICMP_ECHOREPLY 0 /* echo reply */ +#define ICMP_UNREACH 3 /* dest unreachable, codes: */ +#define ICMP_UNREACH_NET 0 /* bad net */ +#define ICMP_UNREACH_HOST 1 /* bad host */ +#define ICMP_UNREACH_PROTO 2 /* bad protocol */ +#define ICMP_UNREACH_PORT 3 /* bad port */ +#define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */ +#define ICMP_UNREACH_SRCFAIL 5 /* src route failed */ +#define ICMP_UNREACH_NET_UNKNOWN 6 /* unknown net */ +#define ICMP_UNREACH_HOST_UNKNOWN 7 /* unknown host */ +#define ICMP_UNREACH_ISOLATED 8 /* src host isolated */ +#define ICMP_UNREACH_NET_PROHIB 9 /* for crypto devs */ +#define ICMP_UNREACH_HOST_PROHIB 10 /* ditto */ +#define ICMP_UNREACH_TOSNET 11 /* bad tos for net */ +#define ICMP_UNREACH_TOSHOST 12 /* bad tos for host */ +#define ICMP_UNREACH_FILTER_PROHIB 13 /* prohibited access */ +#define ICMP_UNREACH_HOST_PRECEDENCE 14 /* precedence error */ +#define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 /* precedence cutoff */ +#define ICMP_SRCQUENCH 4 /* packet lost, slow down */ +#define ICMP_REDIRECT 5 /* shorter route, codes: */ +#define ICMP_REDIRECT_NET 0 /* for network */ +#define ICMP_REDIRECT_HOST 1 /* for host */ +#define ICMP_REDIRECT_TOSNET 2 /* for tos and net */ +#define ICMP_REDIRECT_TOSHOST 3 /* for tos and host */ +#define ICMP_ALTHOSTADDR 6 /* alternate host address */ +#define ICMP_ECHO 8 /* echo service */ +#define ICMP_RTRADVERT 9 /* router advertise, codes: */ +#define ICMP_RTRADVERT_NORMAL 0 /* normal */ +#define ICMP_RTRADVERT_NOROUTE_COMMON 16 /* selective routing */ +#define ICMP_RTRSOLICIT 10 /* router solicitation */ +#define ICMP_TIMEXCEED 11 /* time exceeded, code: */ +#define ICMP_TIMEXCEED_INTRANS 0 /* ttl==0 in transit */ +#define ICMP_TIMEXCEED_REASS 1 /* ttl==0 in reass */ +#define ICMP_PARAMPROB 12 /* ip header bad */ +#define ICMP_PARAMPROB_ERRATPTR 0 /* req. opt. absent */ +#define ICMP_PARAMPROB_OPTABSENT 1 /* req. opt. absent */ +#define ICMP_PARAMPROB_LENGTH 2 /* bad length */ +#define ICMP_TSTAMP 13 /* timestamp request */ +#define ICMP_TSTAMPREPLY 14 /* timestamp reply */ +#define ICMP_INFO 15 /* information request */ +#define ICMP_INFOREPLY 16 /* information reply */ +#define ICMP_MASK 17 /* address mask request */ +#define ICMP_MASKREPLY 18 /* address mask reply */ +#define ICMP_TRACEROUTE 30 /* traceroute */ +#define ICMP_DATACONVERR 31 /* data conversion error */ +#define ICMP_MOBILE_REDIRECT 32 /* mobile host redirect */ +#define ICMP_IPV6_WHEREAREYOU 33 /* IPv6 where-are-you */ +#define ICMP_IPV6_IAMHERE 34 /* IPv6 i-am-here */ +#define ICMP_MOBILE_REG 35 /* mobile registration req */ +#define ICMP_MOBILE_REGREPLY 36 /* mobile registration reply */ +#define ICMP_DNS 37 /* domain name request */ +#define ICMP_DNSREPLY 38 /* domain name reply */ +#define ICMP_SKIP 39 /* SKIP */ +#define ICMP_PHOTURIS 40 /* Photuris */ +#define ICMP_PHOTURIS_UNKNOWN_INDEX 0 /* unknown sec index */ +#define ICMP_PHOTURIS_AUTH_FAILED 1 /* auth failed */ +#define ICMP_PHOTURIS_DECOMPRESS_FAILED 2 /* decompress failed */ +#define ICMP_PHOTURIS_DECRYPT_FAILED 3 /* decrypt failed */ +#define ICMP_PHOTURIS_NEED_AUTHN 4 /* no authentication */ +#define ICMP_PHOTURIS_NEED_AUTHZ 5 /* no authorization */ +#define ICMP_TYPE_MAX 40 + +#define ICMP_INFOTYPE(type) \ + ((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \ + (type) == ICMP_RTRADVERT || (type) == ICMP_RTRSOLICIT || \ + (type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \ + (type) == ICMP_INFO || (type) == ICMP_INFOREPLY || \ + (type) == ICMP_MASK || (type) == ICMP_MASKREPLY) + +/* + * Echo message data + */ +struct icmp_msg_echo { + uint16_t icmp_id; + uint16_t icmp_seq; + uint8_t icmp_data __flexarr; /* optional data */ +}; + +/* + * Fragmentation-needed (unreachable) message data + */ +struct icmp_msg_needfrag { + uint16_t icmp_void; /* must be zero */ + uint16_t icmp_mtu; /* MTU of next-hop network */ + uint8_t icmp_ip __flexarr; /* IP hdr + 8 bytes of pkt */ +}; + +/* + * Unreachable, source quench, redirect, time exceeded, + * parameter problem message data + */ +struct icmp_msg_quote { + uint32_t icmp_void; /* must be zero */ +#define icmp_gwaddr icmp_void /* router IP address to use */ +#define icmp_pptr icmp_void /* ptr to bad octet field */ + uint8_t icmp_ip __flexarr; /* IP hdr + 8 bytes of pkt */ +}; + +/* + * Router advertisement message data, RFC 1256 + */ +struct icmp_msg_rtradvert { + uint8_t icmp_num_addrs; /* # of address / pref pairs */ + uint8_t icmp_wpa; /* words / address == 2 */ + uint16_t icmp_lifetime; /* route lifetime in seconds */ + struct icmp_msg_rtr_data { + uint32_t icmp_void; +#define icmp_gwaddr icmp_void /* router IP address */ + uint32_t icmp_pref; /* router preference (usu 0) */ + } icmp_rtr __flexarr; /* variable # of routers */ +}; +#define ICMP_RTR_PREF_NODEFAULT 0x80000000 /* do not use as default gw */ + +/* + * Timestamp message data + */ +struct icmp_msg_tstamp { + uint32_t icmp_id; /* identifier */ + uint32_t icmp_seq; /* sequence number */ + uint32_t icmp_ts_orig; /* originate timestamp */ + uint32_t icmp_ts_rx; /* receive timestamp */ + uint32_t icmp_ts_tx; /* transmit timestamp */ +}; + +/* + * Address mask message data, RFC 950 + */ +struct icmp_msg_mask { + uint32_t icmp_id; /* identifier */ + uint32_t icmp_seq; /* sequence number */ + uint32_t icmp_mask; /* address mask */ +}; + +/* + * Traceroute message data, RFC 1393, RFC 1812 + */ +struct icmp_msg_traceroute { + uint16_t icmp_id; /* identifier */ + uint16_t icmp_void; /* unused */ + uint16_t icmp_ohc; /* outbound hop count */ + uint16_t icmp_rhc; /* return hop count */ + uint32_t icmp_speed; /* link speed, bytes/sec */ + uint32_t icmp_mtu; /* MTU in bytes */ +}; + +/* + * Domain name reply message data, RFC 1788 + */ +struct icmp_msg_dnsreply { + uint16_t icmp_id; /* identifier */ + uint16_t icmp_seq; /* sequence number */ + uint32_t icmp_ttl; /* time-to-live */ + uint8_t icmp_names __flexarr; /* variable number of names */ +}; + +/* + * Generic identifier, sequence number data + */ +struct icmp_msg_idseq { + uint16_t icmp_id; + uint16_t icmp_seq; +}; + +/* + * ICMP message union + */ +union icmp_msg { + struct icmp_msg_echo echo; /* ICMP_ECHO{REPLY} */ + struct icmp_msg_quote unreach; /* ICMP_UNREACH */ + struct icmp_msg_needfrag needfrag; /* ICMP_UNREACH_NEEDFRAG */ + struct icmp_msg_quote srcquench; /* ICMP_SRCQUENCH */ + struct icmp_msg_quote redirect; /* ICMP_REDIRECT (set to 0) */ + uint32_t rtrsolicit; /* ICMP_RTRSOLICIT */ + struct icmp_msg_rtradvert rtradvert; /* ICMP_RTRADVERT */ + struct icmp_msg_quote timexceed; /* ICMP_TIMEXCEED */ + struct icmp_msg_quote paramprob; /* ICMP_PARAMPROB */ + struct icmp_msg_tstamp tstamp; /* ICMP_TSTAMP{REPLY} */ + struct icmp_msg_idseq info; /* ICMP_INFO{REPLY} */ + struct icmp_msg_mask mask; /* ICMP_MASK{REPLY} */ + struct icmp_msg_traceroute traceroute; /* ICMP_TRACEROUTE */ + struct icmp_msg_idseq dns; /* ICMP_DNS */ + struct icmp_msg_dnsreply dnsreply; /* ICMP_DNSREPLY */ +}; + +#ifndef __GNUC__ +# pragma pack() +#endif + +#define icmp_pack_hdr(hdr, type, code) do { \ + struct icmp_hdr *icmp_pack_p = (struct icmp_hdr *)(hdr); \ + icmp_pack_p->icmp_type = type; icmp_pack_p->icmp_code = code; \ +} while (0) + +#define icmp_pack_hdr_echo(hdr, type, code, id, seq, data, len) do { \ + struct icmp_msg_echo *echo_pack_p = (struct icmp_msg_echo *) \ + ((uint8_t *)(hdr) + ICMP_HDR_LEN); \ + icmp_pack_hdr(hdr, type, code); \ + echo_pack_p->icmp_id = htons(id); \ + echo_pack_p->icmp_seq = htons(seq); \ + memmove(echo_pack_p->icmp_data, data, len); \ +} while (0) + +#define icmp_pack_hdr_quote(hdr, type, code, word, pkt, len) do { \ + struct icmp_msg_quote *quote_pack_p = (struct icmp_msg_quote *) \ + ((uint8_t *)(hdr) + ICMP_HDR_LEN); \ + icmp_pack_hdr(hdr, type, code); \ + quote_pack_p->icmp_void = htonl(word); \ + memmove(quote_pack_p->icmp_ip, pkt, len); \ +} while (0) + +#define icmp_pack_hdr_mask(hdr, type, code, id, seq, mask) do { \ + struct icmp_msg_mask *mask_pack_p = (struct icmp_msg_mask *) \ + ((uint8_t *)(hdr) + ICMP_HDR_LEN); \ + icmp_pack_hdr(hdr, type, code); \ + mask_pack_p->icmp_id = htons(id); \ + mask_pack_p->icmp_seq = htons(seq); \ + mask_pack_p->icmp_mask = htonl(mask); \ +} while (0) + +#define icmp_pack_hdr_needfrag(hdr, type, code, mtu, pkt, len) do { \ + struct icmp_msg_needfrag *frag_pack_p = \ + (struct icmp_msg_needfrag *)((uint8_t *)(hdr) + ICMP_HDR_LEN); \ + icmp_pack_hdr(hdr, type, code); \ + frag_pack_p->icmp_void = 0; \ + frag_pack_p->icmp_mtu = htons(mtu); \ + memmove(frag_pack_p->icmp_ip, pkt, len); \ +} while (0) + +#endif /* DNET_ICMP_H */ diff --git a/ext/dnet/dnet/intf.h b/ext/dnet/dnet/intf.h new file mode 100644 index 000000000..38acd4356 --- /dev/null +++ b/ext/dnet/dnet/intf.h @@ -0,0 +1,68 @@ +/* + * intf.c + * + * Network interface operations. + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * + * $Id: intf.h,v 1.16 2004/01/13 07:41:09 dugsong Exp $ + */ + +#ifndef DNET_INTF_H +#define DNET_INTF_H + +/* + * Interface entry + */ +#define INTF_NAME_LEN 16 + +struct intf_entry { + u_int intf_len; /* length of entry */ + char intf_name[INTF_NAME_LEN]; /* interface name */ + u_short intf_type; /* interface type (r/o) */ + u_short intf_flags; /* interface flags */ + u_int intf_mtu; /* interface MTU */ + struct addr intf_addr; /* interface address */ + struct addr intf_dst_addr; /* point-to-point dst */ + struct addr intf_link_addr; /* link-layer address */ + u_int intf_alias_num; /* number of aliases */ + struct addr intf_alias_addrs __flexarr; /* array of aliases */ +}; + +/* + * MIB-II interface types - http://www.iana.org/assignments/ianaiftype-mib + */ +#define INTF_TYPE_OTHER 1 /* other */ +#define INTF_TYPE_ETH 6 /* Ethernet */ +#define INTF_TYPE_TOKENRING 9 /* Token Ring */ +#define INTF_TYPE_FDDI 15 /* FDDI */ +#define INTF_TYPE_PPP 23 /* Point-to-Point Protocol */ +#define INTF_TYPE_LOOPBACK 24 /* software loopback */ +#define INTF_TYPE_SLIP 28 /* Serial Line Interface Protocol */ +#define INTF_TYPE_TUN 53 /* proprietary virtual/internal */ + +/* + * Interface flags + */ +#define INTF_FLAG_UP 0x01 /* enable interface */ +#define INTF_FLAG_LOOPBACK 0x02 /* is a loopback net (r/o) */ +#define INTF_FLAG_POINTOPOINT 0x04 /* point-to-point link (r/o) */ +#define INTF_FLAG_NOARP 0x08 /* disable ARP */ +#define INTF_FLAG_BROADCAST 0x10 /* supports broadcast (r/o) */ +#define INTF_FLAG_MULTICAST 0x20 /* supports multicast (r/o) */ + +typedef struct intf_handle intf_t; + +typedef int (*intf_handler)(const struct intf_entry *entry, void *arg); + +__BEGIN_DECLS +intf_t *intf_open(void); +int intf_get(intf_t *i, struct intf_entry *entry); +int intf_get_src(intf_t *i, struct intf_entry *entry, struct addr *src); +int intf_get_dst(intf_t *i, struct intf_entry *entry, struct addr *dst); +int intf_set(intf_t *i, const struct intf_entry *entry); +int intf_loop(intf_t *i, intf_handler callback, void *arg); +intf_t *intf_close(intf_t *i); +__END_DECLS + +#endif /* DNET_INTF_H */ diff --git a/ext/dnet/dnet/ip.h b/ext/dnet/dnet/ip.h new file mode 100644 index 000000000..95b7718fb --- /dev/null +++ b/ext/dnet/dnet/ip.h @@ -0,0 +1,487 @@ +/* + * ip.h + * + * Internet Protocol (RFC 791). + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * + * $Id: ip.h,v 1.23 2003/03/16 17:39:17 dugsong Exp $ + */ + +#ifndef DNET_IP_H +#define DNET_IP_H + +#define IP_ADDR_LEN 4 /* IP address length */ +#define IP_ADDR_BITS 32 /* IP address bits */ + +#define IP_HDR_LEN 20 /* base IP header length */ +#define IP_OPT_LEN 2 /* base IP option length */ +#define IP_OPT_LEN_MAX 40 +#define IP_HDR_LEN_MAX (IP_HDR_LEN + IP_OPT_LEN_MAX) + +#define IP_LEN_MAX 65535 +#define IP_LEN_MIN IP_HDR_LEN + +typedef uint32_t ip_addr_t; + +#ifndef __GNUC__ +# define __attribute__(x) +# pragma pack(1) +#endif + +/* + * IP header, without options + */ +struct ip_hdr { +#if DNET_BYTESEX == DNET_BIG_ENDIAN + uint8_t ip_v:4, /* version */ + ip_hl:4; /* header length (incl any options) */ +#elif DNET_BYTESEX == DNET_LIL_ENDIAN + uint8_t ip_hl:4, + ip_v:4; +#else +# error "need to include <dnet.h>" +#endif + uint8_t ip_tos; /* type of service */ + uint16_t ip_len; /* total length (incl header) */ + uint16_t ip_id; /* identification */ + uint16_t ip_off; /* fragment offset and flags */ + uint8_t ip_ttl; /* time to live */ + uint8_t ip_p; /* protocol */ + uint16_t ip_sum; /* checksum */ + ip_addr_t ip_src; /* source address */ + ip_addr_t ip_dst; /* destination address */ +}; + +/* + * Type of service (ip_tos), RFC 1349 ("obsoleted by RFC 2474") + */ +#define IP_TOS_DEFAULT 0x00 /* default */ +#define IP_TOS_LOWDELAY 0x10 /* low delay */ +#define IP_TOS_THROUGHPUT 0x08 /* high throughput */ +#define IP_TOS_RELIABILITY 0x04 /* high reliability */ +#define IP_TOS_LOWCOST 0x02 /* low monetary cost - XXX */ +#define IP_TOS_ECT 0x02 /* ECN-capable transport */ +#define IP_TOS_CE 0x01 /* congestion experienced */ + +/* + * IP precedence (high 3 bits of ip_tos), hopefully unused + */ +#define IP_TOS_PREC_ROUTINE 0x00 +#define IP_TOS_PREC_PRIORITY 0x20 +#define IP_TOS_PREC_IMMEDIATE 0x40 +#define IP_TOS_PREC_FLASH 0x60 +#define IP_TOS_PREC_FLASHOVERRIDE 0x80 +#define IP_TOS_PREC_CRITIC_ECP 0xa0 +#define IP_TOS_PREC_INTERNETCONTROL 0xc0 +#define IP_TOS_PREC_NETCONTROL 0xe0 + +/* + * Fragmentation flags (ip_off) + */ +#define IP_RF 0x8000 /* reserved */ +#define IP_DF 0x4000 /* don't fragment */ +#define IP_MF 0x2000 /* more fragments (not last frag) */ +#define IP_OFFMASK 0x1fff /* mask for fragment offset */ + +/* + * Time-to-live (ip_ttl), seconds + */ +#define IP_TTL_DEFAULT 64 /* default ttl, RFC 1122, RFC 1340 */ +#define IP_TTL_MAX 255 /* maximum ttl */ + +/* + * Protocol (ip_p) - http://www.iana.org/assignments/protocol-numbers + */ +#define IP_PROTO_IP 0 /* dummy for IP */ +#define IP_PROTO_HOPOPTS IP_PROTO_IP /* IPv6 hop-by-hop options */ +#define IP_PROTO_ICMP 1 /* ICMP */ +#define IP_PROTO_IGMP 2 /* IGMP */ +#define IP_PROTO_GGP 3 /* gateway-gateway protocol */ +#define IP_PROTO_IPIP 4 /* IP in IP */ +#define IP_PROTO_ST 5 /* ST datagram mode */ +#define IP_PROTO_TCP 6 /* TCP */ +#define IP_PROTO_CBT 7 /* CBT */ +#define IP_PROTO_EGP 8 /* exterior gateway protocol */ +#define IP_PROTO_IGP 9 /* interior gateway protocol */ +#define IP_PROTO_BBNRCC 10 /* BBN RCC monitoring */ +#define IP_PROTO_NVP 11 /* Network Voice Protocol */ +#define IP_PROTO_PUP 12 /* PARC universal packet */ +#define IP_PROTO_ARGUS 13 /* ARGUS */ +#define IP_PROTO_EMCON 14 /* EMCON */ +#define IP_PROTO_XNET 15 /* Cross Net Debugger */ +#define IP_PROTO_CHAOS 16 /* Chaos */ +#define IP_PROTO_UDP 17 /* UDP */ +#define IP_PROTO_MUX 18 /* multiplexing */ +#define IP_PROTO_DCNMEAS 19 /* DCN measurement */ +#define IP_PROTO_HMP 20 /* Host Monitoring Protocol */ +#define IP_PROTO_PRM 21 /* Packet Radio Measurement */ +#define IP_PROTO_IDP 22 /* Xerox NS IDP */ +#define IP_PROTO_TRUNK1 23 /* Trunk-1 */ +#define IP_PROTO_TRUNK2 24 /* Trunk-2 */ +#define IP_PROTO_LEAF1 25 /* Leaf-1 */ +#define IP_PROTO_LEAF2 26 /* Leaf-2 */ +#define IP_PROTO_RDP 27 /* "Reliable Datagram" proto */ +#define IP_PROTO_IRTP 28 /* Inet Reliable Transaction */ +#define IP_PROTO_TP 29 /* ISO TP class 4 */ +#define IP_PROTO_NETBLT 30 /* Bulk Data Transfer */ +#define IP_PROTO_MFPNSP 31 /* MFE Network Services */ +#define IP_PROTO_MERITINP 32 /* Merit Internodal Protocol */ +#define IP_PROTO_SEP 33 /* Sequential Exchange proto */ +#define IP_PROTO_3PC 34 /* Third Party Connect proto */ +#define IP_PROTO_IDPR 35 /* Interdomain Policy Route */ +#define IP_PROTO_XTP 36 /* Xpress Transfer Protocol */ +#define IP_PROTO_DDP 37 /* Datagram Delivery Proto */ +#define IP_PROTO_CMTP 38 /* IDPR Ctrl Message Trans */ +#define IP_PROTO_TPPP 39 /* TP++ Transport Protocol */ +#define IP_PROTO_IL 40 /* IL Transport Protocol */ +#define IP_PROTO_IPV6 41 /* IPv6 */ +#define IP_PROTO_SDRP 42 /* Source Demand Routing */ +#define IP_PROTO_ROUTING 43 /* IPv6 routing header */ +#define IP_PROTO_FRAGMENT 44 /* IPv6 fragmentation header */ +#define IP_PROTO_RSVP 46 /* Reservation protocol */ +#define IP_PROTO_GRE 47 /* General Routing Encap */ +#define IP_PROTO_MHRP 48 /* Mobile Host Routing */ +#define IP_PROTO_ENA 49 /* ENA */ +#define IP_PROTO_ESP 50 /* Encap Security Payload */ +#define IP_PROTO_AH 51 /* Authentication Header */ +#define IP_PROTO_INLSP 52 /* Integated Net Layer Sec */ +#define IP_PROTO_SWIPE 53 /* SWIPE */ +#define IP_PROTO_NARP 54 /* NBMA Address Resolution */ +#define IP_PROTO_MOBILE 55 /* Mobile IP, RFC 2004 */ +#define IP_PROTO_TLSP 56 /* Transport Layer Security */ +#define IP_PROTO_SKIP 57 /* SKIP */ +#define IP_PROTO_ICMPV6 58 /* ICMP for IPv6 */ +#define IP_PROTO_NONE 59 /* IPv6 no next header */ +#define IP_PROTO_DSTOPTS 60 /* IPv6 destination options */ +#define IP_PROTO_ANYHOST 61 /* any host internal proto */ +#define IP_PROTO_CFTP 62 /* CFTP */ +#define IP_PROTO_ANYNET 63 /* any local network */ +#define IP_PROTO_EXPAK 64 /* SATNET and Backroom EXPAK */ +#define IP_PROTO_KRYPTOLAN 65 /* Kryptolan */ +#define IP_PROTO_RVD 66 /* MIT Remote Virtual Disk */ +#define IP_PROTO_IPPC 67 /* Inet Pluribus Packet Core */ +#define IP_PROTO_DISTFS 68 /* any distributed fs */ +#define IP_PROTO_SATMON 69 /* SATNET Monitoring */ +#define IP_PROTO_VISA 70 /* VISA Protocol */ +#define IP_PROTO_IPCV 71 /* Inet Packet Core Utility */ +#define IP_PROTO_CPNX 72 /* Comp Proto Net Executive */ +#define IP_PROTO_CPHB 73 /* Comp Protocol Heart Beat */ +#define IP_PROTO_WSN 74 /* Wang Span Network */ +#define IP_PROTO_PVP 75 /* Packet Video Protocol */ +#define IP_PROTO_BRSATMON 76 /* Backroom SATNET Monitor */ +#define IP_PROTO_SUNND 77 /* SUN ND Protocol */ +#define IP_PROTO_WBMON 78 /* WIDEBAND Monitoring */ +#define IP_PROTO_WBEXPAK 79 /* WIDEBAND EXPAK */ +#define IP_PROTO_EON 80 /* ISO CNLP */ +#define IP_PROTO_VMTP 81 /* Versatile Msg Transport*/ +#define IP_PROTO_SVMTP 82 /* Secure VMTP */ +#define IP_PROTO_VINES 83 /* VINES */ +#define IP_PROTO_TTP 84 /* TTP */ +#define IP_PROTO_NSFIGP 85 /* NSFNET-IGP */ +#define IP_PROTO_DGP 86 /* Dissimilar Gateway Proto */ +#define IP_PROTO_TCF 87 /* TCF */ +#define IP_PROTO_EIGRP 88 /* EIGRP */ +#define IP_PROTO_OSPF 89 /* Open Shortest Path First */ +#define IP_PROTO_SPRITERPC 90 /* Sprite RPC Protocol */ +#define IP_PROTO_LARP 91 /* Locus Address Resolution */ +#define IP_PROTO_MTP 92 /* Multicast Transport Proto */ +#define IP_PROTO_AX25 93 /* AX.25 Frames */ +#define IP_PROTO_IPIPENCAP 94 /* yet-another IP encap */ +#define IP_PROTO_MICP 95 /* Mobile Internet Ctrl */ +#define IP_PROTO_SCCSP 96 /* Semaphore Comm Sec Proto */ +#define IP_PROTO_ETHERIP 97 /* Ethernet in IPv4 */ +#define IP_PROTO_ENCAP 98 /* encapsulation header */ +#define IP_PROTO_ANYENC 99 /* private encryption scheme */ +#define IP_PROTO_GMTP 100 /* GMTP */ +#define IP_PROTO_IFMP 101 /* Ipsilon Flow Mgmt Proto */ +#define IP_PROTO_PNNI 102 /* PNNI over IP */ +#define IP_PROTO_PIM 103 /* Protocol Indep Multicast */ +#define IP_PROTO_ARIS 104 /* ARIS */ +#define IP_PROTO_SCPS 105 /* SCPS */ +#define IP_PROTO_QNX 106 /* QNX */ +#define IP_PROTO_AN 107 /* Active Networks */ +#define IP_PROTO_IPCOMP 108 /* IP Payload Compression */ +#define IP_PROTO_SNP 109 /* Sitara Networks Protocol */ +#define IP_PROTO_COMPAQPEER 110 /* Compaq Peer Protocol */ +#define IP_PROTO_IPXIP 111 /* IPX in IP */ +#define IP_PROTO_VRRP 112 /* Virtual Router Redundancy */ +#define IP_PROTO_PGM 113 /* PGM Reliable Transport */ +#define IP_PROTO_ANY0HOP 114 /* 0-hop protocol */ +#define IP_PROTO_L2TP 115 /* Layer 2 Tunneling Proto */ +#define IP_PROTO_DDX 116 /* D-II Data Exchange (DDX) */ +#define IP_PROTO_IATP 117 /* Interactive Agent Xfer */ +#define IP_PROTO_STP 118 /* Schedule Transfer Proto */ +#define IP_PROTO_SRP 119 /* SpectraLink Radio Proto */ +#define IP_PROTO_UTI 120 /* UTI */ +#define IP_PROTO_SMP 121 /* Simple Message Protocol */ +#define IP_PROTO_SM 122 /* SM */ +#define IP_PROTO_PTP 123 /* Performance Transparency */ +#define IP_PROTO_ISIS 124 /* ISIS over IPv4 */ +#define IP_PROTO_FIRE 125 /* FIRE */ +#define IP_PROTO_CRTP 126 /* Combat Radio Transport */ +#define IP_PROTO_CRUDP 127 /* Combat Radio UDP */ +#define IP_PROTO_SSCOPMCE 128 /* SSCOPMCE */ +#define IP_PROTO_IPLT 129 /* IPLT */ +#define IP_PROTO_SPS 130 /* Secure Packet Shield */ +#define IP_PROTO_PIPE 131 /* Private IP Encap in IP */ +#define IP_PROTO_SCTP 132 /* Stream Ctrl Transmission */ +#define IP_PROTO_FC 133 /* Fibre Channel */ +#define IP_PROTO_RSVPIGN 134 /* RSVP-E2E-IGNORE */ +#define IP_PROTO_RAW 255 /* Raw IP packets */ +#define IP_PROTO_RESERVED IP_PROTO_RAW /* Reserved */ +#define IP_PROTO_MAX 255 + +/* + * Option types (opt_type) - http://www.iana.org/assignments/ip-parameters + */ +#define IP_OPT_CONTROL 0x00 /* control */ +#define IP_OPT_DEBMEAS 0x40 /* debugging & measurement */ +#define IP_OPT_COPY 0x80 /* copy into all fragments */ +#define IP_OPT_RESERVED1 0x20 +#define IP_OPT_RESERVED2 0x60 + +#define IP_OPT_EOL 0 /* end of option list */ +#define IP_OPT_NOP 1 /* no operation */ +#define IP_OPT_SEC (2|IP_OPT_COPY) /* DoD basic security */ +#define IP_OPT_LSRR (3|IP_OPT_COPY) /* loose source route */ +#define IP_OPT_TS (4|IP_OPT_DEBMEAS) /* timestamp */ +#define IP_OPT_ESEC (5|IP_OPT_COPY) /* DoD extended security */ +#define IP_OPT_CIPSO (6|IP_OPT_COPY) /* commercial security */ +#define IP_OPT_RR 7 /* record route */ +#define IP_OPT_SATID (8|IP_OPT_COPY) /* stream ID (obsolete) */ +#define IP_OPT_SSRR (9|IP_OPT_COPY) /* strict source route */ +#define IP_OPT_ZSU 10 /* experimental measurement */ +#define IP_OPT_MTUP 11 /* MTU probe */ +#define IP_OPT_MTUR 12 /* MTU reply */ +#define IP_OPT_FINN (13|IP_OPT_COPY|IP_OPT_DEBMEAS) /* exp flow control */ +#define IP_OPT_VISA (14|IP_OPT_COPY) /* exp access control */ +#define IP_OPT_ENCODE 15 /* ??? */ +#define IP_OPT_IMITD (16|IP_OPT_COPY) /* IMI traffic descriptor */ +#define IP_OPT_EIP (17|IP_OPT_COPY) /* extended IP, RFC 1385 */ +#define IP_OPT_TR (18|IP_OPT_DEBMEAS) /* traceroute */ +#define IP_OPT_ADDEXT (19|IP_OPT_COPY) /* IPv7 ext addr, RFC 1475 */ +#define IP_OPT_RTRALT (20|IP_OPT_COPY) /* router alert, RFC 2113 */ +#define IP_OPT_SDB (21|IP_OPT_COPY) /* directed bcast, RFC 1770 */ +#define IP_OPT_NSAPA (22|IP_OPT_COPY) /* NSAP addresses */ +#define IP_OPT_DPS (23|IP_OPT_COPY) /* dynamic packet state */ +#define IP_OPT_UMP (24|IP_OPT_COPY) /* upstream multicast */ +#define IP_OPT_MAX 25 + +#define IP_OPT_COPIED(o) ((o) & 0x80) +#define IP_OPT_CLASS(o) ((o) & 0x60) +#define IP_OPT_NUMBER(o) ((o) & 0x1f) +#define IP_OPT_TYPEONLY(o) ((o) == IP_OPT_EOL || (o) == IP_OPT_NOP) + +/* + * Security option data - RFC 791, 3.1 + */ +struct ip_opt_data_sec { + uint16_t s; /* security */ + uint16_t c; /* compartments */ + uint16_t h; /* handling restrictions */ + uint8_t tcc[3]; /* transmission control code */ +} __attribute__((__packed__)); + +#define IP_OPT_SEC_UNCLASS 0x0000 /* unclassified */ +#define IP_OPT_SEC_CONFID 0xf135 /* confidential */ +#define IP_OPT_SEC_EFTO 0x789a /* EFTO */ +#define IP_OPT_SEC_MMMM 0xbc4d /* MMMM */ +#define IP_OPT_SEC_PROG 0x5e26 /* PROG */ +#define IP_OPT_SEC_RESTR 0xaf13 /* restricted */ +#define IP_OPT_SEC_SECRET 0xd788 /* secret */ +#define IP_OPT_SEC_TOPSECRET 0x6bc5 /* top secret */ + +/* + * {Loose Source, Record, Strict Source} Route option data - RFC 791, 3.1 + */ +struct ip_opt_data_rr { + uint8_t ptr; /* from start of option, >= 4 */ + uint32_t iplist __flexarr; /* list of IP addresses */ +} __attribute__((__packed__)); + +/* + * Timestamp option data - RFC 791, 3.1 + */ +struct ip_opt_data_ts { + uint8_t ptr; /* from start of option, >= 5 */ +#if DNET_BYTESEX == DNET_BIG_ENDIAN + uint8_t oflw:4, /* number of IPs skipped */ + flg:4; /* address[ / timestamp] flag */ +#elif DNET_BYTESEX == DNET_LIL_ENDIAN + uint8_t flg:4, + oflw:4; +#endif + uint32_t ipts __flexarr; /* IP address [/ timestamp] pairs */ +} __attribute__((__packed__)); + +#define IP_OPT_TS_TSONLY 0 /* timestamps only */ +#define IP_OPT_TS_TSADDR 1 /* IP address / timestamp pairs */ +#define IP_OPT_TS_PRESPEC 3 /* IP address / zero timestamp pairs */ + +/* + * Traceroute option data - RFC 1393, 2.2 + */ +struct ip_opt_data_tr { + uint16_t id; /* ID number */ + uint16_t ohc; /* outbound hop count */ + uint16_t rhc; /* return hop count */ + uint32_t origip; /* originator IP address */ +} __attribute__((__packed__)); + +/* + * IP option (following IP header) + */ +struct ip_opt { + uint8_t opt_type; /* option type */ + uint8_t opt_len; /* option length >= IP_OPT_LEN */ + union ip_opt_data { + struct ip_opt_data_sec sec; /* IP_OPT_SEC */ + struct ip_opt_data_rr rr; /* IP_OPT_{L,S}RR */ + struct ip_opt_data_ts ts; /* IP_OPT_TS */ + uint16_t satid; /* IP_OPT_SATID */ + uint16_t mtu; /* IP_OPT_MTU{P,R} */ + struct ip_opt_data_tr tr; /* IP_OPT_TR */ + uint32_t addext[2]; /* IP_OPT_ADDEXT */ + uint16_t rtralt; /* IP_OPT_RTRALT */ + uint32_t sdb[9]; /* IP_OPT_SDB */ + uint8_t data8[IP_OPT_LEN_MAX - IP_OPT_LEN]; + } opt_data; +} __attribute__((__packed__)); + +#ifndef __GNUC__ +# pragma pack() +#endif + +/* + * Classful addressing + */ +#define IP_CLASSA(i) (((uint32_t)(i) & htonl(0x80000000)) == \ + htonl(0x00000000)) +#define IP_CLASSA_NET (htonl(0xff000000)) +#define IP_CLASSA_NSHIFT 24 +#define IP_CLASSA_HOST (htonl(0x00ffffff)) +#define IP_CLASSA_MAX 128 + +#define IP_CLASSB(i) (((uint32_t)(i) & htonl(0xc0000000)) == \ + htonl(0x80000000)) +#define IP_CLASSB_NET (htonl(0xffff0000)) +#define IP_CLASSB_NSHIFT 16 +#define IP_CLASSB_HOST (htonl(0x0000ffff)) +#define IP_CLASSB_MAX 65536 + +#define IP_CLASSC(i) (((uint32_t)(i) & htonl(0xe0000000)) == \ + htonl(0xc0000000)) +#define IP_CLASSC_NET (htonl(0xffffff00)) +#define IP_CLASSC_NSHIFT 8 +#define IP_CLASSC_HOST (htonl(0x000000ff)) + +#define IP_CLASSD(i) (((uint32_t)(i) & htonl(0xf0000000)) == \ + htonl(0xe0000000)) +/* These ones aren't really net and host fields, but routing needn't know. */ +#define IP_CLASSD_NET (htonl(0xf0000000)) +#define IP_CLASSD_NSHIFT 28 +#define IP_CLASSD_HOST (htonl(0x0fffffff)) +#define IP_MULTICAST(i) IP_CLASSD(i) + +#define IP_EXPERIMENTAL(i) (((uint32_t)(i) & htonl(0xf0000000)) == \ + htonl(0xf0000000)) +#define IP_BADCLASS(i) (((uint32_t)(i) & htonl(0xf0000000)) == \ + htonl(0xf0000000)) +#define IP_LOCAL_GROUP(i) (((uint32_t)(i) & htonl(0xffffff00)) == \ + htonl(0xe0000000)) +/* + * Reserved addresses + */ +#define IP_ADDR_ANY (htonl(0x00000000)) /* 0.0.0.0 */ +#define IP_ADDR_BROADCAST (htonl(0xffffffff)) /* 255.255.255.255 */ +#define IP_ADDR_LOOPBACK (htonl(0x7f000001)) /* 127.0.0.1 */ +#define IP_ADDR_MCAST_ALL (htonl(0xe0000001)) /* 224.0.0.1 */ +#define IP_ADDR_MCAST_LOCAL (htonl(0xe00000ff)) /* 224.0.0.225 */ + +#define ip_pack_hdr(hdr, tos, len, id, off, ttl, p, src, dst) do { \ + struct ip_hdr *ip_pack_p = (struct ip_hdr *)(hdr); \ + ip_pack_p->ip_v = 4; ip_pack_p->ip_hl = 5; \ + ip_pack_p->ip_tos = tos; ip_pack_p->ip_len = htons(len); \ + ip_pack_p->ip_id = htons(id); ip_pack_p->ip_off = htons(off); \ + ip_pack_p->ip_ttl = ttl; ip_pack_p->ip_p = p; \ + ip_pack_p->ip_src = src; ip_pack_p->ip_dst = dst; \ +} while (0) + +typedef struct ip_handle ip_t; + +__BEGIN_DECLS +ip_t *ip_open(void); +size_t ip_send(ip_t *i, const void *buf, size_t len); +ip_t *ip_close(ip_t *i); + +char *ip_ntop(const ip_addr_t *ip, char *dst, size_t len); +int ip_pton(const char *src, ip_addr_t *dst); +char *ip_ntoa(const ip_addr_t *ip); +#define ip_aton ip_pton + +size_t ip_add_option(void *buf, size_t len, + int proto, const void *optbuf, size_t optlen); +void ip_checksum(void *buf, size_t len); + +inline int +ip_cksum_add(const void *buf, size_t len, int cksum) +{ + uint16_t *sp = (uint16_t *)buf; + int n, sn; + + sn = len / 2; + n = (sn + 15) / 16; + + /* XXX - unroll loop using Duff's device. */ + switch (sn % 16) { + case 0: do { + cksum += *sp++; + case 15: + cksum += *sp++; + case 14: + cksum += *sp++; + case 13: + cksum += *sp++; + case 12: + cksum += *sp++; + case 11: + cksum += *sp++; + case 10: + cksum += *sp++; + case 9: + cksum += *sp++; + case 8: + cksum += *sp++; + case 7: + cksum += *sp++; + case 6: + cksum += *sp++; + case 5: + cksum += *sp++; + case 4: + cksum += *sp++; + case 3: + cksum += *sp++; + case 2: + cksum += *sp++; + case 1: + cksum += *sp++; + } while (--n > 0); + } + if (len & 1) + cksum += htons(*(u_char *)sp << 8); + + return (cksum); +} + +inline uint16_t +ip_cksum_carry(int x) +{ + x = (x >> 16) + (x & 0xffff); + return ~(x + (x >> 16)) & 0xffff; +} + +__END_DECLS + +#endif /* DNET_IP_H */ diff --git a/ext/dnet/dnet/ip6.h b/ext/dnet/dnet/ip6.h new file mode 100644 index 000000000..7fae29b47 --- /dev/null +++ b/ext/dnet/dnet/ip6.h @@ -0,0 +1,183 @@ +/* + * ip6.h + * + * Internet Protocol, Version 6 (RFC 2460). + * + * Copyright (c) 2002 Dug Song <dugsong@monkey.org> + * + * $Id: ip6.h,v 1.6 2004/02/23 10:01:15 dugsong Exp $ + */ + +#ifndef DNET_IP6_H +#define DNET_IP6_H + +#define IP6_ADDR_LEN 16 +#define IP6_ADDR_BITS 128 + +#define IP6_HDR_LEN 40 /* IPv6 header length */ +#define IP6_LEN_MIN IP6_HDR_LEN +#define IP6_LEN_MAX 65535 /* non-jumbo payload */ + +#define IP6_MTU_MIN 1280 /* minimum MTU (1024 + 256) */ + +typedef struct ip6_addr { + uint8_t data[IP6_ADDR_LEN]; +} ip6_addr_t; + +#ifndef __GNUC__ +# define __attribute__(x) +# pragma pack(1) +#endif + +/* + * IPv6 header + */ +struct ip6_hdr { + union { + struct ip6_hdr_ctl { + uint32_t ip6_un1_flow; /* 20 bits of flow ID */ + uint16_t ip6_un1_plen; /* payload length */ + uint8_t ip6_un1_nxt; /* next header */ + uint8_t ip6_un1_hlim; /* hop limit */ + } ip6_un1; + uint8_t ip6_un2_vfc; /* 4 bits version, top 4 bits class */ + } ip6_ctlun; + ip6_addr_t ip6_src; + ip6_addr_t ip6_dst; +} __attribute__((__packed__)); + +#define ip6_vfc ip6_ctlun.ip6_un2_vfc +#define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow +#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen +#define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt /* IP_PROTO_* */ +#define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim + +#define IP6_VERSION 0x60 +#define IP6_VERSION_MASK 0xf0 /* ip6_vfc version */ + +#if DNET_BYTESEX == DNET_BIG_ENDIAN +#define IP6_FLOWINFO_MASK 0x0fffffff /* ip6_flow info (28 bits) */ +#define IP6_FLOWLABEL_MASK 0x000fffff /* ip6_flow label (20 bits) */ +#elif DNET_BYTESEX == DNET_LIL_ENDIAN +#define IP6_FLOWINFO_MASK 0xffffff0f /* ip6_flow info (28 bits) */ +#define IP6_FLOWLABEL_MASK 0xffff0f00 /* ip6_flow label (20 bits) */ +#endif + +/* + * Hop limit (ip6_hlim) + */ +#define IP6_HLIM_DEFAULT 64 +#define IP6_HLIM_MAX 255 + +/* + * Preferred extension header order from RFC 2460, 4.1: + * + * IP_PROTO_IPV6, IP_PROTO_HOPOPTS, IP_PROTO_DSTOPTS, IP_PROTO_ROUTING, + * IP_PROTO_FRAGMENT, IP_PROTO_AH, IP_PROTO_ESP, IP_PROTO_DSTOPTS, IP_PROTO_* + */ + +/* + * Routing header data (IP_PROTO_ROUTING) + */ +struct ip6_ext_data_routing { + uint8_t type; /* routing type */ + uint8_t segleft; /* segments left */ + /* followed by routing type specific data */ +} __attribute__((__packed__)); + +struct ip6_ext_data_routing0 { + uint8_t type; /* always zero */ + uint8_t segleft; /* segments left */ + uint8_t reserved; /* reserved field */ + uint8_t slmap[3]; /* strict/loose bit map */ + ip6_addr_t addr[1]; /* up to 23 addresses */ +} __attribute__((__packed__)); + +/* + * Fragment header data (IP_PROTO_FRAGMENT) + */ +struct ip6_ext_data_fragment { + uint16_t offlg; /* offset, reserved, and flag */ + uint32_t ident; /* identification */ +} __attribute__((__packed__)); + +/* + * Fragmentation offset, reserved, and flags (offlg) + */ +#if DNET_BYTESEX == DNET_BIG_ENDIAN +#define IP6_OFF_MASK 0xfff8 /* mask out offset from offlg */ +#define IP6_RESERVED_MASK 0x0006 /* reserved bits in offlg */ +#define IP6_MORE_FRAG 0x0001 /* more-fragments flag */ +#elif DNET_BYTESEX == DNET_LIL_ENDIAN +#define IP6_OFF_MASK 0xf8ff /* mask out offset from offlg */ +#define IP6_RESERVED_MASK 0x0600 /* reserved bits in offlg */ +#define IP6_MORE_FRAG 0x0100 /* more-fragments flag */ +#endif + +/* + * Option types, for IP_PROTO_HOPOPTS, IP_PROTO_DSTOPTS headers + */ +#define IP6_OPT_PAD1 0x00 /* 00 0 00000 */ +#define IP6_OPT_PADN 0x01 /* 00 0 00001 */ +#define IP6_OPT_JUMBO 0xC2 /* 11 0 00010 = 194 */ +#define IP6_OPT_JUMBO_LEN 6 +#define IP6_OPT_RTALERT 0x05 /* 00 0 00101 */ +#define IP6_OPT_RTALERT_LEN 4 +#define IP6_OPT_RTALERT_MLD 0 /* Datagram contains an MLD message */ +#define IP6_OPT_RTALERT_RSVP 1 /* Datagram contains an RSVP message */ +#define IP6_OPT_RTALERT_ACTNET 2 /* contains an Active Networks msg */ +#define IP6_OPT_LEN_MIN 2 + +#define IP6_OPT_TYPE(o) ((o) & 0xC0) /* high 2 bits of opt_type */ +#define IP6_OPT_TYPE_SKIP 0x00 /* continue processing on failure */ +#define IP6_OPT_TYPE_DISCARD 0x40 /* discard packet on failure */ +#define IP6_OPT_TYPE_FORCEICMP 0x80 /* discard and send ICMP on failure */ +#define IP6_OPT_TYPE_ICMP 0xC0 /* ...only if non-multicast dst */ + +#define IP6_OPT_MUTABLE 0x20 /* option data may change en route */ + +/* + * Extension header (chained via {ip6,ext}_nxt, following IPv6 header) + */ +struct ip6_ext_hdr { + uint8_t ext_nxt; /* next header */ + uint8_t ext_len; /* following length in units of 8 octets */ + union { + struct ip6_ext_data_routing routing; + struct ip6_ext_data_fragment fragment; + } ext_data; +} __attribute__((__packed__)); + +#ifndef __GNUC__ +# pragma pack() +#endif + +/* + * Reserved addresses + */ +#define IP6_ADDR_UNSPEC \ + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +#define IP6_ADDR_LOOPBACK \ + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01" + +#define ip6_pack_hdr(hdr, fc, fl, plen, nxt, hlim, src, dst) do { \ + struct ip6_hdr *ip6 = (struct ip6_hdr *)(hdr); \ + ip6->ip6_flow = htonl(((uint32_t)(fc) << 28) & \ + (IP6_FLOWLABEL_MASK | (fl))); \ + ip6->ip6_vfc = (IP6_VERSION | ((fc) >> 4)); \ + ip6->ip6_plen = htons((plen)); \ + ip6->ip6_nxt = (nxt); ip6->ip6_hlim = (hlim); \ + memmove(&ip6->ip6_src, &(src), IP6_ADDR_LEN); \ + memmove(&ip6->ip6_dst, &(dst), IP6_ADDR_LEN); \ +} while (0); + +__BEGIN_DECLS +char *ip6_ntop(const ip6_addr_t *ip6, char *dst, size_t size); +int ip6_pton(const char *src, ip6_addr_t *dst); +char *ip6_ntoa(const ip6_addr_t *ip6); +#define ip6_aton ip6_pton + +void ip6_checksum(void *buf, size_t len); +__END_DECLS + +#endif /* DNET_IP6_H */ diff --git a/ext/dnet/dnet/os.h b/ext/dnet/dnet/os.h new file mode 100644 index 000000000..cae244781 --- /dev/null +++ b/ext/dnet/dnet/os.h @@ -0,0 +1,117 @@ +/* + * os.h + * + * Sleazy OS-specific defines. + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * + * $Id: os.h,v 1.10 2004/05/04 03:19:42 dugsong Exp $ + */ + +#ifndef DNET_OS_H +#define DNET_OS_H + +#ifdef _WIN32 +# include <windows.h> +# include <winsock2.h> +# include <stdint.h> +/* XXX */ +# undef IP_OPT_LSRR +# undef IP_OPT_TS +# undef IP_OPT_RR +# undef IP_OPT_SSRR +#else +# include <sys/param.h> +# include <sys/types.h> +# include <sys/socket.h> +# include <netinet/in.h> +# include <arpa/inet.h> +# include <netdb.h> +# ifdef __bsdi__ +# include <machine/types.h> + typedef u_int8_t uint8_t; + typedef u_int16_t uint16_t; + typedef u_int32_t uint32_t; + typedef u_int64_t uint64_t; +# else +# include <inttypes.h> +# endif +#endif + +#define DNET_LIL_ENDIAN 1234 +#define DNET_BIG_ENDIAN 4321 + +/* BSD and IRIX */ +#ifdef BYTE_ORDER +#if BYTE_ORDER == LITTLE_ENDIAN +# define DNET_BYTESEX DNET_LIL_ENDIAN +#elif BYTE_ORDER == BIG_ENDIAN +# define DNET_BYTESEX DNET_BIG_ENDIAN +#endif +#endif + +/* Linux */ +#ifdef __BYTE_ORDER +#if __BYTE_ORDER == __LITTLE_ENDIAN +# define DNET_BYTESEX DNET_LIL_ENDIAN +#elif __BYTE_ORDER == __BIG_ENDIAN +# define DNET_BYTESEX DNET_BIG_ENDIAN +#endif +#endif + +/* Solaris */ +#if defined(_BIT_FIELDS_LTOH) +# define DNET_BYTESEX DNET_LIL_ENDIAN +#elif defined (_BIT_FIELDS_HTOL) +# define DNET_BYTESEX DNET_BIG_ENDIAN +#endif + +/* Nastiness from old BIND code. */ +#ifndef DNET_BYTESEX +# if defined(vax) || defined(ns32000) || defined(sun386) || defined(i386) || \ + defined(MIPSEL) || defined(_MIPSEL) || defined(BIT_ZERO_ON_RIGHT) || \ + defined(__alpha__) || defined(__alpha) +# define DNET_BYTESEX DNET_LIL_ENDIAN +# elif defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \ + defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \ + defined(MIPSEB) || defined(_MIPSEB) || defined(_IBMR2) || defined(DGUX) ||\ + defined(apollo) || defined(__convex__) || defined(_CRAY) || \ + defined(__hppa) || defined(__hp9000) || \ + defined(__hp9000s300) || defined(__hp9000s700) || defined(__ia64) || \ + defined (BIT_ZERO_ON_LEFT) || defined(m68k) +# define DNET_BYTESEX DNET_BIG_ENDIAN +# else +# error "bytesex unknown" +# endif +#endif + +/* C++ support. */ +#undef __BEGIN_DECLS +#undef __END_DECLS +#ifdef __cplusplus +# define __BEGIN_DECLS extern "C" { +# define __END_DECLS } /* extern "C" */ +#else +# define __BEGIN_DECLS +# define __END_DECLS +#endif + +/* Support for flexible arrays. */ +#undef __flexarr +#if defined(__GNUC__) && ((__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)) +/* GCC 2.97 supports C99 flexible array members. */ +# define __flexarr [] +#else +# ifdef __GNUC__ +# define __flexarr [0] +# else +# if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L +# define __flexarr [] +# else +/* Some other non-C99 compiler. Approximate with [1]. */ +# define __flexarr [1] +# endif +# endif +#endif + +#endif /* DNET_OS_H */ diff --git a/ext/dnet/dnet/rand.h b/ext/dnet/dnet/rand.h new file mode 100644 index 000000000..49121930c --- /dev/null +++ b/ext/dnet/dnet/rand.h @@ -0,0 +1,33 @@ +/* + * rand.h + * + * Pseudo-random number generation, based on OpenBSD arc4random(). + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * Copyright (c) 1996 David Mazieres <dm@lcs.mit.edu> + * + * $Id: rand.h,v 1.4 2002/04/07 19:01:25 dugsong Exp $ + */ + +#ifndef DNET_RAND_H +#define DNET_RAND_H + +typedef struct rand_handle rand_t; + +__BEGIN_DECLS +rand_t *rand_open(void); + +int rand_get(rand_t *r, void *buf, size_t len); +int rand_set(rand_t *r, const void *seed, size_t len); +int rand_add(rand_t *r, const void *buf, size_t len); + +uint8_t rand_uint8(rand_t *r); +uint16_t rand_uint16(rand_t *r); +uint32_t rand_uint32(rand_t *r); + +int rand_shuffle(rand_t *r, void *base, size_t nmemb, size_t size); + +rand_t *rand_close(rand_t *r); +__END_DECLS + +#endif /* DNET_RAND_H */ diff --git a/ext/dnet/dnet/route.h b/ext/dnet/dnet/route.h new file mode 100644 index 000000000..74c21419c --- /dev/null +++ b/ext/dnet/dnet/route.h @@ -0,0 +1,35 @@ +/* + * route.c + * + * Kernel route table operations. + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * + * $Id: route.h,v 1.6 2002/02/04 04:02:22 dugsong Exp $ + */ + +#ifndef DNET_ROUTE_H +#define DNET_ROUTE_H + +/* + * Routing table entry + */ +struct route_entry { + struct addr route_dst; /* destination address */ + struct addr route_gw; /* gateway address */ +}; + +typedef struct route_handle route_t; + +typedef int (*route_handler)(const struct route_entry *entry, void *arg); + +__BEGIN_DECLS +route_t *route_open(void); +int route_add(route_t *r, const struct route_entry *entry); +int route_delete(route_t *r, const struct route_entry *entry); +int route_get(route_t *r, struct route_entry *entry); +int route_loop(route_t *r, route_handler callback, void *arg); +route_t *route_close(route_t *r); +__END_DECLS + +#endif /* DNET_ROUTE_H */ diff --git a/ext/dnet/dnet/tcp.h b/ext/dnet/dnet/tcp.h new file mode 100644 index 000000000..008946384 --- /dev/null +++ b/ext/dnet/dnet/tcp.h @@ -0,0 +1,158 @@ +/* + * tcp.h + * + * Transmission Control Protocol (RFC 793). + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * + * $Id: tcp.h,v 1.17 2004/02/23 10:02:11 dugsong Exp $ + */ + +#ifndef DNET_TCP_H +#define DNET_TCP_H + +#define TCP_HDR_LEN 20 /* base TCP header length */ +#define TCP_OPT_LEN 2 /* base TCP option length */ +#define TCP_OPT_LEN_MAX 40 +#define TCP_HDR_LEN_MAX (TCP_HDR_LEN + TCP_OPT_LEN_MAX) + +#ifndef __GNUC__ +# define __attribute__(x) +# pragma pack(1) +#endif + +/* + * TCP header, without options + */ +struct tcp_hdr { + uint16_t th_sport; /* source port */ + uint16_t th_dport; /* destination port */ + uint32_t th_seq; /* sequence number */ + uint32_t th_ack; /* acknowledgment number */ +#if DNET_BYTESEX == DNET_BIG_ENDIAN + uint8_t th_off:4, /* data offset */ + th_x2:4; /* (unused) */ +#elif DNET_BYTESEX == DNET_LIL_ENDIAN + uint8_t th_x2:4, + th_off:4; +#else +# error "need to include <dnet.h>" +#endif + uint8_t th_flags; /* control flags */ + uint16_t th_win; /* window */ + uint16_t th_sum; /* checksum */ + uint16_t th_urp; /* urgent pointer */ +}; + +/* + * TCP control flags (th_flags) + */ +#define TH_FIN 0x01 /* end of data */ +#define TH_SYN 0x02 /* synchronize sequence numbers */ +#define TH_RST 0x04 /* reset connection */ +#define TH_PUSH 0x08 /* push */ +#define TH_ACK 0x10 /* acknowledgment number set */ +#define TH_URG 0x20 /* urgent pointer set */ +#define TH_ECE 0x40 /* ECN echo, RFC 3168 */ +#define TH_CWR 0x80 /* congestion window reduced */ + +#define TCP_PORT_MAX 65535 /* maximum port */ +#define TCP_WIN_MAX 65535 /* maximum (unscaled) window */ + +/* + * Sequence number comparison macros + */ +#define TCP_SEQ_LT(a,b) ((int)((a)-(b)) < 0) +#define TCP_SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0) +#define TCP_SEQ_GT(a,b) ((int)((a)-(b)) > 0) +#define TCP_SEQ_GEQ(a,b) ((int)((a)-(b)) >= 0) + +/* + * TCP FSM states + */ +#define TCP_STATE_CLOSED 0 /* closed */ +#define TCP_STATE_LISTEN 1 /* listening from connection */ +#define TCP_STATE_SYN_SENT 2 /* active, have sent SYN */ +#define TCP_STATE_SYN_RECEIVED 3 /* have sent and received SYN */ + +#define TCP_STATE_ESTABLISHED 4 /* established */ +#define TCP_STATE_CLOSE_WAIT 5 /* rcvd FIN, waiting for close */ + +#define TCP_STATE_FIN_WAIT_1 6 /* have closed, sent FIN */ +#define TCP_STATE_CLOSING 7 /* closed xchd FIN, await FIN-ACK */ +#define TCP_STATE_LAST_ACK 8 /* had FIN and close, await FIN-ACK */ + +#define TCP_STATE_FIN_WAIT_2 9 /* have closed, FIN is acked */ +#define TCP_STATE_TIME_WAIT 10 /* in 2*MSL quiet wait after close */ +#define TCP_STATE_MAX 11 + +/* + * Options (opt_type) - http://www.iana.org/assignments/tcp-parameters + */ +#define TCP_OPT_EOL 0 /* end of option list */ +#define TCP_OPT_NOP 1 /* no operation */ +#define TCP_OPT_MSS 2 /* maximum segment size */ +#define TCP_OPT_WSCALE 3 /* window scale factor, RFC 1072 */ +#define TCP_OPT_SACKOK 4 /* SACK permitted, RFC 2018 */ +#define TCP_OPT_SACK 5 /* SACK, RFC 2018 */ +#define TCP_OPT_ECHO 6 /* echo (obsolete), RFC 1072 */ +#define TCP_OPT_ECHOREPLY 7 /* echo reply (obsolete), RFC 1072 */ +#define TCP_OPT_TIMESTAMP 8 /* timestamp, RFC 1323 */ +#define TCP_OPT_POCONN 9 /* partial order conn, RFC 1693 */ +#define TCP_OPT_POSVC 10 /* partial order service, RFC 1693 */ +#define TCP_OPT_CC 11 /* connection count, RFC 1644 */ +#define TCP_OPT_CCNEW 12 /* CC.NEW, RFC 1644 */ +#define TCP_OPT_CCECHO 13 /* CC.ECHO, RFC 1644 */ +#define TCP_OPT_ALTSUM 14 /* alt checksum request, RFC 1146 */ +#define TCP_OPT_ALTSUMDATA 15 /* alt checksum data, RFC 1146 */ +#define TCP_OPT_SKEETER 16 /* Skeeter */ +#define TCP_OPT_BUBBA 17 /* Bubba */ +#define TCP_OPT_TRAILSUM 18 /* trailer checksum */ +#define TCP_OPT_MD5 19 /* MD5 signature, RFC 2385 */ +#define TCP_OPT_SCPS 20 /* SCPS capabilities */ +#define TCP_OPT_SNACK 21 /* selective negative acks */ +#define TCP_OPT_REC 22 /* record boundaries */ +#define TCP_OPT_CORRUPT 23 /* corruption experienced */ +#define TCP_OPT_SNAP 24 /* SNAP */ +#define TCP_OPT_TCPCOMP 26 /* TCP compression filter */ +#define TCP_OPT_MAX 27 + +#define TCP_OPT_TYPEONLY(type) \ + ((type) == TCP_OPT_EOL || (type) == TCP_OPT_NOP) + +/* + * TCP option (following TCP header) + */ +struct tcp_opt { + uint8_t opt_type; /* option type */ + uint8_t opt_len; /* option length >= TCP_OPT_LEN */ + union tcp_opt_data { + uint16_t mss; /* TCP_OPT_MSS */ + uint8_t wscale; /* TCP_OPT_WSCALE */ + uint16_t sack[19]; /* TCP_OPT_SACK */ + uint32_t echo; /* TCP_OPT_ECHO{REPLY} */ + uint32_t timestamp[2]; /* TCP_OPT_TIMESTAMP */ + uint32_t cc; /* TCP_OPT_CC{NEW,ECHO} */ + uint8_t cksum; /* TCP_OPT_ALTSUM */ + uint8_t md5[16]; /* TCP_OPT_MD5 */ + uint8_t data8[TCP_OPT_LEN_MAX - TCP_OPT_LEN]; + } opt_data; +} __attribute__((__packed__)); + +#ifndef __GNUC__ +# pragma pack() +#endif + +#define tcp_pack_hdr(hdr, sport, dport, seq, ack, flags, win, urp) do { \ + struct tcp_hdr *tcp_pack_p = (struct tcp_hdr *)(hdr); \ + tcp_pack_p->th_sport = htons(sport); \ + tcp_pack_p->th_dport = htons(dport); \ + tcp_pack_p->th_seq = htonl(seq); \ + tcp_pack_p->th_ack = htonl(ack); \ + tcp_pack_p->th_x2 = 0; tcp_pack_p->th_off = 5; \ + tcp_pack_p->th_flags = flags; \ + tcp_pack_p->th_win = htons(win); \ + tcp_pack_p->th_urp = htons(urp); \ +} while (0) + +#endif /* DNET_TCP_H */ diff --git a/ext/dnet/dnet/udp.h b/ext/dnet/dnet/udp.h new file mode 100644 index 000000000..73839a92a --- /dev/null +++ b/ext/dnet/dnet/udp.h @@ -0,0 +1,32 @@ +/* + * udp.h + * + * User Datagram Protocol (RFC 768). + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * + * $Id: udp.h,v 1.8 2002/04/02 05:05:39 dugsong Exp $ + */ + +#ifndef DNET_UDP_H +#define DNET_UDP_H + +#define UDP_HDR_LEN 8 + +struct udp_hdr { + uint16_t uh_sport; /* source port */ + uint16_t uh_dport; /* destination port */ + uint16_t uh_ulen; /* udp length (including header) */ + uint16_t uh_sum; /* udp checksum */ +}; + +#define UDP_PORT_MAX 65535 + +#define udp_pack_hdr(hdr, sport, dport, ulen) do { \ + struct udp_hdr *udp_pack_p = (struct udp_hdr *)(hdr); \ + udp_pack_p->uh_sport = htons(sport); \ + udp_pack_p->uh_dport = htons(dport); \ + udp_pack_p->uh_ulen = htons(ulen); \ +} while (0) + +#endif /* DNET_UDP_H */ diff --git a/ext/ply/CHANGES b/ext/ply/CHANGES new file mode 100644 index 000000000..9c7334066 --- /dev/null +++ b/ext/ply/CHANGES @@ -0,0 +1,158 @@ +Version 1.3 +------------------------------ +12/10/02: jmdyck + Various minor adjustments to the code that Dave checked in today. + Updated test/yacc_{inf,unused}.exp to reflect today's changes. + +12/10/02: beazley + Incorporated a variety of minor bug fixes to empty production + handling and infinite recursion checking. Contributed by + Michael Dyck. + +12/10/02: beazley + Removed bogus recover() method call in yacc.restart() + +Version 1.2 +------------------------------ +11/27/02: beazley + Lexer and parser objects are now available as an attribute + of tokens and slices respectively. For example: + + def t_NUMBER(t): + r'\d+' + print t.lexer + + def p_expr_plus(t): + 'expr: expr PLUS expr' + print t.lexer + print t.parser + + This can be used for state management (if needed). + +10/31/02: beazley + Modified yacc.py to work with Python optimize mode. To make + this work, you need to use + + yacc.yacc(optimize=1) + + Furthermore, you need to first run Python in normal mode + to generate the necessary parsetab.py files. After that, + you can use python -O or python -OO. + + Note: optimized mode turns off a lot of error checking. + Only use when you are sure that your grammar is working. + Make sure parsetab.py is up to date! + +10/30/02: beazley + Added cloning of Lexer objects. For example: + + import copy + l = lex.lex() + lc = copy.copy(l) + + l.input("Some text") + lc.input("Some other text") + ... + + This might be useful if the same "lexer" is meant to + be used in different contexts---or if multiple lexers + are running concurrently. + +10/30/02: beazley + Fixed subtle bug with first set computation and empty productions. + Patch submitted by Michael Dyck. + +10/30/02: beazley + Fixed error messages to use "filename:line: message" instead + of "filename:line. message". This makes error reporting more + friendly to emacs. Patch submitted by François Pinard. + +10/30/02: beazley + Improvements to parser.out file. Terminals and nonterminals + are sorted instead of being printed in random order. + Patch submitted by François Pinard. + +10/30/02: beazley + Improvements to parser.out file output. Rules are now printed + in a way that's easier to understand. Contributed by Russ Cox. + +10/30/02: beazley + Added 'nonassoc' associativity support. This can be used + to disable the chaining of operators like a < b < c. + To use, simply specify 'nonassoc' in the precedence table + + precedence = ( + ('nonassoc', 'LESSTHAN', 'GREATERTHAN'), # Nonassociative operators + ('left', 'PLUS', 'MINUS'), + ('left', 'TIMES', 'DIVIDE'), + ('right', 'UMINUS'), # Unary minus operator + ) + + Patch contributed by Russ Cox. + +10/30/02: beazley + Modified the lexer to provide optional support for Python -O and -OO + modes. To make this work, Python *first* needs to be run in + unoptimized mode. This reads the lexing information and creates a + file "lextab.py". Then, run lex like this: + + # module foo.py + ... + ... + lex.lex(optimize=1) + + Once the lextab file has been created, subsequent calls to + lex.lex() will read data from the lextab file instead of using + introspection. In optimized mode (-O, -OO) everything should + work normally despite the loss of doc strings. + + To change the name of the file 'lextab.py' use the following: + + lex.lex(lextab="footab") + + (this creates a file footab.py) + + +Version 1.1 October 25, 2001 +------------------------------ + +10/25/01: beazley + Modified the table generator to produce much more compact data. + This should greatly reduce the size of the parsetab.py[c] file. + Caveat: the tables still need to be constructed so a little more + work is done in parsetab on import. + +10/25/01: beazley + There may be a possible bug in the cycle detector that reports errors + about infinite recursion. I'm having a little trouble tracking it + down, but if you get this problem, you can disable the cycle + detector as follows: + + yacc.yacc(check_recursion = 0) + +10/25/01: beazley + Fixed a bug in lex.py that sometimes caused illegal characters to be + reported incorrectly. Reported by Sverre Jørgensen. + +7/8/01 : beazley + Added a reference to the underlying lexer object when tokens are handled by + functions. The lexer is available as the 'lexer' attribute. This + was added to provide better lexing support for languages such as Fortran + where certain types of tokens can't be conveniently expressed as regular + expressions (and where the tokenizing function may want to perform a + little backtracking). Suggested by Pearu Peterson. + +6/20/01 : beazley + Modified yacc() function so that an optional starting symbol can be specified. + For example: + + yacc.yacc(start="statement") + + Normally yacc always treats the first production rule as the starting symbol. + However, if you are debugging your grammar it may be useful to specify + an alternative starting symbol. Idea suggested by Rich Salz. + +Version 1.0 June 18, 2001 +-------------------------- +Initial public offering + diff --git a/ext/ply/COPYING b/ext/ply/COPYING new file mode 100644 index 000000000..b1e3f5a26 --- /dev/null +++ b/ext/ply/COPYING @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/ext/ply/README b/ext/ply/README new file mode 100644 index 000000000..35b458d4c --- /dev/null +++ b/ext/ply/README @@ -0,0 +1,249 @@ +PLY (Python Lex-Yacc) Version 1.2 (November 27, 2002) + +David M. Beazley +Department of Computer Science +University of Chicago +Chicago, IL 60637 +beazley@cs.uchicago.edu + +Copyright (C) 2001 David M. Beazley + +$Header: /home/stever/bk/newmem2/ext/ply/README 1.1 03/06/06 14:53:34-00:00 stever@ $ + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +See the file COPYING for a complete copy of the LGPL. + +Introduction +============ + +PLY is a 100% Python implementation of the common parsing tools lex +and yacc. Although several other parsing tools are available for +Python, there are several reasons why you might want to consider PLY: + + - The tools are very closely modeled after traditional lex/yacc. + If you know how to use these tools in C, you will find PLY + to be similar. + + - PLY provides *very* extensive error reporting and diagnostic + information to assist in parser construction. The original + implementation was developed for instructional purposes. As + a result, the system tries to identify the most common types + of errors made by novice users. + + - PLY provides full support for empty productions, error recovery, + precedence specifiers, and moderately ambiguous grammars. + + - Parsing is based on LR-parsing which is fast, memory efficient, + better suited to large grammars, and which has a number of nice + properties when dealing with syntax errors and other parsing problems. + Currently, PLY builds its parsing tables using the SLR algorithm which + is slightly weaker than LALR(1) used in traditional yacc. + + - Like John Aycock's excellent SPARK toolkit, PLY uses Python + reflection to build lexers and parsers. This greatly simplifies + the task of parser construction since it reduces the number of files + and eliminates the need to run a separate lex/yacc tool before + running your program. + + - PLY can be used to build parsers for "real" programming languages. + Although it is not ultra-fast due to its Python implementation, + PLY can be used to parse grammars consisting of several hundred + rules (as might be found for a language like C). The lexer and LR + parser are also reasonably efficient when parsing typically + sized programs. + +The original version of PLY was developed for an Introduction to +Compilers course where students used it to build a compiler for a +simple Pascal-like language. Their compiler had to include lexical +analysis, parsing, type checking, type inference, and generation of +assembly code for the SPARC processor. Because of this, the current +implementation has been extensively tested and debugged. In addition, +most of the API and error checking steps have been adapted to address +common usability problems. + +How to Use +========== + +PLY consists of two files : lex.py and yacc.py. To use the system, +simply copy these files to your project and import them like standard +Python modules. + +The file doc/ply.html contains complete documentation on how to use +the system. + +The example directory contains several different examples including a +PLY specification for ANSI C as given in K&R 2nd Ed. Note: To use +the examples, you will need to copy the lex.py and yacc.py files to +the example directory. + +A simple example is found at the end of this document + +Requirements +============ +PLY requires the use of Python 2.0 or greater. It should work on +just about any platform. + +Resources +========= + +More information about PLY can be obtained on the PLY webpage at: + + http://systems.cs.uchicago.edu/ply + +For a detailed overview of parsing theory, consult the excellent +book "Compilers : Principles, Techniques, and Tools" by Aho, Sethi, and +Ullman. The topics found in "Lex & Yacc" by Levine, Mason, and Brown +may also be useful. + +Given that this is the first release, I welcome your comments on how +to improve the current implementation. See the TODO file for things that +still need to be done. + +Acknowledgments +=============== + +A special thanks is in order for all of the students in CS326 who +suffered through about 25 different versions of these tools :-). + +Example +======= + +Here is a simple example showing a PLY implementation of a calculator with variables. + +# ----------------------------------------------------------------------------- +# calc.py +# +# A simple calculator with variables. +# ----------------------------------------------------------------------------- + +tokens = ( + 'NAME','NUMBER', + 'PLUS','MINUS','TIMES','DIVIDE','EQUALS', + 'LPAREN','RPAREN', + ) + +# Tokens + +t_PLUS = r'\+' +t_MINUS = r'-' +t_TIMES = r'\*' +t_DIVIDE = r'/' +t_EQUALS = r'=' +t_LPAREN = r'\(' +t_RPAREN = r'\)' +t_NAME = r'[a-zA-Z_][a-zA-Z0-9_]*' + +def t_NUMBER(t): + r'\d+' + try: + t.value = int(t.value) + except ValueError: + print "Integer value too large", t.value + t.value = 0 + return t + +# Ignored characters +t_ignore = " \t" + +def t_newline(t): + r'\n+' + t.lineno += t.value.count("\n") + +def t_error(t): + print "Illegal character '%s'" % t.value[0] + t.skip(1) + +# Build the lexer +import lex +lex.lex() + +# Precedence rules for the arithmetic operators +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names (for storing variables) +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[2] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + +while 1: + try: + s = raw_input('calc > ') + except EOFError: + break + yacc.parse(s) + + + + + + + + + + + + + + + + + diff --git a/ext/ply/TODO b/ext/ply/TODO new file mode 100644 index 000000000..b2978150d --- /dev/null +++ b/ext/ply/TODO @@ -0,0 +1,22 @@ +The PLY to-do list: + +$Header: /home/stever/bk/newmem2/ext/ply/TODO 1.1 03/06/06 14:53:34-00:00 stever@ $ + +1. Create a Python package using distutils + +2. More interesting parsing examples. + +3. Work on the ANSI C grammar so that it can actually parse C programs. To do this, + some extra code needs to be added to the lexer to deal with typedef names and enumeration + constants. + +4. Get LALR(1) to work. Hard, but not impossible. + +5. More tests in the test directory. + +6. Performance improvements and cleanup in yacc.py. + +7. More documentation. + +8. Lots and lots of cleanup. + diff --git a/ext/ply/doc/ply.html b/ext/ply/doc/ply.html new file mode 100644 index 000000000..2596066fe --- /dev/null +++ b/ext/ply/doc/ply.html @@ -0,0 +1,1642 @@ +<html> +<head> +<title>PLY (Python Lex-Yacc)</title> +</head> +<body bgcolor="#ffffff"> + +<h1>PLY (Python Lex-Yacc)</h1> + +<b> +David M. Beazley <br> +Department of Computer Science <br> +University of Chicago <br> +Chicago, IL 60637 <br> +beazley@cs.uchicago.edu <br> +</b> + +<p> +Documentation version: $Header: /home/stever/bk/newmem2/ext/ply/doc/ply.html 1.1 03/06/06 14:53:34-00:00 stever@ $ + +<h2>Introduction</h2> + +PLY is a Python-only implementation of the popular compiler +construction tools lex and yacc. The implementation borrows ideas +from a number of previous efforts; most notably John Aycock's SPARK +toolkit. However, the overall flavor of the implementation is more +closely modeled after the C version of lex and yacc. The other +significant feature of PLY is that it provides extensive input +validation and error reporting--much more so than other Python parsing +tools. + +<p> +Early versions of PLY were developed to support the Introduction to +Compilers Course at the University of Chicago. In this course, +students built a fully functional compiler for a simple Pascal-like +language. Their compiler, implemented entirely in Python, had to +include lexical analysis, parsing, type checking, type inference, +nested scoping, and code generation for the SPARC processor. +Approximately 30 different compiler implementations were completed in +this course. Most of PLY's interface and operation has been motivated by common +usability problems encountered by students. + +<p> +Because PLY was primarily developed as an instructional tool, you will +find it to be <em>MUCH</em> more picky about token and grammar rule +specification than most other Python parsing tools. In part, this +added formality is meant to catch common programming mistakes made by +novice users. However, advanced users will also find such features to +be useful when building complicated grammars for real programming +languages. It should also be noted that PLY does not provide much in the way +of bells and whistles (e.g., automatic construction of abstract syntax trees, +tree traversal, etc.). Instead, you will find a bare-bones, yet +fully capable lex/yacc implementation written entirely in Python. + +<p> +The rest of this document assumes that you are somewhat familar with +parsing theory, syntax directed translation, and automatic tools such +as lex and yacc. If you are unfamilar with these topics, you will +probably want to consult an introductory text such as "Compilers: +Principles, Techniques, and Tools", by Aho, Sethi, and Ullman. "Lex +and Yacc" by John Levine may also be handy. + +<h2>PLY Overview</h2> + +PLY consists of two separate tools; <tt>lex.py</tt> and +<tt>yacc.py</tt>. <tt>lex.py</tt> is used to break input text into a +collection of tokens specified by a collection of regular expression +rules. <tt>yacc.py</tt> is used to recognize language syntax that has +been specified in the form of a context free grammar. Currently, +<tt>yacc.py</tt> uses LR parsing and generates its parsing tables +using the SLR algorithm. LALR(1) parsing may be supported in a future +release. + +<p> +The two tools are meant to work together. Specifically, +<tt>lex.py</tt> provides an external interface in the form of a +<tt>token()</tt> function that returns the next valid token on the +input stream. <tt>yacc.py</tt> calls this repeatedly to retrieve +tokens and invoke grammar rules. The output of <tt>yacc.py</tt> is +often an Abstract Syntax Tree (AST). However, this is entirely up to +the user. If desired, <tt>yacc.py</tt> can also be used to implement +simple one-pass compilers. + +<p> +Like its Unix counterpart, <tt>yacc.py</tt> provides most of the +features you expect including extensive error checking, grammar +validation, support for empty productions, error tokens, and ambiguity +resolution via precedence rules. The primary difference between +<tt>yacc.py</tt> and <tt>yacc</tt> is the use of SLR parsing instead +of LALR(1). Although this slightly restricts the types of grammars +than can be successfully parsed, it is sufficiently powerful to handle most +kinds of normal programming language constructs. + +<p> +Finally, it is important to note that PLY relies on reflection +(introspection) to build its lexers and parsers. Unlike traditional +lex/yacc which require a special input file that is converted into a +separate source file, the specifications given to PLY <em>are</em> +valid Python programs. This means that there are no extra source +files nor is there a special compiler construction step (e.g., running +yacc to generate Python code for the compiler). + +<h2>Lex Example</h2> + +<tt>lex.py</tt> is used to write tokenizers. To do this, each token +must be defined by a regular expression rule. The following file +implements a very simple lexer for tokenizing simple integer expressions: + +<blockquote> +<pre> +# ------------------------------------------------------------ +# calclex.py +# +# tokenizer for a simple expression evaluator for +# numbers and +,-,*,/ +# ------------------------------------------------------------ +import lex + +# List of token names. This is always required +tokens = ( + 'NUMBER', + 'PLUS', + 'MINUS', + 'TIMES', + 'DIVIDE', + 'LPAREN', + 'RPAREN', +) + +# Regular expression rules for simple tokens +t_PLUS = r'\+' +t_MINUS = r'-' +t_TIMES = r'\*' +t_DIVIDE = r'/' +t_LPAREN = r'\(' +t_RPAREN = r'\)' + +# A regular expression rule with some action code +def t_NUMBER(t): + r'\d+' + try: + t.value = int(t.value) + except ValueError: + print "Line %d: Number %s is too large!" % (t.lineno,t.value) + t.value = 0 + return t + +# Define a rule so we can track line numbers +def t_newline(t): + r'\n+' + t.lineno += len(t.value) + +# A string containing ignored characters (spaces and tabs) +t_ignore = ' \t' + +# Error handling rule +def t_error(t): + print "Illegal character '%s'" % t.value[0] + t.skip(1) + +# Build the lexer +lex.lex() + +# Test it out +data = ''' +3 + 4 * 10 + + -20 *2 +''' + +# Give the lexer some input +lex.input(data) + +# Tokenize +while 1: + tok = lex.token() + if not tok: break # No more input + print tok +</pre> +</blockquote> + +In the example, the <tt>tokens</tt> list defines all of the possible +token names that can be produced by the lexer. This list is always required +and is used to perform a variety of validation checks. Following the <tt>tokens</tt> +list, regular expressions are written for each token. Each of these +rules are defined by making declarations with a special prefix <tt>t_</tt> to indicate that it +defines a token. For simple tokens, the regular expression can +be specified as strings such as this (note: Python raw strings are used since they are the +most convenient way to write regular expression strings): + +<blockquote> +<pre> +t_PLUS = r'\+' +</pre> +</blockquote> + +In this case, the name following the <tt>t_</tt> must exactly match one of the +names supplied in <tt>tokens</tt>. If some kind of action needs to be performed, +a token rule can be specified as a function. For example: + +<blockquote> +<pre> +def t_NUMBER(t): + r'\d+' + try: + t.value = int(t.value) + except ValueError: + print "Number %s is too large!" % t.value + t.value = 0 + return t +</pre> +</blockquote> + +In this case, the regular expression rule is specified in the function documentation string. +The function always takes a single argument which is an instance of +<tt>LexToken</tt>. This object has attributes of <tt>t.type</tt> which is the token type, +<tt>t.value</tt> which is the lexeme, and <tt>t.lineno</tt> which is the current line number. +By default, <tt>t.type</tt> is set to the name following the <tt>t_</tt> prefix. The action +function can modify the contents of the <tt>LexToken</tt> object as appropriate. However, +when it is done, the resulting token should be returned. If no value is returned by the action +function, the token is simply discarded and the next token read. + +<p> +The rule <tt>t_newline()</tt> illustrates a regular expression rule +for a discarded token. In this case, a rule is written to match +newlines so that proper line number tracking can be performed. +By returning no value, the function causes the newline character to be +discarded. + +<p> +The special <tt>t_ignore</tt> rule is reserved by <tt>lex.py</tt> for characters +that should be completely ignored in the input stream. +Usually this is used to skip over whitespace and other non-essential characters. +Although it is possible to define a regular expression rule for whitespace in a manner +similar to <tt>t_newline()</tt>, the use of <tt>t_ignore</tt> provides substantially better +lexing performance because it is handled as a special case and is checked in a much +more efficient manner than the normal regular expression rules. + +<p> +Finally, the <tt>t_error()</tt> +function is used to handle lexing errors that occur when illegal +characters are detected. In this case, the <tt>t.value</tt> attribute contains the +rest of the input string that has not been tokenized. In the example, we simply print +the offending character and skip ahead one character by calling <tt>t.skip(1)</tt>. + +<p> +To build the lexer, the function <tt>lex.lex()</tt> is used. This function +uses Python reflection (or introspection) to read the the regular expression rules +out of the calling context and build the lexer. Once the lexer has been built, two functions can +be used to control the lexer. + +<ul> +<li><tt>lex.input(data)</tt>. Reset the lexer and store a new input string. +<li><tt>lex.token()</tt>. Return the next token. Returns a special <tt>LexToken</tt> instance on success or +None if the end of the input text has been reached. +</ul> + +The code at the bottom of the example shows how the lexer is actually used. When executed, +the following output will be produced: + +<blockquote> +<pre> +$ python example.py +LexToken(NUMBER,3,2) +LexToken(PLUS,'+',2) +LexToken(NUMBER,4,2) +LexToken(TIMES,'*',2) +LexToken(NUMBER,10,2) +LexToken(PLUS,'+',3) +LexToken(MINUS,'-',3) +LexToken(NUMBER,20,3) +LexToken(TIMES,'*',3) +LexToken(NUMBER,2,3) +</pre> +</blockquote> + +<h2>Lex Implementation Notes</h2> + +<ul> +<li><tt>lex.py</tt> uses the <tt>re</tt> module to do its patten matching. When building the master regular expression, +rules are added in the following order: +<p> +<ol> +<li>All tokens defined by functions are added in the same order as they appear in the lexer file. +<li>Tokens defined by strings are added by sorting them in order of decreasing regular expression length (longer expressions +are added first). +</ol> +<p> +Without this ordering, it can be difficult to correctly match certain types of tokens. For example, if you +wanted to have separate tokens for "=" and "==", you need to make sure that "==" is checked first. By sorting regular +expressions in order of decreasing length, this problem is solved for rules defined as strings. For functions, +the order can be explicitly controlled since rules appearing first are checked first. + +<P> +<li>The lexer requires input to be supplied as a single input string. Since most machines have more than enough memory, this +rarely presents a performance concern. However, it means that the lexer currently can't be used with streaming data +such as open files or sockets. This limitation is primarily a side-effect of using the <tt>re</tt> module. + +<p> +<li> +To handle reserved words, it is usually easier to just match an identifier and do a special name lookup in a function +like this: + +<blockquote> +<pre> +reserved = { + 'if' : 'IF', + 'then' : 'THEN', + 'else' : 'ELSE', + 'while' : 'WHILE', + ... +} + +def t_ID(t): + r'[a-zA-Z_][a-zA-Z_0-9]*' + t.type = reserved.get(t.value,'ID') # Check for reserved words + return t +</pre> +</blockquote> + +<p> +<li>The lexer requires tokens to be defined as class instances with <tt>t.type</tt>, <tt>t.value</tt>, and <tt>t.lineno</tt> +attributes. By default, tokens are created as instances of the <tt>LexToken</tt> class defined internally to <tt>lex.py</tt>. +If desired, you can create new kinds of tokens provided that they have the three required attributes. However, +in practice, it is probably safer to stick with the default. + +<p> +<li>The only safe attribute for assigning token properties is <tt>t.value</tt>. In some cases, you may want to attach +a number of different properties to a token (e.g., symbol table entries for identifiers). To do this, replace <tt>t.value</tt> +with a tuple or class instance. For example: + +<blockquote> +<pre> +def t_ID(t): + ... + # For identifiers, create a (lexeme, symtab) tuple + t.value = (t.value, symbol_lookup(t.value)) + ... + return t +</pre> +</blockquote> + +Although allowed, do NOT assign additional attributes to the token object. For example, +<blockquote> +<pre> +def t_ID(t): + ... + # Bad implementation of above + t.symtab = symbol_lookup(t.value) + ... +</pre> +</blockquote> + +The reason you don't want to do this is that the <tt>yacc.py</tt> +module only provides public access to the <tt>t.value</tt> attribute of each token. +Therefore, any other attributes you assign are inaccessible (if you are familiar +with the internals of C lex/yacc, <tt>t.value</tt> is the same as <tt>yylval.tok</tt>). + +<p> +<li>To track line numbers, the lexer internally maintains a line +number variable. Each token automatically gets the value of the +current line number in the <tt>t.lineno</tt> attribute. To modify the +current line number, simply change the <tt>t.lineno</tt> attribute +in a function rule (as previously shown for +<tt>t_newline()</tt>). Even if the resulting token is discarded, +changes to the line number remain in effect for subsequent tokens. + +<p> +<li>To support multiple scanners in the same application, the <tt>lex.lex()</tt> function +actually returns a special <tt>Lexer</tt> object. This object has two methods +<tt>input()</tt> and <tt>token()</tt> that can be used to supply input and get tokens. For example: + +<blockquote> +<pre> +lexer = lex.lex() +lexer.input(sometext) +while 1: + tok = lexer.token() + if not tok: break + print tok +</pre> +</blockquote> + +The functions <tt>lex.input()</tt> and <tt>lex.token()</tt> are bound to the <tt>input()</tt> +and <tt>token()</tt> methods of the last lexer created by the lex module. + + +<p> +<li>To reduce compiler startup time and improve performance, the lexer can be built in optimized mode as follows: + +<blockquote> +<pre> +lex.lex(optimize=1) +</pre> +</blockquote> + +When used, most error checking and validation is disabled. This provides a slight performance +gain while tokenizing and tends to chop a few tenths of a second off startup time. Since it disables +error checking, this mode is not the default and is not recommended during development. However, once +you have your compiler fully working, it is usually safe to disable the error checks. + +<p> +<li>You can enable some additional debugging by building the lexer like this: + +<blockquote> +<pre> +lex.lex(debug=1) +</pre> +</blockquote> + +<p> +<li>To help you debug your lexer, <tt>lex.py</tt> comes with a simple main program which will either +tokenize input read from standard input or from a file. To use it, simply put this in your lexer: + +<blockquote> +<pre> +if __name__ == '__main__': + lex.runmain() +</pre> +</blockquote> + +Then, run you lexer as a main program such as <tt>python mylex.py</tt> + +<p> +<li>Since the lexer is written entirely in Python, its performance is +largely determined by that of the Python <tt>re</tt> module. Although +the lexer has been written to be as efficient as possible, it's not +blazingly fast when used on very large input files. Sorry. If +performance is concern, you might consider upgrading to the most +recent version of Python, creating a hand-written lexer, or offloading +the lexer into a C extension module. In defense of <tt>lex.py</tt>, +it's performance is not <em>that</em> bad when used on reasonably +sized input files. For instance, lexing a 4700 line C program with +32000 input tokens takes about 20 seconds on a 200 Mhz PC. Obviously, +it will run much faster on a more speedy machine. + +</ul> + +<h2>Parsing basics</h2> + +<tt>yacc.py</tt> is used to parse language syntax. Before showing an +example, there are a few important bits of background that must be +mentioned. First, <tt>syntax</tt> is usually specified in terms of a +context free grammar (CFG). For example, if you wanted to parse +simple arithmetic expressions, you might first write an unambiguous +grammar specification like this: + +<blockquote> +<pre> +expression : expression + term + | expression - term + | term + +term : term * factor + | term / factor + | factor + +factor : NUMBER + | ( expression ) +</pre> +</blockquote> + +Next, the semantic behavior of a language is often specified using a +technique known as syntax directed translation. In syntax directed +translation, attributes are attached to each symbol in a given grammar +rule along with an action. Whenever a particular grammar rule is +recognized, the action describes what to do. For example, given the +expression grammar above, you might write the specification for a +simple calculator like this: + +<blockquote> +<pre> +Grammar Action +-------------------------------- -------------------------------------------- +expression0 : expression1 + term expression0.val = expression1.val + term.val + | expression1 - term expression0.val = expression1.val - term.val + | term expression0.val = term.val + +term0 : term1 * factor term0.val = term1.val * factor.val + | term1 / factor term0.val = term1.val / factor.val + | factor term0.val = factor.val + +factor : NUMBER factor.val = int(NUMBER.lexval) + | ( expression ) factor.val = expression.val +</pre> +</blockquote> + +Finally, Yacc uses a parsing technique known as LR-parsing or shift-reduce parsing. LR parsing is a +bottom up technique that tries to recognize the right-hand-side of various grammar rules. +Whenever a valid right-hand-side is found in the input, the appropriate action code is triggered and the +grammar symbols are replaced by the grammar symbol on the left-hand-side. + +<p> +LR parsing is commonly implemented by shifting grammar symbols onto a stack and looking at the stack and the next +input token for patterns. The details of the algorithm can be found in a compiler text, but the +following example illustrates the steps that are performed if you wanted to parse the expression +<tt>3 + 5 * (10 - 20)</tt> using the grammar defined above: + +<blockquote> +<pre> +Step Symbol Stack Input Tokens Action +---- --------------------- --------------------- ------------------------------- +1 $ 3 + 5 * ( 10 - 20 )$ Shift 3 +2 $ 3 + 5 * ( 10 - 20 )$ Reduce factor : NUMBER +3 $ factor + 5 * ( 10 - 20 )$ Reduce term : factor +4 $ term + 5 * ( 10 - 20 )$ Reduce expr : term +5 $ expr + 5 * ( 10 - 20 )$ Shift + +6 $ expr + 5 * ( 10 - 20 )$ Shift 5 +7 $ expr + 5 * ( 10 - 20 )$ Reduce factor : NUMBER +8 $ expr + factor * ( 10 - 20 )$ Reduce term : factor +9 $ expr + term * ( 10 - 20 )$ Shift * +10 $ expr + term * ( 10 - 20 )$ Shift ( +11 $ expr + term * ( 10 - 20 )$ Shift 10 +12 $ expr + term * ( 10 - 20 )$ Reduce factor : NUMBER +13 $ expr + term * ( factor - 20 )$ Reduce term : factor +14 $ expr + term * ( term - 20 )$ Reduce expr : term +15 $ expr + term * ( expr - 20 )$ Shift - +16 $ expr + term * ( expr - 20 )$ Shift 20 +17 $ expr + term * ( expr - 20 )$ Reduce factor : NUMBER +18 $ expr + term * ( expr - factor )$ Reduce term : factor +19 $ expr + term * ( expr - term )$ Reduce expr : expr - term +20 $ expr + term * ( expr )$ Shift ) +21 $ expr + term * ( expr ) $ Reduce factor : (expr) +22 $ expr + term * factor $ Reduce term : term * factor +23 $ expr + term $ Reduce expr : expr + term +24 $ expr $ Reduce expr +25 $ $ Success! +</pre> +</blockquote> + +When parsing the expression, an underlying state machine and the current input token determine what to do next. +If the next token looks like part of a valid grammar rule (based on other items on the stack), it is generally shifted +onto the stack. If the top of the stack contains a valid right-hand-side of a grammar rule, it is +usually "reduced" and the symbols replaced with the symbol on the left-hand-side. When this reduction occurs, the +appropriate action is triggered (if defined). If the input token can't be shifted and the top of stack doesn't match +any grammar rules, a syntax error has occurred and the parser must take some kind of recovery step (or bail out). + +<p> +It is important to note that the underlying implementation is actually built around a large finite-state machine +and some tables. The construction of these tables is quite complicated and beyond the scope of this discussion. +However, subtle details of this process explain why, in the example above, the parser chooses to shift a token +onto the stack in step 9 rather than reducing the rule <tt>expr : expr + term</tt>. + +<h2>Yacc example</h2> + +Suppose you wanted to make a grammar for simple arithmetic expressions as previously described. Here is +how you would do it with <tt>yacc.py</tt>: + +<blockquote> +<pre> +# Yacc example + +import yacc + +# Get the token map from the lexer. This is required. +from calclex import tokens + +def p_expression_plus(t): + 'expression : expression PLUS term' + t[0] = t[1] + t[3] + +def p_expression_minus(t): + 'expression : expression MINUS term' + t[0] = t[1] - t[3] + +def p_expression_term(t): + 'expression : term' + t[0] = t[1] + +def p_term_times(t): + 'term : term TIMES factor' + t[0] = t[1] * t[3] + +def p_term_div(t): + 'term : term DIVIDE factor' + t[0] = t[1] / t[3] + +def p_term_factor(t): + 'term : factor' + t[0] = t[1] + +def p_factor_num(t): + 'factor : NUMBER' + t[0] = t[1] + +def p_factor_expr(t): + 'factor : LPAREN expression RPAREN' + t[0] = t[2] + +# Error rule for syntax errors +def p_error(t): + print "Syntax error in input!" + +# Build the parser +yacc.yacc() + +while 1: + try: + s = raw_input('calc > ') + except EOFError: + break + if not s: continue + result = yacc.parse(s) + print result +</pre> +</blockquote> + +In this example, each grammar rule is defined by a Python function where the docstring to that function contains the +appropriate context-free grammar specification (an idea borrowed from John Aycock's SPARK toolkit). Each function accepts a single +argument <tt>t</tt> that is a sequence containing the values of each grammar symbol in the corresponding rule. The values of +<tt>t[i]</tt> are mapped to grammar symbols as shown here: + +<blockquote> +<pre> +def p_expression_plus(t): + 'expression : expression PLUS term' + # ^ ^ ^ ^ + # t[0] t[1] t[2] t[3] + + t[0] = t[1] + t[3] +</pre> +</blockquote> + +For tokens, the "value" in the corresponding <tt>t[i]</tt> is the +<em>same</em> as the value of the <tt>t.value</tt> attribute assigned +in the lexer module. For non-terminals, the value is determined by +whatever is placed in <tt>t[0]</tt> when rules are reduced. This +value can be anything at all. However, it probably most common for +the value to be a simple Python type, a tuple, or an instance. In this example, we +are relying on the fact that the <tt>NUMBER</tt> token stores an integer value in its value +field. All of the other rules simply perform various types of integer operations and store +the result. + +<p> +The first rule defined in the yacc specification determines the starting grammar +symbol (in this case, a rule for <tt>expression</tt> appears first). Whenever +the starting rule is reduced by the parser and no more input is available, parsing +stops and the final value is returned (this value will be whatever the top-most rule +placed in <tt>t[0]</tt>). + +<p>The <tt>p_error(t)</tt> rule is defined to catch syntax errors. See the error handling section +below for more detail. + +<p> +To build the parser, call the <tt>yacc.yacc()</tt> function. This function +looks at the module and attempts to construct all of the LR parsing tables for the grammar +you have specified. The first time <tt>yacc.yacc()</tt> is invoked, you will get a message +such as this: + +<blockquote> +<pre> +$ python calcparse.py +yacc: Generating SLR parsing table... +calc > +</pre> +</blockquote> + +Since table construction is relatively expensive (especially for large +grammars), the resulting parsing table is written to the current +directory in a file called <tt>parsetab.py</tt>. In addition, a +debugging file called <tt>parser.out</tt> is created. On subsequent +executions, <tt>yacc</tt> will reload the table from +<tt>parsetab.py</tt> unless it has detected a change in the underlying +grammar (in which case the tables and <tt>parsetab.py</tt> file are +regenerated). + +<p> +If any errors are detected in your grammar specification, <tt>yacc.py</tt> will produce +diagnostic messages and possibly raise an exception. Some of the errors that can be detected include: + +<ul> +<li>Duplicated function names (if more than one rule function have the same name in the grammar file). +<li>Shift/reduce and reduce/reduce conflicts generated by ambiguous grammars. +<li>Badly specified grammar rules. +<li>Infinite recursion (rules that can never terminate). +<li>Unused rules and tokens +<li>Undefined rules and tokens +</ul> + +The next few sections now discuss a few finer points of grammar construction. + +<h2>Combining Grammar Rule Functions</h2> + +When grammar rules are similar, they can be combined into a single function. +For example, consider the two rules in our earlier example: + +<blockquote> +<pre> +def p_expression_plus(t): + 'expression : expression PLUS term' + t[0] = t[1] + t[3] + +def p_expression_minus(t): + 'expression : expression MINUS term' + t[0] = t[1] - t[3] +</pre> +</blockquote> + +Instead of writing two functions, you might write a single function like this: + +<blockquote> +<pre> +def p_expression(t): + '''expression : expression PLUS term + | expression MINUS term''' + if t[2] == '+': + t[0] = t[1] + t[3] + elif t[2] == '-': + t[0] = t[1] - t[3] +</pre> +</blockquote> + +In general, the doc string for any given function can contain multiple grammar rules. So, it would +have also been legal (although possibly confusing) to write this: + +<blockquote> +<pre> +def p_binary_operators(t): + '''expression : expression PLUS term + | expression MINUS term + term : term TIMES factor + | term DIVIDE factor''' + if t[2] == '+': + t[0] = t[1] + t[3] + elif t[2] == '-': + t[0] = t[1] - t[3] + elif t[2] == '*': + t[0] = t[1] * t[3] + elif t[2] == '/': + t[0] = t[1] / t[3] +</pre> +</blockquote> + +When combining grammar rules into a single function, it is usually a good idea for all of the rules to have +a similar structure (e.g., the same number of terms). Otherwise, the corresponding action code may be more +complicated than necessary. + +<h2>Empty Productions</h2> + +<tt>yacc.py</tt> can handle empty productions by defining a rule like this: + +<blockquote> +<pre> +def p_empty(t): + 'empty :' + pass +</pre> +</blockquote> + +Now to use the empty production, simply use 'empty' as a symbol. For example: + +<blockquote> +<pre> +def p_optitem(t): + 'optitem : item' + ' | empty' + ... +</pre> +</blockquote> + +<h2>Dealing With Ambiguous Grammars</h2> + +The expression grammar given in the earlier example has been written in a special format to eliminate ambiguity. +However, in many situations, it is extremely difficult or awkward to write grammars in this format. A +much more natural way to express the grammar is in a more compact form like this: + +<blockquote> +<pre> +expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression + | LPAREN expression RPAREN + | NUMBER +</pre> +</blockquote> + +Unfortunately, this grammar specification is ambiguous. For example, if you are parsing the string +"3 * 4 + 5", there is no way to tell how the operators are supposed to be grouped. +For example, does this expression mean "(3 * 4) + 5" or is it "3 * (4+5)"? + +<p> +When an ambiguous grammar is given to <tt>yacc.py</tt> it will print messages about "shift/reduce conflicts" +or a "reduce/reduce conflicts". A shift/reduce conflict is caused when the parser generator can't decide +whether or not to reduce a rule or shift a symbol on the parsing stack. For example, consider +the string "3 * 4 + 5" and the internal parsing stack: + +<blockquote> +<pre> +Step Symbol Stack Input Tokens Action +---- --------------------- --------------------- ------------------------------- +1 $ 3 * 4 + 5$ Shift 3 +2 $ 3 * 4 + 5$ Reduce : expression : NUMBER +3 $ expr * 4 + 5$ Shift * +4 $ expr * 4 + 5$ Shift 4 +5 $ expr * 4 + 5$ Reduce: expression : NUMBER +6 $ expr * expr + 5$ SHIFT/REDUCE CONFLICT ???? +</pre> +</blockquote> + +In this case, when the parser reaches step 6, it has two options. One is the reduce the +rule <tt>expr : expr * expr</tt> on the stack. The other option is to shift the +token <tt>+</tt> on the stack. Both options are perfectly legal from the rules +of the context-free-grammar. + +<p> +By default, all shift/reduce conflicts are resolved in favor of shifting. Therefore, in the above +example, the parser will always shift the <tt>+</tt> instead of reducing. Although this +strategy works in many cases (including the ambiguous if-then-else), it is not enough for arithmetic +expressions. In fact, in the above example, the decision to shift <tt>+</tt> is completely wrong---we should have +reduced <tt>expr * expr</tt> since multiplication has higher precedence than addition. + +<p>To resolve ambiguity, especially in expression grammars, <tt>yacc.py</tt> allows individual +tokens to be assigned a precedence level and associativity. This is done by adding a variable +<tt>precedence</tt> to the grammar file like this: + +<blockquote> +<pre> +precedence = ( + ('left', 'PLUS', 'MINUS'), + ('left', 'TIMES', 'DIVIDE'), +) +</pre> +</blockquote> + +This declaration specifies that <tt>PLUS</tt>/<tt>MINUS</tt> have +the same precedence level and are left-associative and that +<tt>TIMES</tt>/<tt>DIVIDE</tt> have the same precedence and are left-associative. +Furthermore, the declaration specifies that <tt>TIMES</tt>/<tt>DIVIDE</tt> have higher +precedence than <tt>PLUS</tt>/<tt>MINUS</tt> (since they appear later in the +precedence specification). + +<p> +The precedence specification is used to attach a numerical precedence value and associativity direction +to each grammar rule. This is always determined by the precedence of the right-most terminal symbol. Therefore, +if PLUS/MINUS had a precedence of 1 and TIMES/DIVIDE had a precedence of 2, the grammar rules +would have precedence values as follows: + +<blockquote> +<pre> +expression : expression PLUS expression # prec = 1, left + | expression MINUS expression # prec = 1, left + | expression TIMES expression # prec = 2, left + | expression DIVIDE expression # prec = 2, left + | LPAREN expression RPAREN # prec = unknown + | NUMBER # prec = unknown +</pre> +</blockquote> + +When shift/reduce conflicts are encountered, the parser generator resolves the conflict by +looking at the precedence rules and associativity specifiers. + +<p> +<ol> +<li>If the current token has higher precedence, it is shifted. +<li>If the grammar rule on the stack has higher precedence, the rule is reduced. +<li>If the current token and the grammar rule have the same precedence, the +rule is reduced for left associativity, whereas the token is shifted for right associativity. +<li>If nothing is known about the precedence, shift/reduce conflicts are resolved in +favor of shifting (the default). +</ol> + +<p> +When shift/reduce conflicts are resolved using the first three techniques (with the help of +precedence rules), <tt>yacc.py</tt> will report no errors or conflicts in the grammar. + +<p> +One problem with the precedence specifier technique is that it is sometimes necessary to +change the precedence of an operator in certain contents. For example, consider a unary-minus operator +in "3 + 4 * -5". Normally, unary minus has a very high precedence--being evaluated before the multiply. +However, in our precedence specifier, MINUS has a lower precedence than TIMES. To deal with this, +precedence rules can be given for fictitious tokens like this: + +<blockquote> +<pre> +precedence = ( + ('left', 'PLUS', 'MINUS'), + ('left', 'TIMES', 'DIVIDE'), + ('right', 'UMINUS'), # Unary minus operator +) +</pre> +</blockquote> + +Now, in the grammar file, we can write our unary minus rule like this: + +<blockquote> +<pre> +def p_expr_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] +</pre> +</blockquote> + +In this case, <tt>%prec UMINUS</tt> overrides the default rule precedence--setting it to that +of UMINUS in the precedence specifier. + +<p> +It is also possible to specify non-associativity in the <tt>precedence</tt> table. This would +be used when you <em>don't</em> want operations to chain together. For example, suppose +you wanted to support a comparison operators like <tt><</tt> and <tt>></tt> but you didn't want to allow +combinations like <tt>a < b < c</tt>. To do this, simply specify a rule like this: + +<blockquote> +<pre> +precedence = ( + ('nonassoc', 'LESSTHAN', 'GREATERTHAN'), # Nonassociative operators + ('left', 'PLUS', 'MINUS'), + ('left', 'TIMES', 'DIVIDE'), + ('right', 'UMINUS'), # Unary minus operator +) +</pre> +</blockquote> + +<p> +Reduce/reduce conflicts are caused when there are multiple grammar +rules that can be applied to a given set of symbols. This kind of +conflict is almost always bad and is always resolved by picking the +rule that appears first in the grammar file. Reduce/reduce conflicts +are almost always caused when different sets of grammar rules somehow +generate the same set of symbols. For example: + +<blockquote> +<pre> +assignment : ID EQUALS NUMBER + | ID EQUALS expression + +expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression + | LPAREN expression RPAREN + | NUMBER +</pre> +</blockquote> + +In this case, a reduce/reduce conflict exists between these two rules: + +<blockquote> +<pre> +assignment : ID EQUALS NUMBER +expression : NUMBER +</pre> +</blockquote> + +For example, if you wrote "a = 5", the parser can't figure out if this +is supposed to reduced as <tt>assignment : ID EQUALS NUMBER</tt> or +whether it's supposed to reduce the 5 as an expression and then reduce +the rule <tt>assignment : ID EQUALS expression</tt>. + +<h2>The parser.out file</h2> + +Tracking down shift/reduce and reduce/reduce conflicts is one of the finer pleasures of using an LR +parsing algorithm. To assist in debugging, <tt>yacc.py</tt> creates a debugging file called +'parser.out' when it generates the parsing table. The contents of this file look like the following: + +<blockquote> +<pre> +Unused terminals: + + +Grammar + +Rule 1 expression -> expression PLUS expression +Rule 2 expression -> expression MINUS expression +Rule 3 expression -> expression TIMES expression +Rule 4 expression -> expression DIVIDE expression +Rule 5 expression -> NUMBER +Rule 6 expression -> LPAREN expression RPAREN + +Terminals, with rules where they appear + +TIMES : 3 +error : +MINUS : 2 +RPAREN : 6 +LPAREN : 6 +DIVIDE : 4 +PLUS : 1 +NUMBER : 5 + +Nonterminals, with rules where they appear + +expression : 1 1 2 2 3 3 4 4 6 0 + + +Parsing method: SLR + + +state 0 + + S' -> . expression + expression -> . expression PLUS expression + expression -> . expression MINUS expression + expression -> . expression TIMES expression + expression -> . expression DIVIDE expression + expression -> . NUMBER + expression -> . LPAREN expression RPAREN + + NUMBER shift and go to state 3 + LPAREN shift and go to state 2 + + +state 1 + + S' -> expression . + expression -> expression . PLUS expression + expression -> expression . MINUS expression + expression -> expression . TIMES expression + expression -> expression . DIVIDE expression + + PLUS shift and go to state 6 + MINUS shift and go to state 5 + TIMES shift and go to state 4 + DIVIDE shift and go to state 7 + + +state 2 + + expression -> LPAREN . expression RPAREN + expression -> . expression PLUS expression + expression -> . expression MINUS expression + expression -> . expression TIMES expression + expression -> . expression DIVIDE expression + expression -> . NUMBER + expression -> . LPAREN expression RPAREN + + NUMBER shift and go to state 3 + LPAREN shift and go to state 2 + + +state 3 + + expression -> NUMBER . + + $ reduce using rule 5 + PLUS reduce using rule 5 + MINUS reduce using rule 5 + TIMES reduce using rule 5 + DIVIDE reduce using rule 5 + RPAREN reduce using rule 5 + + +state 4 + + expression -> expression TIMES . expression + expression -> . expression PLUS expression + expression -> . expression MINUS expression + expression -> . expression TIMES expression + expression -> . expression DIVIDE expression + expression -> . NUMBER + expression -> . LPAREN expression RPAREN + + NUMBER shift and go to state 3 + LPAREN shift and go to state 2 + + +state 5 + + expression -> expression MINUS . expression + expression -> . expression PLUS expression + expression -> . expression MINUS expression + expression -> . expression TIMES expression + expression -> . expression DIVIDE expression + expression -> . NUMBER + expression -> . LPAREN expression RPAREN + + NUMBER shift and go to state 3 + LPAREN shift and go to state 2 + + +state 6 + + expression -> expression PLUS . expression + expression -> . expression PLUS expression + expression -> . expression MINUS expression + expression -> . expression TIMES expression + expression -> . expression DIVIDE expression + expression -> . NUMBER + expression -> . LPAREN expression RPAREN + + NUMBER shift and go to state 3 + LPAREN shift and go to state 2 + + +state 7 + + expression -> expression DIVIDE . expression + expression -> . expression PLUS expression + expression -> . expression MINUS expression + expression -> . expression TIMES expression + expression -> . expression DIVIDE expression + expression -> . NUMBER + expression -> . LPAREN expression RPAREN + + NUMBER shift and go to state 3 + LPAREN shift and go to state 2 + + +state 8 + + expression -> LPAREN expression . RPAREN + expression -> expression . PLUS expression + expression -> expression . MINUS expression + expression -> expression . TIMES expression + expression -> expression . DIVIDE expression + + RPAREN shift and go to state 13 + PLUS shift and go to state 6 + MINUS shift and go to state 5 + TIMES shift and go to state 4 + DIVIDE shift and go to state 7 + + +state 9 + + expression -> expression TIMES expression . + expression -> expression . PLUS expression + expression -> expression . MINUS expression + expression -> expression . TIMES expression + expression -> expression . DIVIDE expression + + $ reduce using rule 3 + PLUS reduce using rule 3 + MINUS reduce using rule 3 + TIMES reduce using rule 3 + DIVIDE reduce using rule 3 + RPAREN reduce using rule 3 + + ! PLUS [ shift and go to state 6 ] + ! MINUS [ shift and go to state 5 ] + ! TIMES [ shift and go to state 4 ] + ! DIVIDE [ shift and go to state 7 ] + +state 10 + + expression -> expression MINUS expression . + expression -> expression . PLUS expression + expression -> expression . MINUS expression + expression -> expression . TIMES expression + expression -> expression . DIVIDE expression + + $ reduce using rule 2 + PLUS reduce using rule 2 + MINUS reduce using rule 2 + RPAREN reduce using rule 2 + TIMES shift and go to state 4 + DIVIDE shift and go to state 7 + + ! TIMES [ reduce using rule 2 ] + ! DIVIDE [ reduce using rule 2 ] + ! PLUS [ shift and go to state 6 ] + ! MINUS [ shift and go to state 5 ] + +state 11 + + expression -> expression PLUS expression . + expression -> expression . PLUS expression + expression -> expression . MINUS expression + expression -> expression . TIMES expression + expression -> expression . DIVIDE expression + + $ reduce using rule 1 + PLUS reduce using rule 1 + MINUS reduce using rule 1 + RPAREN reduce using rule 1 + TIMES shift and go to state 4 + DIVIDE shift and go to state 7 + + ! TIMES [ reduce using rule 1 ] + ! DIVIDE [ reduce using rule 1 ] + ! PLUS [ shift and go to state 6 ] + ! MINUS [ shift and go to state 5 ] + +state 12 + + expression -> expression DIVIDE expression . + expression -> expression . PLUS expression + expression -> expression . MINUS expression + expression -> expression . TIMES expression + expression -> expression . DIVIDE expression + + $ reduce using rule 4 + PLUS reduce using rule 4 + MINUS reduce using rule 4 + TIMES reduce using rule 4 + DIVIDE reduce using rule 4 + RPAREN reduce using rule 4 + + ! PLUS [ shift and go to state 6 ] + ! MINUS [ shift and go to state 5 ] + ! TIMES [ shift and go to state 4 ] + ! DIVIDE [ shift and go to state 7 ] + +state 13 + + expression -> LPAREN expression RPAREN . + + $ reduce using rule 6 + PLUS reduce using rule 6 + MINUS reduce using rule 6 + TIMES reduce using rule 6 + DIVIDE reduce using rule 6 + RPAREN reduce using rule 6 +</pre> +</blockquote> + +In the file, each state of the grammar is described. Within each state the "." indicates the current +location of the parse within any applicable grammar rules. In addition, the actions for each valid +input token are listed. When a shift/reduce or reduce/reduce conflict arises, rules <em>not</em> selected +are prefixed with an !. For example: + +<blockquote> +<pre> + ! TIMES [ reduce using rule 2 ] + ! DIVIDE [ reduce using rule 2 ] + ! PLUS [ shift and go to state 6 ] + ! MINUS [ shift and go to state 5 ] +</pre> +</blockquote> + +By looking at these rules (and with a little practice), you can usually track down the source +of most parsing conflicts. It should also be stressed that not all shift-reduce conflicts are +bad. However, the only way to be sure that they are resolved correctly is to look at <tt>parser.out</tt>. + +<h2>Syntax Error Handling</h2> + +When a syntax error occurs during parsing, the error is immediately +detected (i.e., the parser does not read any more tokens beyond the +source of the error). Error recovery in LR parsers is a delicate +topic that involves ancient rituals and black-magic. The recovery mechanism +provided by <tt>yacc.py</tt> is comparable to Unix yacc so you may want +consult a book like O'Reilly's "Lex and Yacc" for some of the finer details. + +<p> +When a syntax error occurs, <tt>yacc.py</tt> performs the following steps: + +<ol> +<li>On the first occurrence of an error, the user-defined <tt>p_error()</tt> function +is called with the offending token as an argument. Afterwards, the parser enters +an "error-recovery" mode in which it will not make future calls to <tt>p_error()</tt> until it +has successfully shifted at least 3 tokens onto the parsing stack. + +<p> +<li>If no recovery action is taken in <tt>p_error()</tt>, the offending lookahead token is replaced +with a special <tt>error</tt> token. + +<p> +<li>If the offending lookahead token is already set to <tt>error</tt>, the top item of the parsing stack is +deleted. + +<p> +<li>If the entire parsing stack is unwound, the parser enters a restart state and attempts to start +parsing from its initial state. + +<p> +<li>If a grammar rule accepts <tt>error</tt> as a token, it will be +shifted onto the parsing stack. + +<p> +<li>If the top item of the parsing stack is <tt>error</tt>, lookahead tokens will be discarded until the +parser can successfully shift a new symbol or reduce a rule involving <tt>error</tt>. +</ol> + +<h4>Recovery and resynchronization with error rules</h4> + +The most well-behaved approach for handling syntax errors is to write grammar rules that include the <tt>error</tt> +token. For example, suppose your language had a grammar rule for a print statement like this: + +<blockquote> +<pre> +def p_statement_print(t): + 'statement : PRINT expr SEMI' + ... +</pre> +</blockquote> + +To account for the possibility of a bad expression, you might write an additional grammar rule like this: + +<blockquote> +<pre> +def p_statement_print_error(t): + 'statement : PRINT error SEMI' + print "Syntax error in print statement. Bad expression" + +</pre> +</blockquote> + +In this case, the <tt>error</tt> token will match any sequence of +tokens that might appear up to the first semicolon that is +encountered. Once the semicolon is reached, the rule will be +invoked and the <tt>error</tt> token will go away. + +<p> +This type of recovery is sometimes known as parser resynchronization. +The <tt>error</tt> token acts as a wildcard for any bad input text and +the token immediately following <tt>error</tt> acts as a +synchronization token. + +<p> +It is important to note that the <tt>error</tt> token usually does not appear as the last token +on the right in an error rule. For example: + +<blockquote> +<pre> +def p_statement_print_error(t): + 'statement : PRINT error' + print "Syntax error in print statement. Bad expression" +</pre> +</blockquote> + +This is because the first bad token encountered will cause the rule to +be reduced--which may make it difficult to recover if more bad tokens +immediately follow. + +<h4>Panic mode recovery</h4> + +An alternative error recovery scheme is to enter a panic mode recovery in which tokens are +discarded to a point where the parser might be able to recover in some sensible manner. + +<p> +Panic mode recovery is implemented entirely in the <tt>p_error()</tt> function. For example, this +function starts discarding tokens until it reaches a closing '}'. Then, it restarts the +parser in its initial state. + +<blockquote> +<pre> +def p_error(t): + print "Whoa. You are seriously hosed." + # Read ahead looking for a closing '}' + while 1: + tok = yacc.token() # Get the next token + if not tok or tok.type == 'RBRACE': break + yacc.restart() +</pre> +</blockquote> + +<p> +This function simply discards the bad token and tells the parser that the error was ok. + +<blockquote> +<pre> +def p_error(t): + print "Syntax error at token", t.type + # Just discard the token and tell the parser it's okay. + yacc.errok() +</pre> +</blockquote> + +<P> +Within the <tt>p_error()</tt> function, three functions are available to control the behavior +of the parser: +<p> +<ul> +<li><tt>yacc.errok()</tt>. This resets the parser state so it doesn't think it's in error-recovery +mode. This will prevent an <tt>error</tt> token from being generated and will reset the internal +error counters so that the next syntax error will call <tt>p_error()</tt> again. + +<p> +<li><tt>yacc.token()</tt>. This returns the next token on the input stream. + +<p> +<li><tt>yacc.restart()</tt>. This discards the entire parsing stack and resets the parser +to its initial state. +</ul> + +Note: these functions are only available when invoking <tt>p_error()</tt> and are not available +at any other time. + +<p> +To supply the next lookahead token to the parser, <tt>p_error()</tt> can return a token. This might be +useful if trying to synchronize on special characters. For example: + +<blockquote> +<pre> +def p_error(t): + # Read ahead looking for a terminating ";" + while 1: + tok = yacc.token() # Get the next token + if not tok or tok.type == 'SEMI': break + yacc.errok() + + # Return SEMI to the parser as the next lookahead token + return tok +</pre> +</blockquote> + +<h4>General comments on error handling</h4> + +For normal types of languages, error recovery with error rules and resynchronization characters is probably the most reliable +technique. This is because you can instrument the grammar to catch errors at selected places where it is relatively easy +to recover and continue parsing. Panic mode recovery is really only useful in certain specialized applications where you might want +to discard huge portions of the input text to find a valid restart point. + +<h2>Line Number Tracking</h2> + +<tt>yacc.py</tt> automatically tracks line numbers for all of the grammar symbols and tokens it processes. To retrieve the line +numbers, two functions are used in grammar rules: + +<ul> +<li><tt>t.lineno(num)</tt>. Return the starting line number for symbol <em>num</em> +<li><tt>t.linespan(num)</tt>. Return a tuple (startline,endline) with the starting and ending line number for symbol <em>num</em>. +</ul> + +For example: + +<blockquote> +<pre> +def t_expression(t): + 'expression : expression PLUS expression' + t.lineno(1) # Line number of the left expression + t.lineno(2) # line number of the PLUS operator + t.lineno(3) # line number of the right expression + ... + start,end = t.linespan(3) # Start,end lines of the right expression + +</pre> +</blockquote> + +Since line numbers are managed internally by the parser, there is usually no need to modify the line +numbers. However, if you want to save the line numbers in a parse-tree node, you will need to make your own +private copy. + +<h2>AST Construction</h2> + +<tt>yacc.py</tt> provides no special functions for constructing an abstract syntax tree. However, such +construction is easy enough to do on your own. Simply create a data structure for abstract syntax tree nodes +and assign nodes to <tt>t[0]</tt> in each rule. + +For example: + +<blockquote> +<pre> +class Expr: pass + +class BinOp(Expr): + def __init__(self,left,op,right): + self.type = "binop" + self.left = left + self.right = right + self.op = op + +class Number(Expr): + def __init__(self,value): + self.type = "number" + self.value = value + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + + t[0] = BinOp(t[1],t[2],t[3]) + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = Number(t[1]) +</pre> +</blockquote> + +To simplify tree traversal, it may make sense to pick a very generic tree structure for your parse tree nodes. +For example: + +<blockquote> +<pre> +class Node: + def __init__(self,type,children=None,leaf=None): + self.type = type + if children: + self.children = children + else: + self.children = [ ] + self.leaf = leaf + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + + t[0] = Node("binop", [t[1],t[3]], t[2]) +</pre> +</blockquote> + +<h2>Yacc implementation notes</h2> + +<ul> +<li>By default, <tt>yacc.py</tt> relies on <tt>lex.py</tt> for tokenizing. However, an alternative tokenizer +can be supplied as follows: + +<blockquote> +<pre> +yacc.parse(lexer=x) +</pre> +</blockquote> +in this case, <tt>x</tt> must be a Lexer object that minimally has a <tt>x.token()</tt> method for retrieving the next +token. If an input string is given to <tt>yacc.parse()</tt>, the lexer must also have an <tt>x.input()</tt> method. + +<p> +<li>By default, the yacc generates tables in debugging mode (which produces the parser.out file and other output). +To disable this, use + +<blockquote> +<pre> +yacc.yacc(debug=0) +</pre> +</blockquote> + +<p> +<li>To change the name of the <tt>parsetab.py</tt> file, use: + +<blockquote> +<pre> +yacc.yacc(tabmodule="foo") +</pre> +</blockquote> + +<P> +<li>To print copious amounts of debugging during parsing, use: + +<blockquote> +<pre> +yacc.parse(debug=1) +</pre> +</blockquote> + +<p> +<li>The <tt>yacc.yacc()</tt> function really returns a parser object. If you want to support multiple +parsers in the same application, do this: + +<blockquote> +<pre> +p = yacc.yacc() +... +p.parse() +</pre> +</blockquote> + +Note: The function <tt>yacc.parse()</tt> is bound to the last parser that was generated. + +<p> +<li>Since the generation of the SLR tables is relatively expensive, previously generated tables are +cached and reused if possible. The decision to regenerate the tables is determined by taking an MD5 +checksum of all grammar rules and precedence rules. Only in the event of a mismatch are the tables regenerated. + +<p> +It should be noted that table generation is reasonably efficient, even for grammars that involve around a 100 rules +and several hundred states. For more complex languages such as C, table generation may take 30-60 seconds on a slow +machine. Please be patient. + +<p> +<li>Since LR parsing is mostly driven by tables, the performance of the parser is largely independent of the +size of the grammar. The biggest bottlenecks will be the lexer and the complexity of your grammar rules. +</ul> + +<h2>Parser and Lexer State Management</h2> + +In advanced parsing applications, you may want to have multiple +parsers and lexers. Furthermore, the parser may want to control the +behavior of the lexer in some way. + +<p> +To do this, it is important to note that both the lexer and parser are +actually implemented as objects. These objects are returned by the +<tt>lex()</tt> and <tt>yacc()</tt> functions respectively. For example: + +<blockquote> +<pre> +lexer = lex.lex() # Return lexer object +parser = yacc.yacc() # Return parser object +</pre> +</blockquote> + +Within lexer and parser rules, these objects are also available. In the lexer, +the "lexer" attribute of a token refers to the lexer object in use. For example: + +<blockquote> +<pre> +def t_NUMBER(t): + r'\d+' + ... + print t.lexer # Show lexer object +</pre> +</blockquote> + +In the parser, the "lexer" and "parser" attributes refer to the lexer +and parser objects respectively. + +<blockquote> +<pre> +def p_expr_plus(t): + 'expr : expr PLUS expr' + ... + print t.parser # Show parser object + print t.lexer # Show lexer object +</pre> +</blockquote> + +If necessary, arbitrary attributes can be attached to the lexer or parser object. +For example, if you wanted to have different parsing modes, you could attach a mode +attribute to the parser object and look at it later. + +<h2>Using Python's Optimized Mode</h2> + +Because PLY uses information from doc-strings, parsing and lexing +information must be gathered while running the Python interpreter in +normal mode (i.e., not with the -O or -OO options). However, if you +specify optimized mode like this: + +<blockquote> +<pre> +lex.lex(optimize=1) +yacc.yacc(optimize=1) +</pre> +</blockquote> + +then PLY can later be used when Python runs in optimized mode. To make this work, +make sure you first run Python in normal mode. Once the lexing and parsing tables +have been generated the first time, run Python in optimized mode. PLY will use +the tables without the need for doc strings. + +<p> +Beware: running PLY in optimized mode disables a lot of error +checking. You should only do this when your project has stabilized +and you don't need to do any debugging. + +<h2>Where to go from here?</h2> + +The <tt>examples</tt> directory of the PLY distribution contains several simple examples. Please consult a +compilers textbook for the theory and underlying implementation details or LR parsing. + +</body> +</html> + + + + + + + diff --git a/ext/ply/example/ansic/README b/ext/ply/example/ansic/README new file mode 100644 index 000000000..e049d3b4e --- /dev/null +++ b/ext/ply/example/ansic/README @@ -0,0 +1,2 @@ +This example is incomplete. Was going to specify an ANSI C parser. +This is part of it. diff --git a/ext/ply/example/ansic/clex.py b/ext/ply/example/ansic/clex.py new file mode 100644 index 000000000..afd995208 --- /dev/null +++ b/ext/ply/example/ansic/clex.py @@ -0,0 +1,161 @@ +# ---------------------------------------------------------------------- +# clex.py +# +# A lexer for ANSI C. +# ---------------------------------------------------------------------- + +import lex + +# Reserved words +reserved = ( + 'AUTO', 'BREAK', 'CASE', 'CHAR', 'CONST', 'CONTINUE', 'DEFAULT', 'DO', 'DOUBLE', + 'ELSE', 'ENUM', 'EXTERN', 'FLOAT', 'FOR', 'GOTO', 'IF', 'INT', 'LONG', 'REGISTER', + 'RETURN', 'SHORT', 'SIGNED', 'SIZEOF', 'STATIC', 'STRUCT', 'SWITCH', 'TYPEDEF', + 'UNION', 'UNSIGNED', 'VOID', 'VOLATILE', 'WHILE', + ) + +tokens = reserved + ( + # Literals (identifier, integer constant, float constant, string constant, char const) + 'ID', 'TYPEID', 'ICONST', 'FCONST', 'SCONST', 'CCONST', + + # Operators (+,-,*,/,%,|,&,~,^,<<,>>, ||, &&, !, <, <=, >, >=, ==, !=) + 'PLUS', 'MINUS', 'TIMES', 'DIVIDE', 'MOD', + 'OR', 'AND', 'NOT', 'XOR', 'LSHIFT', 'RSHIFT', + 'LOR', 'LAND', 'LNOT', + 'LT', 'LE', 'GT', 'GE', 'EQ', 'NE', + + # Assignment (=, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |=) + 'EQUALS', 'TIMESEQUAL', 'DIVEQUAL', 'MODEQUAL', 'PLUSEQUAL', 'MINUSEQUAL', + 'LSHIFTEQUAL','RSHIFTEQUAL', 'ANDEQUAL', 'XOREQUAL', 'OREQUAL', + + # Increment/decrement (++,--) + 'PLUSPLUS', 'MINUSMINUS', + + # Structure dereference (->) + 'ARROW', + + # Conditional operator (?) + 'CONDOP', + + # Delimeters ( ) [ ] { } , . ; : + 'LPAREN', 'RPAREN', + 'LBRACKET', 'RBRACKET', + 'LBRACE', 'RBRACE', + 'COMMA', 'PERIOD', 'SEMI', 'COLON', + + # Ellipsis (...) + 'ELLIPSIS', + ) + +# Completely ignored characters +t_ignore = ' \t\x0c' + +# Newlines +def t_NEWLINE(t): + r'\n+' + t.lineno += t.value.count("\n") + +# Operators +t_PLUS = r'\+' +t_MINUS = r'-' +t_TIMES = r'\*' +t_DIVIDE = r'/' +t_MOD = r'%' +t_OR = r'\|' +t_AND = r'&' +t_NOT = r'~' +t_XOR = r'^' +t_LSHIFT = r'<<' +t_RSHIFT = r'>>' +t_LOR = r'\|\|' +t_LAND = r'&&' +t_LNOT = r'!' +t_LT = r'<' +t_GT = r'>' +t_LE = r'<=' +t_GE = r'>=' +t_EQ = r'==' +t_NE = r'!=' + +# Assignment operators + +t_EQUALS = r'=' +t_TIMESEQUAL = r'\*=' +t_DIVEQUAL = r'/=' +t_MODEQUAL = r'%=' +t_PLUSEQUAL = r'\+=' +t_MINUSEQUAL = r'-=' +t_LSHIFTEQUAL = r'<<=' +t_RSHIFTEQUAL = r'>>=' +t_ANDEQUAL = r'&=' +t_OREQUAL = r'\|=' +t_XOREQUAL = r'^=' + +# Increment/decrement +t_PLUSPLUS = r'\+\+' +t_MINUSMINUS = r'--' + +# -> +t_ARROW = r'->' + +# ? +t_CONDOP = r'\?' + +# Delimeters +t_LPAREN = r'\(' +t_RPAREN = r'\)' +t_LBRACKET = r'\[' +t_RBRACKET = r'\]' +t_LBRACE = r'\{' +t_RBRACE = r'\}' +t_COMMA = r',' +t_PERIOD = r'\.' +t_SEMI = r';' +t_COLON = r':' +t_ELLIPSIS = r'\.\.\.' + +# Identifiers and reserved words + +reserved_map = { } +for r in reserved: + reserved_map[r.lower()] = r + +def t_ID(t): + r'[A-Za-z_][\w_]*' + t.type = reserved_map.get(t.value,"ID") + return t + +# Integer literal +t_ICONST = r'\d+([uU]|[lL]|[uU][lL]|[lL][uU])?' + +# Floating literal +t_FCONST = r'((\d+)(\.\d+)(e(\+|-)?(\d+))? | (\d+)e(\+|-)?(\d+))([lL]|[fF])?' + +# String literal +t_SCONST = r'\"([^\\\n]|(\\.))*?\"' + +# Character constant 'c' or L'c' +t_CCONST = r'(L)?\'([^\\\n]|(\\.))*?\'' + +# Comments +def t_comment(t): + r' /\*(.|\n)*?\*/' + t.lineno += t.value.count('\n') + +# Preprocessor directive (ignored) +def t_preprocessor(t): + r'\#(.)*?\n' + t.lineno += 1 + +def t_error(t): + print "Illegal character %s" % repr(t.value[0]) + t.skip(1) + +lexer = lex.lex(optimize=1) +if __name__ == "__main__": + lex.runmain(lexer) + + + + + diff --git a/ext/ply/example/ansic/cparse.py b/ext/ply/example/ansic/cparse.py new file mode 100644 index 000000000..ddfd5c72b --- /dev/null +++ b/ext/ply/example/ansic/cparse.py @@ -0,0 +1,859 @@ +# ----------------------------------------------------------------------------- +# cparse.py +# +# Simple parser for ANSI C. Based on the grammar in K&R, 2nd Ed. +# ----------------------------------------------------------------------------- + +import yacc +import clex + +# Get the token map +tokens = clex.tokens + +# translation-unit: + +def p_translation_unit_1(t): + 'translation_unit : external_declaration' + pass + +def p_translation_unit_2(t): + 'translation_unit : translation_unit external_declaration' + pass + +# external-declaration: + +def p_external_declaration_1(t): + 'external_declaration : function_definition' + pass + +def p_external_declaration_2(t): + 'external_declaration : declaration' + pass + +# function-definition: + +def p_function_definition_1(t): + 'function_definition : declaration_specifiers declarator declaration_list compound_statement' + pass + +def p_function_definition_2(t): + 'function_definition : declarator declaration_list compound_statement' + pass + +def p_function_definition_3(t): + 'function_definition : declarator compound_statement' + pass + +def p_function_definition_4(t): + 'function_definition : declaration_specifiers declarator compound_statement' + pass + +# declaration: + +def p_declaration_1(t): + 'declaration : declaration_specifiers init_declarator_list SEMI' + pass + +def p_declaration_2(t): + 'declaration : declaration_specifiers SEMI' + pass + +# declaration-list: + +def p_declaration_list_1(t): + 'declaration_list : declaration' + pass + +def p_declaration_list_2(t): + 'declaration_list : declaration_list declaration ' + pass + +# declaration-specifiers +def p_declaration_specifiers_1(t): + 'declaration_specifiers : storage_class_specifier declaration_specifiers' + pass + +def p_declaration_specifiers_2(t): + 'declaration_specifiers : type_specifier declaration_specifiers' + pass + +def p_declaration_specifiers_3(t): + 'declaration_specifiers : type_qualifier declaration_specifiers' + pass + +def p_declaration_specifiers_4(t): + 'declaration_specifiers : storage_class_specifier' + pass + +def p_declaration_specifiers_5(t): + 'declaration_specifiers : type_specifier' + pass + +def p_declaration_specifiers_6(t): + 'declaration_specifiers : type_qualifier' + pass + +# storage-class-specifier +def p_storage_class_specifier(t): + '''storage_class_specifier : AUTO + | REGISTER + | STATIC + | EXTERN + | TYPEDEF + ''' + pass + +# type-specifier: +def p_type_specifier(t): + '''type_specifier : VOID + | CHAR + | SHORT + | INT + | LONG + | FLOAT + | DOUBLE + | SIGNED + | UNSIGNED + | struct_or_union_specifier + | enum_specifier + | TYPEID + ''' + pass + +# type-qualifier: +def p_type_qualifier(t): + '''type_qualifier : CONST + | VOLATILE''' + pass + +# struct-or-union-specifier + +def p_struct_or_union_specifier_1(t): + 'struct_or_union_specifier : struct_or_union ID LBRACE struct_declaration_list RBRACE' + pass + +def p_struct_or_union_specifier_2(t): + 'struct_or_union_specifier : struct_or_union LBRACE struct_declaration_list RBRACE' + pass + +def p_struct_or_union_specifier_3(t): + 'struct_or_union_specifier : struct_or_union ID' + pass + +# struct-or-union: +def p_struct_or_union(t): + '''struct_or_union : STRUCT + | UNION + ''' + pass + +# struct-declaration-list: + +def p_struct_declaration_list_1(t): + 'struct_declaration_list : struct_declaration' + pass + +def p_struct_declaration_list_2(t): + 'struct_declaration_list : struct_declarator_list struct_declaration' + pass + +# init-declarator-list: + +def p_init_declarator_list_1(t): + 'init_declarator_list : init_declarator' + pass + +def p_init_declarator_list_2(t): + 'init_declarator_list : init_declarator_list COMMA init_declarator' + pass + +# init-declarator + +def p_init_declarator_1(t): + 'init_declarator : declarator' + pass + +def p_init_declarator_2(t): + 'init_declarator : declarator EQUALS initializer' + pass + +# struct-declaration: + +def p_struct_declaration(t): + 'struct_declaration : specifier_qualifier_list struct_declarator_list SEMI' + pass + +# specifier-qualifier-list: + +def p_specifier_qualifier_list_1(t): + 'specifier_qualifier_list : type_specifier specifier_qualifier_list' + pass + +def p_specifier_qualifier_list_2(t): + 'specifier_qualifier_list : type_specifier' + pass + +def p_specifier_qualifier_list_3(t): + 'specifier_qualifier_list : type_qualifier specifier_qualifier_list' + pass + +def p_specifier_qualifier_list_4(t): + 'specifier_qualifier_list : type_qualifier' + pass + +# struct-declarator-list: + +def p_struct_declarator_list_1(t): + 'struct_declarator_list : struct_declarator' + pass + +def p_struct_declarator_list_2(t): + 'struct_declarator_list : struct_declarator_list COMMA struct_declarator' + pass + +# struct-declarator: + +def p_struct_declarator_1(t): + 'struct_declarator : declarator' + pass + +def p_struct_declarator_2(t): + 'struct_declarator : declarator COLON constant_expression' + pass + +def p_struct_declarator_3(t): + 'struct_declarator : COLON constant_expression' + pass + +# enum-specifier: + +def p_enum_specifier_1(t): + 'enum_specifier : ENUM ID LBRACE enumerator_list RBRACE' + pass + +def p_enum_specifier_2(t): + 'enum_specifier : ENUM LBRACE enumerator_list RBRACE' + pass + +def p_enum_specifier_3(t): + 'enum_specifier : ENUM ID' + pass + +# enumerator_list: +def p_enumerator_list_1(t): + 'enumerator_list : enumerator' + pass + +def p_enumerator_list_2(t): + 'enumerator_list : enumerator_list COMMA enumerator' + pass + +# enumerator: +def p_enumerator_1(t): + 'enumerator : ID' + pass + +def p_enumerator_2(t): + 'enumerator : ID EQUALS constant_expression' + pass + +# declarator: + +def p_declarator_1(t): + 'declarator : pointer direct_declarator' + pass + +def p_declarator_2(t): + 'declarator : direct_declarator' + pass + +# direct-declarator: + +def p_direct_declarator_1(t): + 'direct_declarator : ID' + pass + +def p_direct_declarator_2(t): + 'direct_declarator : LPAREN declarator RPAREN' + pass + +def p_direct_declarator_3(t): + 'direct_declarator : direct_declarator LBRACKET constant_expression_opt RBRACKET' + pass + +def p_direct_declarator_4(t): + 'direct_declarator : direct_declarator LPAREN parameter_type_list RPAREN ' + pass + +def p_direct_declarator_5(t): + 'direct_declarator : direct_declarator LPAREN identifier_list RPAREN ' + pass + +def p_direct_declarator_6(t): + 'direct_declarator : direct_declarator LPAREN RPAREN ' + pass + +# pointer: +def p_pointer_1(t): + 'pointer : TIMES type_qualifier_list' + pass + +def p_pointer_2(t): + 'pointer : TIMES' + pass + +def p_pointer_3(t): + 'pointer : TIMES type_qualifier_list pointer' + pass + +def p_pointer_4(t): + 'pointer : TIMES pointer' + pass + +# type-qualifier-list: + +def p_type_qualifier_list_1(t): + 'type_qualifier_list : type_qualifier' + pass + +def p_type_qualifier_list_2(t): + 'type_qualifier_list : type_qualifier_list type_qualifier' + pass + +# parameter-type-list: + +def p_parameter_type_list_1(t): + 'parameter_type_list : parameter_list' + pass + +def p_parameter_type_list_2(t): + 'parameter_type_list : parameter_list COMMA ELLIPSIS' + pass + +# parameter-list: + +def p_parameter_list_1(t): + 'parameter_list : parameter_declaration' + pass + +def p_parameter_list_2(t): + 'parameter_list : parameter_list COMMA parameter_declaration' + pass + +# parameter-declaration: +def p_parameter_declaration_1(t): + 'parameter_declaration : declaration_specifiers declarator' + pass + +def p_parameter_declaration_2(t): + 'parameter_declaration : declaration_specifiers abstract_declarator_opt' + pass + +# identifier-list: +def p_identifier_list_1(t): + 'identifier_list : ID' + pass + +def p_identifier_list_2(t): + 'identifier_list : identifier_list COMMA ID' + pass + +# initializer: + +def p_initializer_1(t): + 'initializer : assignment_expression' + pass + +def p_initializer_2(t): + '''initializer : LBRACE initializer_list RBRACE + | LBRACE initializer_list COMMA RBRACE''' + pass + +# initializer-list: + +def p_initializer_list_1(t): + 'initializer_list : initializer' + pass + +def p_initializer_list_2(t): + 'initializer_list : initializer_list COMMA initializer' + pass + +# type-name: + +def p_type_name(t): + 'type_name : specifier_qualifier_list abstract_declarator_opt' + pass + +def p_abstract_declarator_opt_1(t): + 'abstract_declarator_opt : empty' + pass + +def p_abstract_declarator_opt_2(t): + 'abstract_declarator_opt : abstract_declarator' + pass + +# abstract-declarator: + +def p_abstract_declarator_1(t): + 'abstract_declarator : pointer ' + pass + +def p_abstract_declarator_2(t): + 'abstract_declarator : pointer direct_abstract_declarator' + pass + +def p_abstract_declarator_3(t): + 'abstract_declarator : direct_abstract_declarator' + pass + +# direct-abstract-declarator: + +def p_direct_abstract_declarator_1(t): + 'direct_abstract_declarator : LPAREN abstract_declarator RPAREN' + pass + +def p_direct_abstract_declarator_2(t): + 'direct_abstract_declarator : direct_abstract_declarator LBRACKET constant_expression_opt RBRACKET' + pass + +def p_direct_abstract_declarator_3(t): + 'direct_abstract_declarator : LBRACKET constant_expression_opt RBRACKET' + pass + +def p_direct_abstract_declarator_4(t): + 'direct_abstract_declarator : direct_abstract_declarator LPAREN parameter_type_list_opt RPAREN' + pass + +def p_direct_abstract_declarator_5(t): + 'direct_abstract_declarator : LPAREN parameter_type_list_opt RPAREN' + pass + +# Optional fields in abstract declarators + +def p_constant_expression_opt_1(t): + 'constant_expression_opt : empty' + pass + +def p_constant_expression_opt_2(t): + 'constant_expression_opt : constant_expression' + pass + +def p_parameter_type_list_opt_1(t): + 'parameter_type_list_opt : empty' + pass + +def p_parameter_type_list_opt_2(t): + 'parameter_type_list_opt : parameter_type_list' + pass + +# statement: + +def p_statement(t): + ''' + statement : labeled_statement + | expression_statement + | compound_statement + | selection_statement + | iteration_statement + | jump_statement + ''' + pass + +# labeled-statement: + +def p_labeled_statement_1(t): + 'labeled_statement : ID COLON statement' + pass + +def p_labeled_statement_2(t): + 'labeled_statement : CASE constant_expression COLON statement' + pass + +def p_labeled_statement_3(t): + 'labeled_statement : DEFAULT COLON statement' + pass + +# expression-statement: +def p_expression_statement(t): + 'expression_statement : expression_opt SEMI' + pass + +# compound-statement: + +def p_compound_statement_1(t): + 'compound_statement : LBRACE declaration_list statement_list RBRACE' + pass + +def p_compound_statement_2(t): + 'compound_statement : LBRACE statement_list RBRACE' + pass + +def p_compound_statement_3(t): + 'compound_statement : LBRACE declaration_list RBRACE' + pass + +def p_compound_statement_4(t): + 'compound_statement : LBRACE RBRACE' + pass + +# statement-list: + +def p_statement_list_1(t): + 'statement_list : statement' + pass + +def p_statement_list_2(t): + 'statement_list : statement_list statement' + pass + +# selection-statement + +def p_selection_statement_1(t): + 'selection_statement : IF LPAREN expression RPAREN statement' + pass + +def p_selection_statement_2(t): + 'selection_statement : IF LPAREN expression RPAREN statement ELSE statement ' + pass + +def p_selection_statement_3(t): + 'selection_statement : SWITCH LPAREN expression RPAREN statement ' + pass + +# iteration_statement: + +def p_iteration_statement_1(t): + 'iteration_statement : WHILE LPAREN expression RPAREN statement' + pass + +def p_iteration_statement_2(t): + 'iteration_statement : FOR LPAREN expression_opt SEMI expression_opt SEMI expression_opt RPAREN statement ' + pass + +def p_iteration_statement_3(t): + 'iteration_statement : DO statement WHILE LPAREN expression RPAREN SEMI' + pass + +# jump_statement: + +def p_jump_statement_1(t): + 'jump_statement : GOTO ID SEMI' + pass + +def p_jump_statement_2(t): + 'jump_statement : CONTINUE SEMI' + pass + +def p_jump_statement_3(t): + 'jump_statement : BREAK SEMI' + pass + +def p_jump_statement_4(t): + 'jump_statement : RETURN expression_opt SEMI' + pass + +def p_expression_opt_1(t): + 'expression_opt : empty' + pass + +def p_expression_opt_2(t): + 'expression_opt : expression' + pass + +# expression: +def p_expression_1(t): + 'expression : assignment_expression' + pass + +def p_expression_2(t): + 'expression : expression COMMA assignment_expression' + pass + +# assigment_expression: +def p_assignment_expression_1(t): + 'assignment_expression : conditional_expression' + pass + +def p_assignment_expression_2(t): + 'assignment_expression : unary_expression assignment_operator assignment_expression' + pass + +# assignment_operator: +def p_assignment_operator(t): + ''' + assignment_operator : EQUALS + | TIMESEQUAL + | DIVEQUAL + | MODEQUAL + | PLUSEQUAL + | MINUSEQUAL + | LSHIFTEQUAL + | RSHIFTEQUAL + | ANDEQUAL + | OREQUAL + | XOREQUAL + ''' + pass + +# conditional-expression +def p_conditional_expression_1(t): + 'conditional_expression : logical_or_expression' + pass + +def p_conditional_expression_2(t): + 'conditional_expression : logical_or_expression CONDOP expression COLON conditional_expression ' + pass + +# constant-expression + +def p_constant_expression(t): + 'constant_expression : conditional_expression' + pass + +# logical-or-expression + +def p_logical_or_expression_1(t): + 'logical_or_expression : logical_and_expression' + pass + +def p_logical_or_expression_2(t): + 'logical_or_expression : logical_or_expression LOR logical_and_expression' + pass + +# logical-and-expression + +def p_logical_and_expression_1(t): + 'logical_and_expression : inclusive_or_expression' + pass + +def p_logical_and_expression_2(t): + 'logical_and_expression : logical_and_expression LAND inclusive_or_expression' + pass + +# inclusive-or-expression: + +def p_inclusive_or_expression_1(t): + 'inclusive_or_expression : exclusive_or_expression' + pass + +def p_inclusive_or_expression_2(t): + 'inclusive_or_expression : inclusive_or_expression OR exclusive_or_expression' + pass + +# exclusive-or-expression: + +def p_exclusive_or_expression_1(t): + 'exclusive_or_expression : and_expression' + pass + +def p_exclusive_or_expression_2(t): + 'exclusive_or_expression : exclusive_or_expression XOR and_expression' + pass + +# AND-expression + +def p_and_expression_1(t): + 'and_expression : equality_expression' + pass + +def p_and_expression_2(t): + 'and_expression : and_expression AND equality_expression' + pass + + +# equality-expression: +def p_equality_expression_1(t): + 'equality_expression : relational_expression' + pass + +def p_equality_expression_2(t): + 'equality_expression : equality_expression EQ relational_expression' + pass + +def p_equality_expression_3(t): + 'equality_expression : equality_expression NE relational_expression' + pass + + +# relational-expression: +def p_relational_expression_1(t): + 'relational_expression : shift_expression' + pass + +def p_relational_expression_2(t): + 'relational_expression : relational_expression LT shift_expression' + pass + +def p_relational_expression_3(t): + 'relational_expression : relational_expression GT shift_expression' + pass + +def p_relational_expression_4(t): + 'relational_expression : relational_expression LE shift_expression' + pass + +def p_relational_expression_5(t): + 'relational_expression : relational_expression GE shift_expression' + pass + +# shift-expression + +def p_shift_expression_1(t): + 'shift_expression : additive_expression' + pass + +def p_shift_expression_2(t): + 'shift_expression : shift_expression LSHIFT additive_expression' + pass + +def p_shift_expression_3(t): + 'shift_expression : shift_expression RSHIFT additive_expression' + pass + +# additive-expression + +def p_additive_expression_1(t): + 'additive_expression : multiplicative_expression' + pass + +def p_additive_expression_2(t): + 'additive_expression : additive_expression PLUS multiplicative_expression' + pass + +def p_additive_expression_3(t): + 'additive_expression : additive_expression MINUS multiplicative_expression' + pass + +# multiplicative-expression + +def p_multiplicative_expression_1(t): + 'multiplicative_expression : cast_expression' + pass + +def p_multiplicative_expression_2(t): + 'multiplicative_expression : multiplicative_expression TIMES cast_expression' + pass + +def p_multiplicative_expression_3(t): + 'multiplicative_expression : multiplicative_expression DIVIDE cast_expression' + pass + +def p_multiplicative_expression_4(t): + 'multiplicative_expression : multiplicative_expression MOD cast_expression' + pass + +# cast-expression: + +def p_cast_expression_1(t): + 'cast_expression : unary_expression' + pass + +def p_cast_expression_2(t): + 'cast_expression : LPAREN type_name RPAREN cast_expression' + pass + +# unary-expression: +def p_unary_expression_1(t): + 'unary_expression : postfix_expression' + pass + +def p_unary_expression_2(t): + 'unary_expression : PLUSPLUS unary_expression' + pass + +def p_unary_expression_3(t): + 'unary_expression : MINUSMINUS unary_expression' + pass + +def p_unary_expression_4(t): + 'unary_expression : unary_operator cast_expression' + pass + +def p_unary_expression_5(t): + 'unary_expression : SIZEOF unary_expression' + pass + +def p_unary_expression_6(t): + 'unary_expression : SIZEOF LPAREN type_name RPAREN' + pass + +#unary-operator +def p_unary_operator(t): + '''unary_operator : AND + | TIMES + | PLUS + | MINUS + | NOT + | LNOT ''' + pass + +# postfix-expression: +def p_postfix_expression_1(t): + 'postfix_expression : primary_expression' + pass + +def p_postfix_expression_2(t): + 'postfix_expression : postfix_expression LBRACKET expression RBRACKET' + pass + +def p_postfix_expression_3(t): + 'postfix_expression : postfix_expression LPAREN argument_expression_list RPAREN' + pass + +def p_postfix_expression_4(t): + 'postfix_expression : postfix_expression LPAREN RPAREN' + pass + +def p_postfix_expression_5(t): + 'postfix_expression : postfix_expression PERIOD ID' + pass + +def p_postfix_expression_6(t): + 'postfix_expression : postfix_expression ARROW ID' + pass + +def p_postfix_expression_7(t): + 'postfix_expression : postfix_expression PLUSPLUS' + pass + +def p_postfix_expression_8(t): + 'postfix_expression : postfix_expression MINUSMINUS' + pass + +# primary-expression: +def p_primary_expression(t): + '''primary_expression : ID + | constant + | SCONST + | LPAREN expression RPAREN''' + pass + +# argument-expression-list: +def p_argument_expression_list(t): + '''argument_expression_list : assignment_expression + | argument_expression_list COMMA assignment_expression''' + pass + +# constant: +def p_constant(t): + '''constant : ICONST + | FCONST + | CCONST''' + pass + + +def p_empty(t): + 'empty : ' + pass + +def p_error(t): + print "Whoa. We're hosed" + +import profile +# Build the grammar +profile.run("yacc.yacc()") + + + + diff --git a/ext/ply/example/calc/calc.py b/ext/ply/example/calc/calc.py new file mode 100644 index 000000000..aeb23c246 --- /dev/null +++ b/ext/ply/example/calc/calc.py @@ -0,0 +1,108 @@ +# ----------------------------------------------------------------------------- +# calc.py +# +# A simple calculator with variables. This is from O'Reilly's +# "Lex and Yacc", p. 63. +# ----------------------------------------------------------------------------- + +tokens = ( + 'NAME','NUMBER', + 'PLUS','MINUS','TIMES','DIVIDE','EQUALS', + 'LPAREN','RPAREN', + ) + +# Tokens + +t_PLUS = r'\+' +t_MINUS = r'-' +t_TIMES = r'\*' +t_DIVIDE = r'/' +t_EQUALS = r'=' +t_LPAREN = r'\(' +t_RPAREN = r'\)' +t_NAME = r'[a-zA-Z_][a-zA-Z0-9_]*' + +def t_NUMBER(t): + r'\d+' + try: + t.value = int(t.value) + except ValueError: + print "Integer value too large", t.value + t.value = 0 + return t + +t_ignore = " \t" + +def t_newline(t): + r'\n+' + t.lineno += t.value.count("\n") + +def t_error(t): + print "Illegal character '%s'" % t.value[0] + t.skip(1) + +# Build the lexer +import lex +lex.lex() + +# Parsing rules + +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[2] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + +while 1: + try: + s = raw_input('calc > ') + except EOFError: + break + yacc.parse(s) diff --git a/ext/ply/example/hedit/hedit.py b/ext/ply/example/hedit/hedit.py new file mode 100644 index 000000000..f00427bf5 --- /dev/null +++ b/ext/ply/example/hedit/hedit.py @@ -0,0 +1,44 @@ +# ----------------------------------------------------------------------------- +# hedit.py +# +# Paring of Fortran H Edit descriptions (Contributed by Pearu Peterson) +# +# These tokens can't be easily tokenized because they are of the following +# form: +# +# nHc1...cn +# +# where n is a positive integer and c1 ... cn are characters. +# +# This example shows how to modify the state of the lexer to parse +# such tokens +# ----------------------------------------------------------------------------- + +tokens = ( + 'H_EDIT_DESCRIPTOR', + ) + +# Tokens +t_ignore = " \t\n" + +def t_H_EDIT_DESCRIPTOR(t): + r"\d+H.*" # This grabs all of the remaining text + i = t.value.index('H') + n = eval(t.value[:i]) + + # Adjust the tokenizing position + t.lexer.lexpos -= len(t.value) - (i+1+n) + + t.value = t.value[i+1:i+1+n] + return t + +def t_error(t): + print "Illegal character '%s'" % t.value[0] + t.skip(1) + +# Build the lexer +import lex +lex.lex() +lex.runmain() + + diff --git a/ext/ply/example/optcalc/README b/ext/ply/example/optcalc/README new file mode 100644 index 000000000..6d196f0ee --- /dev/null +++ b/ext/ply/example/optcalc/README @@ -0,0 +1,9 @@ +An example showing how to use Python optimized mode. +To run: + + - First run 'python calc.py' + + - Then run 'python -OO calc.py' + +If working corretly, the second version should run the +same way. diff --git a/ext/ply/example/optcalc/calc.py b/ext/ply/example/optcalc/calc.py new file mode 100644 index 000000000..fa66cda5b --- /dev/null +++ b/ext/ply/example/optcalc/calc.py @@ -0,0 +1,110 @@ +# ----------------------------------------------------------------------------- +# calc.py +# +# A simple calculator with variables. This is from O'Reilly's +# "Lex and Yacc", p. 63. +# ----------------------------------------------------------------------------- + +tokens = ( + 'NAME','NUMBER', + 'PLUS','MINUS','TIMES','DIVIDE','EQUALS', + 'LPAREN','RPAREN', + ) + +# Tokens + +t_PLUS = r'\+' +t_MINUS = r'-' +t_TIMES = r'\*' +t_DIVIDE = r'/' +t_EQUALS = r'=' +t_LPAREN = r'\(' +t_RPAREN = r'\)' +t_NAME = r'[a-zA-Z_][a-zA-Z0-9_]*' + +def t_NUMBER(t): + r'\d+' + try: + t.value = int(t.value) + except ValueError: + print "Integer value too large", t.value + t.value = 0 + return t + +t_ignore = " \t" + +def t_newline(t): + r'\n+' + t.lineno += t.value.count("\n") + +def t_error(t): + print "Illegal character '%s'" % t.value[0] + t.skip(1) + +# Build the lexer +import lex +lex.lex(optimize=1) + +# Parsing rules + +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[2] == '/': t[0] = t[1] / t[3] + elif t[2] == '<': t[0] = t[1] < t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc(optimize=1) + +while 1: + try: + s = raw_input('calc > ') + except EOFError: + break + yacc.parse(s) + diff --git a/ext/ply/lex.py b/ext/ply/lex.py new file mode 100644 index 000000000..7ad7a394b --- /dev/null +++ b/ext/ply/lex.py @@ -0,0 +1,681 @@ +#----------------------------------------------------------------------------- +# ply: lex.py +# +# Author: David M. Beazley (beazley@cs.uchicago.edu) +# Department of Computer Science +# University of Chicago +# Chicago, IL 60637 +# +# Copyright (C) 2001, David M. Beazley +# +# $Header: /home/stever/bk/newmem2/ext/ply/lex.py 1.1 03/06/06 14:53:34-00:00 stever@ $ +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See the file COPYING for a complete copy of the LGPL. +# +# +# This module automatically constructs a lexical analysis module from regular +# expression rules defined in a user-defined module. The idea is essentially the same +# as that used in John Aycock's Spark framework, but the implementation works +# at the module level rather than requiring the use of classes. +# +# This module tries to provide an interface that is closely modeled after +# the traditional lex interface in Unix. It also differs from Spark +# in that: +# +# - It provides more extensive error checking and reporting if +# the user supplies a set of regular expressions that can't +# be compiled or if there is any other kind of a problem in +# the specification. +# +# - The interface is geared towards LALR(1) and LR(1) parser +# generators. That is tokens are generated one at a time +# rather than being generated in advanced all in one step. +# +# There are a few limitations of this module +# +# - The module interface makes it somewhat awkward to support more +# than one lexer at a time. Although somewhat inelegant from a +# design perspective, this is rarely a practical concern for +# most compiler projects. +# +# - The lexer requires that the entire input text be read into +# a string before scanning. I suppose that most machines have +# enough memory to make this a minor issues, but it makes +# the lexer somewhat difficult to use in interactive sessions +# or with streaming data. +# +#----------------------------------------------------------------------------- + +r""" +lex.py + +This module builds lex-like scanners based on regular expression rules. +To use the module, simply write a collection of regular expression rules +and actions like this: + +# lexer.py +import lex + +# Define a list of valid tokens +tokens = ( + 'IDENTIFIER', 'NUMBER', 'PLUS', 'MINUS' + ) + +# Define tokens as functions +def t_IDENTIFIER(t): + r' ([a-zA-Z_](\w|_)* ' + return t + +def t_NUMBER(t): + r' \d+ ' + return t + +# Some simple tokens with no actions +t_PLUS = r'\+' +t_MINUS = r'-' + +# Initialize the lexer +lex.lex() + +The tokens list is required and contains a complete list of all valid +token types that the lexer is allowed to produce. Token types are +restricted to be valid identifiers. This means that 'MINUS' is a valid +token type whereas '-' is not. + +Rules are defined by writing a function with a name of the form +t_rulename. Each rule must accept a single argument which is +a token object generated by the lexer. This token has the following +attributes: + + t.type = type string of the token. This is initially set to the + name of the rule without the leading t_ + t.value = The value of the lexeme. + t.lineno = The value of the line number where the token was encountered + +For example, the t_NUMBER() rule above might be called with the following: + + t.type = 'NUMBER' + t.value = '42' + t.lineno = 3 + +Each rule returns the token object it would like to supply to the +parser. In most cases, the token t is returned with few, if any +modifications. To discard a token for things like whitespace or +comments, simply return nothing. For instance: + +def t_whitespace(t): + r' \s+ ' + pass + +For faster lexing, you can also define this in terms of the ignore set like this: + +t_ignore = ' \t' + +The characters in this string are ignored by the lexer. Use of this feature can speed +up parsing significantly since scanning will immediately proceed to the next token. + +lex requires that the token returned by each rule has an attribute +t.type. Other than this, rules are free to return any kind of token +object that they wish and may construct a new type of token object +from the attributes of t (provided the new object has the required +type attribute). + +If illegal characters are encountered, the scanner executes the +function t_error(t) where t is a token representing the rest of the +string that hasn't been matched. If this function isn't defined, a +LexError exception is raised. The .text attribute of this exception +object contains the part of the string that wasn't matched. + +The t.skip(n) method can be used to skip ahead n characters in the +input stream. This is usually only used in the error handling rule. +For instance, the following rule would print an error message and +continue: + +def t_error(t): + print "Illegal character in input %s" % t.value[0] + t.skip(1) + +Of course, a nice scanner might wish to skip more than one character +if the input looks very corrupted. + +The lex module defines a t.lineno attribute on each token that can be used +to track the current line number in the input. The value of this +variable is not modified by lex so it is up to your lexer module +to correctly update its value depending on the lexical properties +of the input language. To do this, you might write rules such as +the following: + +def t_newline(t): + r' \n+ ' + t.lineno += t.value.count("\n") + +To initialize your lexer so that it can be used, simply call the lex.lex() +function in your rule file. If there are any errors in your +specification, warning messages or an exception will be generated to +alert you to the problem. + +(dave: this needs to be rewritten) +To use the newly constructed lexer from another module, simply do +this: + + import lex + import lexer + plex.input("position = initial + rate*60") + + while 1: + token = plex.token() # Get a token + if not token: break # No more tokens + ... do whatever ... + +Assuming that the module 'lexer' has initialized plex as shown +above, parsing modules can safely import 'plex' without having +to import the rule file or any additional imformation about the +scanner you have defined. +""" + +# ----------------------------------------------------------------------------- + + +__version__ = "1.3" + +import re, types, sys, copy + +# Exception thrown when invalid token encountered and no default +class LexError(Exception): + def __init__(self,message,s): + self.args = (message,) + self.text = s + +# Token class +class LexToken: + def __str__(self): + return "LexToken(%s,%r,%d)" % (self.type,self.value,self.lineno) + def __repr__(self): + return str(self) + def skip(self,n): + try: + self._skipn += n + except AttributeError: + self._skipn = n + +# ----------------------------------------------------------------------------- +# Lexer class +# +# input() - Store a new string in the lexer +# token() - Get the next token +# ----------------------------------------------------------------------------- + +class Lexer: + def __init__(self): + self.lexre = None # Master regular expression + self.lexdata = None # Actual input data (as a string) + self.lexpos = 0 # Current position in input text + self.lexlen = 0 # Length of the input text + self.lexindexfunc = [ ] # Reverse mapping of groups to functions and types + self.lexerrorf = None # Error rule (if any) + self.lextokens = None # List of valid tokens + self.lexignore = None # Ignored characters + self.lineno = 1 # Current line number + self.debug = 0 # Debugging mode + self.optimize = 0 # Optimized mode + self.token = self.errtoken + + def __copy__(self): + c = Lexer() + c.lexre = self.lexre + c.lexdata = self.lexdata + c.lexpos = self.lexpos + c.lexlen = self.lexlen + c.lenindexfunc = self.lexindexfunc + c.lexerrorf = self.lexerrorf + c.lextokens = self.lextokens + c.lexignore = self.lexignore + c.lineno = self.lineno + c.optimize = self.optimize + c.token = c.realtoken + + # ------------------------------------------------------------ + # input() - Push a new string into the lexer + # ------------------------------------------------------------ + def input(self,s): + if not isinstance(s,types.StringType): + raise ValueError, "Expected a string" + self.lexdata = s + self.lexpos = 0 + self.lexlen = len(s) + self.token = self.realtoken + + # Change the token routine to point to realtoken() + global token + if token == self.errtoken: + token = self.token + + # ------------------------------------------------------------ + # errtoken() - Return error if token is called with no data + # ------------------------------------------------------------ + def errtoken(self): + raise RuntimeError, "No input string given with input()" + + # ------------------------------------------------------------ + # token() - Return the next token from the Lexer + # + # Note: This function has been carefully implemented to be as fast + # as possible. Don't make changes unless you really know what + # you are doing + # ------------------------------------------------------------ + def realtoken(self): + # Make local copies of frequently referenced attributes + lexpos = self.lexpos + lexlen = self.lexlen + lexignore = self.lexignore + lexdata = self.lexdata + + while lexpos < lexlen: + # This code provides some short-circuit code for whitespace, tabs, and other ignored characters + if lexdata[lexpos] in lexignore: + lexpos += 1 + continue + + # Look for a regular expression match + m = self.lexre.match(lexdata,lexpos) + if m: + i = m.lastindex + lexpos = m.end() + tok = LexToken() + tok.value = m.group() + tok.lineno = self.lineno + tok.lexer = self + func,tok.type = self.lexindexfunc[i] + if not func: + self.lexpos = lexpos + return tok + + # If token is processed by a function, call it + self.lexpos = lexpos + newtok = func(tok) + self.lineno = tok.lineno # Update line number + + # Every function must return a token, if nothing, we just move to next token + if not newtok: continue + + # Verify type of the token. If not in the token map, raise an error + if not self.optimize: + if not self.lextokens.has_key(newtok.type): + raise LexError, ("%s:%d: Rule '%s' returned an unknown token type '%s'" % ( + func.func_code.co_filename, func.func_code.co_firstlineno, + func.__name__, newtok.type),lexdata[lexpos:]) + + return newtok + + # No match. Call t_error() if defined. + if self.lexerrorf: + tok = LexToken() + tok.value = self.lexdata[lexpos:] + tok.lineno = self.lineno + tok.type = "error" + tok.lexer = self + oldpos = lexpos + newtok = self.lexerrorf(tok) + lexpos += getattr(tok,"_skipn",0) + if oldpos == lexpos: + # Error method didn't change text position at all. This is an error. + self.lexpos = lexpos + raise LexError, ("Scanning error. Illegal character '%s'" % (lexdata[lexpos]), lexdata[lexpos:]) + if not newtok: continue + self.lexpos = lexpos + return newtok + + self.lexpos = lexpos + raise LexError, ("No match found", lexdata[lexpos:]) + + # No more input data + self.lexpos = lexpos + 1 + return None + + +# ----------------------------------------------------------------------------- +# validate_file() +# +# This checks to see if there are duplicated t_rulename() functions or strings +# in the parser input file. This is done using a simple regular expression +# match on each line in the filename. +# ----------------------------------------------------------------------------- + +def validate_file(filename): + import os.path + base,ext = os.path.splitext(filename) + if ext != '.py': return 1 # No idea what the file is. Return OK + + try: + f = open(filename) + lines = f.readlines() + f.close() + except IOError: + return 1 # Oh well + + fre = re.compile(r'\s*def\s+(t_[a-zA-Z_0-9]*)\(') + sre = re.compile(r'\s*(t_[a-zA-Z_0-9]*)\s*=') + counthash = { } + linen = 1 + noerror = 1 + for l in lines: + m = fre.match(l) + if not m: + m = sre.match(l) + if m: + name = m.group(1) + prev = counthash.get(name) + if not prev: + counthash[name] = linen + else: + print "%s:%d: Rule %s redefined. Previously defined on line %d" % (filename,linen,name,prev) + noerror = 0 + linen += 1 + return noerror + +# ----------------------------------------------------------------------------- +# _read_lextab(module) +# +# Reads lexer table from a lextab file instead of using introspection. +# ----------------------------------------------------------------------------- + +def _read_lextab(lexer, fdict, module): + exec "import %s as lextab" % module + lexer.lexre = re.compile(lextab._lexre, re.VERBOSE) + lexer.lexindexfunc = lextab._lextab + for i in range(len(lextab._lextab)): + t = lexer.lexindexfunc[i] + if t: + if t[0]: + lexer.lexindexfunc[i] = (fdict[t[0]],t[1]) + lexer.lextokens = lextab._lextokens + lexer.lexignore = lextab._lexignore + if lextab._lexerrorf: + lexer.lexerrorf = fdict[lextab._lexerrorf] + +# ----------------------------------------------------------------------------- +# lex(module) +# +# Build all of the regular expression rules from definitions in the supplied module +# ----------------------------------------------------------------------------- +def lex(module=None,debug=0,optimize=0,lextab="lextab"): + ldict = None + regex = "" + error = 0 + files = { } + lexer = Lexer() + lexer.debug = debug + lexer.optimize = optimize + global token,input + + if module: + if not isinstance(module, types.ModuleType): + raise ValueError,"Expected a module" + + ldict = module.__dict__ + + else: + # No module given. We might be able to get information from the caller. + try: + raise RuntimeError + except RuntimeError: + e,b,t = sys.exc_info() + f = t.tb_frame + f = f.f_back # Walk out to our calling function + ldict = f.f_globals # Grab its globals dictionary + + if optimize and lextab: + try: + _read_lextab(lexer,ldict, lextab) + if not lexer.lexignore: lexer.lexignore = "" + token = lexer.token + input = lexer.input + return lexer + + except ImportError: + pass + + # Get the tokens map + tokens = ldict.get("tokens",None) + if not tokens: + raise SyntaxError,"lex: module does not define 'tokens'" + if not (isinstance(tokens,types.ListType) or isinstance(tokens,types.TupleType)): + raise SyntaxError,"lex: tokens must be a list or tuple." + + # Build a dictionary of valid token names + lexer.lextokens = { } + if not optimize: + + # Utility function for verifying tokens + def is_identifier(s): + for c in s: + if not (c.isalnum() or c == '_'): return 0 + return 1 + + for n in tokens: + if not is_identifier(n): + print "lex: Bad token name '%s'" % n + error = 1 + if lexer.lextokens.has_key(n): + print "lex: Warning. Token '%s' multiply defined." % n + lexer.lextokens[n] = None + else: + for n in tokens: lexer.lextokens[n] = None + + + if debug: + print "lex: tokens = '%s'" % lexer.lextokens.keys() + + # Get a list of symbols with the t_ prefix + tsymbols = [f for f in ldict.keys() if f[:2] == 't_'] + + # Now build up a list of functions and a list of strings + fsymbols = [ ] + ssymbols = [ ] + for f in tsymbols: + if isinstance(ldict[f],types.FunctionType): + fsymbols.append(ldict[f]) + elif isinstance(ldict[f],types.StringType): + ssymbols.append((f,ldict[f])) + else: + print "lex: %s not defined as a function or string" % f + error = 1 + + # Sort the functions by line number + fsymbols.sort(lambda x,y: cmp(x.func_code.co_firstlineno,y.func_code.co_firstlineno)) + + # Sort the strings by regular expression length + ssymbols.sort(lambda x,y: (len(x[1]) < len(y[1])) - (len(x[1]) > len(y[1]))) + + # Check for non-empty symbols + if len(fsymbols) == 0 and len(ssymbols) == 0: + raise SyntaxError,"lex: no rules of the form t_rulename are defined." + + # Add all of the rules defined with actions first + for f in fsymbols: + + line = f.func_code.co_firstlineno + file = f.func_code.co_filename + files[file] = None + + if not optimize: + if f.func_code.co_argcount > 1: + print "%s:%d: Rule '%s' has too many arguments." % (file,line,f.__name__) + error = 1 + continue + + if f.func_code.co_argcount < 1: + print "%s:%d: Rule '%s' requires an argument." % (file,line,f.__name__) + error = 1 + continue + + if f.__name__ == 't_ignore': + print "%s:%d: Rule '%s' must be defined as a string." % (file,line,f.__name__) + error = 1 + continue + + if f.__name__ == 't_error': + lexer.lexerrorf = f + continue + + if f.__doc__: + if not optimize: + try: + c = re.compile(f.__doc__, re.VERBOSE) + except re.error,e: + print "%s:%d: Invalid regular expression for rule '%s'. %s" % (file,line,f.__name__,e) + error = 1 + continue + + if debug: + print "lex: Adding rule %s -> '%s'" % (f.__name__,f.__doc__) + + # Okay. The regular expression seemed okay. Let's append it to the master regular + # expression we're building + + if (regex): regex += "|" + regex += "(?P<%s>%s)" % (f.__name__,f.__doc__) + else: + print "%s:%d: No regular expression defined for rule '%s'" % (file,line,f.__name__) + + # Now add all of the simple rules + for name,r in ssymbols: + + if name == 't_ignore': + lexer.lexignore = r + continue + + if not optimize: + if name == 't_error': + raise SyntaxError,"lex: Rule 't_error' must be defined as a function" + error = 1 + continue + + if not lexer.lextokens.has_key(name[2:]): + print "lex: Rule '%s' defined for an unspecified token %s." % (name,name[2:]) + error = 1 + continue + try: + c = re.compile(r,re.VERBOSE) + except re.error,e: + print "lex: Invalid regular expression for rule '%s'. %s" % (name,e) + error = 1 + continue + if debug: + print "lex: Adding rule %s -> '%s'" % (name,r) + + if regex: regex += "|" + regex += "(?P<%s>%s)" % (name,r) + + if not optimize: + for f in files.keys(): + if not validate_file(f): + error = 1 + try: + if debug: + print "lex: regex = '%s'" % regex + lexer.lexre = re.compile(regex, re.VERBOSE) + + # Build the index to function map for the matching engine + lexer.lexindexfunc = [ None ] * (max(lexer.lexre.groupindex.values())+1) + for f,i in lexer.lexre.groupindex.items(): + handle = ldict[f] + if isinstance(handle,types.FunctionType): + lexer.lexindexfunc[i] = (handle,handle.__name__[2:]) + else: + # If rule was specified as a string, we build an anonymous + # callback function to carry out the action + lexer.lexindexfunc[i] = (None,f[2:]) + + # If a lextab was specified, we create a file containing the precomputed + # regular expression and index table + + if lextab and optimize: + lt = open(lextab+".py","w") + lt.write("# %s.py. This file automatically created by PLY. Don't edit.\n" % lextab) + lt.write("_lexre = %s\n" % repr(regex)) + lt.write("_lextab = [\n"); + for i in range(0,len(lexer.lexindexfunc)): + t = lexer.lexindexfunc[i] + if t: + if t[0]: + lt.write(" ('%s',%s),\n"% (t[0].__name__, repr(t[1]))) + else: + lt.write(" (None,%s),\n" % repr(t[1])) + else: + lt.write(" None,\n") + + lt.write("]\n"); + lt.write("_lextokens = %s\n" % repr(lexer.lextokens)) + lt.write("_lexignore = %s\n" % repr(lexer.lexignore)) + if (lexer.lexerrorf): + lt.write("_lexerrorf = %s\n" % repr(lexer.lexerrorf.__name__)) + else: + lt.write("_lexerrorf = None\n") + lt.close() + + except re.error,e: + print "lex: Fatal error. Unable to compile regular expression rules. %s" % e + error = 1 + if error: + raise SyntaxError,"lex: Unable to build lexer." + if not lexer.lexerrorf: + print "lex: Warning. no t_error rule is defined." + + if not lexer.lexignore: lexer.lexignore = "" + + # Create global versions of the token() and input() functions + token = lexer.token + input = lexer.input + + return lexer + +# ----------------------------------------------------------------------------- +# run() +# +# This runs the lexer as a main program +# ----------------------------------------------------------------------------- + +def runmain(lexer=None,data=None): + if not data: + try: + filename = sys.argv[1] + f = open(filename) + data = f.read() + f.close() + except IndexError: + print "Reading from standard input (type EOF to end):" + data = sys.stdin.read() + + if lexer: + _input = lexer.input + else: + _input = input + _input(data) + if lexer: + _token = lexer.token + else: + _token = token + + while 1: + tok = _token() + if not tok: break + print "(%s,'%s',%d)" % (tok.type, tok.value, tok.lineno) + + + + diff --git a/ext/ply/test/README b/ext/ply/test/README new file mode 100644 index 000000000..bca748497 --- /dev/null +++ b/ext/ply/test/README @@ -0,0 +1,9 @@ +This directory mostly contains tests for various types of error +conditions. To run: + + $ python testlex.py . + $ python testyacc.py . + +(make sure lex.py and yacc.py exist in this directory before +running the tests). + diff --git a/ext/ply/test/calclex.py b/ext/ply/test/calclex.py new file mode 100644 index 000000000..f8eb91a09 --- /dev/null +++ b/ext/ply/test/calclex.py @@ -0,0 +1,46 @@ +# ----------------------------------------------------------------------------- +# calclex.py +# ----------------------------------------------------------------------------- + +tokens = ( + 'NAME','NUMBER', + 'PLUS','MINUS','TIMES','DIVIDE','EQUALS', + 'LPAREN','RPAREN', + ) + +# Tokens + +t_PLUS = r'\+' +t_MINUS = r'-' +t_TIMES = r'\*' +t_DIVIDE = r'/' +t_EQUALS = r'=' +t_LPAREN = r'\(' +t_RPAREN = r'\)' +t_NAME = r'[a-zA-Z_][a-zA-Z0-9_]*' + +def t_NUMBER(t): + r'\d+' + try: + t.value = int(t.value) + except ValueError: + print "Integer value too large", t.value + t.value = 0 + return t + +t_ignore = " \t" + +def t_newline(t): + r'\n+' + t.lineno += t.value.count("\n") + +def t_error(t): + print "Illegal character '%s'" % t.value[0] + t.skip(1) + +# Build the lexer +import lex +lex.lex() + + + diff --git a/ext/ply/test/lex_doc1.exp b/ext/ply/test/lex_doc1.exp new file mode 100644 index 000000000..29381911d --- /dev/null +++ b/ext/ply/test/lex_doc1.exp @@ -0,0 +1 @@ +./lex_doc1.py:15: No regular expression defined for rule 't_NUMBER' diff --git a/ext/ply/test/lex_doc1.py b/ext/ply/test/lex_doc1.py new file mode 100644 index 000000000..fb0fb885e --- /dev/null +++ b/ext/ply/test/lex_doc1.py @@ -0,0 +1,27 @@ +# lex_token.py +# +# Missing documentation string + +import lex + +tokens = [ + "PLUS", + "MINUS", + "NUMBER", + ] + +t_PLUS = r'\+' +t_MINUS = r'-' +def t_NUMBER(t): + pass + +def t_error(t): + pass + + +import sys +sys.tracebacklimit = 0 + +lex.lex() + + diff --git a/ext/ply/test/lex_dup1.exp b/ext/ply/test/lex_dup1.exp new file mode 100644 index 000000000..22bca3190 --- /dev/null +++ b/ext/ply/test/lex_dup1.exp @@ -0,0 +1,2 @@ +./lex_dup1.py:17: Rule t_NUMBER redefined. Previously defined on line 15 +SyntaxError: lex: Unable to build lexer. diff --git a/ext/ply/test/lex_dup1.py b/ext/ply/test/lex_dup1.py new file mode 100644 index 000000000..88bbe00e9 --- /dev/null +++ b/ext/ply/test/lex_dup1.py @@ -0,0 +1,27 @@ +# lex_token.py +# +# Duplicated rule specifiers + +import lex + +tokens = [ + "PLUS", + "MINUS", + "NUMBER", + ] + +t_PLUS = r'\+' +t_MINUS = r'-' +t_NUMBER = r'\d+' + +t_NUMBER = r'\d+' + +def t_error(t): + pass + +import sys +sys.tracebacklimit = 0 + +lex.lex() + + diff --git a/ext/ply/test/lex_dup2.exp b/ext/ply/test/lex_dup2.exp new file mode 100644 index 000000000..883bdad46 --- /dev/null +++ b/ext/ply/test/lex_dup2.exp @@ -0,0 +1,2 @@ +./lex_dup2.py:19: Rule t_NUMBER redefined. Previously defined on line 15 +SyntaxError: lex: Unable to build lexer. diff --git a/ext/ply/test/lex_dup2.py b/ext/ply/test/lex_dup2.py new file mode 100644 index 000000000..65e0b21a2 --- /dev/null +++ b/ext/ply/test/lex_dup2.py @@ -0,0 +1,31 @@ +# lex_token.py +# +# Duplicated rule specifiers + +import lex + +tokens = [ + "PLUS", + "MINUS", + "NUMBER", + ] + +t_PLUS = r'\+' +t_MINUS = r'-' +def t_NUMBER(t): + r'\d+' + pass + +def t_NUMBER(t): + r'\d+' + pass + +def t_error(t): + pass + +import sys +sys.tracebacklimit = 0 + +lex.lex() + + diff --git a/ext/ply/test/lex_dup3.exp b/ext/ply/test/lex_dup3.exp new file mode 100644 index 000000000..916612aa1 --- /dev/null +++ b/ext/ply/test/lex_dup3.exp @@ -0,0 +1,2 @@ +./lex_dup3.py:17: Rule t_NUMBER redefined. Previously defined on line 15 +SyntaxError: lex: Unable to build lexer. diff --git a/ext/ply/test/lex_dup3.py b/ext/ply/test/lex_dup3.py new file mode 100644 index 000000000..424101823 --- /dev/null +++ b/ext/ply/test/lex_dup3.py @@ -0,0 +1,29 @@ +# lex_token.py +# +# Duplicated rule specifiers + +import lex + +tokens = [ + "PLUS", + "MINUS", + "NUMBER", + ] + +t_PLUS = r'\+' +t_MINUS = r'-' +t_NUMBER = r'\d+' + +def t_NUMBER(t): + r'\d+' + pass + +def t_error(t): + pass + +import sys +sys.tracebacklimit = 0 + +lex.lex() + + diff --git a/ext/ply/test/lex_empty.exp b/ext/ply/test/lex_empty.exp new file mode 100644 index 000000000..af38602d5 --- /dev/null +++ b/ext/ply/test/lex_empty.exp @@ -0,0 +1 @@ +SyntaxError: lex: no rules of the form t_rulename are defined. diff --git a/ext/ply/test/lex_empty.py b/ext/ply/test/lex_empty.py new file mode 100644 index 000000000..6472832f1 --- /dev/null +++ b/ext/ply/test/lex_empty.py @@ -0,0 +1,18 @@ +# lex_token.py +# +# No rules defined + +import lex + +tokens = [ + "PLUS", + "MINUS", + "NUMBER", + ] + +import sys +sys.tracebacklimit = 0 + +lex.lex() + + diff --git a/ext/ply/test/lex_error1.exp b/ext/ply/test/lex_error1.exp new file mode 100644 index 000000000..baa19e5b3 --- /dev/null +++ b/ext/ply/test/lex_error1.exp @@ -0,0 +1 @@ +lex: Warning. no t_error rule is defined. diff --git a/ext/ply/test/lex_error1.py b/ext/ply/test/lex_error1.py new file mode 100644 index 000000000..ed7980346 --- /dev/null +++ b/ext/ply/test/lex_error1.py @@ -0,0 +1,22 @@ +# lex_token.py +# +# Missing t_error() rule + +import lex + +tokens = [ + "PLUS", + "MINUS", + "NUMBER", + ] + +t_PLUS = r'\+' +t_MINUS = r'-' +t_NUMBER = r'\d+' + +import sys +sys.tracebacklimit = 0 + +lex.lex() + + diff --git a/ext/ply/test/lex_error2.exp b/ext/ply/test/lex_error2.exp new file mode 100644 index 000000000..fb1b55c8b --- /dev/null +++ b/ext/ply/test/lex_error2.exp @@ -0,0 +1 @@ +SyntaxError: lex: Rule 't_error' must be defined as a function diff --git a/ext/ply/test/lex_error2.py b/ext/ply/test/lex_error2.py new file mode 100644 index 000000000..80020f72b --- /dev/null +++ b/ext/ply/test/lex_error2.py @@ -0,0 +1,24 @@ +# lex_token.py +# +# t_error defined, but not function + +import lex + +tokens = [ + "PLUS", + "MINUS", + "NUMBER", + ] + +t_PLUS = r'\+' +t_MINUS = r'-' +t_NUMBER = r'\d+' + +t_error = "foo" + +import sys +sys.tracebacklimit = 0 + +lex.lex() + + diff --git a/ext/ply/test/lex_error3.exp b/ext/ply/test/lex_error3.exp new file mode 100644 index 000000000..936828f93 --- /dev/null +++ b/ext/ply/test/lex_error3.exp @@ -0,0 +1,2 @@ +./lex_error3.py:17: Rule 't_error' requires an argument. +SyntaxError: lex: Unable to build lexer. diff --git a/ext/ply/test/lex_error3.py b/ext/ply/test/lex_error3.py new file mode 100644 index 000000000..46facf589 --- /dev/null +++ b/ext/ply/test/lex_error3.py @@ -0,0 +1,25 @@ +# lex_token.py +# +# t_error defined as function, but with wrong # args + +import lex + +tokens = [ + "PLUS", + "MINUS", + "NUMBER", + ] + +t_PLUS = r'\+' +t_MINUS = r'-' +t_NUMBER = r'\d+' + +def t_error(): + pass + +import sys +sys.tracebacklimit = 0 + +lex.lex() + + diff --git a/ext/ply/test/lex_error4.exp b/ext/ply/test/lex_error4.exp new file mode 100644 index 000000000..242516576 --- /dev/null +++ b/ext/ply/test/lex_error4.exp @@ -0,0 +1,2 @@ +./lex_error4.py:17: Rule 't_error' has too many arguments. +SyntaxError: lex: Unable to build lexer. diff --git a/ext/ply/test/lex_error4.py b/ext/ply/test/lex_error4.py new file mode 100644 index 000000000..d777fee84 --- /dev/null +++ b/ext/ply/test/lex_error4.py @@ -0,0 +1,25 @@ +# lex_token.py +# +# t_error defined as function, but too many args + +import lex + +tokens = [ + "PLUS", + "MINUS", + "NUMBER", + ] + +t_PLUS = r'\+' +t_MINUS = r'-' +t_NUMBER = r'\d+' + +def t_error(t,s): + pass + +import sys +sys.tracebacklimit = 0 + +lex.lex() + + diff --git a/ext/ply/test/lex_hedit.exp b/ext/ply/test/lex_hedit.exp new file mode 100644 index 000000000..0b09827c6 --- /dev/null +++ b/ext/ply/test/lex_hedit.exp @@ -0,0 +1,3 @@ +(H_EDIT_DESCRIPTOR,'abc',1) +(H_EDIT_DESCRIPTOR,'abcdefghij',1) +(H_EDIT_DESCRIPTOR,'xy',1) diff --git a/ext/ply/test/lex_hedit.py b/ext/ply/test/lex_hedit.py new file mode 100644 index 000000000..68f9fcbd1 --- /dev/null +++ b/ext/ply/test/lex_hedit.py @@ -0,0 +1,44 @@ +# ----------------------------------------------------------------------------- +# hedit.py +# +# Paring of Fortran H Edit descriptions (Contributed by Pearu Peterson) +# +# These tokens can't be easily tokenized because they are of the following +# form: +# +# nHc1...cn +# +# where n is a positive integer and c1 ... cn are characters. +# +# This example shows how to modify the state of the lexer to parse +# such tokens +# ----------------------------------------------------------------------------- + +tokens = ( + 'H_EDIT_DESCRIPTOR', + ) + +# Tokens +t_ignore = " \t\n" + +def t_H_EDIT_DESCRIPTOR(t): + r"\d+H.*" # This grabs all of the remaining text + i = t.value.index('H') + n = eval(t.value[:i]) + + # Adjust the tokenizing position + t.lexer.lexpos -= len(t.value) - (i+1+n) + t.value = t.value[i+1:i+1+n] + return t + +def t_error(t): + print "Illegal character '%s'" % t.value[0] + t.skip(1) + +# Build the lexer +import lex +lex.lex() +lex.runmain(data="3Habc 10Habcdefghij 2Hxy") + + + diff --git a/ext/ply/test/lex_ignore.exp b/ext/ply/test/lex_ignore.exp new file mode 100644 index 000000000..c3b04a154 --- /dev/null +++ b/ext/ply/test/lex_ignore.exp @@ -0,0 +1,2 @@ +./lex_ignore.py:17: Rule 't_ignore' must be defined as a string. +SyntaxError: lex: Unable to build lexer. diff --git a/ext/ply/test/lex_ignore.py b/ext/ply/test/lex_ignore.py new file mode 100644 index 000000000..49c303f81 --- /dev/null +++ b/ext/ply/test/lex_ignore.py @@ -0,0 +1,29 @@ +# lex_token.py +# +# Improperly specific ignore declaration + +import lex + +tokens = [ + "PLUS", + "MINUS", + "NUMBER", + ] + +t_PLUS = r'\+' +t_MINUS = r'-' +t_NUMBER = r'\d+' + +def t_ignore(t): + ' \t' + pass + +def t_error(t): + pass + +import sys +sys.tracebacklimit = 0 + +lex.lex() + + diff --git a/ext/ply/test/lex_re1.exp b/ext/ply/test/lex_re1.exp new file mode 100644 index 000000000..634eefefe --- /dev/null +++ b/ext/ply/test/lex_re1.exp @@ -0,0 +1,2 @@ +lex: Invalid regular expression for rule 't_NUMBER'. unbalanced parenthesis +SyntaxError: lex: Unable to build lexer. diff --git a/ext/ply/test/lex_re1.py b/ext/ply/test/lex_re1.py new file mode 100644 index 000000000..4a055ad72 --- /dev/null +++ b/ext/ply/test/lex_re1.py @@ -0,0 +1,25 @@ +# lex_token.py +# +# Bad regular expression in a string + +import lex + +tokens = [ + "PLUS", + "MINUS", + "NUMBER", + ] + +t_PLUS = r'\+' +t_MINUS = r'-' +t_NUMBER = r'(\d+' + +def t_error(t): + pass + +import sys +sys.tracebacklimit = 0 + +lex.lex() + + diff --git a/ext/ply/test/lex_rule1.exp b/ext/ply/test/lex_rule1.exp new file mode 100644 index 000000000..0c23ca294 --- /dev/null +++ b/ext/ply/test/lex_rule1.exp @@ -0,0 +1,2 @@ +lex: t_NUMBER not defined as a function or string +SyntaxError: lex: Unable to build lexer. diff --git a/ext/ply/test/lex_rule1.py b/ext/ply/test/lex_rule1.py new file mode 100644 index 000000000..ff3764ea1 --- /dev/null +++ b/ext/ply/test/lex_rule1.py @@ -0,0 +1,25 @@ +# lex_token.py +# +# Rule defined as some other type + +import lex + +tokens = [ + "PLUS", + "MINUS", + "NUMBER", + ] + +t_PLUS = r'\+' +t_MINUS = r'-' +t_NUMBER = 1 + +def t_error(t): + pass + +import sys +sys.tracebacklimit = 0 + +lex.lex() + + diff --git a/ext/ply/test/lex_token1.exp b/ext/ply/test/lex_token1.exp new file mode 100644 index 000000000..3792831fa --- /dev/null +++ b/ext/ply/test/lex_token1.exp @@ -0,0 +1 @@ +SyntaxError: lex: module does not define 'tokens' diff --git a/ext/ply/test/lex_token1.py b/ext/ply/test/lex_token1.py new file mode 100644 index 000000000..e8eca2b63 --- /dev/null +++ b/ext/ply/test/lex_token1.py @@ -0,0 +1,19 @@ +# lex_token.py +# +# Tests for absence of tokens variable + +import lex + +t_PLUS = r'\+' +t_MINUS = r'-' +t_NUMBER = r'\d+' + +def t_error(t): + pass + +import sys +sys.tracebacklimit = 0 + +lex.lex() + + diff --git a/ext/ply/test/lex_token2.exp b/ext/ply/test/lex_token2.exp new file mode 100644 index 000000000..3f98fe51d --- /dev/null +++ b/ext/ply/test/lex_token2.exp @@ -0,0 +1 @@ +SyntaxError: lex: tokens must be a list or tuple. diff --git a/ext/ply/test/lex_token2.py b/ext/ply/test/lex_token2.py new file mode 100644 index 000000000..38b34dabe --- /dev/null +++ b/ext/ply/test/lex_token2.py @@ -0,0 +1,21 @@ +# lex_token.py +# +# Tests for tokens of wrong type + +import lex + +tokens = "PLUS MINUS NUMBER" + +t_PLUS = r'\+' +t_MINUS = r'-' +t_NUMBER = r'\d+' + +def t_error(t): + pass + +import sys +sys.tracebacklimit = 0 + +lex.lex() + + diff --git a/ext/ply/test/lex_token3.exp b/ext/ply/test/lex_token3.exp new file mode 100644 index 000000000..d991d3c37 --- /dev/null +++ b/ext/ply/test/lex_token3.exp @@ -0,0 +1,2 @@ +lex: Rule 't_MINUS' defined for an unspecified token MINUS. +SyntaxError: lex: Unable to build lexer. diff --git a/ext/ply/test/lex_token3.py b/ext/ply/test/lex_token3.py new file mode 100644 index 000000000..909f9180d --- /dev/null +++ b/ext/ply/test/lex_token3.py @@ -0,0 +1,24 @@ +# lex_token.py +# +# tokens is right type, but is missing a token for one rule + +import lex + +tokens = [ + "PLUS", + "NUMBER", + ] + +t_PLUS = r'\+' +t_MINUS = r'-' +t_NUMBER = r'\d+' + +def t_error(t): + pass + +import sys +sys.tracebacklimit = 0 + +lex.lex() + + diff --git a/ext/ply/test/lex_token4.exp b/ext/ply/test/lex_token4.exp new file mode 100644 index 000000000..3dd88e05a --- /dev/null +++ b/ext/ply/test/lex_token4.exp @@ -0,0 +1,2 @@ +lex: Bad token name '-' +SyntaxError: lex: Unable to build lexer. diff --git a/ext/ply/test/lex_token4.py b/ext/ply/test/lex_token4.py new file mode 100644 index 000000000..d77d1662c --- /dev/null +++ b/ext/ply/test/lex_token4.py @@ -0,0 +1,26 @@ +# lex_token.py +# +# Bad token name + +import lex + +tokens = [ + "PLUS", + "MINUS", + "-", + "NUMBER", + ] + +t_PLUS = r'\+' +t_MINUS = r'-' +t_NUMBER = r'\d+' + +def t_error(t): + pass + +import sys +sys.tracebacklimit = 0 + +lex.lex() + + diff --git a/ext/ply/test/lex_token5.exp b/ext/ply/test/lex_token5.exp new file mode 100644 index 000000000..d7bcb2e7c --- /dev/null +++ b/ext/ply/test/lex_token5.exp @@ -0,0 +1 @@ +lex.LexError: ./lex_token5.py:16: Rule 't_NUMBER' returned an unknown token type 'NUM' diff --git a/ext/ply/test/lex_token5.py b/ext/ply/test/lex_token5.py new file mode 100644 index 000000000..d9b0c96aa --- /dev/null +++ b/ext/ply/test/lex_token5.py @@ -0,0 +1,31 @@ +# lex_token.py +# +# Return a bad token name + +import lex + +tokens = [ + "PLUS", + "MINUS", + "NUMBER", + ] + +t_PLUS = r'\+' +t_MINUS = r'-' + +def t_NUMBER(t): + r'\d+' + t.type = "NUM" + return t + +def t_error(t): + pass + +import sys +sys.tracebacklimit = 0 + +lex.lex() +lex.input("1234") +t = lex.token() + + diff --git a/ext/ply/test/testlex.py b/ext/ply/test/testlex.py new file mode 100755 index 000000000..df000b83d --- /dev/null +++ b/ext/ply/test/testlex.py @@ -0,0 +1,57 @@ +#!/usr/local/bin +# ---------------------------------------------------------------------- +# testlex.py +# +# Run tests for the lexing module +# ---------------------------------------------------------------------- + +import sys,os,glob + +if len(sys.argv) < 2: + print "Usage: python testlex.py directory" + raise SystemExit + +dirname = None +make = 0 + +for o in sys.argv[1:]: + if o == '-make': + make = 1 + else: + dirname = o + break + +if not dirname: + print "Usage: python testlex.py [-make] directory" + raise SystemExit + +f = glob.glob("%s/%s" % (dirname,"lex_*.py")) + +print "**** Running tests for lex ****" + +for t in f: + name = t[:-3] + print "Testing %-32s" % name, + if make: + if not os.path.exists("%s.exp" % name): + os.system("python %s.py >%s.exp 2>&1" % (name,name)) + passed = 1 + else: + os.system("python %s.py >%s.out 2>&1" % (name,name)) + a = os.system("diff %s.out %s.exp >%s.dif" % (name,name,name)) + if a == 0: + passed = 1 + else: + passed = 0 + + if passed: + print "Passed" + else: + print "Failed. See %s.dif" % name + + + + + + + diff --git a/ext/ply/test/testyacc.py b/ext/ply/test/testyacc.py new file mode 100644 index 000000000..a185cbb29 --- /dev/null +++ b/ext/ply/test/testyacc.py @@ -0,0 +1,58 @@ +#!/usr/local/bin +# ---------------------------------------------------------------------- +# testyacc.py +# +# Run tests for the yacc module +# ---------------------------------------------------------------------- + +import sys,os,glob + +if len(sys.argv) < 2: + print "Usage: python testyacc.py directory" + raise SystemExit + +dirname = None +make = 0 + +for o in sys.argv[1:]: + if o == '-make': + make = 1 + else: + dirname = o + break + +if not dirname: + print "Usage: python testyacc.py [-make] directory" + raise SystemExit + +f = glob.glob("%s/%s" % (dirname,"yacc_*.py")) + +print "**** Running tests for yacc ****" + +for t in f: + name = t[:-3] + print "Testing %-32s" % name, + os.system("rm -f %s/parsetab.*" % dirname) + if make: + if not os.path.exists("%s.exp" % name): + os.system("python %s.py >%s.exp 2>&1" % (name,name)) + passed = 1 + else: + os.system("python %s.py >%s.out 2>&1" % (name,name)) + a = os.system("diff %s.out %s.exp >%s.dif" % (name,name,name)) + if a == 0: + passed = 1 + else: + passed = 0 + + if passed: + print "Passed" + else: + print "Failed. See %s.dif" % name + + + + + + + diff --git a/ext/ply/test/yacc_badargs.exp b/ext/ply/test/yacc_badargs.exp new file mode 100644 index 000000000..b145c51f2 --- /dev/null +++ b/ext/ply/test/yacc_badargs.exp @@ -0,0 +1,3 @@ +./yacc_badargs.py:21: Rule 'p_statement_assign' has too many arguments. +./yacc_badargs.py:25: Rule 'p_statement_expr' requires an argument. +yacc.YaccError: Unable to construct parser. diff --git a/ext/ply/test/yacc_badargs.py b/ext/ply/test/yacc_badargs.py new file mode 100644 index 000000000..12075efcc --- /dev/null +++ b/ext/ply/test/yacc_badargs.py @@ -0,0 +1,67 @@ +# ----------------------------------------------------------------------------- +# yacc_badargs.py +# +# Rules with wrong # args +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t,s): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_badprec.exp b/ext/ply/test/yacc_badprec.exp new file mode 100644 index 000000000..7764b0246 --- /dev/null +++ b/ext/ply/test/yacc_badprec.exp @@ -0,0 +1 @@ +yacc.YaccError: precedence must be a list or tuple. diff --git a/ext/ply/test/yacc_badprec.py b/ext/ply/test/yacc_badprec.py new file mode 100644 index 000000000..55bf7720d --- /dev/null +++ b/ext/ply/test/yacc_badprec.py @@ -0,0 +1,63 @@ +# ----------------------------------------------------------------------------- +# yacc_badprec.py +# +# Bad precedence specifier +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = "blah" + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_badprec2.exp b/ext/ply/test/yacc_badprec2.exp new file mode 100644 index 000000000..1df1427b2 --- /dev/null +++ b/ext/ply/test/yacc_badprec2.exp @@ -0,0 +1,3 @@ +yacc: Invalid precedence table. +yacc: Generating SLR parsing table... +yacc: 4 shift/reduce conflicts diff --git a/ext/ply/test/yacc_badprec2.py b/ext/ply/test/yacc_badprec2.py new file mode 100644 index 000000000..9cbc99827 --- /dev/null +++ b/ext/ply/test/yacc_badprec2.py @@ -0,0 +1,67 @@ +# ----------------------------------------------------------------------------- +# yacc_badprec2.py +# +# Bad precedence +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = ( + 42, + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_badrule.exp b/ext/ply/test/yacc_badrule.exp new file mode 100644 index 000000000..553779778 --- /dev/null +++ b/ext/ply/test/yacc_badrule.exp @@ -0,0 +1,5 @@ +./yacc_badrule.py:22: Syntax error. Expected ':' +./yacc_badrule.py:26: Syntax error in rule 'statement' +./yacc_badrule.py:31: Syntax error. Expected ':' +./yacc_badrule.py:40: Syntax error. Expected ':' +yacc.YaccError: Unable to construct parser. diff --git a/ext/ply/test/yacc_badrule.py b/ext/ply/test/yacc_badrule.py new file mode 100644 index 000000000..cad3a967e --- /dev/null +++ b/ext/ply/test/yacc_badrule.py @@ -0,0 +1,67 @@ +# ----------------------------------------------------------------------------- +# yacc_badrule.py +# +# Syntax problems in the rule strings +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression: MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_badtok.exp b/ext/ply/test/yacc_badtok.exp new file mode 100644 index 000000000..f6e64726c --- /dev/null +++ b/ext/ply/test/yacc_badtok.exp @@ -0,0 +1 @@ +yacc.YaccError: tokens must be a list or tuple. diff --git a/ext/ply/test/yacc_badtok.py b/ext/ply/test/yacc_badtok.py new file mode 100644 index 000000000..a17d26aaa --- /dev/null +++ b/ext/ply/test/yacc_badtok.py @@ -0,0 +1,68 @@ +# ----------------------------------------------------------------------------- +# yacc_badtok.py +# +# A grammar, but tokens is a bad datatype +# ----------------------------------------------------------------------------- + +import sys +sys.tracebacklimit = 0 + +tokens = "Hello" + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_dup.exp b/ext/ply/test/yacc_dup.exp new file mode 100644 index 000000000..99f3fe22c --- /dev/null +++ b/ext/ply/test/yacc_dup.exp @@ -0,0 +1,4 @@ +./yacc_dup.py:25: Function p_statement redefined. Previously defined on line 21 +yacc: Warning. Token 'EQUALS' defined, but not used. +yacc: Warning. There is 1 unused token. +yacc: Generating SLR parsing table... diff --git a/ext/ply/test/yacc_dup.py b/ext/ply/test/yacc_dup.py new file mode 100644 index 000000000..557cd0ae1 --- /dev/null +++ b/ext/ply/test/yacc_dup.py @@ -0,0 +1,67 @@ +# ----------------------------------------------------------------------------- +# yacc_dup.py +# +# Duplicated rule name +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_error1.exp b/ext/ply/test/yacc_error1.exp new file mode 100644 index 000000000..980fc905c --- /dev/null +++ b/ext/ply/test/yacc_error1.exp @@ -0,0 +1 @@ +yacc.YaccError: ./yacc_error1.py:59: p_error() requires 1 argument. diff --git a/ext/ply/test/yacc_error1.py b/ext/ply/test/yacc_error1.py new file mode 100644 index 000000000..413004520 --- /dev/null +++ b/ext/ply/test/yacc_error1.py @@ -0,0 +1,67 @@ +# ----------------------------------------------------------------------------- +# yacc_error1.py +# +# Bad p_error() function +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t,s): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_error2.exp b/ext/ply/test/yacc_error2.exp new file mode 100644 index 000000000..d0573b4dd --- /dev/null +++ b/ext/ply/test/yacc_error2.exp @@ -0,0 +1 @@ +yacc.YaccError: ./yacc_error2.py:59: p_error() requires 1 argument. diff --git a/ext/ply/test/yacc_error2.py b/ext/ply/test/yacc_error2.py new file mode 100644 index 000000000..d4fd1d219 --- /dev/null +++ b/ext/ply/test/yacc_error2.py @@ -0,0 +1,67 @@ +# ----------------------------------------------------------------------------- +# yacc_error1.py +# +# Bad p_error() function +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_error3.exp b/ext/ply/test/yacc_error3.exp new file mode 100644 index 000000000..31eaee754 --- /dev/null +++ b/ext/ply/test/yacc_error3.exp @@ -0,0 +1 @@ +yacc.YaccError: 'p_error' defined, but is not a function. diff --git a/ext/ply/test/yacc_error3.py b/ext/ply/test/yacc_error3.py new file mode 100644 index 000000000..7093fab48 --- /dev/null +++ b/ext/ply/test/yacc_error3.py @@ -0,0 +1,66 @@ +# ----------------------------------------------------------------------------- +# yacc_error1.py +# +# Bad p_error() function +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +p_error = "blah" + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_inf.exp b/ext/ply/test/yacc_inf.exp new file mode 100644 index 000000000..a7f47dada --- /dev/null +++ b/ext/ply/test/yacc_inf.exp @@ -0,0 +1,5 @@ +yacc: Warning. Token 'NUMBER' defined, but not used. +yacc: Warning. There is 1 unused token. +yacc: Infinite recursion detected for symbol 'statement'. +yacc: Infinite recursion detected for symbol 'expression'. +yacc.YaccError: Unable to construct parser. diff --git a/ext/ply/test/yacc_inf.py b/ext/ply/test/yacc_inf.py new file mode 100644 index 000000000..885e2c4df --- /dev/null +++ b/ext/ply/test/yacc_inf.py @@ -0,0 +1,55 @@ +# ----------------------------------------------------------------------------- +# yacc_inf.py +# +# Infinite recursion +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_missing1.exp b/ext/ply/test/yacc_missing1.exp new file mode 100644 index 000000000..065d6a54a --- /dev/null +++ b/ext/ply/test/yacc_missing1.exp @@ -0,0 +1,2 @@ +./yacc_missing1.py:22: Symbol 'location' used, but not defined as a token or a rule. +yacc.YaccError: Unable to construct parser. diff --git a/ext/ply/test/yacc_missing1.py b/ext/ply/test/yacc_missing1.py new file mode 100644 index 000000000..e63904d0e --- /dev/null +++ b/ext/ply/test/yacc_missing1.py @@ -0,0 +1,67 @@ +# ----------------------------------------------------------------------------- +# yacc_missing1.py +# +# Grammar with a missing rule +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : location EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_nodoc.exp b/ext/ply/test/yacc_nodoc.exp new file mode 100644 index 000000000..3f52a3287 --- /dev/null +++ b/ext/ply/test/yacc_nodoc.exp @@ -0,0 +1,2 @@ +./yacc_nodoc.py:25: No documentation string specified in function 'p_statement_expr' +yacc: Generating SLR parsing table... diff --git a/ext/ply/test/yacc_nodoc.py b/ext/ply/test/yacc_nodoc.py new file mode 100644 index 000000000..e3941bdaa --- /dev/null +++ b/ext/ply/test/yacc_nodoc.py @@ -0,0 +1,66 @@ +# ----------------------------------------------------------------------------- +# yacc_nodoc.py +# +# Rule with a missing doc-string +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_noerror.exp b/ext/ply/test/yacc_noerror.exp new file mode 100644 index 000000000..986fa31fa --- /dev/null +++ b/ext/ply/test/yacc_noerror.exp @@ -0,0 +1,2 @@ +yacc: Warning. no p_error() function is defined. +yacc: Generating SLR parsing table... diff --git a/ext/ply/test/yacc_noerror.py b/ext/ply/test/yacc_noerror.py new file mode 100644 index 000000000..d92f48ea6 --- /dev/null +++ b/ext/ply/test/yacc_noerror.py @@ -0,0 +1,64 @@ +# ----------------------------------------------------------------------------- +# yacc_noerror.py +# +# No p_error() rule defined. +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_nop.exp b/ext/ply/test/yacc_nop.exp new file mode 100644 index 000000000..062878b9e --- /dev/null +++ b/ext/ply/test/yacc_nop.exp @@ -0,0 +1,2 @@ +./yacc_nop.py:25: Warning. Possible grammar rule 'statement_expr' defined without p_ prefix. +yacc: Generating SLR parsing table... diff --git a/ext/ply/test/yacc_nop.py b/ext/ply/test/yacc_nop.py new file mode 100644 index 000000000..c599ffd5d --- /dev/null +++ b/ext/ply/test/yacc_nop.py @@ -0,0 +1,67 @@ +# ----------------------------------------------------------------------------- +# yacc_nop.py +# +# Possible grammar rule defined without p_ prefix +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_notfunc.exp b/ext/ply/test/yacc_notfunc.exp new file mode 100644 index 000000000..271167341 --- /dev/null +++ b/ext/ply/test/yacc_notfunc.exp @@ -0,0 +1,4 @@ +yacc: Warning. 'p_statement_assign' not defined as a function +yacc: Warning. Token 'EQUALS' defined, but not used. +yacc: Warning. There is 1 unused token. +yacc: Generating SLR parsing table... diff --git a/ext/ply/test/yacc_notfunc.py b/ext/ply/test/yacc_notfunc.py new file mode 100644 index 000000000..f61663d60 --- /dev/null +++ b/ext/ply/test/yacc_notfunc.py @@ -0,0 +1,65 @@ +# ----------------------------------------------------------------------------- +# yacc_notfunc.py +# +# p_rule not defined as a function +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +p_statement_assign = "Blah" + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_notok.exp b/ext/ply/test/yacc_notok.exp new file mode 100644 index 000000000..708f6f597 --- /dev/null +++ b/ext/ply/test/yacc_notok.exp @@ -0,0 +1 @@ +yacc.YaccError: module does not define a list 'tokens' diff --git a/ext/ply/test/yacc_notok.py b/ext/ply/test/yacc_notok.py new file mode 100644 index 000000000..dfa0059be --- /dev/null +++ b/ext/ply/test/yacc_notok.py @@ -0,0 +1,66 @@ +# ----------------------------------------------------------------------------- +# yacc_notok.py +# +# A grammar, but we forgot to import the tokens list +# ----------------------------------------------------------------------------- + +import sys +sys.tracebacklimit = 0 + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_rr.exp b/ext/ply/test/yacc_rr.exp new file mode 100644 index 000000000..0ec556d16 --- /dev/null +++ b/ext/ply/test/yacc_rr.exp @@ -0,0 +1,2 @@ +yacc: Generating SLR parsing table... +yacc: 1 reduce/reduce conflict diff --git a/ext/ply/test/yacc_rr.py b/ext/ply/test/yacc_rr.py new file mode 100644 index 000000000..c061c2c17 --- /dev/null +++ b/ext/ply/test/yacc_rr.py @@ -0,0 +1,71 @@ +# ----------------------------------------------------------------------------- +# yacc_rr.py +# +# A grammar with a reduce/reduce conflict +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_assign_2(t): + 'statement : NAME EQUALS NUMBER' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_simple.exp b/ext/ply/test/yacc_simple.exp new file mode 100644 index 000000000..de7964b6f --- /dev/null +++ b/ext/ply/test/yacc_simple.exp @@ -0,0 +1 @@ +yacc: Generating SLR parsing table... diff --git a/ext/ply/test/yacc_simple.py b/ext/ply/test/yacc_simple.py new file mode 100644 index 000000000..7b4b40b17 --- /dev/null +++ b/ext/ply/test/yacc_simple.py @@ -0,0 +1,67 @@ +# ----------------------------------------------------------------------------- +# yacc_simple.py +# +# A simple, properly specifier grammar +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_sr.exp b/ext/ply/test/yacc_sr.exp new file mode 100644 index 000000000..7225ad94b --- /dev/null +++ b/ext/ply/test/yacc_sr.exp @@ -0,0 +1,2 @@ +yacc: Generating SLR parsing table... +yacc: 20 shift/reduce conflicts diff --git a/ext/ply/test/yacc_sr.py b/ext/ply/test/yacc_sr.py new file mode 100644 index 000000000..4341f6997 --- /dev/null +++ b/ext/ply/test/yacc_sr.py @@ -0,0 +1,62 @@ +# ----------------------------------------------------------------------------- +# yacc_sr.py +# +# A grammar with shift-reduce conflicts +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_term1.exp b/ext/ply/test/yacc_term1.exp new file mode 100644 index 000000000..422d2bacd --- /dev/null +++ b/ext/ply/test/yacc_term1.exp @@ -0,0 +1,2 @@ +./yacc_term1.py:22: Illegal rule name 'NUMBER'. Already defined as a token. +yacc.YaccError: Unable to construct parser. diff --git a/ext/ply/test/yacc_term1.py b/ext/ply/test/yacc_term1.py new file mode 100644 index 000000000..97a2e7a60 --- /dev/null +++ b/ext/ply/test/yacc_term1.py @@ -0,0 +1,67 @@ +# ----------------------------------------------------------------------------- +# yacc_term1.py +# +# Terminal used on the left-hand-side +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'NUMBER : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_unused.exp b/ext/ply/test/yacc_unused.exp new file mode 100644 index 000000000..390754de3 --- /dev/null +++ b/ext/ply/test/yacc_unused.exp @@ -0,0 +1,4 @@ +./yacc_unused.py:60: Symbol 'COMMA' used, but not defined as a token or a rule. +yacc: Symbol 'COMMA' is unreachable. +yacc: Symbol 'exprlist' is unreachable. +yacc.YaccError: Unable to construct parser. diff --git a/ext/ply/test/yacc_unused.py b/ext/ply/test/yacc_unused.py new file mode 100644 index 000000000..4cbd63327 --- /dev/null +++ b/ext/ply/test/yacc_unused.py @@ -0,0 +1,76 @@ +# ----------------------------------------------------------------------------- +# yacc_unused.py +# +# A grammar with an unused rule +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules +precedence = ( + ('left','PLUS','MINUS'), + ('left','TIMES','DIVIDE'), + ('right','UMINUS'), + ) + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_expr_list(t): + 'exprlist : exprlist COMMA expression' + pass + +def p_expr_list_2(t): + 'exprlist : expression' + pass + + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/test/yacc_uprec.exp b/ext/ply/test/yacc_uprec.exp new file mode 100644 index 000000000..b1a71a250 --- /dev/null +++ b/ext/ply/test/yacc_uprec.exp @@ -0,0 +1,2 @@ +./yacc_uprec.py:35: Nothing known about the precedence of 'UMINUS' +yacc.YaccError: Unable to construct parser. diff --git a/ext/ply/test/yacc_uprec.py b/ext/ply/test/yacc_uprec.py new file mode 100644 index 000000000..139ce6318 --- /dev/null +++ b/ext/ply/test/yacc_uprec.py @@ -0,0 +1,62 @@ +# ----------------------------------------------------------------------------- +# yacc_uprec.py +# +# A grammar with a bad %prec specifier +# ----------------------------------------------------------------------------- +import sys +sys.tracebacklimit = 0 + +from calclex import tokens + +# Parsing rules + +# dictionary of names +names = { } + +def p_statement_assign(t): + 'statement : NAME EQUALS expression' + names[t[1]] = t[3] + +def p_statement_expr(t): + 'statement : expression' + print t[1] + +def p_expression_binop(t): + '''expression : expression PLUS expression + | expression MINUS expression + | expression TIMES expression + | expression DIVIDE expression''' + if t[2] == '+' : t[0] = t[1] + t[3] + elif t[2] == '-': t[0] = t[1] - t[3] + elif t[2] == '*': t[0] = t[1] * t[3] + elif t[3] == '/': t[0] = t[1] / t[3] + +def p_expression_uminus(t): + 'expression : MINUS expression %prec UMINUS' + t[0] = -t[2] + +def p_expression_group(t): + 'expression : LPAREN expression RPAREN' + t[0] = t[2] + +def p_expression_number(t): + 'expression : NUMBER' + t[0] = t[1] + +def p_expression_name(t): + 'expression : NAME' + try: + t[0] = names[t[1]] + except LookupError: + print "Undefined name '%s'" % t[1] + t[0] = 0 + +def p_error(t): + print "Syntax error at '%s'" % t.value + +import yacc +yacc.yacc() + + + + diff --git a/ext/ply/yacc.py b/ext/ply/yacc.py new file mode 100644 index 000000000..1041745ed --- /dev/null +++ b/ext/ply/yacc.py @@ -0,0 +1,1846 @@ +#----------------------------------------------------------------------------- +# ply: yacc.py +# +# Author: David M. Beazley (beazley@cs.uchicago.edu) +# Department of Computer Science +# University of Chicago +# Chicago, IL 60637 +# +# Copyright (C) 2001, David M. Beazley +# +# $Header: /home/stever/bk/newmem2/ext/ply/yacc.py 1.3 03/06/06 14:59:28-00:00 stever@ $ +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See the file COPYING for a complete copy of the LGPL. +# +# +# This implements an LR parser that is constructed from grammar rules defined +# as Python functions. Roughly speaking, this module is a cross between +# John Aycock's Spark system and the GNU bison utility. +# +# Disclaimer: This is a work in progress. SLR parsing seems to work fairly +# well and there is extensive error checking. LALR(1) is in progress. The +# rest of this file is a bit of a mess. Please pardon the dust. +# +# The current implementation is only somewhat object-oriented. The +# LR parser itself is defined in terms of an object (which allows multiple +# parsers to co-exist). However, most of the variables used during table +# construction are defined in terms of global variables. Users shouldn't +# notice unless they are trying to define multiple parsers at the same +# time using threads (in which case they should have their head examined). +#----------------------------------------------------------------------------- + +__version__ = "1.3" + +#----------------------------------------------------------------------------- +# === User configurable parameters === +# +# Change these to modify the default behavior of yacc (if you wish) +#----------------------------------------------------------------------------- + +yaccdebug = 1 # Debugging mode. If set, yacc generates a + # a 'parser.out' file in the current directory + +debug_file = 'parser.out' # Default name of the debugging file +tab_module = 'parsetab' # Default name of the table module +default_lr = 'SLR' # Default LR table generation method + +error_count = 3 # Number of symbols that must be shifted to leave recovery mode + +import re, types, sys, cStringIO, md5, os.path + +# Exception raised for yacc-related errors +class YaccError(Exception): pass + +#----------------------------------------------------------------------------- +# === LR Parsing Engine === +# +# The following classes are used for the LR parser itself. These are not +# used during table construction and are independent of the actual LR +# table generation algorithm +#----------------------------------------------------------------------------- + +# This class is used to hold non-terminal grammar symbols during parsing. +# It normally has the following attributes set: +# .type = Grammar symbol type +# .value = Symbol value +# .lineno = Starting line number +# .endlineno = Ending line number (optional, set automatically) + +class YaccSymbol: + def __str__(self): return self.type + def __repr__(self): return str(self) + +# This class is a wrapper around the objects actually passed to each +# grammar rule. Index lookup and assignment actually assign the +# .value attribute of the underlying YaccSymbol object. +# The lineno() method returns the line number of a given +# item (or 0 if not defined). The linespan() method returns +# a tuple of (startline,endline) representing the range of lines +# for a symbol. + +class YaccSlice: + def __init__(self,s): + self.slice = s + self.pbstack = [] + + def __getitem__(self,n): + return self.slice[n].value + + def __setitem__(self,n,v): + self.slice[n].value = v + + def __len__(self): + return len(self.slice) + + def lineno(self,n): + return getattr(self.slice[n],"lineno",0) + + def linespan(self,n): + startline = getattr(self.slice[n],"lineno",0) + endline = getattr(self.slice[n],"endlineno",startline) + return startline,endline + + def pushback(self,n): + if n <= 0: + raise ValueError, "Expected a positive value" + if n > (len(self.slice)-1): + raise ValueError, "Can't push %d tokens. Only %d are available." % (n,len(self.slice)-1) + for i in range(0,n): + self.pbstack.append(self.slice[-i-1]) + +# The LR Parsing engine. This is defined as a class so that multiple parsers +# can exist in the same process. A user never instantiates this directly. +# Instead, the global yacc() function should be used to create a suitable Parser +# object. + +class Parser: + def __init__(self,magic=None): + + # This is a hack to keep users from trying to instantiate a Parser + # object directly. + + if magic != "xyzzy": + raise YaccError, "Can't instantiate Parser. Use yacc() instead." + + # Reset internal state + self.productions = None # List of productions + self.errorfunc = None # Error handling function + self.action = { } # LR Action table + self.goto = { } # LR goto table + self.require = { } # Attribute require table + self.method = "Unknown LR" # Table construction method used + + def errok(self): + self.errorcount = 0 + + def restart(self): + del self.statestack[:] + del self.symstack[:] + sym = YaccSymbol() + sym.type = '$' + self.symstack.append(sym) + self.statestack.append(0) + + def parse(self,input=None,lexer=None,debug=0): + lookahead = None # Current lookahead symbol + lookaheadstack = [ ] # Stack of lookahead symbols + actions = self.action # Local reference to action table + goto = self.goto # Local reference to goto table + prod = self.productions # Local reference to production list + pslice = YaccSlice(None) # Slice object passed to grammar rules + pslice.parser = self # Parser object + self.errorcount = 0 # Used during error recovery + + # If no lexer was given, we will try to use the lex module + if not lexer: + import lex as lexer + + pslice.lexer = lexer + + # If input was supplied, pass to lexer + if input: + lexer.input(input) + + # Tokenize function + get_token = lexer.token + + statestack = [ ] # Stack of parsing states + self.statestack = statestack + symstack = [ ] # Stack of grammar symbols + self.symstack = symstack + + errtoken = None # Err token + + # The start state is assumed to be (0,$) + statestack.append(0) + sym = YaccSymbol() + sym.type = '$' + symstack.append(sym) + + while 1: + # Get the next symbol on the input. If a lookahead symbol + # is already set, we just use that. Otherwise, we'll pull + # the next token off of the lookaheadstack or from the lexer + if not lookahead: + if not lookaheadstack: + lookahead = get_token() # Get the next token + else: + lookahead = lookaheadstack.pop() + if not lookahead: + lookahead = YaccSymbol() + lookahead.type = '$' + if debug: + print "%-20s : %s" % (lookahead, [xx.type for xx in symstack]) + + # Check the action table + s = statestack[-1] + ltype = lookahead.type + t = actions.get((s,ltype),None) + + if t is not None: + if t > 0: + # shift a symbol on the stack + if ltype == '$': + # Error, end of input + print "yacc: Parse error. EOF" + return + statestack.append(t) + symstack.append(lookahead) + lookahead = None + + # Decrease error count on successful shift + if self.errorcount > 0: + self.errorcount -= 1 + + continue + + if t < 0: + # reduce a symbol on the stack, emit a production + p = prod[-t] + pname = p.name + plen = p.len + + # Get production function + sym = YaccSymbol() + sym.type = pname # Production name + sym.value = None + + if plen: + targ = symstack[-plen-1:] + targ[0] = sym + try: + sym.lineno = targ[1].lineno + sym.endlineno = getattr(targ[-1],"endlineno",targ[-1].lineno) + except AttributeError: + sym.lineno = 0 + del symstack[-plen:] + del statestack[-plen:] + else: + sym.lineno = 0 + targ = [ sym ] + pslice.slice = targ + pslice.pbstack = [] + # Call the grammar rule with our special slice object + p.func(pslice) + + # Validate attributes of the resulting value attribute +# if require: +# try: +# t0 = targ[0] +# r = Requires.get(t0.type,None) +# t0d = t0.__dict__ +# if r: +# for field in r: +# tn = t0 +# for fname in field: +# try: +# tf = tn.__dict__ +# tn = tf.get(fname) +# except StandardError: +# tn = None +# if not tn: +# print "%s:%d: Rule %s doesn't set required attribute '%s'" % \ +# (p.file,p.line,p.name,".".join(field)) +# except TypeError,LookupError: +# print "Bad requires directive " % r +# pass + + + # If there was a pushback, put that on the stack + if pslice.pbstack: + lookaheadstack.append(lookahead) + for _t in pslice.pbstack: + lookaheadstack.append(_t) + lookahead = None + + symstack.append(sym) + statestack.append(goto[statestack[-1],pname]) + continue + + if t == 0: + n = symstack[-1] + return getattr(n,"value",None) + + if t == None: + # We have some kind of parsing error here. To handle this, + # we are going to push the current token onto the tokenstack + # and replace it with an 'error' token. If there are any synchronization + # rules, they may catch it. + # + # In addition to pushing the error token, we call call the user defined p_error() + # function if this is the first syntax error. This function is only called + # if errorcount == 0. + + if not self.errorcount: + self.errorcount = error_count + errtoken = lookahead + if errtoken.type == '$': + errtoken = None # End of file! + if self.errorfunc: + global errok,token,restart + errok = self.errok # Set some special functions available in error recovery + token = get_token + restart = self.restart + tok = self.errorfunc(errtoken) + del errok, token, restart # Delete special functions + + if not self.errorcount: + # User must have done some kind of panic mode recovery on their own. The returned token + # is the next lookahead + lookahead = tok + errtoken = None + continue + else: + if errtoken: + if hasattr(errtoken,"lineno"): lineno = lookahead.lineno + else: lineno = 0 + if lineno: + print "yacc: Syntax error at line %d, token=%s" % (lineno, errtoken.type) + else: + print "yacc: Syntax error, token=%s" % errtoken.type + else: + print "yacc: Parse error in input. EOF" + return + + else: + self.errorcount = error_count + + # case 1: the statestack only has 1 entry on it. If we're in this state, the + # entire parse has been rolled back and we're completely hosed. The token is + # discarded and we just keep going. + + if len(statestack) <= 1 and lookahead.type != '$': + lookahead = None + errtoken = None + # Nuke the pushback stack + del lookaheadstack[:] + continue + + # case 2: the statestack has a couple of entries on it, but we're + # at the end of the file. nuke the top entry and generate an error token + + # Start nuking entries on the stack + if lookahead.type == '$': + # Whoa. We're really hosed here. Bail out + return + + if lookahead.type != 'error': + sym = symstack[-1] + if sym.type == 'error': + # Hmmm. Error is on top of stack, we'll just nuke input + # symbol and continue + lookahead = None + continue + t = YaccSymbol() + t.type = 'error' + if hasattr(lookahead,"lineno"): + t.lineno = lookahead.lineno + t.value = lookahead + lookaheadstack.append(lookahead) + lookahead = t + else: + symstack.pop() + statestack.pop() + + continue + + # Call an error function here + raise RuntimeError, "yacc: internal parser error!!!\n" + +# ----------------------------------------------------------------------------- +# === Parser Construction === +# +# The following functions and variables are used to implement the yacc() function +# itself. This is pretty hairy stuff involving lots of error checking, +# construction of LR items, kernels, and so forth. Although a lot of +# this work is done using global variables, the resulting Parser object +# is completely self contained--meaning that it is safe to repeatedly +# call yacc() with different grammars in the same application. +# ----------------------------------------------------------------------------- + +# ----------------------------------------------------------------------------- +# validate_file() +# +# This function checks to see if there are duplicated p_rulename() functions +# in the parser module file. Without this function, it is really easy for +# users to make mistakes by cutting and pasting code fragments (and it's a real +# bugger to try and figure out why the resulting parser doesn't work). Therefore, +# we just do a little regular expression pattern matching of def statements +# to try and detect duplicates. +# ----------------------------------------------------------------------------- + +def validate_file(filename): + base,ext = os.path.splitext(filename) + if ext != '.py': return 1 # No idea. Assume it's okay. + + try: + f = open(filename) + lines = f.readlines() + f.close() + except IOError: + return 1 # Oh well + + # Match def p_funcname( + fre = re.compile(r'\s*def\s+(p_[a-zA-Z_0-9]*)\(') + counthash = { } + linen = 1 + noerror = 1 + for l in lines: + m = fre.match(l) + if m: + name = m.group(1) + prev = counthash.get(name) + if not prev: + counthash[name] = linen + else: + print "%s:%d: Function %s redefined. Previously defined on line %d" % (filename,linen,name,prev) + noerror = 0 + linen += 1 + return noerror + +# This function looks for functions that might be grammar rules, but which don't have the proper p_suffix. +def validate_dict(d): + for n,v in d.items(): + if n[0:2] == 'p_' and isinstance(v,types.FunctionType): continue + if n[0:2] == 't_': continue + + if n[0:2] == 'p_': + print "yacc: Warning. '%s' not defined as a function" % n + if isinstance(v,types.FunctionType) and v.func_code.co_argcount == 1: + try: + doc = v.__doc__.split(" ") + if doc[1] == ':': + print "%s:%d: Warning. Possible grammar rule '%s' defined without p_ prefix." % (v.func_code.co_filename, v.func_code.co_firstlineno,n) + except StandardError: + pass + +# ----------------------------------------------------------------------------- +# === GRAMMAR FUNCTIONS === +# +# The following global variables and functions are used to store, manipulate, +# and verify the grammar rules specified by the user. +# ----------------------------------------------------------------------------- + +# Initialize all of the global variables used during grammar construction +def initialize_vars(): + global Productions, Prodnames, Prodmap, Terminals + global Nonterminals, First, Follow, Precedence, LRitems + global Errorfunc, Signature, Requires + + Productions = [None] # A list of all of the productions. The first + # entry is always reserved for the purpose of + # building an augmented grammar + + Prodnames = { } # A dictionary mapping the names of nonterminals to a list of all + # productions of that nonterminal. + + Prodmap = { } # A dictionary that is only used to detect duplicate + # productions. + + Terminals = { } # A dictionary mapping the names of terminal symbols to a + # list of the rules where they are used. + + Nonterminals = { } # A dictionary mapping names of nonterminals to a list + # of rule numbers where they are used. + + First = { } # A dictionary of precomputed FIRST(x) symbols + + Follow = { } # A dictionary of precomputed FOLLOW(x) symbols + + Precedence = { } # Precedence rules for each terminal. Contains tuples of the + # form ('right',level) or ('nonassoc', level) or ('left',level) + + LRitems = [ ] # A list of all LR items for the grammar. These are the + # productions with the "dot" like E -> E . PLUS E + + Errorfunc = None # User defined error handler + + Signature = md5.new() # Digital signature of the grammar rules, precedence + # and other information. Used to determined when a + # parsing table needs to be regenerated. + + Requires = { } # Requires list + + # File objects used when creating the parser.out debugging file + global _vf, _vfc + _vf = cStringIO.StringIO() + _vfc = cStringIO.StringIO() + +# ----------------------------------------------------------------------------- +# class Production: +# +# This class stores the raw information about a single production or grammar rule. +# It has a few required attributes: +# +# name - Name of the production (nonterminal) +# prod - A list of symbols making up its production +# number - Production number. +# +# In addition, a few additional attributes are used to help with debugging or +# optimization of table generation. +# +# file - File where production action is defined. +# lineno - Line number where action is defined +# func - Action function +# prec - Precedence level +# lr_next - Next LR item. Example, if we are ' E -> E . PLUS E' +# then lr_next refers to 'E -> E PLUS . E' +# lr_index - LR item index (location of the ".") in the prod list. +# len - Length of the production (number of symbols on right hand side) +# ----------------------------------------------------------------------------- + +class Production: + def __init__(self,**kw): + for k,v in kw.items(): + setattr(self,k,v) + self.lr_index = -1 + self.lr0_added = 0 # Flag indicating whether or not added to LR0 closure + self.usyms = [ ] + + def __str__(self): + if self.prod: + s = "%s -> %s" % (self.name," ".join(self.prod)) + else: + s = "%s -> <empty>" % self.name + return s + + def __repr__(self): + return str(self) + + # Compute lr_items from the production + def lr_item(self,n): + if n > len(self.prod): return None + p = Production() + p.name = self.name + p.prod = list(self.prod) + p.number = self.number + p.lr_index = n + p.prod.insert(n,".") + p.prod = tuple(p.prod) + p.len = len(p.prod) + p.usyms = self.usyms + + # Precompute list of productions immediately following + try: + p.lrafter = Prodnames[p.prod[n+1]] + except (IndexError,KeyError),e: + p.lrafter = [] + try: + p.lrbefore = p.prod[n-1] + except IndexError: + p.lrbefore = None + + return p + +class MiniProduction: + pass + +# Utility function +def is_identifier(s): + for c in s: + if not (c.isalnum() or c == '_'): return 0 + return 1 + +# ----------------------------------------------------------------------------- +# add_production() +# +# Given an action function, this function assembles a production rule. +# The production rule is assumed to be found in the function's docstring. +# This rule has the general syntax: +# +# name1 ::= production1 +# | production2 +# | production3 +# ... +# | productionn +# name2 ::= production1 +# | production2 +# ... +# ----------------------------------------------------------------------------- + +def add_production(f,file,line,prodname,syms): + + if Terminals.has_key(prodname): + print "%s:%d: Illegal rule name '%s'. Already defined as a token." % (file,line,prodname) + return -1 + if prodname == 'error': + print "%s:%d: Illegal rule name '%s'. error is a reserved word." % (file,line,prodname) + return -1 + + if not is_identifier(prodname): + print "%s:%d: Illegal rule name '%s'" % (file,line,prodname) + return -1 + + for s in syms: + if not is_identifier(s) and s != '%prec': + print "%s:%d: Illegal name '%s' in rule '%s'" % (file,line,s, prodname) + return -1 + + # See if the rule is already in the rulemap + map = "%s -> %s" % (prodname,syms) + if Prodmap.has_key(map): + m = Prodmap[map] + print "%s:%d: Duplicate rule %s." % (file,line, m) + print "%s:%d: Previous definition at %s:%d" % (file,line, m.file, m.line) + return -1 + + p = Production() + p.name = prodname + p.prod = syms + p.file = file + p.line = line + p.func = f + p.number = len(Productions) + + + Productions.append(p) + Prodmap[map] = p + if not Nonterminals.has_key(prodname): + Nonterminals[prodname] = [ ] + + # Add all terminals to Terminals + i = 0 + while i < len(p.prod): + t = p.prod[i] + if t == '%prec': + try: + precname = p.prod[i+1] + except IndexError: + print "%s:%d: Syntax error. Nothing follows %%prec." % (p.file,p.line) + return -1 + + prec = Precedence.get(precname,None) + if not prec: + print "%s:%d: Nothing known about the precedence of '%s'" % (p.file,p.line,precname) + return -1 + else: + p.prec = prec + del p.prod[i] + del p.prod[i] + continue + + if Terminals.has_key(t): + Terminals[t].append(p.number) + # Is a terminal. We'll assign a precedence to p based on this + if not hasattr(p,"prec"): + p.prec = Precedence.get(t,('right',0)) + else: + if not Nonterminals.has_key(t): + Nonterminals[t] = [ ] + Nonterminals[t].append(p.number) + i += 1 + + if not hasattr(p,"prec"): + p.prec = ('right',0) + + # Set final length of productions + p.len = len(p.prod) + p.prod = tuple(p.prod) + + # Calculate unique syms in the production + p.usyms = [ ] + for s in p.prod: + if s not in p.usyms: + p.usyms.append(s) + + # Add to the global productions list + try: + Prodnames[p.name].append(p) + except KeyError: + Prodnames[p.name] = [ p ] + return 0 + +# Given a raw rule function, this function rips out its doc string +# and adds rules to the grammar + +def add_function(f): + line = f.func_code.co_firstlineno + file = f.func_code.co_filename + error = 0 + + if f.func_code.co_argcount > 1: + print "%s:%d: Rule '%s' has too many arguments." % (file,line,f.__name__) + return -1 + + if f.func_code.co_argcount < 1: + print "%s:%d: Rule '%s' requires an argument." % (file,line,f.__name__) + return -1 + + if f.__doc__: + # Split the doc string into lines + pstrings = f.__doc__.splitlines() + lastp = None + dline = line + for ps in pstrings: + dline += 1 + p = ps.split() + if not p: continue + try: + if p[0] == '|': + # This is a continuation of a previous rule + if not lastp: + print "%s:%d: Misplaced '|'." % (file,dline) + return -1 + prodname = lastp + if len(p) > 1: + syms = p[1:] + else: + syms = [ ] + else: + prodname = p[0] + lastp = prodname + assign = p[1] + if len(p) > 2: + syms = p[2:] + else: + syms = [ ] + if assign != ':' and assign != '::=': + print "%s:%d: Syntax error. Expected ':'" % (file,dline) + return -1 + e = add_production(f,file,dline,prodname,syms) + error += e + except StandardError: + print "%s:%d: Syntax error in rule '%s'" % (file,dline,ps) + error -= 1 + else: + print "%s:%d: No documentation string specified in function '%s'" % (file,line,f.__name__) + return error + + +# Cycle checking code (Michael Dyck) + +def compute_reachable(): + ''' + Find each symbol that can be reached from the start symbol. + Print a warning for any nonterminals that can't be reached. + (Unused terminals have already had their warning.) + ''' + Reachable = { } + for s in Terminals.keys() + Nonterminals.keys(): + Reachable[s] = 0 + + mark_reachable_from( Productions[0].prod[0], Reachable ) + + for s in Nonterminals.keys(): + if not Reachable[s]: + print "yacc: Symbol '%s' is unreachable." % s + +def mark_reachable_from(s, Reachable): + ''' + Mark all symbols that are reachable from symbol s. + ''' + if Reachable[s]: + # We've already reached symbol s. + return + Reachable[s] = 1 + for p in Prodnames.get(s,[]): + for r in p.prod: + mark_reachable_from(r, Reachable) + +# ----------------------------------------------------------------------------- +# compute_terminates() +# +# This function looks at the various parsing rules and tries to detect +# infinite recursion cycles (grammar rules where there is no possible way +# to derive a string of only terminals). +# ----------------------------------------------------------------------------- +def compute_terminates(): + ''' + Raise an error for any symbols that don't terminate. + ''' + Terminates = {} + + # Terminals: + for t in Terminals.keys(): + Terminates[t] = 1 + + Terminates['$'] = 1 + + # Nonterminals: + + # Initialize to false: + for n in Nonterminals.keys(): + Terminates[n] = 0 + + # Then propagate termination until no change: + while 1: + some_change = 0 + for (n,pl) in Prodnames.items(): + # Nonterminal n terminates iff any of its productions terminates. + for p in pl: + # Production p terminates iff all of its rhs symbols terminate. + for s in p.prod: + if not Terminates[s]: + # The symbol s does not terminate, + # so production p does not terminate. + p_terminates = 0 + break + else: + # didn't break from the loop, + # so every symbol s terminates + # so production p terminates. + p_terminates = 1 + + if p_terminates: + # symbol n terminates! + if not Terminates[n]: + Terminates[n] = 1 + some_change = 1 + # Don't need to consider any more productions for this n. + break + + if not some_change: + break + + some_error = 0 + for (s,terminates) in Terminates.items(): + if not terminates: + if not Prodnames.has_key(s) and not Terminals.has_key(s) and s != 'error': + # s is used-but-not-defined, and we've already warned of that, + # so it would be overkill to say that it's also non-terminating. + pass + else: + print "yacc: Infinite recursion detected for symbol '%s'." % s + some_error = 1 + + return some_error + +# ----------------------------------------------------------------------------- +# verify_productions() +# +# This function examines all of the supplied rules to see if they seem valid. +# ----------------------------------------------------------------------------- +def verify_productions(cycle_check=1): + error = 0 + for p in Productions: + if not p: continue + + for s in p.prod: + if not Prodnames.has_key(s) and not Terminals.has_key(s) and s != 'error': + print "%s:%d: Symbol '%s' used, but not defined as a token or a rule." % (p.file,p.line,s) + error = 1 + continue + + unused_tok = 0 + # Now verify all of the tokens + if yaccdebug: + _vf.write("Unused terminals:\n\n") + for s,v in Terminals.items(): + if s != 'error' and not v: + print "yacc: Warning. Token '%s' defined, but not used." % s + if yaccdebug: _vf.write(" %s\n"% s) + unused_tok += 1 + + # Print out all of the productions + if yaccdebug: + _vf.write("\nGrammar\n\n") + for i in range(1,len(Productions)): + _vf.write("Rule %-5d %s\n" % (i, Productions[i])) + + unused_prod = 0 + # Verify the use of all productions + for s,v in Nonterminals.items(): + if not v: + p = Prodnames[s][0] + print "%s:%d: Warning. Rule '%s' defined, but not used." % (p.file,p.line, s) + unused_prod += 1 + + + if unused_tok == 1: + print "yacc: Warning. There is 1 unused token." + if unused_tok > 1: + print "yacc: Warning. There are %d unused tokens." % unused_tok + + if unused_prod == 1: + print "yacc: Warning. There is 1 unused rule." + if unused_prod > 1: + print "yacc: Warning. There are %d unused rules." % unused_prod + + if yaccdebug: + _vf.write("\nTerminals, with rules where they appear\n\n") + ks = Terminals.keys() + ks.sort() + for k in ks: + _vf.write("%-20s : %s\n" % (k, " ".join([str(s) for s in Terminals[k]]))) + _vf.write("\nNonterminals, with rules where they appear\n\n") + ks = Nonterminals.keys() + ks.sort() + for k in ks: + _vf.write("%-20s : %s\n" % (k, " ".join([str(s) for s in Nonterminals[k]]))) + + if (cycle_check): + compute_reachable() + error += compute_terminates() +# error += check_cycles() + return error + +# ----------------------------------------------------------------------------- +# build_lritems() +# +# This function walks the list of productions and builds a complete set of the +# LR items. The LR items are stored in two ways: First, they are uniquely +# numbered and placed in the list _lritems. Second, a linked list of LR items +# is built for each production. For example: +# +# E -> E PLUS E +# +# Creates the list +# +# [E -> . E PLUS E, E -> E . PLUS E, E -> E PLUS . E, E -> E PLUS E . ] +# ----------------------------------------------------------------------------- + +def build_lritems(): + for p in Productions: + lastlri = p + lri = p.lr_item(0) + i = 0 + while 1: + lri = p.lr_item(i) + lastlri.lr_next = lri + if not lri: break + lri.lr_num = len(LRitems) + LRitems.append(lri) + lastlri = lri + i += 1 + + # In order for the rest of the parser generator to work, we need to + # guarantee that no more lritems are generated. Therefore, we nuke + # the p.lr_item method. (Only used in debugging) + # Production.lr_item = None + +# ----------------------------------------------------------------------------- +# add_precedence() +# +# Given a list of precedence rules, add to the precedence table. +# ----------------------------------------------------------------------------- + +def add_precedence(plist): + plevel = 0 + error = 0 + for p in plist: + plevel += 1 + try: + prec = p[0] + terms = p[1:] + if prec != 'left' and prec != 'right' and prec != 'nonassoc': + print "yacc: Invalid precedence '%s'" % prec + return -1 + for t in terms: + if Precedence.has_key(t): + print "yacc: Precedence already specified for terminal '%s'" % t + error += 1 + continue + Precedence[t] = (prec,plevel) + except: + print "yacc: Invalid precedence table." + error += 1 + + return error + +# ----------------------------------------------------------------------------- +# augment_grammar() +# +# Compute the augmented grammar. This is just a rule S' -> start where start +# is the starting symbol. +# ----------------------------------------------------------------------------- + +def augment_grammar(start=None): + if not start: + start = Productions[1].name + Productions[0] = Production(name="S'",prod=[start],number=0,len=1,prec=('right',0),func=None) + Productions[0].usyms = [ start ] + Nonterminals[start].append(0) + + +# ------------------------------------------------------------------------- +# first() +# +# Compute the value of FIRST1(beta) where beta is a tuple of symbols. +# +# During execution of compute_first1, the result may be incomplete. +# Afterward (e.g., when called from compute_follow()), it will be complete. +# ------------------------------------------------------------------------- +def first(beta): + + # We are computing First(x1,x2,x3,...,xn) + result = [ ] + for x in beta: + x_produces_empty = 0 + + # Add all the non-<empty> symbols of First[x] to the result. + for f in First[x]: + if f == '<empty>': + x_produces_empty = 1 + else: + if f not in result: result.append(f) + + if x_produces_empty: + # We have to consider the next x in beta, + # i.e. stay in the loop. + pass + else: + # We don't have to consider any further symbols in beta. + break + else: + # There was no 'break' from the loop, + # so x_produces_empty was true for all x in beta, + # so beta produces empty as well. + result.append('<empty>') + + return result + + +# FOLLOW(x) +# Given a non-terminal. This function computes the set of all symbols +# that might follow it. Dragon book, p. 189. + +def compute_follow(start=None): + # Add '$' to the follow list of the start symbol + for k in Nonterminals.keys(): + Follow[k] = [ ] + + if not start: + start = Productions[1].name + + Follow[start] = [ '$' ] + + while 1: + didadd = 0 + for p in Productions[1:]: + # Here is the production set + for i in range(len(p.prod)): + B = p.prod[i] + if Nonterminals.has_key(B): + # Okay. We got a non-terminal in a production + fst = first(p.prod[i+1:]) + hasempty = 0 + for f in fst: + if f != '<empty>' and f not in Follow[B]: + Follow[B].append(f) + didadd = 1 + if f == '<empty>': + hasempty = 1 + if hasempty or i == (len(p.prod)-1): + # Add elements of follow(a) to follow(b) + for f in Follow[p.name]: + if f not in Follow[B]: + Follow[B].append(f) + didadd = 1 + if not didadd: break + + if 0 and yaccdebug: + _vf.write('\nFollow:\n') + for k in Nonterminals.keys(): + _vf.write("%-20s : %s\n" % (k, " ".join([str(s) for s in Follow[k]]))) + +# ------------------------------------------------------------------------- +# compute_first1() +# +# Compute the value of FIRST1(X) for all symbols +# ------------------------------------------------------------------------- +def compute_first1(): + + # Terminals: + for t in Terminals.keys(): + First[t] = [t] + + First['$'] = ['$'] + First['#'] = ['#'] # what's this for? + + # Nonterminals: + + # Initialize to the empty set: + for n in Nonterminals.keys(): + First[n] = [] + + # Then propagate symbols until no change: + while 1: + some_change = 0 + for n in Nonterminals.keys(): + for p in Prodnames[n]: + for f in first(p.prod): + if f not in First[n]: + First[n].append( f ) + some_change = 1 + if not some_change: + break + + if 0 and yaccdebug: + _vf.write('\nFirst:\n') + for k in Nonterminals.keys(): + _vf.write("%-20s : %s\n" % + (k, " ".join([str(s) for s in First[k]]))) + +# ----------------------------------------------------------------------------- +# === SLR Generation === +# +# The following functions are used to construct SLR (Simple LR) parsing tables +# as described on p.221-229 of the dragon book. +# ----------------------------------------------------------------------------- + +# Global variables for the LR parsing engine +def lr_init_vars(): + global _lr_action, _lr_goto, _lr_method + global _lr_goto_cache + + _lr_action = { } # Action table + _lr_goto = { } # Goto table + _lr_method = "Unknown" # LR method used + _lr_goto_cache = { } + +# Compute the LR(0) closure operation on I, where I is a set of LR(0) items. +# prodlist is a list of productions. + +_add_count = 0 # Counter used to detect cycles + +def lr0_closure(I): + global _add_count + + _add_count += 1 + prodlist = Productions + + # Add everything in I to J + J = I[:] + didadd = 1 + while didadd: + didadd = 0 + for j in J: + for x in j.lrafter: + if x.lr0_added == _add_count: continue + # Add B --> .G to J + J.append(x.lr_next) + x.lr0_added = _add_count + didadd = 1 + + return J + +# Compute the LR(0) goto function goto(I,X) where I is a set +# of LR(0) items and X is a grammar symbol. This function is written +# in a way that guarantees uniqueness of the generated goto sets +# (i.e. the same goto set will never be returned as two different Python +# objects). With uniqueness, we can later do fast set comparisons using +# id(obj) instead of element-wise comparison. + +def lr0_goto(I,x): + # First we look for a previously cached entry + g = _lr_goto_cache.get((id(I),x),None) + if g: return g + + # Now we generate the goto set in a way that guarantees uniqueness + # of the result + + s = _lr_goto_cache.get(x,None) + if not s: + s = { } + _lr_goto_cache[x] = s + + gs = [ ] + for p in I: + n = p.lr_next + if n and n.lrbefore == x: + s1 = s.get(id(n),None) + if not s1: + s1 = { } + s[id(n)] = s1 + gs.append(n) + s = s1 + g = s.get('$',None) + if not g: + if gs: + g = lr0_closure(gs) + s['$'] = g + else: + s['$'] = gs + _lr_goto_cache[(id(I),x)] = g + return g + +# Compute the kernel of a set of LR(0) items +def lr0_kernel(I): + KI = [ ] + for p in I: + if p.name == "S'" or p.lr_index > 0 or p.len == 0: + KI.append(p) + + return KI + +_lr0_cidhash = { } + +# Compute the LR(0) sets of item function +def lr0_items(): + + C = [ lr0_closure([Productions[0].lr_next]) ] + i = 0 + for I in C: + _lr0_cidhash[id(I)] = i + i += 1 + + # Loop over the items in C and each grammar symbols + i = 0 + while i < len(C): + I = C[i] + i += 1 + + # Collect all of the symbols that could possibly be in the goto(I,X) sets + asyms = { } + for ii in I: + for s in ii.usyms: + asyms[s] = None + + for x in asyms.keys(): + g = lr0_goto(I,x) + if not g: continue + if _lr0_cidhash.has_key(id(g)): continue + _lr0_cidhash[id(g)] = len(C) + C.append(g) + + return C + +# ----------------------------------------------------------------------------- +# slr_parse_table() +# +# This function constructs an SLR table. +# ----------------------------------------------------------------------------- +def slr_parse_table(): + global _lr_method + goto = _lr_goto # Goto array + action = _lr_action # Action array + actionp = { } # Action production array (temporary) + + _lr_method = "SLR" + + n_srconflict = 0 + n_rrconflict = 0 + + if yaccdebug: + _vf.write("\n\nParsing method: SLR\n\n") + + # Step 1: Construct C = { I0, I1, ... IN}, collection of LR(0) items + # This determines the number of states + + C = lr0_items() + + # Build the parser table, state by state + st = 0 + for I in C: + # Loop over each production in I + actlist = [ ] # List of actions + + if yaccdebug: + _vf.write("\nstate %d\n\n" % st) + for p in I: + _vf.write(" (%d) %s\n" % (p.number, str(p))) + _vf.write("\n") + + for p in I: + try: + if p.prod[-1] == ".": + if p.name == "S'": + # Start symbol. Accept! + action[st,"$"] = 0 + actionp[st,"$"] = p + else: + # We are at the end of a production. Reduce! + for a in Follow[p.name]: + actlist.append((a,p,"reduce using rule %d (%s)" % (p.number,p))) + r = action.get((st,a),None) + if r is not None: + # Whoa. Have a shift/reduce or reduce/reduce conflict + if r > 0: + # Need to decide on shift or reduce here + # By default we favor shifting. Need to add + # some precedence rules here. + sprec,slevel = Productions[actionp[st,a].number].prec + rprec,rlevel = Precedence.get(a,('right',0)) + if (slevel < rlevel) or ((slevel == rlevel) and (rprec == 'left')): + # We really need to reduce here. + action[st,a] = -p.number + actionp[st,a] = p + if not slevel and not rlevel: + _vfc.write("shift/reduce conflict in state %d resolved as reduce.\n" % st) + _vf.write(" ! shift/reduce conflict for %s resolved as reduce.\n" % a) + n_srconflict += 1 + elif (slevel == rlevel) and (rprec == 'nonassoc'): + action[st,a] = None + else: + # Hmmm. Guess we'll keep the shift + if not slevel and not rlevel: + _vfc.write("shift/reduce conflict in state %d resolved as shift.\n" % st) + _vf.write(" ! shift/reduce conflict for %s resolved as shift.\n" % a) + n_srconflict +=1 + elif r < 0: + # Reduce/reduce conflict. In this case, we favor the rule + # that was defined first in the grammar file + oldp = Productions[-r] + pp = Productions[p.number] + if oldp.line > pp.line: + action[st,a] = -p.number + actionp[st,a] = p + # print "Reduce/reduce conflict in state %d" % st + n_rrconflict += 1 + _vfc.write("reduce/reduce conflict in state %d resolved using rule %d (%s).\n" % (st, actionp[st,a].number, actionp[st,a])) + _vf.write(" ! reduce/reduce conflict for %s resolved using rule %d (%s).\n" % (a,actionp[st,a].number, actionp[st,a])) + else: + print "Unknown conflict in state %d" % st + else: + action[st,a] = -p.number + actionp[st,a] = p + else: + i = p.lr_index + a = p.prod[i+1] # Get symbol right after the "." + if Terminals.has_key(a): + g = lr0_goto(I,a) + j = _lr0_cidhash.get(id(g),-1) + if j >= 0: + # We are in a shift state + actlist.append((a,p,"shift and go to state %d" % j)) + r = action.get((st,a),None) + if r is not None: + # Whoa have a shift/reduce or shift/shift conflict + if r > 0: + if r != j: + print "Shift/shift conflict in state %d" % st + elif r < 0: + # Do a precedence check. + # - if precedence of reduce rule is higher, we reduce. + # - if precedence of reduce is same and left assoc, we reduce. + # - otherwise we shift + rprec,rlevel = Productions[actionp[st,a].number].prec + sprec,slevel = Precedence.get(a,('right',0)) + if (slevel > rlevel) or ((slevel == rlevel) and (rprec != 'left')): + # We decide to shift here... highest precedence to shift + action[st,a] = j + actionp[st,a] = p + if not slevel and not rlevel: + n_srconflict += 1 + _vfc.write("shift/reduce conflict in state %d resolved as shift.\n" % st) + _vf.write(" ! shift/reduce conflict for %s resolved as shift.\n" % a) + elif (slevel == rlevel) and (rprec == 'nonassoc'): + action[st,a] = None + else: + # Hmmm. Guess we'll keep the reduce + if not slevel and not rlevel: + n_srconflict +=1 + _vfc.write("shift/reduce conflict in state %d resolved as reduce.\n" % st) + _vf.write(" ! shift/reduce conflict for %s resolved as reduce.\n" % a) + + else: + print "Unknown conflict in state %d" % st + else: + action[st,a] = j + actionp[st,a] = p + + except StandardError,e: + raise YaccError, "Hosed in slr_parse_table", e + + # Print the actions associated with each terminal + if yaccdebug: + for a,p,m in actlist: + if action.has_key((st,a)): + if p is actionp[st,a]: + _vf.write(" %-15s %s\n" % (a,m)) + _vf.write("\n") + for a,p,m in actlist: + if action.has_key((st,a)): + if p is not actionp[st,a]: + _vf.write(" ! %-15s [ %s ]\n" % (a,m)) + + # Construct the goto table for this state + if yaccdebug: + _vf.write("\n") + nkeys = { } + for ii in I: + for s in ii.usyms: + if Nonterminals.has_key(s): + nkeys[s] = None + for n in nkeys.keys(): + g = lr0_goto(I,n) + j = _lr0_cidhash.get(id(g),-1) + if j >= 0: + goto[st,n] = j + if yaccdebug: + _vf.write(" %-15s shift and go to state %d\n" % (n,j)) + + st += 1 + + if n_srconflict == 1: + print "yacc: %d shift/reduce conflict" % n_srconflict + if n_srconflict > 1: + print "yacc: %d shift/reduce conflicts" % n_srconflict + if n_rrconflict == 1: + print "yacc: %d reduce/reduce conflict" % n_rrconflict + if n_rrconflict > 1: + print "yacc: %d reduce/reduce conflicts" % n_rrconflict + + +# ----------------------------------------------------------------------------- +# ==== LALR(1) Parsing ==== +# **** UNFINISHED! 6/16/01 +# ----------------------------------------------------------------------------- + + +# Compute the lr1_closure of a set I. I is a list of tuples (p,a) where +# p is a LR0 item and a is a terminal + +_lr1_add_count = 0 + +def lr1_closure(I): + global _lr1_add_count + + _lr1_add_count += 1 + + J = I[:] + + # Loop over items (p,a) in I. + ji = 0 + while ji < len(J): + p,a = J[ji] + # p = [ A -> alpha . B beta] + + # For each production B -> gamma + for B in p.lr1_after: + f = tuple(p.lr1_beta + (a,)) + + # For each terminal b in first(Beta a) + for b in first(f): + # Check if (B -> . gamma, b) is in J + # Only way this can happen is if the add count mismatches + pn = B.lr_next + if pn.lr_added.get(b,0) == _lr1_add_count: continue + pn.lr_added[b] = _lr1_add_count + J.append((pn,b)) + ji += 1 + + return J + +def lalr_parse_table(): + + # Compute some lr1 information about all of the productions + for p in LRitems: + try: + after = p.prod[p.lr_index + 1] + p.lr1_after = Prodnames[after] + p.lr1_beta = p.prod[p.lr_index + 2:] + except LookupError: + p.lr1_after = [ ] + p.lr1_beta = [ ] + p.lr_added = { } + + # Compute the LR(0) items + C = lr0_items() + CK = [] + for I in C: + CK.append(lr0_kernel(I)) + + print CK + +# ----------------------------------------------------------------------------- +# ==== LR Utility functions ==== +# ----------------------------------------------------------------------------- + +# ----------------------------------------------------------------------------- +# _lr_write_tables() +# +# This function writes the LR parsing tables to a file +# ----------------------------------------------------------------------------- + +def lr_write_tables(modulename=tab_module): + filename = modulename + ".py" + try: + f = open(filename,"w") + + f.write(""" +# %s +# This file is automatically generated. Do not edit. + +_lr_method = %s + +_lr_signature = %s +""" % (filename, repr(_lr_method), repr(Signature.digest()))) + + # Change smaller to 0 to go back to original tables + smaller = 1 + + # Factor out names to try and make smaller + if smaller: + items = { } + + for k,v in _lr_action.items(): + i = items.get(k[1]) + if not i: + i = ([],[]) + items[k[1]] = i + i[0].append(k[0]) + i[1].append(v) + + f.write("\n_lr_action_items = {") + for k,v in items.items(): + f.write("%r:([" % k) + for i in v[0]: + f.write("%r," % i) + f.write("],[") + for i in v[1]: + f.write("%r," % i) + + f.write("]),") + f.write("}\n") + + f.write(""" +_lr_action = { } +for _k, _v in _lr_action_items.items(): + for _x,_y in zip(_v[0],_v[1]): + _lr_action[(_x,_k)] = _y +del _lr_action_items +""") + + else: + f.write("\n_lr_action = { "); + for k,v in _lr_action.items(): + f.write("(%r,%r):%r," % (k[0],k[1],v)) + f.write("}\n"); + + if smaller: + # Factor out names to try and make smaller + items = { } + + for k,v in _lr_goto.items(): + i = items.get(k[1]) + if not i: + i = ([],[]) + items[k[1]] = i + i[0].append(k[0]) + i[1].append(v) + + f.write("\n_lr_goto_items = {") + for k,v in items.items(): + f.write("%r:([" % k) + for i in v[0]: + f.write("%r," % i) + f.write("],[") + for i in v[1]: + f.write("%r," % i) + + f.write("]),") + f.write("}\n") + + f.write(""" +_lr_goto = { } +for _k, _v in _lr_goto_items.items(): + for _x,_y in zip(_v[0],_v[1]): + _lr_goto[(_x,_k)] = _y +del _lr_goto_items +""") + else: + f.write("\n_lr_goto = { "); + for k,v in _lr_goto.items(): + f.write("(%r,%r):%r," % (k[0],k[1],v)) + f.write("}\n"); + + # Write production table + f.write("_lr_productions = [\n") + for p in Productions: + if p: + if (p.func): + f.write(" (%r,%d,%r,%r,%d),\n" % (p.name, p.len, p.func.__name__,p.file,p.line)) + else: + f.write(" (%r,%d,None,None,None),\n" % (p.name, p.len)) + else: + f.write(" None,\n") + f.write("]\n") + f.close() + + except IOError,e: + print "Unable to create '%s'" % filename + print e + return + +def lr_read_tables(module=tab_module,optimize=0): + global _lr_action, _lr_goto, _lr_productions, _lr_method + try: + exec "import %s as parsetab" % module + + if (optimize) or (Signature.digest() == parsetab._lr_signature): + _lr_action = parsetab._lr_action + _lr_goto = parsetab._lr_goto + _lr_productions = parsetab._lr_productions + _lr_method = parsetab._lr_method + return 1 + else: + return 0 + + except (ImportError,AttributeError): + return 0 + +# ----------------------------------------------------------------------------- +# yacc(module) +# +# Build the parser module +# ----------------------------------------------------------------------------- + +def yacc(method=default_lr, debug=yaccdebug, module=None, tabmodule=tab_module, start=None, check_recursion=1, optimize=0): + global yaccdebug + yaccdebug = debug + + initialize_vars() + files = { } + error = 0 + + # Add starting symbol to signature + if start: + Signature.update(start) + + # Try to figure out what module we are working with + if module: + # User supplied a module object. + if not isinstance(module, types.ModuleType): + raise ValueError,"Expected a module" + + ldict = module.__dict__ + + else: + # No module given. We might be able to get information from the caller. + # Throw an exception and unwind the traceback to get the globals + + try: + raise RuntimeError + except RuntimeError: + e,b,t = sys.exc_info() + f = t.tb_frame + f = f.f_back # Walk out to our calling function + ldict = f.f_globals # Grab its globals dictionary + + # If running in optimized mode. We're going to + + if (optimize and lr_read_tables(tabmodule,1)): + # Read parse table + del Productions[:] + for p in _lr_productions: + if not p: + Productions.append(None) + else: + m = MiniProduction() + m.name = p[0] + m.len = p[1] + m.file = p[3] + m.line = p[4] + if p[2]: + m.func = ldict[p[2]] + Productions.append(m) + + else: + # Get the tokens map + tokens = ldict.get("tokens",None) + + if not tokens: + raise YaccError,"module does not define a list 'tokens'" + if not (isinstance(tokens,types.ListType) or isinstance(tokens,types.TupleType)): + raise YaccError,"tokens must be a list or tuple." + + # Check to see if a requires dictionary is defined. + requires = ldict.get("require",None) + if requires: + if not (isinstance(requires,types.DictType)): + raise YaccError,"require must be a dictionary." + + for r,v in requires.items(): + try: + if not (isinstance(v,types.ListType)): + raise TypeError + v1 = [x.split(".") for x in v] + Requires[r] = v1 + except StandardError: + print "Invalid specification for rule '%s' in require. Expected a list of strings" % r + + + # Build the dictionary of terminals. We a record a 0 in the + # dictionary to track whether or not a terminal is actually + # used in the grammar + + if 'error' in tokens: + print "yacc: Illegal token 'error'. Is a reserved word." + raise YaccError,"Illegal token name" + + for n in tokens: + if Terminals.has_key(n): + print "yacc: Warning. Token '%s' multiply defined." % n + Terminals[n] = [ ] + + Terminals['error'] = [ ] + + # Get the precedence map (if any) + prec = ldict.get("precedence",None) + if prec: + if not (isinstance(prec,types.ListType) or isinstance(prec,types.TupleType)): + raise YaccError,"precedence must be a list or tuple." + add_precedence(prec) + Signature.update(repr(prec)) + + for n in tokens: + if not Precedence.has_key(n): + Precedence[n] = ('right',0) # Default, right associative, 0 precedence + + # Look for error handler + ef = ldict.get('p_error',None) + if ef: + if not isinstance(ef,types.FunctionType): + raise YaccError,"'p_error' defined, but is not a function." + eline = ef.func_code.co_firstlineno + efile = ef.func_code.co_filename + files[efile] = None + + if (ef.func_code.co_argcount != 1): + raise YaccError,"%s:%d: p_error() requires 1 argument." % (efile,eline) + global Errorfunc + Errorfunc = ef + else: + print "yacc: Warning. no p_error() function is defined." + + # Get the list of built-in functions with p_ prefix + symbols = [ldict[f] for f in ldict.keys() + if (isinstance(ldict[f],types.FunctionType) and ldict[f].__name__[:2] == 'p_' + and ldict[f].__name__ != 'p_error')] + + # Check for non-empty symbols + if len(symbols) == 0: + raise YaccError,"no rules of the form p_rulename are defined." + + # Sort the symbols by line number + symbols.sort(lambda x,y: cmp(x.func_code.co_firstlineno,y.func_code.co_firstlineno)) + + # Add all of the symbols to the grammar + for f in symbols: + if (add_function(f)) < 0: + error += 1 + else: + files[f.func_code.co_filename] = None + + # Make a signature of the docstrings + for f in symbols: + if f.__doc__: + Signature.update(f.__doc__) + + lr_init_vars() + + if error: + raise YaccError,"Unable to construct parser." + + if not lr_read_tables(tabmodule): + + # Validate files + for filename in files.keys(): + if not validate_file(filename): + error = 1 + + # Validate dictionary + validate_dict(ldict) + + if start and not Prodnames.has_key(start): + raise YaccError,"Bad starting symbol '%s'" % start + + augment_grammar(start) + error = verify_productions(cycle_check=check_recursion) + otherfunc = [ldict[f] for f in ldict.keys() + if (isinstance(ldict[f],types.FunctionType) and ldict[f].__name__[:2] != 'p_')] + + if error: + raise YaccError,"Unable to construct parser." + + build_lritems() + compute_first1() + compute_follow(start) + + if method == 'SLR': + slr_parse_table() + elif method == 'LALR1': + lalr_parse_table() + return + else: + raise YaccError, "Unknown parsing method '%s'" % method + + lr_write_tables(tabmodule) + + if yaccdebug: + try: + f = open(debug_file,"w") + f.write(_vfc.getvalue()) + f.write("\n\n") + f.write(_vf.getvalue()) + f.close() + except IOError,e: + print "yacc: can't create '%s'" % debug_file,e + + # Made it here. Create a parser object and set up its internal state. + # Set global parse() method to bound method of parser object. + + p = Parser("xyzzy") + p.productions = Productions + p.errorfunc = Errorfunc + p.action = _lr_action + p.goto = _lr_goto + p.method = _lr_method + p.require = Requires + + global parse + parse = p.parse + + # Clean up all of the globals we created + if (not optimize): + yacc_cleanup() + return p + +# yacc_cleanup function. Delete all of the global variables +# used during table construction + +def yacc_cleanup(): + global _lr_action, _lr_goto, _lr_method, _lr_goto_cache + del _lr_action, _lr_goto, _lr_method, _lr_goto_cache + + global Productions, Prodnames, Prodmap, Terminals + global Nonterminals, First, Follow, Precedence, LRitems + global Errorfunc, Signature, Requires + + del Productions, Prodnames, Prodmap, Terminals + del Nonterminals, First, Follow, Precedence, LRitems + del Errorfunc, Signature, Requires + + global _vf, _vfc + del _vf, _vfc + + +# Stub that raises an error if parsing is attempted without first calling yacc() +def parse(*args,**kwargs): + raise YaccError, "yacc: No parser built with yacc()" + diff --git a/kern/kernel_stats.cc b/kern/kernel_stats.cc deleted file mode 100644 index 6bb166535..000000000 --- a/kern/kernel_stats.cc +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <map> -#include <stack> -#include <string> - -#include "arch/alpha/osfpal.hh" -#include "base/trace.hh" -#include "cpu/exec_context.hh" -#include "kern/kernel_stats.hh" -#include "kern/tru64/tru64_syscalls.hh" -#include "sim/system.hh" - -using namespace std; -using namespace Stats; - -namespace Kernel { - -const char *modestr[] = { "kernel", "user", "idle" }; - -Statistics::Statistics(System *system) - : idleProcess((Addr)-1), themode(kernel), lastModeTick(0), - iplLast(0), iplLastTick(0) -{ -} - -void -Statistics::regStats(const string &_name) -{ - myname = _name; - - _arm - .name(name() + ".inst.arm") - .desc("number of arm instructions executed") - ; - - _quiesce - .name(name() + ".inst.quiesce") - .desc("number of quiesce instructions executed") - ; - - _ivlb - .name(name() + ".inst.ivlb") - .desc("number of ivlb instructions executed") - ; - - _ivle - .name(name() + ".inst.ivle") - .desc("number of ivle instructions executed") - ; - - _hwrei - .name(name() + ".inst.hwrei") - .desc("number of hwrei instructions executed") - ; - - _iplCount - .init(32) - .name(name() + ".ipl_count") - .desc("number of times we switched to this ipl") - .flags(total | pdf | nozero | nonan) - ; - - _iplGood - .init(32) - .name(name() + ".ipl_good") - .desc("number of times we switched to this ipl from a different ipl") - .flags(total | pdf | nozero | nonan) - ; - - _iplTicks - .init(32) - .name(name() + ".ipl_ticks") - .desc("number of cycles we spent at this ipl") - .flags(total | pdf | nozero | nonan) - ; - - _iplUsed - .name(name() + ".ipl_used") - .desc("fraction of swpipl calls that actually changed the ipl") - .flags(total | nozero | nonan) - ; - - _iplUsed = _iplGood / _iplCount; - - _callpal - .init(256) - .name(name() + ".callpal") - .desc("number of callpals executed") - .flags(total | pdf | nozero | nonan) - ; - - for (int i = 0; i < PAL::NumCodes; ++i) { - const char *str = PAL::name(i); - if (str) - _callpal.subname(i, str); - } - - _syscall - .init(SystemCalls<Tru64>::Number) - .name(name() + ".syscall") - .desc("number of syscalls executed") - .flags(total | pdf | nozero | nonan) - ; - - for (int i = 0; i < SystemCalls<Tru64>::Number; ++i) { - const char *str = SystemCalls<Tru64>::name(i); - if (str) { - _syscall.subname(i, str); - } - } - - _mode - .init(cpu_mode_num) - .name(name() + ".mode_switch") - .desc("number of protection mode switches") - ; - - for (int i = 0; i < cpu_mode_num; ++i) - _mode.subname(i, modestr[i]); - - _modeGood - .init(cpu_mode_num) - .name(name() + ".mode_good") - ; - - for (int i = 0; i < cpu_mode_num; ++i) - _modeGood.subname(i, modestr[i]); - - _modeFraction - .name(name() + ".mode_switch_good") - .desc("fraction of useful protection mode switches") - .flags(total) - ; - - for (int i = 0; i < cpu_mode_num; ++i) - _modeFraction.subname(i, modestr[i]); - - _modeFraction = _modeGood / _mode; - - _modeTicks - .init(cpu_mode_num) - .name(name() + ".mode_ticks") - .desc("number of ticks spent at the given mode") - .flags(pdf) - ; - for (int i = 0; i < cpu_mode_num; ++i) - _modeTicks.subname(i, modestr[i]); - - _swap_context - .name(name() + ".swap_context") - .desc("number of times the context was actually changed") - ; -} - -void -Statistics::setIdleProcess(Addr idlepcbb, ExecContext *xc) -{ - assert(themode == kernel); - idleProcess = idlepcbb; - themode = idle; - changeMode(themode, xc); -} - -void -Statistics::changeMode(cpu_mode newmode, ExecContext *xc) -{ - _mode[newmode]++; - - if (newmode == themode) - return; - - DPRINTF(Context, "old mode=%-8s new mode=%-8s\n", - modestr[themode], modestr[newmode]); - - _modeGood[newmode]++; - _modeTicks[themode] += curTick - lastModeTick; - - lastModeTick = curTick; - themode = newmode; -} - -void -Statistics::swpipl(int ipl) -{ - assert(ipl >= 0 && ipl <= 0x1f && "invalid IPL\n"); - - _iplCount[ipl]++; - - if (ipl == iplLast) - return; - - _iplGood[ipl]++; - _iplTicks[iplLast] += curTick - iplLastTick; - iplLastTick = curTick; - iplLast = ipl; -} - -void -Statistics::mode(cpu_mode newmode, ExecContext *xc) -{ - Addr pcbb = xc->readMiscReg(AlphaISA::IPR_PALtemp23); - - if (newmode == kernel && pcbb == idleProcess) - newmode = idle; - - changeMode(newmode, xc); -} - -void -Statistics::context(Addr oldpcbb, Addr newpcbb, ExecContext *xc) -{ - assert(themode != user); - - _swap_context++; - changeMode(newpcbb == idleProcess ? idle : kernel, xc); -} - -void -Statistics::callpal(int code, ExecContext *xc) -{ - if (!PAL::name(code)) - return; - - _callpal[code]++; - - switch (code) { - case PAL::callsys: { - int number = xc->readIntReg(0); - if (SystemCalls<Tru64>::validSyscallNumber(number)) { - int cvtnum = SystemCalls<Tru64>::convert(number); - _syscall[cvtnum]++; - } - } break; - } -} - -void -Statistics::serialize(ostream &os) -{ - int exemode = themode; - SERIALIZE_SCALAR(exemode); - SERIALIZE_SCALAR(idleProcess); - SERIALIZE_SCALAR(iplLast); - SERIALIZE_SCALAR(iplLastTick); - SERIALIZE_SCALAR(lastModeTick); -} - -void -Statistics::unserialize(Checkpoint *cp, const string §ion) -{ - int exemode; - UNSERIALIZE_SCALAR(exemode); - UNSERIALIZE_SCALAR(idleProcess); - UNSERIALIZE_SCALAR(iplLast); - UNSERIALIZE_SCALAR(iplLastTick); - UNSERIALIZE_SCALAR(lastModeTick); - themode = (cpu_mode)exemode; -} - -/* end namespace Kernel */ } diff --git a/kern/kernel_stats.hh b/kern/kernel_stats.hh deleted file mode 100644 index f63b5e38b..000000000 --- a/kern/kernel_stats.hh +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __KERNEL_STATS_HH__ -#define __KERNEL_STATS_HH__ - -#include <map> -#include <stack> -#include <string> -#include <vector> - -#include "cpu/static_inst.hh" - -class BaseCPU; -class ExecContext; -class FnEvent; -// What does kernel stats expect is included? -class System; - -namespace Kernel { - -enum cpu_mode { kernel, user, idle, cpu_mode_num }; -extern const char *modestr[]; - -class Statistics : public Serializable -{ - private: - std::string myname; - - Addr idleProcess; - cpu_mode themode; - Tick lastModeTick; - - void changeMode(cpu_mode newmode, ExecContext *xc); - - private: - Stats::Scalar<> _arm; - Stats::Scalar<> _quiesce; - Stats::Scalar<> _ivlb; - Stats::Scalar<> _ivle; - Stats::Scalar<> _hwrei; - - Stats::Vector<> _iplCount; - Stats::Vector<> _iplGood; - Stats::Vector<> _iplTicks; - Stats::Formula _iplUsed; - - Stats::Vector<> _callpal; - Stats::Vector<> _syscall; -// Stats::Vector<> _faults; - - Stats::Vector<> _mode; - Stats::Vector<> _modeGood; - Stats::Formula _modeFraction; - Stats::Vector<> _modeTicks; - - Stats::Scalar<> _swap_context; - - private: - int iplLast; - Tick iplLastTick; - - public: - Statistics(System *system); - - const std::string name() const { return myname; } - void regStats(const std::string &name); - - public: - void arm() { _arm++; } - void quiesce() { _quiesce++; } - void ivlb() { _ivlb++; } - void ivle() { _ivle++; } - void hwrei() { _hwrei++; } - void swpipl(int ipl); - void mode(cpu_mode newmode, ExecContext *xc); - void context(Addr oldpcbb, Addr newpcbb, ExecContext *xc); - void callpal(int code, ExecContext *xc); - - void setIdleProcess(Addr idle, ExecContext *xc); - - public: - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); -}; - -/* end namespace Kernel */ } - -#endif // __KERNEL_STATS_HH__ diff --git a/kern/linux/events.cc b/kern/linux/events.cc deleted file mode 100644 index 9f50eef04..000000000 --- a/kern/linux/events.cc +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "arch/arguments.hh" -#include "base/trace.hh" -#include "cpu/exec_context.hh" -#include "kern/linux/events.hh" -#include "kern/linux/printk.hh" -#include "kern/system_events.hh" -#include "sim/system.hh" - - -namespace Linux { - -void -DebugPrintkEvent::process(ExecContext *xc) -{ - if (DTRACE(DebugPrintf)) { - if (!raw) { - StringWrap name(xc->getSystemPtr()->name() + ".dprintk"); - DPRINTFN(""); - } - - AlphaArguments args(xc); - Printk(args); - SkipFuncEvent::process(xc); - } -} - -} // namespace linux diff --git a/kern/linux/events.hh b/kern/linux/events.hh deleted file mode 100644 index 95c268976..000000000 --- a/kern/linux/events.hh +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2004-2006 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __KERN_LINUX_EVENTS_HH__ -#define __KERN_LINUX_EVENTS_HH__ - -#include "kern/system_events.hh" - -namespace Linux { - -class DebugPrintkEvent : public SkipFuncEvent -{ - private: - bool raw; - - public: - DebugPrintkEvent(PCEventQueue *q, const std::string &desc, Addr addr, - bool r = false) - : SkipFuncEvent(q, desc, addr), raw(r) {} - virtual void process(ExecContext *xc); -}; - -} - -#endif diff --git a/kern/linux/linux.hh b/kern/linux/linux.hh deleted file mode 100644 index 0dbccf546..000000000 --- a/kern/linux/linux.hh +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __LINUX_HH__ -#define __LINUX_HH__ -#include "config/full_system.hh" - -#if FULL_SYSTEM - -class Linux {}; - -#else //!FULL_SYSTEM - -#include <dirent.h> -#include <errno.h> -#include <fcntl.h> // for host open() flags -#include <string.h> // for memset() -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - -#include "sim/syscall_emul.hh" - -/// -/// This class encapsulates the types, structures, constants, -/// functions, and syscall-number mappings specific to the Alpha Linux -/// syscall interface. -/// -class Linux { - - public: - - //@{ - /// Basic Linux types. - typedef uint64_t size_t; - typedef uint64_t off_t; - typedef int64_t time_t; - typedef uint32_t uid_t; - typedef uint32_t gid_t; - //@} - -#if BSD_HOST - typedef struct stat hst_stat; - typedef struct stat hst_stat64; -#else - typedef struct stat hst_stat ; - typedef struct stat64 hst_stat64; -#endif - - - //@{ - /// open(2) flag values. - static const int TGT_O_RDONLY = 00000000; //!< O_RDONLY - static const int TGT_O_WRONLY = 00000001; //!< O_WRONLY - static const int TGT_O_RDWR = 00000002; //!< O_RDWR - static const int TGT_O_NONBLOCK = 00000004; //!< O_NONBLOCK - static const int TGT_O_APPEND = 00000010; //!< O_APPEND - static const int TGT_O_CREAT = 00001000; //!< O_CREAT - static const int TGT_O_TRUNC = 00002000; //!< O_TRUNC - static const int TGT_O_EXCL = 00004000; //!< O_EXCL - static const int TGT_O_NOCTTY = 00010000; //!< O_NOCTTY - static const int TGT_O_SYNC = 00040000; //!< O_SYNC - static const int TGT_O_DRD = 00100000; //!< O_DRD - static const int TGT_O_DIRECTIO = 00200000; //!< O_DIRECTIO - static const int TGT_O_CACHE = 00400000; //!< O_CACHE - static const int TGT_O_DSYNC = 02000000; //!< O_DSYNC - static const int TGT_O_RSYNC = 04000000; //!< O_RSYNC - //@} - - /// This table maps the target open() flags to the corresponding - /// host open() flags. - static OpenFlagTransTable openFlagTable[]; - - /// Number of entries in openFlagTable[]. - static const int NUM_OPEN_FLAGS; - - /// Stat buffer. Note that we can't call it 'stat' since that - /// gets #defined to something else on some systems. - struct tgt_stat { - uint32_t st_dev; //!< device - uint32_t st_ino; //!< inode - uint32_t st_mode; //!< mode - uint32_t st_nlink; //!< link count - uint32_t st_uid; //!< owner's user ID - uint32_t st_gid; //!< owner's group ID - uint32_t st_rdev; //!< device number - int32_t _pad1; //!< for alignment - int64_t st_size; //!< file size in bytes - uint64_t st_atimeX; //!< time of last access - uint64_t st_mtimeX; //!< time of last modification - uint64_t st_ctimeX; //!< time of last status change - uint32_t st_blksize; //!< optimal I/O block size - int32_t st_blocks; //!< number of blocks allocated - uint32_t st_flags; //!< flags - uint32_t st_gen; //!< unknown - }; - - // same for stat64 - struct tgt_stat64 { - uint64_t st_dev; - uint64_t st_ino; - uint64_t st_rdev; - int64_t st_size; - uint64_t st_blocks; - - uint32_t st_mode; - uint32_t st_uid; - uint32_t st_gid; - uint32_t st_blksize; - uint32_t st_nlink; - uint32_t __pad0; - - uint64_t tgt_st_atime; - uint64_t st_atime_nsec; - uint64_t tgt_st_mtime; - uint64_t st_mtime_nsec; - uint64_t tgt_st_ctime; - uint64_t st_ctime_nsec; - int64_t ___unused[3]; - }; - - /// Length of strings in struct utsname (plus 1 for null char). - static const int _SYS_NMLN = 65; - - /// Interface struct for uname(). - struct utsname { - char sysname[_SYS_NMLN]; //!< System name. - char nodename[_SYS_NMLN]; //!< Node name. - char release[_SYS_NMLN]; //!< OS release. - char version[_SYS_NMLN]; //!< OS version. - char machine[_SYS_NMLN]; //!< Machine type. - }; - - - //@{ - /// ioctl() command codes. - static const unsigned TIOCGETP = 0x40067408; - static const unsigned TIOCSETP = 0x80067409; - static const unsigned TIOCSETN = 0x8006740a; - static const unsigned TIOCSETC = 0x80067411; - static const unsigned TIOCGETC = 0x40067412; - static const unsigned FIONREAD = 0x4004667f; - static const unsigned TIOCISATTY = 0x2000745e; - static const unsigned TIOCGETS = 0x402c7413; - static const unsigned TIOCGETA = 0x40127417; - //@} - - /// Resource enumeration for getrlimit(). - enum rlimit_resources { - TGT_RLIMIT_CPU = 0, - TGT_RLIMIT_FSIZE = 1, - TGT_RLIMIT_DATA = 2, - TGT_RLIMIT_STACK = 3, - TGT_RLIMIT_CORE = 4, - TGT_RLIMIT_RSS = 5, - TGT_RLIMIT_NOFILE = 6, - TGT_RLIMIT_AS = 7, - TGT_RLIMIT_VMEM = 7, - TGT_RLIMIT_NPROC = 8, - TGT_RLIMIT_MEMLOCK = 9, - TGT_RLIMIT_LOCKS = 10 - }; - - /// Limit struct for getrlimit/setrlimit. - struct rlimit { - uint64_t rlim_cur; //!< soft limit - uint64_t rlim_max; //!< hard limit - }; - - - /// For mmap(). - static const unsigned TGT_MAP_ANONYMOUS = 0x10; - - /// For gettimeofday(). - struct timeval { - int64_t tv_sec; //!< seconds - int64_t tv_usec; //!< microseconds - }; - - // For writev/readv - struct tgt_iovec { - uint64_t iov_base; // void * - uint64_t iov_len; - }; - - //@{ - /// For getrusage(). - static const int TGT_RUSAGE_SELF = 0; - static const int TGT_RUSAGE_CHILDREN = -1; - static const int TGT_RUSAGE_BOTH = -2; - //@} - - /// For getrusage(). - struct rusage { - struct timeval ru_utime; //!< user time used - struct timeval ru_stime; //!< system time used - int64_t ru_maxrss; //!< max rss - int64_t ru_ixrss; //!< integral shared memory size - int64_t ru_idrss; //!< integral unshared data " - int64_t ru_isrss; //!< integral unshared stack " - int64_t ru_minflt; //!< page reclaims - total vmfaults - int64_t ru_majflt; //!< page faults - int64_t ru_nswap; //!< swaps - int64_t ru_inblock; //!< block input operations - int64_t ru_oublock; //!< block output operations - int64_t ru_msgsnd; //!< messages sent - int64_t ru_msgrcv; //!< messages received - int64_t ru_nsignals; //!< signals received - int64_t ru_nvcsw; //!< voluntary context switches - int64_t ru_nivcsw; //!< involuntary " - }; - - /// Helper function to convert a host stat buffer to a target stat - /// buffer. Also copies the target buffer out to the simulated - /// memory space. Used by stat(), fstat(), and lstat(). -#if !BSD_HOST - static void - copyOutStatBuf(FunctionalMemory *mem, Addr addr, hst_stat *host) - { - TypedBufferArg<Linux::tgt_stat> tgt(addr); - - tgt->st_dev = htog(host->st_dev); - tgt->st_ino = htog(host->st_ino); - tgt->st_mode = htog(host->st_mode); - tgt->st_nlink = htog(host->st_nlink); - tgt->st_uid = htog(host->st_uid); - tgt->st_gid = htog(host->st_gid); - tgt->st_rdev = htog(host->st_rdev); - tgt->st_size = htog(host->st_size); - tgt->st_atimeX = htog(host->st_atime); - tgt->st_mtimeX = htog(host->st_mtime); - tgt->st_ctimeX = htog(host->st_ctime); - tgt->st_blksize = htog(host->st_blksize); - tgt->st_blocks = htog(host->st_blocks); - - tgt.copyOut(mem); - } -#else - // Third version for bsd systems which no longer have any support for - // the old stat() call and stat() is actually a stat64() - static void - copyOutStatBuf(FunctionalMemory *mem, Addr addr, hst_stat64 *host) - { - TypedBufferArg<Linux::tgt_stat> tgt(addr); - - tgt->st_dev = htog(host->st_dev); - tgt->st_ino = htog(host->st_ino); - tgt->st_mode = htog(host->st_mode); - tgt->st_nlink = htog(host->st_nlink); - tgt->st_uid = htog(host->st_uid); - tgt->st_gid = htog(host->st_gid); - tgt->st_rdev = htog(host->st_rdev); - tgt->st_size = htog(host->st_size); - tgt->st_atimeX = htog(host->st_atime); - tgt->st_mtimeX = htog(host->st_mtime); - tgt->st_ctimeX = htog(host->st_ctime); - tgt->st_blksize = htog(host->st_blksize); - tgt->st_blocks = htog(host->st_blocks); - - tgt.copyOut(mem); - } -#endif - - - // Same for stat64 - static void - copyOutStat64Buf(FunctionalMemory *mem, int fd, Addr addr, hst_stat64 *host) - { - TypedBufferArg<Linux::tgt_stat64> tgt(addr); - - // fd == 1 checks are because libc does some checks - // that the stdout is interactive vs. a file - // this makes it work on non-linux systems - if (fd == 1) - tgt->st_dev = htog((uint64_t)0xA); - else - tgt->st_dev = htog((uint64_t)host->st_dev); - // XXX What about STAT64_HAS_BROKEN_ST_INO ??? - tgt->st_ino = htog((uint64_t)host->st_ino); - if (fd == 1) - tgt->st_rdev = htog((uint64_t)0x880d); - else - tgt->st_rdev = htog((uint64_t)host->st_rdev); - tgt->st_size = htog((int64_t)host->st_size); - tgt->st_blocks = htog((uint64_t)host->st_blocks); - - if (fd == 1) - tgt->st_mode = htog((uint32_t)0x2190); - else - tgt->st_mode = htog((uint32_t)host->st_mode); - tgt->st_uid = htog((uint32_t)host->st_uid); - tgt->st_gid = htog((uint32_t)host->st_gid); - tgt->st_blksize = htog((uint32_t)host->st_blksize); - tgt->st_nlink = htog((uint32_t)host->st_nlink); - tgt->tgt_st_atime = htog((uint64_t)host->st_atime); - tgt->tgt_st_mtime = htog((uint64_t)host->st_mtime); - tgt->tgt_st_ctime = htog((uint64_t)host->st_ctime); -#if defined(STAT_HAVE_NSEC) - tgt->st_atime_nsec = htog(host->st_atime_nsec); - tgt->st_mtime_nsec = htog(host->st_mtime_nsec); - tgt->st_ctime_nsec = htog(host->st_ctime_nsec); -#else - tgt->st_atime_nsec = 0; - tgt->st_mtime_nsec = 0; - tgt->st_ctime_nsec = 0; -#endif - - tgt.copyOut(mem); - } - -}; // class Linux - - -#endif // FULL_SYSTEM - -#endif // __LINUX_HH__ diff --git a/kern/linux/linux_syscalls.cc b/kern/linux/linux_syscalls.cc deleted file mode 100644 index c85b6d28f..000000000 --- a/kern/linux/linux_syscalls.cc +++ /dev/null @@ -1,374 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "kern/linux/linux_syscalls.hh" - -namespace { - const char * - standard_strings[SystemCalls<Linux>::Number] = { - - - "llseek", //0 - "newselect", //1 - "sysctl", //2 - "access", //3 - "acct", //4 - "adjtimex", //5 - "afs_syscall", //6 - "alarm", //7 - "bdflush", //8 - "break", //9 - - - "brk", //10 - "capget", //11 - "capset", //12 - "chdir", //13 - "chmod", //14 - "chown", //15 - "chown32", //16 - "chroot", //17 - "clock_getres", //18 - "clock_gettime", //19 - - - "clock_nanosleep", //20 - "clock_settime", //21 - "clone", //22 - "close", //23 - "creat", //24 - "create_module", //25 - "delete_module", //26 - "dup", //27 - "dup2", //28 - "epoll_create", //29 - - - "epoll_ctl", //30 - "epoll_wait", //31 - "execve", //32 - "exit", //33 - "exit_group", //34 - "fadvise64", //35 - "fadvise64_64", //36 - "fchdir", //37 - "fchmod", //38 - "fchown", //39 - - - "fchown32", //40 - "fcntl", //41 - "fcntl64", //42 - "fdatasync", //43 - "fgetxattr", //44 - "flistxattr", //45 - "flock", //46 - "fork", //47 - "fremovexattr", //48 - "fsetxattr", //49 - - - "fstat", //50 - "fstat64", //51 - "fstatfs", //52 - "fstatfs64", //53 - "fsync", //54 - "ftime", //55 - "ftruncate", //56 - "ftruncate64", //57 - "futex", //58 - "get_kernel_syms", //59 - - - "get_thread_area", //60 - "getcwd", //61 - "getdents", //62 - "getdents64", //63 - "getegid", //64 - "getegid32", //65 - "geteuid", //66 - "geteuid32", //67 - "getgid", //68 - "getgid32", //69 - - - "getgroups", //70 - "getgroups32", //71 - "getitimer", //72 - "getpgid", //73 - "getpgrp", //74 - "getpid", //75 - "getpmsg", //76 - "getppid", //77 - "getpriority", //78 - "getresgid", //79 - - - "getresgid32", //80 - "getresuid", //81 - "getresuid32", //82 - "getrlimit", //83 - "getrusage", //84 - "getsid", //85 - "gettid", //86 - "gettimeofday", //87 - "getuid", //88 - "getuid32", //89 - - - "getxattr", //90 - "gtty", //91 - "idle", //92 - "init_module", //93 - "io_cancel", //94 - "io_destroy", //95 - "io_getevents", //96 - "io_setup", //97 - "io_submit", //98 - "ioctl", //99 - - - "ioperm", //100 - "iopl", //101 - "ipc", //102 - "kill", //103 - "lchown", //104 - "lchown32", //105 - "lgetxattr", //106 - "link", //107 - "listxattr", //108 - "llistxattr", //109 - - - "lock", //110 - "lookup_dcookie", //111 - "lremovexattr", //112 - "lseek", //113 - "lsetxattr", //114 - "lstat", //115 - "lstat64", //116 - "madvise", //117 - "madvise1", //118 - "mincore", //119 - - - "mkdir", //120 - "mknod", //121 - "mlock", //122 - "mlockall", //123 - "mmap", //124 - "mmap2", //125 - "modify_ldt", //126 - "mount", //127 - "mprotect", //128 - "mpx", //129 - - - "mremap", //130 - "msync", //131 - "munlock", //132 - "munlockall", //133 - "munmap", //134 - "nanosleep", //135 - "nfsservctl", //136 - "nice", //137 - "oldfstat", //138 - "oldlstat", //139 - - - "oldolduname", //140 - "oldstat", //141 - "olduname", //142 - "open", //143 - "pause", //144 - "personality", //145 - "pipe", //146 - "pivot_root", //147 - "poll", //148 - "prctl", //149 - - - "pread64", //150 - "prof", //151 - "profil", //152 - "ptrace", //153 - "putpmsg", //154 - "pwrite64", //155 - "query_module", //156 - "quotactl", //157 - "read", //158 - "readahead", //159 - - - "readdir", //160 - "readlink", //161 - "readv", //162 - "reboot", //163 - "remap_file_pages", //164 - "removexattr", //165 - "rename", //166 - "restart_syscall", //167 - "rmdir", //168 - "rt_sigaction", //169 - - - "rt_sigpending", //170 - "rt_sigprocmask", //171 - "rt_sigqueueinfo", //172 - "rt_sigreturn", //173 - "rt_sigsuspend", //174 - "rt_sigtimedwait", //175 - "sched_get_priority_max", //176 - "sched_get_priority_min", //177 - "sched_getaffinity", //178 - "sched_getparam", //179 - - - "sched_getscheduler", //180 - "sched_rr_get_interval", //181 - "sched_setaffinity", //182 - "sched_setparam", //183 - "sched_setscheduler", //184 - "sched_yield", //185 - "select", //186 - "sendfile", //187 - "sendfile64", //188 - "set_thread_area", //189 - - - "set_tid_address", //190 - "setdomainname", //191 - "setfsgid", //192 - "setfsgid32", //193 - "setfsuid", //194 - "setfsuid32", //195 - "setgid", //196 - "setgid32", //197 - "setgroups", //198 - "setgroups32", //199 - - - "sethostname", //200 - "setitimer", //201 - "setpgid", //202 - "setpriority", //203 - "setregid", //204 - "setregid32", //205 - "setresgid", //206 - "setresgid32", //207 - "setresuid", //208 - "setresuid32", //209 - - - "setreuid", //210 - "setreuid32", //211 - "setrlimit", //212 - "setsid", //213 - "settimeofday", //214 - "setuid", //215 - "setuid32", //216 - "setxattr", //217 - "sgetmask", //218 - "sigaction", //219 - - - "sigaltstack", //220 - "signal", //221 - "sigpending", //222 - "sigprocmask", //223 - "sigreturn", //224 - "sigsuspend", //225 - "socketcall", //226 - "ssetmask", //227 - "stat", //228 - "stat64", //229 - - - "statfs", //230 - "statfs64", //231 - "stime", //232 - "stty", //233 - "swapoff", //234 - "swapon", //235 - "symlink", //236 - "sync", //237 - "sysfs", //238 - "sysinfo", //239 - - - "syslog", //240 - "tgkill", //241 - "time", //242 - "timer_create", //243 - "timer_delete", //244 - "timer_getoverrun", //245 - "timer_gettime", //246 - "timer_settime", //247 - "times", //248 - "tkill", //249 - - - "truncate", //250 - "truncate64", //251 - "ugetrlimit", //252 - "ulimit", //253 - "umask", //254 - "umount", //255 - "umount2", //256 - "uname", //257 - "unlink", //258 - "uselib", //259 - - - "ustat", //260 - "utime", //261 - "utimes", //262 - "vfork", //263 - "vhangup", //264 - "vm86", //265 - "vm86old", //266 - "vserver", //267 - "wait4", //268 - "waitpid", //269 - - - "write", //270 - "writev", //271 - }; - - -} - -const char * -SystemCalls<Linux>::name(int num) -{ - if ((num >= 0) && (num < Number)) - return standard_strings[num]; - else - return 0; -} diff --git a/kern/linux/linux_syscalls.hh b/kern/linux/linux_syscalls.hh deleted file mode 100644 index 7f2a08ea9..000000000 --- a/kern/linux/linux_syscalls.hh +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __KERN_LINUX_LINUX_SYSCALLS_HH__ -#define __KERN_LINUX_LINUX_SYSCALLS_HH__ - -#include "kern/linux/linux.hh" - -template <class OS> -class SystemCalls; - -template <> -class SystemCalls<Linux> -{ - public: - enum { - syscall = 0, - llseek = 1, - newselect = 2, - sysctl = 3, - access = 4, - acct = 5, - adjtimex = 6, - afs_syscall = 7, - alarm = 8, - bdflush = 9, - _break = 10, /*renamed from break*/ - brk = 11, - capget = 12, - capset = 13, - chdir = 14, - chmod = 15, - chown = 16, - chown32 = 17, - chroot = 18, - clock_getres = 19, - clock_gettime = 20, - clock_nanosleep = 21, - clock_settime = 22, - clone = 23, - close = 24, - creat = 25, - create_module = 26, - delete_module = 27, - dup = 28, - dup2 = 29, - epoll_create = 30, - epoll_ctl = 31, - epoll_wait = 32, - execve = 33, - exit = 34, - exit_group = 35, - fadvise64 = 36, - fadvise64_64 = 37, - fchdir = 38, - fchmod = 39, - fchown = 40, - fchown32 = 41, - fcntl = 42, - fcntl64 = 43, - fdatasync = 44, - fgetxattr = 45, - flistxattr = 46, - flock = 47, - fork = 48, - fremovexattr = 49, - fsetxattr = 50, - fstat = 51, - fstat64 = 52, - fstatfs = 53, - fstatfs64 = 54, - fsync = 55, - ftime = 56, - ftruncate = 57, - ftruncate64 = 58, - futex = 59, - get_kernel_syms = 60, - get_thread_area = 61, - getcwd = 62, - getdents = 63, - getdents64 = 64, - getegid = 65, - getegid32 = 66, - geteuid = 67, - geteuid32 = 68, - getgid = 69, - getgid32 = 70, - getgroups = 71, - getgroups32 = 72, - getitimer = 73, - getpgid = 74, - getpgrp = 75, - getpid = 76, - getpmsg = 77, - getppid = 78, - getpriority = 79, - getresgid = 80, - getresgid32 = 81, - getresuid = 82, - getresuid32 = 83, - getrlimit = 84, - getrusage = 85, - getsid = 86, - gettid = 87, - gettimeofday = 88, - getuid = 89, - getuid32 = 90, - getxattr = 91, - gtty = 92, - idle = 93, - init_module = 94, - io_cancel = 95, - io_destroy = 96, - io_getevents = 97, - io_setup = 98, - io_submit = 99, - ioctl = 100, - ioperm = 101, - iopl = 102, - ipc = 103, - kill = 104, - lchown = 105, - lchown32 = 106, - lgetxattr = 107, - link = 108, - listxattr = 109, - llistxattr = 110, - lock = 111, - lookup_dcookie = 112, - lremovexattr = 113, - lseek = 114, - lsetxattr = 115, - lstat = 116, - lstat64 = 117, - madvise = 118, - madvise1 = 119, - mincore = 120, - mkdir = 121, - mknod = 122, - mlock = 123, - mlockall = 124, - mmap = 125, - mmap2 = 126, - modify_ldt = 127, - mount = 128, - mprotect = 129, - mpx = 130, - mremap = 131, - msync = 132, - munlock = 133, - munlockall = 134, - munmap = 135, - nanosleep = 136, - nfsservctl = 137, - nice = 138, - oldfstat = 139, - oldlstat = 140, - oldolduname = 141, - oldstat = 142, - olduname = 143, - open = 144, - pause = 145, - personality = 146, - pipe = 147, - pivot_root = 148, - poll = 149, - prctl = 150, - pread64 = 151, - prof = 152, - profil = 153, - ptrace = 154, - putpmsg = 155, - pwrite64 = 156, - query_module = 157, - quotactl = 158, - read = 159, - readahead = 160, - readdir = 161, - readlink = 162, - readv = 163, - reboot = 164, - remap_file_pages = 165, - removexattr = 166, - rename = 167, - restart_syscall = 168, - rmdir = 169, - rt_sigaction = 170, - rt_sigpending = 171, - rt_sigprocmask = 172, - rt_sigqueueinfo = 173, - rt_sigreturn = 174, - rt_sigsuspend = 175, - rt_sigtimedwait = 176, - sched_get_priority_max = 177, - sched_get_priority_min = 178, - sched_getaffinity = 179, - sched_getparam = 180, - sched_getscheduler = 181, - sched_rr_get_interval = 182, - sched_setaffinity = 183, - sched_setparam = 184, - sched_setscheduler = 185, - sched_yield = 186, - select = 187, - sendfile = 188, - sendfile64 = 189, - set_thread_area = 190, - set_tid_address = 191, - setdomainname = 192, - setfsgid = 193, - setfsgid32 = 194, - setfsuid = 195, - setfsuid32 = 196, - setgid = 197, - setgid32 = 198, - setgroups = 199, - setgroups32 = 200, - sethostname = 201, - setitimer = 202, - setpgid = 203, - setpriority = 204, - setregid = 205, - setregid32 = 206, - setresgid = 207, - setresgid32 = 208, - setresuid = 209, - setresuid32 = 210, - setreuid = 211, - setreuid32 = 212, - setrlimit = 213, - setsid = 214, - settimeofday = 215, - setuid = 216, - setuid32 = 217, - setxattr = 218, - sgetmask = 219, - sigaction = 220, - sigaltstack = 221, - signal = 222, - sigpending = 223, - sigprocmask = 224, - sigreturn = 225, - sigsuspend = 226, - socketcall = 227, - ssetmask = 228, - stat = 229, - stat64 = 230, - statfs = 231, - statfs64 = 232, - stime = 233, - stty = 234, - swapoff = 235, - swapon = 236, - symlink = 237, - sync = 238, - sysfs = 239, - sysinfo = 240, - syslog = 241, - tgkill = 242, - time = 243, - timer_create = 244, - timer_delete = 245, - timer_getoverrun = 246, - timer_gettime = 247, - timer_settime = 248, - times = 249, - tkill = 250, - truncate = 251, - truncate64 = 252, - ugetrlimit = 253, - ulimit = 254, - umask = 255, - umount = 256, - umount2 = 257, - uname = 258, - unlink = 259, - uselib = 260, - ustat = 261, - utime = 262, - utimes = 263, - vfork = 264, - vhangup = 265, - vm86 = 266, - vm86old = 267, - vserver = 268, - wait4 = 269, - waitpid = 270, - write = 271, - writev = 272, - Number - }; - - static const char *name(int num); - - static bool validSyscallNumber(int num) { - return num < Number; - } - -}; - -#endif // __KERN_LINUX_LINUX_SYSCALLS_HH__ diff --git a/kern/linux/printk.cc b/kern/linux/printk.cc deleted file mode 100644 index f5313759b..000000000 --- a/kern/linux/printk.cc +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/types.h> -#include <algorithm> - -#include "base/trace.hh" -#include "arch/arguments.hh" - -using namespace std; - - -void -Printk(AlphaArguments args) -{ - char *p = (char *)args++; - - ios::fmtflags saved_flags = DebugOut().flags(); - char old_fill = DebugOut().fill(); - int old_precision = DebugOut().precision(); - - while (*p) { - switch (*p) { - case '%': { - bool more = true; - bool islong = false; - bool leftjustify = false; - bool format = false; - bool zero = false; - int width = 0; - while (more && *++p) { - switch (*p) { - case 'l': - case 'L': - islong = true; - break; - case '-': - leftjustify = true; - break; - case '#': - format = true; - break; - case '0': - if (width) - width *= 10; - else - zero = true; - break; - default: - if (*p >= '1' && *p <= '9') - width = 10 * width + *p - '0'; - else - more = false; - break; - } - } - - bool hexnum = false; - bool octal = false; - bool sign = false; - switch (*p) { - case 'X': - case 'x': - hexnum = true; - break; - case 'O': - case 'o': - octal = true; - break; - case 'D': - case 'd': - sign = true; - break; - case 'P': - format = true; - case 'p': - hexnum = true; - break; - } - - switch (*p) { - case 'D': - case 'd': - case 'U': - case 'u': - case 'X': - case 'x': - case 'O': - case 'o': - case 'P': - case 'p': { - if (hexnum) - DebugOut() << hex; - - if (octal) - DebugOut() << oct; - - if (format) { - if (!zero) - DebugOut().setf(ios::showbase); - else { - if (hexnum) { - DebugOut() << "0x"; - width -= 2; - } else if (octal) { - DebugOut() << "0"; - width -= 1; - } - } - } - - if (zero) - DebugOut().fill('0'); - - if (width > 0) - DebugOut().width(width); - - if (leftjustify && !zero) - DebugOut().setf(ios::left); - - if (sign) { - if (islong) - DebugOut() << (int64_t)args; - else - DebugOut() << (int32_t)args; - } else { - if (islong) - DebugOut() << (uint64_t)args; - else - DebugOut() << (uint32_t)args; - } - - if (zero) - DebugOut().fill(' '); - - if (width > 0) - DebugOut().width(0); - - DebugOut() << dec; - - ++args; - } - break; - - case 's': { - char *s = (char *)args; - if (!s) - s = "<NULL>"; - - if (width > 0) - DebugOut().width(width); - if (leftjustify) - DebugOut().setf(ios::left); - - DebugOut() << s; - ++args; - } - break; - case 'C': - case 'c': { - uint64_t mask = (*p == 'C') ? 0xffL : 0x7fL; - uint64_t num; - int width; - - if (islong) { - num = (uint64_t)args; - width = sizeof(uint64_t); - } else { - num = (uint32_t)args; - width = sizeof(uint32_t); - } - - while (width-- > 0) { - char c = (char)(num & mask); - if (c) - DebugOut() << c; - num >>= 8; - } - - ++args; - } - break; - case 'b': { - uint64_t n = (uint64_t)args++; - char *s = (char *)args++; - DebugOut() << s << ": " << n; - } - break; - case 'n': - case 'N': { - args += 2; -#if 0 - uint64_t n = (uint64_t)args++; - struct reg_values *rv = (struct reg_values *)args++; -#endif - } - break; - case 'r': - case 'R': { - args += 2; -#if 0 - uint64_t n = (uint64_t)args++; - struct reg_desc *rd = (struct reg_desc *)args++; -#endif - } - break; - case '%': - DebugOut() << '%'; - break; - } - ++p; - } - break; - case '\n': - DebugOut() << endl; - ++p; - break; - case '\r': - ++p; - if (*p != '\n') - DebugOut() << endl; - break; - - default: { - size_t len = strcspn(p, "%\n\r\0"); - DebugOut().write(p, len); - p += len; - } - } - } - - DebugOut().flags(saved_flags); - DebugOut().fill(old_fill); - DebugOut().precision(old_precision); -} - diff --git a/kern/linux/printk.hh b/kern/linux/printk.hh deleted file mode 100644 index 45eab6b88..000000000 --- a/kern/linux/printk.hh +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __PRINTK_HH__ -#define __PRINTK_HH__ - -class AlphaArguments; - -void Printk(AlphaArguments args); - -#endif // __PRINTK_HH__ diff --git a/kern/linux/sched.hh b/kern/linux/sched.hh deleted file mode 100644 index a11fa590d..000000000 --- a/kern/linux/sched.hh +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __KERN_LINUX_SCHED_HH__ -#define __KERN_LINUX_SCHED_HH__ - -namespace Linux { - struct task_struct { - uint8_t junk1[0xf4]; - int32_t pid; - uint8_t junk2[0x190]; - uint64_ta start; - uint8_t junk3[0x5c]; - char name[16]; - }; - - -} - -#endif // __KERN_LINUX_SCHED_HH__ diff --git a/kern/system_events.cc b/kern/system_events.cc deleted file mode 100644 index b76627dbf..000000000 --- a/kern/system_events.cc +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "encumbered/cpu/full/cpu.hh" -#include "kern/kernel_stats.hh" - -using namespace TheISA; - -void -SkipFuncEvent::process(ExecContext *xc) -{ - Addr newpc = xc->readIntReg(ReturnAddressReg); - - DPRINTF(PCEvent, "skipping %s: pc=%x, newpc=%x\n", description, - xc->readPC(), newpc); - - xc->setPC(newpc); - xc->setNextPC(xc->readPC() + sizeof(TheISA::MachInst)); - - BranchPred *bp = xc->getCpuPtr()->getBranchPred(); - if (bp != NULL) { - bp->popRAS(xc->getThreadNum()); - } -} - -void -IdleStartEvent::process(ExecContext *xc) -{ - if (xc->getKernelStats()) - xc->getKernelStats()->setIdleProcess( - xc->readMiscReg(AlphaISA::IPR_PALtemp23), xc); - remove(); -} diff --git a/kern/system_events.hh b/kern/system_events.hh deleted file mode 100644 index c836cf4a7..000000000 --- a/kern/system_events.hh +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __SYSTEM_EVENTS_HH__ -#define __SYSTEM_EVENTS_HH__ - -#include "cpu/pc_event.hh" - -class System; - -class SkipFuncEvent : public PCEvent -{ - public: - SkipFuncEvent(PCEventQueue *q, const std::string &desc, Addr addr) - : PCEvent(q, desc, addr) - {} - virtual void process(ExecContext *xc); -}; - -class IdleStartEvent : public PCEvent -{ - public: - IdleStartEvent(PCEventQueue *q, const std::string &desc, Addr addr) - : PCEvent(q, desc, addr) - {} - virtual void process(ExecContext *xc); -}; - -#endif // __SYSTEM_EVENTS_HH__ diff --git a/kern/tru64/dump_mbuf.cc b/kern/tru64/dump_mbuf.cc deleted file mode 100644 index c3c37531a..000000000 --- a/kern/tru64/dump_mbuf.cc +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include <sys/types.h> -#include <algorithm> - -#include "base/cprintf.hh" -#include "base/trace.hh" -#include "base/loader/symtab.hh" -#include "cpu/exec_context.hh" -#include "kern/tru64/mbuf.hh" -#include "sim/host.hh" -#include "sim/system.hh" -#include "arch/arguments.hh" -#include "arch/isa_traits.hh" -#include "arch/vtophys.hh" - -using namespace TheISA; - -namespace tru64 { - -void -DumpMbuf(AlphaArguments args) -{ - ExecContext *xc = args.getExecContext(); - Addr addr = (Addr)args; - struct mbuf m; - - CopyOut(xc, &m, addr, sizeof(m)); - - int count = m.m_pkthdr.len; - - ccprintf(DebugOut(), "m=%#lx, m->m_pkthdr.len=%#d\n", addr, - m.m_pkthdr.len); - - while (count > 0) { - ccprintf(DebugOut(), "m=%#lx, m->m_data=%#lx, m->m_len=%d\n", - addr, m.m_data, m.m_len); - char *buffer = new char[m.m_len]; - CopyOut(xc, buffer, m.m_data, m.m_len); - Trace::dataDump(curTick, xc->getSystemPtr()->name(), (uint8_t *)buffer, - m.m_len); - delete [] buffer; - - count -= m.m_len; - if (!m.m_next) - break; - - CopyOut(xc, &m, m.m_next, sizeof(m)); - } -} - -} // namespace Tru64 diff --git a/kern/tru64/dump_mbuf.hh b/kern/tru64/dump_mbuf.hh deleted file mode 100644 index 0ff5da3d7..000000000 --- a/kern/tru64/dump_mbuf.hh +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __DUMP_MBUF_HH__ -#define __DUMP_MBUF_HH__ - -class AlphaArguments; - -namespace tru64 { - void DumpMbuf(AlphaArguments args); -} - -#endif // __DUMP_MBUF_HH__ diff --git a/kern/tru64/mbuf.hh b/kern/tru64/mbuf.hh deleted file mode 100644 index 93424858f..000000000 --- a/kern/tru64/mbuf.hh +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __MBUF_HH__ -#define __MBUF_HH__ - -#include "sim/host.hh" -#include "arch/isa_traits.hh" - -namespace tru64 { - -struct m_hdr { - Addr mh_next; // 0x00 - Addr mh_nextpkt; // 0x08 - Addr mh_data; // 0x10 - int32_t mh_len; // 0x18 - int32_t mh_type; // 0x1C - int32_t mh_flags; // 0x20 - int32_t mh_pad0; // 0x24 - Addr mh_foo[4]; // 0x28, 0x30, 0x38, 0x40 -}; - -struct pkthdr { - int32_t len; - int32_t protocolSum; - Addr rcvif; -}; - -struct m_ext { - Addr ext_buf; // 0x00 - Addr ext_free; // 0x08 - uint32_t ext_size; // 0x10 - uint32_t ext_pad0; // 0x14 - Addr ext_arg; // 0x18 - struct ext_refq { - Addr forw, back; // 0x20, 0x28 - } ext_ref; - Addr uiomove_f; // 0x30 - int32_t protocolSum; // 0x38 - int32_t bytesSummed; // 0x3C - Addr checksum; // 0x40 -}; - -struct mbuf { - struct m_hdr m_hdr; - union { - struct { - struct pkthdr MH_pkthdr; - union { - struct m_ext MH_ext; - char MH_databuf[1]; - } MH_dat; - } MH; - char M_databuf[1]; - } M_dat; -}; - -#define m_attr m_hdr.mh_attr -#define m_next m_hdr.mh_next -#define m_len m_hdr.mh_len -#define m_data m_hdr.mh_data -#define m_type m_hdr.mh_type -#define m_flags m_hdr.mh_flags -#define m_nextpkt m_hdr.mh_nextpkt -#define m_act m_nextpkt -#define m_pkthdr M_dat.MH.MH_pkthdr -#define m_ext M_dat.MH.MH_dat.MH_ext -#define m_pktdat M_dat.MH.MH_dat.MH_databuf -#define m_dat M_dat.M_databuf - -} - -#endif // __MBUF_HH__ diff --git a/kern/tru64/printf.cc b/kern/tru64/printf.cc deleted file mode 100644 index 77ac17c3a..000000000 --- a/kern/tru64/printf.cc +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include <sys/types.h> -#include <algorithm> - -#include "base/cprintf.hh" -#include "base/trace.hh" -#include "sim/host.hh" -#include "arch/arguments.hh" -#include "arch/vtophys.hh" - -using namespace std; - -namespace tru64 { - -void -Printf(AlphaArguments args) -{ - char *p = (char *)args++; - - ios::fmtflags saved_flags = DebugOut().flags(); - char old_fill = DebugOut().fill(); - int old_precision = DebugOut().precision(); - - while (*p) { - switch (*p) { - case '%': { - bool more = true; - bool islong = false; - bool leftjustify = false; - bool format = false; - bool zero = false; - int width = 0; - while (more && *++p) { - switch (*p) { - case 'l': - case 'L': - islong = true; - break; - case '-': - leftjustify = true; - break; - case '#': - format = true; - break; - case '0': - if (width) - width *= 10; - else - zero = true; - break; - default: - if (*p >= '1' && *p <= '9') - width = 10 * width + *p - '0'; - else - more = false; - break; - } - } - - bool hexnum = false; - bool octal = false; - bool sign = false; - switch (*p) { - case 'X': - case 'x': - hexnum = true; - break; - case 'O': - case 'o': - octal = true; - break; - case 'D': - case 'd': - sign = true; - break; - case 'P': - format = true; - case 'p': - hexnum = true; - break; - } - - switch (*p) { - case 'D': - case 'd': - case 'U': - case 'u': - case 'X': - case 'x': - case 'O': - case 'o': - case 'P': - case 'p': { - if (hexnum) - DebugOut() << hex; - - if (octal) - DebugOut() << oct; - - if (format) { - if (!zero) - DebugOut().setf(ios::showbase); - else { - if (hexnum) { - DebugOut() << "0x"; - width -= 2; - } else if (octal) { - DebugOut() << "0"; - width -= 1; - } - } - } - - if (zero) - DebugOut().fill('0'); - - if (width > 0) - DebugOut().width(width); - - if (leftjustify && !zero) - DebugOut().setf(ios::left); - - if (sign) { - if (islong) - DebugOut() << (int64_t)args; - else - DebugOut() << (int32_t)args; - } else { - if (islong) - DebugOut() << (uint64_t)args; - else - DebugOut() << (uint32_t)args; - } - - if (zero) - DebugOut().fill(' '); - - if (width > 0) - DebugOut().width(0); - - DebugOut() << dec; - - ++args; - } - break; - - case 's': { - char *s = (char *)args; - if (!s) - s = "<NULL>"; - - if (width > 0) - DebugOut().width(width); - if (leftjustify) - DebugOut().setf(ios::left); - - DebugOut() << s; - ++args; - } - break; - case 'C': - case 'c': { - uint64_t mask = (*p == 'C') ? 0xffL : 0x7fL; - uint64_t num; - int width; - - if (islong) { - num = (uint64_t)args; - width = sizeof(uint64_t); - } else { - num = (uint32_t)args; - width = sizeof(uint32_t); - } - - while (width-- > 0) { - char c = (char)(num & mask); - if (c) - DebugOut() << c; - num >>= 8; - } - - ++args; - } - break; - case 'b': { - uint64_t n = (uint64_t)args++; - char *s = (char *)args++; - DebugOut() << s << ": " << n; - } - break; - case 'n': - case 'N': { - args += 2; -#if 0 - uint64_t n = (uint64_t)args++; - struct reg_values *rv = (struct reg_values *)args++; -#endif - } - break; - case 'r': - case 'R': { - args += 2; -#if 0 - uint64_t n = (uint64_t)args++; - struct reg_desc *rd = (struct reg_desc *)args++; -#endif - } - break; - case '%': - DebugOut() << '%'; - break; - } - ++p; - } - break; - case '\n': - DebugOut() << endl; - ++p; - break; - case '\r': - ++p; - if (*p != '\n') - DebugOut() << endl; - break; - - default: { - size_t len = strcspn(p, "%\n\r\0"); - DebugOut().write(p, len); - p += len; - } - } - } - - DebugOut().flags(saved_flags); - DebugOut().fill(old_fill); - DebugOut().precision(old_precision); -} - -} // namespace Tru64 diff --git a/kern/tru64/printf.hh b/kern/tru64/printf.hh deleted file mode 100644 index a48b4482c..000000000 --- a/kern/tru64/printf.hh +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __PRINTF_HH__ -#define __PRINTF_HH__ - -class AlphaArguments; - -namespace tru64 { - void Printf(AlphaArguments args); -} - -#endif // __PRINTF_HH__ diff --git a/kern/tru64/tru64.hh b/kern/tru64/tru64.hh deleted file mode 100644 index b8adab8a8..000000000 --- a/kern/tru64/tru64.hh +++ /dev/null @@ -1,1324 +0,0 @@ -/* - * 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. - */ - -#ifndef __TRU64_HH__ -#define __TRU64_HH__ -#include "config/full_system.hh" - -#if FULL_SYSTEM - -class Tru64 {}; - -#else //!FULL_SYSTEM - -#include <sys/types.h> -#include <sys/stat.h> -#if defined(__OpenBSD__) || defined(__APPLE__) || defined(__FreeBSD__) -#include <sys/param.h> -#include <sys/mount.h> -#else -#include <sys/statfs.h> -#endif - -#include <dirent.h> -#include <errno.h> -#include <fcntl.h> -#include <string.h> // for memset() -#include <unistd.h> - -#include "cpu/base.hh" -#include "sim/root.hh" -#include "sim/syscall_emul.hh" - -using namespace std; - -typedef struct stat global_stat; -typedef struct statfs global_statfs; -typedef struct dirent global_dirent; - -/// -/// This class encapsulates the types, structures, constants, -/// functions, and syscall-number mappings specific to the Alpha Tru64 -/// syscall interface. -/// -class Tru64 { - - public: - - //@{ - /// Basic Tru64 types. - typedef uint64_t size_t; - typedef uint64_t off_t; - typedef uint16_t nlink_t; - typedef int32_t dev_t; - typedef uint32_t uid_t; - typedef uint32_t gid_t; - typedef uint32_t time_t; - typedef uint32_t mode_t; - typedef uint32_t ino_t; - typedef struct { int val[2]; } quad; - typedef quad fsid_t; - //@} - - //@{ - /// open(2) flag values. - static const int TGT_O_RDONLY = 00000000; - static const int TGT_O_WRONLY = 00000001; - static const int TGT_O_RDWR = 00000002; - static const int TGT_O_NONBLOCK = 00000004; - static const int TGT_O_APPEND = 00000010; - static const int TGT_O_CREAT = 00001000; - static const int TGT_O_TRUNC = 00002000; - static const int TGT_O_EXCL = 00004000; - static const int TGT_O_NOCTTY = 00010000; - static const int TGT_O_SYNC = 00040000; - static const int TGT_O_DRD = 00100000; - static const int TGT_O_DIRECTIO = 00200000; - static const int TGT_O_CACHE = 00400000; - static const int TGT_O_DSYNC = 02000000; - static const int TGT_O_RSYNC = 04000000; - //@} - - /// This table maps the target open() flags to the corresponding - /// host open() flags. - static OpenFlagTransTable openFlagTable[]; - - /// Number of entries in openFlagTable[]. - static const int NUM_OPEN_FLAGS; - - /// Stat buffer. Note that Tru64 v5.0+ use a new "F64" stat - /// structure, and a new set of syscall numbers for stat calls. - /// On some hosts (notably Linux) define st_atime, st_mtime, and - /// st_ctime as macros, so we append an X to get around this. - struct F64_stat { - dev_t st_dev; //!< st_dev - int32_t st_retired1; //!< st_retired1 - mode_t st_mode; //!< st_mode - nlink_t st_nlink; //!< st_nlink - uint16_t st_nlink_reserved; //!< st_nlink_reserved - uid_t st_uid; //!< st_uid - gid_t st_gid; //!< st_gid - dev_t st_rdev; //!< st_rdev - dev_t st_ldev; //!< st_ldev - off_t st_size; //!< st_size - time_t st_retired2; //!< st_retired2 - int32_t st_uatime; //!< st_uatime - time_t st_retired3; //!< st_retired3 - int32_t st_umtime; //!< st_umtime - time_t st_retired4; //!< st_retired4 - int32_t st_uctime; //!< st_uctime - int32_t st_retired5; //!< st_retired5 - int32_t st_retired6; //!< st_retired6 - uint32_t st_flags; //!< st_flags - uint32_t st_gen; //!< st_gen - uint64_t st_spare[4]; //!< st_spare[4] - ino_t st_ino; //!< st_ino - int32_t st_ino_reserved; //!< st_ino_reserved - time_t st_atimeX; //!< st_atime - int32_t st_atime_reserved; //!< st_atime_reserved - time_t st_mtimeX; //!< st_mtime - int32_t st_mtime_reserved; //!< st_mtime_reserved - time_t st_ctimeX; //!< st_ctime - int32_t st_ctime_reserved; //!< st_ctime_reserved - uint64_t st_blksize; //!< st_blksize - uint64_t st_blocks; //!< st_blocks - }; - - - /// Old Tru64 v4.x stat struct. - /// Tru64 maintains backwards compatibility with v4.x by - /// implementing another set of stat functions using the old - /// structure definition and binding them to the old syscall - /// numbers. - - struct pre_F64_stat { - dev_t st_dev; - ino_t st_ino; - mode_t st_mode; - nlink_t st_nlink; - uid_t st_uid __attribute__ ((aligned(sizeof(uid_t)))); - gid_t st_gid; - dev_t st_rdev; - off_t st_size __attribute__ ((aligned(sizeof(off_t)))); - time_t st_atimeX; - int32_t st_uatime; - time_t st_mtimeX; - int32_t st_umtime; - time_t st_ctimeX; - int32_t st_uctime; - uint32_t st_blksize; - int32_t st_blocks; - uint32_t st_flags; - uint32_t st_gen; - }; - - /// For statfs(). - struct F64_statfs { - int16_t f_type; - int16_t f_flags; - int32_t f_retired1; - int32_t f_retired2; - int32_t f_retired3; - int32_t f_retired4; - int32_t f_retired5; - int32_t f_retired6; - int32_t f_retired7; - fsid_t f_fsid; - int32_t f_spare[9]; - char f_retired8[90]; - char f_retired9[90]; - uint64_t dummy[10]; // was union mount_info mount_info; - uint64_t f_flags2; - int64_t f_spare2[14]; - int64_t f_fsize; - int64_t f_bsize; - int64_t f_blocks; - int64_t f_bfree; - int64_t f_bavail; - int64_t f_files; - int64_t f_ffree; - char f_mntonname[1024]; - char f_mntfromname[1024]; - }; - - /// For old Tru64 v4.x statfs() - struct pre_F64_statfs { - int16_t f_type; - int16_t f_flags; - int32_t f_fsize; - int32_t f_bsize; - int32_t f_blocks; - int32_t f_bfree; - int32_t f_bavail; - int32_t f_files; - int32_t f_ffree; - fsid_t f_fsid; - int32_t f_spare[9]; - char f_mntonname[90]; - char f_mntfromname[90]; - uint64_t dummy[10]; // was union mount_info mount_info; - }; - - /// For getdirentries(). - struct dirent - { - ino_t d_ino; //!< file number of entry - uint16_t d_reclen; //!< length of this record - uint16_t d_namlen; //!< length of string in d_name - char d_name[256]; //!< dummy name length - }; - - - /// Length of strings in struct utsname (plus 1 for null char). - static const int _SYS_NMLN = 32; - - /// Interface struct for uname(). - struct utsname { - char sysname[_SYS_NMLN]; //!< System name. - char nodename[_SYS_NMLN]; //!< Node name. - char release[_SYS_NMLN]; //!< OS release. - char version[_SYS_NMLN]; //!< OS version. - char machine[_SYS_NMLN]; //!< Machine type. - }; - - //@{ - /// ioctl() command codes. - static const unsigned TIOCGETP = 0x40067408; - static const unsigned TIOCSETP = 0x80067409; - static const unsigned TIOCSETN = 0x8006740a; - static const unsigned TIOCSETC = 0x80067411; - static const unsigned TIOCGETC = 0x40067412; - static const unsigned FIONREAD = 0x4004667f; - static const unsigned TIOCISATTY = 0x2000745e; - // TIOCGETS not defined in tru64, so I made up a number - static const unsigned TIOCGETS = 0x40000000; - static const unsigned TIOCGETA = 0x402c7413; - //@} - - /// Resource enumeration for getrlimit(). - enum rlimit_resources { - TGT_RLIMIT_CPU = 0, - TGT_RLIMIT_FSIZE = 1, - TGT_RLIMIT_DATA = 2, - TGT_RLIMIT_STACK = 3, - TGT_RLIMIT_CORE = 4, - TGT_RLIMIT_RSS = 5, - TGT_RLIMIT_NOFILE = 6, - TGT_RLIMIT_AS = 7, - TGT_RLIMIT_VMEM = 7 - }; - - /// Limit struct for getrlimit/setrlimit. - struct rlimit { - uint64_t rlim_cur; //!< soft limit - uint64_t rlim_max; //!< hard limit - }; - - - /// For mmap(). - static const unsigned TGT_MAP_ANONYMOUS = 0x10; - - - //@{ - /// For getsysinfo(). - static const unsigned GSI_PLATFORM_NAME = 103; //!< platform name as string - static const unsigned GSI_CPU_INFO = 59; //!< CPU information - static const unsigned GSI_PROC_TYPE = 60; //!< get proc_type - static const unsigned GSI_MAX_CPU = 30; //!< max # cpu's on this machine - static const unsigned GSI_CPUS_IN_BOX = 55; //!< number of CPUs in system - static const unsigned GSI_PHYSMEM = 19; //!< Physical memory in KB - static const unsigned GSI_CLK_TCK = 42; //!< clock freq in Hz - //@} - - /// For getsysinfo() GSI_CPU_INFO option. - struct cpu_info { - uint32_t current_cpu; //!< current_cpu - uint32_t cpus_in_box; //!< cpus_in_box - uint32_t cpu_type; //!< cpu_type - uint32_t ncpus; //!< ncpus - uint64_t cpus_present; //!< cpus_present - uint64_t cpus_running; //!< cpus_running - uint64_t cpu_binding; //!< cpu_binding - uint64_t cpu_ex_binding; //!< cpu_ex_binding - uint32_t mhz; //!< mhz - uint32_t unused[3]; //!< future expansion - }; - - //@{ - /// For setsysinfo(). - static const unsigned SSI_IEEE_FP_CONTROL = 14; //!< ieee_set_fp_control() - //@} - - /// For gettimeofday. - struct timeval { - uint32_t tv_sec; //!< seconds - uint32_t tv_usec; //!< microseconds - }; - - //@{ - /// For getrusage(). - static const int TGT_RUSAGE_THREAD = 1; - static const int TGT_RUSAGE_SELF = 0; - static const int TGT_RUSAGE_CHILDREN = -1; - //@} - - /// For getrusage(). - struct rusage { - struct timeval ru_utime; //!< user time used - struct timeval ru_stime; //!< system time used - uint64_t ru_maxrss; //!< ru_maxrss - uint64_t ru_ixrss; //!< integral shared memory size - uint64_t ru_idrss; //!< integral unshared data " - uint64_t ru_isrss; //!< integral unshared stack " - uint64_t ru_minflt; //!< page reclaims - total vmfaults - uint64_t ru_majflt; //!< page faults - uint64_t ru_nswap; //!< swaps - uint64_t ru_inblock; //!< block input operations - uint64_t ru_oublock; //!< block output operations - uint64_t ru_msgsnd; //!< messages sent - uint64_t ru_msgrcv; //!< messages received - uint64_t ru_nsignals; //!< signals received - uint64_t ru_nvcsw; //!< voluntary context switches - uint64_t ru_nivcsw; //!< involuntary " - }; - - /// For sigreturn(). - struct sigcontext { - int64_t sc_onstack; //!< sigstack state to restore - int64_t sc_mask; //!< signal mask to restore - int64_t sc_pc; //!< pc at time of signal - int64_t sc_ps; //!< psl to retore - int64_t sc_regs[32]; //!< processor regs 0 to 31 - int64_t sc_ownedfp; //!< fp has been used - int64_t sc_fpregs[32]; //!< fp regs 0 to 31 - uint64_t sc_fpcr; //!< floating point control reg - uint64_t sc_fp_control; //!< software fpcr - int64_t sc_reserved1; //!< reserved for kernel - uint32_t sc_kreserved1; //!< reserved for kernel - uint32_t sc_kreserved2; //!< reserved for kernel - size_t sc_ssize; //!< stack size - caddr_t sc_sbase; //!< stack start - uint64_t sc_traparg_a0; //!< a0 argument to trap on exc - uint64_t sc_traparg_a1; //!< a1 argument to trap on exc - uint64_t sc_traparg_a2; //!< a2 argument to trap on exc - uint64_t sc_fp_trap_pc; //!< imprecise pc - uint64_t sc_fp_trigger_sum; //!< Exception summary at trigg - uint64_t sc_fp_trigger_inst; //!< Instruction at trigger pc - }; - - - /// For table(). - static const int TBL_SYSINFO = 12; - - /// For table(). - struct tbl_sysinfo { - uint64_t si_user; //!< User time - uint64_t si_nice; //!< Nice time - uint64_t si_sys; //!< System time - uint64_t si_idle; //!< Idle time - uint64_t si_hz; //!< hz - uint64_t si_phz; //!< phz - uint64_t si_boottime; //!< Boot time in seconds - uint64_t wait; //!< Wait time - uint32_t si_max_procs; //!< rpb->rpb_numprocs - uint32_t pad; //!< padding - }; - - - /// For stack_create. - struct vm_stack { - // was void * - Addr address; //!< address hint - size_t rsize; //!< red zone size - size_t ysize; //!< yellow zone size - size_t gsize; //!< green zone size - size_t swap; //!< amount of swap to reserve - size_t incr; //!< growth increment - uint64_t align; //!< address alignment - uint64_t flags; //!< MAP_FIXED etc. - // was struct memalloc_attr * - Addr attr; //!< allocation policy - uint64_t reserved; //!< reserved - }; - - /// Return values for nxm calls. - enum { - KERN_NOT_RECEIVER = 7, - KERN_NOT_IN_SET = 12 - }; - - /// For nxm_task_init. - static const int NXM_TASK_INIT_VP = 2; //!< initial thread is VP - - /// Task attribute structure. - struct nxm_task_attr { - int64_t nxm_callback; //!< nxm_callback - unsigned int nxm_version; //!< nxm_version - unsigned short nxm_uniq_offset; //!< nxm_uniq_offset - unsigned short flags; //!< flags - int nxm_quantum; //!< nxm_quantum - int pad1; //!< pad1 - int64_t pad2; //!< pad2 - }; - - /// Signal set. - typedef uint64_t sigset_t; - - /// Thread state shared between user & kernel. - struct ushared_state { - sigset_t sigmask; //!< thread signal mask - sigset_t sig; //!< thread pending mask - // struct nxm_pth_state * - Addr pth_id; //!< out-of-line state - int flags; //!< shared flags -#define US_SIGSTACK 0x1 // thread called sigaltstack -#define US_ONSTACK 0x2 // thread is running on altstack -#define US_PROFILE 0x4 // thread called profil -#define US_SYSCALL 0x8 // thread in syscall -#define US_TRAP 0x10 // thread has trapped -#define US_YELLOW 0x20 // thread has mellowed yellow -#define US_YZONE 0x40 // thread has zoned out -#define US_FP_OWNED 0x80 // thread used floating point - - int cancel_state; //!< thread's cancelation state -#define US_CANCEL 0x1 // cancel pending -#define US_NOCANCEL 0X2 // synch cancel disabled -#define US_SYS_NOCANCEL 0x4 // syscall cancel disabled -#define US_ASYNC_NOCANCEL 0x8 // asynch cancel disabled -#define US_CANCEL_BITS (US_NOCANCEL|US_SYS_NOCANCEL|US_ASYNC_NOCANCEL) -#define US_CANCEL_MASK (US_CANCEL|US_NOCANCEL|US_SYS_NOCANCEL| \ - US_ASYNC_NOCANCEL) - - // These are semi-shared. They are always visible to - // the kernel but are never context-switched by the library. - - int nxm_ssig; //!< scheduler's synchronous signals - int reserved1; //!< reserved1 - int64_t nxm_active; //!< scheduler active - int64_t reserved2; //!< reserved2 - }; - - struct nxm_sched_state { - struct ushared_state nxm_u; //!< state own by user thread - unsigned int nxm_bits; //!< scheduler state / slot - int nxm_quantum; //!< quantum count-down value - int nxm_set_quantum; //!< quantum reset value - int nxm_sysevent; //!< syscall state - // struct nxm_upcall * - Addr nxm_uc_ret; //!< stack ptr of null thread - // void * - Addr nxm_tid; //!< scheduler's thread id - int64_t nxm_va; //!< page fault address - // struct nxm_pth_state * - Addr nxm_pthid; //!< id of null thread - uint64_t nxm_bound_pcs_count; //!< bound PCS thread count - int64_t pad[2]; //!< pad - }; - - /// nxm_shared. - struct nxm_shared { - int64_t nxm_callback; //!< address of upcall routine - unsigned int nxm_version; //!< version number - unsigned short nxm_uniq_offset; //!< correction factor for TEB - unsigned short pad1; //!< pad1 - int64_t space[2]; //!< future growth - struct nxm_sched_state nxm_ss[1]; //!< array of shared areas - }; - - /// nxm_slot_state_t. - enum nxm_slot_state_t { - NXM_SLOT_AVAIL, - NXM_SLOT_BOUND, - NXM_SLOT_UNBOUND, - NXM_SLOT_EMPTY - }; - - /// nxm_config_info - struct nxm_config_info { - int nxm_nslots_per_rad; //!< max number of VP slots per RAD - int nxm_nrads; //!< max number of RADs - // nxm_slot_state_t * - Addr nxm_slot_state; //!< per-VP slot state - // struct nxm_shared * - Addr nxm_rad[1]; //!< per-RAD shared areas - }; - - /// For nxm_thread_create. - enum nxm_thread_type { - NXM_TYPE_SCS = 0, - NXM_TYPE_VP = 1, - NXM_TYPE_MANAGER = 2 - }; - - /// Thread attributes. - struct nxm_thread_attr { - int version; //!< version - int type; //!< type - int cancel_flags; //!< cancel_flags - int priority; //!< priority - int policy; //!< policy - int signal_type; //!< signal_type - // void * - Addr pthid; //!< pthid - sigset_t sigmask; //!< sigmask - /// Initial register values. - struct { - uint64_t pc; //!< pc - uint64_t sp; //!< sp - uint64_t a0; //!< a0 - } registers; - uint64_t pad2[2]; //!< pad2 - }; - - /// Helper function to convert a host stat buffer to a target stat - /// buffer. Also copies the target buffer out to the simulated - /// memory space. Used by stat(), fstat(), and lstat(). - template <class T> - static void - copyOutStatBuf(FunctionalMemory *mem, Addr addr, global_stat *host) - { - TypedBufferArg<T> tgt(addr); - - tgt->st_dev = htog(host->st_dev); - tgt->st_ino = htog(host->st_ino); - tgt->st_mode = htog(host->st_mode); - tgt->st_nlink = htog(host->st_nlink); - tgt->st_uid = htog(host->st_uid); - tgt->st_gid = htog(host->st_gid); - tgt->st_rdev = htog(host->st_rdev); - tgt->st_size = htog(host->st_size); - tgt->st_atimeX = htog(host->st_atime); - tgt->st_mtimeX = htog(host->st_mtime); - tgt->st_ctimeX = htog(host->st_ctime); - tgt->st_blksize = htog(host->st_blksize); - tgt->st_blocks = htog(host->st_blocks); - - tgt.copyOut(mem); - } - - /// Helper function to convert a host statfs buffer to a target statfs - /// buffer. Also copies the target buffer out to the simulated - /// memory space. Used by statfs() and fstatfs(). - template <class T> - static void - copyOutStatfsBuf(FunctionalMemory *mem, Addr addr, global_statfs *host) - { - TypedBufferArg<T> tgt(addr); - -#if defined(__OpenBSD__) || defined(__APPLE__) || defined(__FreeBSD__) - tgt->f_type = 0; -#else - tgt->f_type = htog(host->f_type); -#endif - tgt->f_bsize = htog(host->f_bsize); - tgt->f_blocks = htog(host->f_blocks); - tgt->f_bfree = htog(host->f_bfree); - tgt->f_bavail = htog(host->f_bavail); - tgt->f_files = htog(host->f_files); - tgt->f_ffree = htog(host->f_ffree); - - // Is this as string normally? - memcpy(&tgt->f_fsid, &host->f_fsid, sizeof(host->f_fsid)); - - tgt.copyOut(mem); - } - - class F64 { - public: - static void copyOutStatBuf(FunctionalMemory *mem, Addr addr, - global_stat *host) - { - Tru64::copyOutStatBuf<Tru64::F64_stat>(mem, addr, host); - } - - static void copyOutStatfsBuf(FunctionalMemory *mem, Addr addr, - global_statfs *host) - { - Tru64::copyOutStatfsBuf<Tru64::F64_statfs>(mem, addr, host); - } - }; - - class PreF64 { - public: - static void copyOutStatBuf(FunctionalMemory *mem, Addr addr, - global_stat *host) - { - Tru64::copyOutStatBuf<Tru64::pre_F64_stat>(mem, addr, host); - } - - static void copyOutStatfsBuf(FunctionalMemory *mem, Addr addr, - global_statfs *host) - { - Tru64::copyOutStatfsBuf<Tru64::pre_F64_statfs>(mem, addr, host); - } - }; - - /// Helper function to convert a host stat buffer to an old pre-F64 - /// (4.x) target stat buffer. Also copies the target buffer out to - /// the simulated memory space. Used by pre_F64_stat(), - /// pre_F64_fstat(), and pre_F64_lstat(). - static void - copyOutPreF64StatBuf(FunctionalMemory *mem, Addr addr, struct stat *host) - { - TypedBufferArg<Tru64::pre_F64_stat> tgt(addr); - - tgt->st_dev = htog(host->st_dev); - tgt->st_ino = htog(host->st_ino); - tgt->st_mode = htog(host->st_mode); - tgt->st_nlink = htog(host->st_nlink); - tgt->st_uid = htog(host->st_uid); - tgt->st_gid = htog(host->st_gid); - tgt->st_rdev = htog(host->st_rdev); - tgt->st_size = htog(host->st_size); - tgt->st_atimeX = htog(host->st_atime); - tgt->st_mtimeX = htog(host->st_mtime); - tgt->st_ctimeX = htog(host->st_ctime); - tgt->st_blksize = htog(host->st_blksize); - tgt->st_blocks = htog(host->st_blocks); - - tgt.copyOut(mem); - } - - - /// The target system's hostname. - static const char *hostname; - - - /// Target getdirentries() handler. - static SyscallReturn - getdirentriesFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { -#ifdef __CYGWIN__ - panic("getdirent not implemented on cygwin!"); -#else - int fd = process->sim_fd(xc->getSyscallArg(0)); - Addr tgt_buf = xc->getSyscallArg(1); - int tgt_nbytes = xc->getSyscallArg(2); - Addr tgt_basep = xc->getSyscallArg(3); - - char * const host_buf = new char[tgt_nbytes]; - - // just pass basep through uninterpreted. - TypedBufferArg<int64_t> basep(tgt_basep); - basep.copyIn(xc->getMemPtr()); - long host_basep = (off_t)htog((int64_t)*basep); - int host_result = getdirentries(fd, host_buf, tgt_nbytes, &host_basep); - - // check for error - if (host_result < 0) { - delete [] host_buf; - return -errno; - } - - // no error: copy results back to target space - Addr tgt_buf_ptr = tgt_buf; - char *host_buf_ptr = host_buf; - char *host_buf_end = host_buf + host_result; - while (host_buf_ptr < host_buf_end) { - global_dirent *host_dp = (global_dirent *)host_buf_ptr; - int namelen = strlen(host_dp->d_name); - - // Actual size includes padded string rounded up for alignment. - // Subtract 256 for dummy char array in Tru64::dirent definition. - // Add 1 to namelen for terminating null char. - int tgt_bufsize = sizeof(Tru64::dirent) - 256 + roundUp(namelen+1, 8); - TypedBufferArg<Tru64::dirent> tgt_dp(tgt_buf_ptr, tgt_bufsize); - tgt_dp->d_ino = host_dp->d_ino; - tgt_dp->d_reclen = tgt_bufsize; - tgt_dp->d_namlen = namelen; - strcpy(tgt_dp->d_name, host_dp->d_name); - tgt_dp.copyOut(xc->getMemPtr()); - - tgt_buf_ptr += tgt_bufsize; - host_buf_ptr += host_dp->d_reclen; - } - - delete [] host_buf; - - *basep = htog((int64_t)host_basep); - basep.copyOut(xc->getMemPtr()); - - return tgt_buf_ptr - tgt_buf; -#endif - } - - /// Target sigreturn() handler. - static SyscallReturn - sigreturnFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - using TheISA::RegFile; - TypedBufferArg<Tru64::sigcontext> sc(xc->getSyscallArg(0)); - - sc.copyIn(xc->getMemPtr()); - - // Restore state from sigcontext structure. - // Note that we'll advance PC <- NPC before the end of the cycle, - // so we need to restore the desired PC into NPC. - // The current regs->pc will get clobbered. - xc->setNextPC(htog(sc->sc_pc)); - - for (int i = 0; i < 31; ++i) { - xc->setIntReg(i, htog(sc->sc_regs[i])); - xc->setFloatRegInt(i, htog(sc->sc_fpregs[i])); - } - - xc->setMiscReg(TheISA::Fpcr_DepTag, htog(sc->sc_fpcr)); - - return 0; - } - - /// Target table() handler. - static SyscallReturn - tableFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - int id = xc->getSyscallArg(0); // table ID - int index = xc->getSyscallArg(1); // index into table - // arg 2 is buffer pointer; type depends on table ID - int nel = xc->getSyscallArg(3); // number of elements - int lel = xc->getSyscallArg(4); // expected element size - - switch (id) { - case Tru64::TBL_SYSINFO: { - if (index != 0 || nel != 1 || lel != sizeof(Tru64::tbl_sysinfo)) - return -EINVAL; - TypedBufferArg<Tru64::tbl_sysinfo> elp(xc->getSyscallArg(2)); - - const int clk_hz = one_million; - elp->si_user = htog(curTick / (Clock::Frequency / clk_hz)); - elp->si_nice = htog(0); - elp->si_sys = htog(0); - elp->si_idle = htog(0); - elp->wait = htog(0); - elp->si_hz = htog(clk_hz); - elp->si_phz = htog(clk_hz); - elp->si_boottime = htog(seconds_since_epoch); // seconds since epoch? - elp->si_max_procs = htog(process->numCpus()); - elp.copyOut(xc->getMemPtr()); - return 0; - } - - default: - cerr << "table(): id " << id << " unknown." << endl; - return -EINVAL; - } - } - - // - // Mach syscalls -- identified by negated syscall numbers - // - - /// Create a stack region for a thread. - static SyscallReturn - stack_createFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - TypedBufferArg<Tru64::vm_stack> argp(xc->getSyscallArg(0)); - - argp.copyIn(xc->getMemPtr()); - - // if the user chose an address, just let them have it. Otherwise - // pick one for them. - if (htog(argp->address) == 0) { - argp->address = htog(process->next_thread_stack_base); - int stack_size = (htog(argp->rsize) + htog(argp->ysize) + - htog(argp->gsize)); - process->next_thread_stack_base -= stack_size; - argp.copyOut(xc->getMemPtr()); - } - - return 0; - } - - /// NXM library version stamp. - static - const int NXM_LIB_VERSION = 301003; - - /// This call sets up the interface between the user and kernel - /// schedulers by creating a shared-memory region. The shared memory - /// region has several structs, some global, some per-RAD, some per-VP. - static SyscallReturn - nxm_task_initFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - TypedBufferArg<Tru64::nxm_task_attr> attrp(xc->getSyscallArg(0)); - TypedBufferArg<Addr> configptr_ptr(xc->getSyscallArg(1)); - - attrp.copyIn(xc->getMemPtr()); - - if (gtoh(attrp->nxm_version) != NXM_LIB_VERSION) { - cerr << "nxm_task_init: thread library version mismatch! " - << "got " << attrp->nxm_version - << ", expected " << NXM_LIB_VERSION << endl; - abort(); - } - - if (gtoh(attrp->flags) != Tru64::NXM_TASK_INIT_VP) { - cerr << "nxm_task_init: bad flag value " << attrp->flags - << " (expected " << Tru64::NXM_TASK_INIT_VP << ")" << endl; - abort(); - } - - const Addr base_addr = 0x12000; // was 0x3f0000000LL; - Addr cur_addr = base_addr; // next addresses to use - // first comes the config_info struct - Addr config_addr = cur_addr; - cur_addr += sizeof(Tru64::nxm_config_info); - // next comes the per-cpu state vector - Addr slot_state_addr = cur_addr; - int slot_state_size = - process->numCpus() * sizeof(Tru64::nxm_slot_state_t); - cur_addr += slot_state_size; - // now the per-RAD state struct (we only support one RAD) - cur_addr = 0x14000; // bump up addr for alignment - Addr rad_state_addr = cur_addr; - int rad_state_size = - (sizeof(Tru64::nxm_shared) - + (process->numCpus()-1) * sizeof(Tru64::nxm_sched_state)); - cur_addr += rad_state_size; - - // now initialize a config_info struct and copy it out to user space - TypedBufferArg<Tru64::nxm_config_info> config(config_addr); - - config->nxm_nslots_per_rad = htog(process->numCpus()); - config->nxm_nrads = htog(1); // only one RAD in our system! - config->nxm_slot_state = htog(slot_state_addr); - config->nxm_rad[0] = htog(rad_state_addr); - - config.copyOut(xc->getMemPtr()); - - // initialize the slot_state array and copy it out - TypedBufferArg<Tru64::nxm_slot_state_t> slot_state(slot_state_addr, - slot_state_size); - for (int i = 0; i < process->numCpus(); ++i) { - // CPU 0 is bound to the calling process; all others are available - // XXX this code should have an endian conversion, but I don't think - // it works anyway - slot_state[i] = - (i == 0) ? Tru64::NXM_SLOT_BOUND : Tru64::NXM_SLOT_AVAIL; - } - - slot_state.copyOut(xc->getMemPtr()); - - // same for the per-RAD "shared" struct. Note that we need to - // allocate extra bytes for the per-VP array which is embedded at - // the end. - TypedBufferArg<Tru64::nxm_shared> rad_state(rad_state_addr, - rad_state_size); - - rad_state->nxm_callback = attrp->nxm_callback; - rad_state->nxm_version = attrp->nxm_version; - rad_state->nxm_uniq_offset = attrp->nxm_uniq_offset; - for (int i = 0; i < process->numCpus(); ++i) { - Tru64::nxm_sched_state *ssp = &rad_state->nxm_ss[i]; - ssp->nxm_u.sigmask = htog(0); - ssp->nxm_u.sig = htog(0); - ssp->nxm_u.flags = htog(0); - ssp->nxm_u.cancel_state = htog(0); - ssp->nxm_u.nxm_ssig = 0; - ssp->nxm_bits = htog(0); - ssp->nxm_quantum = attrp->nxm_quantum; - ssp->nxm_set_quantum = attrp->nxm_quantum; - ssp->nxm_sysevent = htog(0); - - if (i == 0) { - uint64_t uniq = xc->readMiscReg(TheISA::Uniq_DepTag); - ssp->nxm_u.pth_id = htog(uniq + gtoh(attrp->nxm_uniq_offset)); - ssp->nxm_u.nxm_active = htog(uniq | 1); - } - else { - ssp->nxm_u.pth_id = htog(0); - ssp->nxm_u.nxm_active = htog(0); - } - } - - rad_state.copyOut(xc->getMemPtr()); - - // - // copy pointer to shared config area out to user - // - *configptr_ptr = htog(config_addr); - configptr_ptr.copyOut(xc->getMemPtr()); - - // Register this as a valid address range with the process - process->nxm_start = base_addr; - process->nxm_end = cur_addr; - - return 0; - } - - /// Initialize execution context. - static void - init_exec_context(ExecContext *ec, - Tru64::nxm_thread_attr *attrp, uint64_t uniq_val) - { - ec->clearArchRegs(); - - ec->setIntReg(TheISA::ArgumentReg0, gtoh(attrp->registers.a0)); - ec->setIntReg(27/*t12*/, gtoh(attrp->registers.pc)); - ec->setIntReg(TheISA::StackPointerReg, gtoh(attrp->registers.sp)); - ec->setMiscReg(TheISA::Uniq_DepTag, uniq_val); - - ec->setPC(gtoh(attrp->registers.pc)); - ec->setNextPC(gtoh(attrp->registers.pc) + sizeof(TheISA::MachInst)); - - ec->activate(); - } - - /// Create thread. - static SyscallReturn - nxm_thread_createFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - TypedBufferArg<Tru64::nxm_thread_attr> attrp(xc->getSyscallArg(0)); - TypedBufferArg<uint64_t> kidp(xc->getSyscallArg(1)); - int thread_index = xc->getSyscallArg(2); - - // get attribute args - attrp.copyIn(xc->getMemPtr()); - - if (gtoh(attrp->version) != NXM_LIB_VERSION) { - cerr << "nxm_thread_create: thread library version mismatch! " - << "got " << attrp->version - << ", expected " << NXM_LIB_VERSION << endl; - abort(); - } - - if (thread_index < 0 | thread_index > process->numCpus()) { - cerr << "nxm_thread_create: bad thread index " << thread_index - << endl; - abort(); - } - - // On a real machine, the per-RAD shared structure is in - // shared memory, so both the user and kernel can get at it. - // We don't have that luxury, so we just copy it in and then - // back out again. - int rad_state_size = - (sizeof(Tru64::nxm_shared) + - (process->numCpus()-1) * sizeof(Tru64::nxm_sched_state)); - - TypedBufferArg<Tru64::nxm_shared> rad_state(0x14000, - rad_state_size); - rad_state.copyIn(xc->getMemPtr()); - - uint64_t uniq_val = gtoh(attrp->pthid) - gtoh(rad_state->nxm_uniq_offset); - - if (gtoh(attrp->type) == Tru64::NXM_TYPE_MANAGER) { - // DEC pthreads seems to always create one of these (in - // addition to N application threads), but we don't use it, - // so don't bother creating it. - - // This is supposed to be a port number. Make something up. - *kidp = htog(99); - kidp.copyOut(xc->getMemPtr()); - - return 0; - } else if (gtoh(attrp->type) == Tru64::NXM_TYPE_VP) { - // A real "virtual processor" kernel thread. Need to fork - // this thread on another CPU. - Tru64::nxm_sched_state *ssp = &rad_state->nxm_ss[thread_index]; - - if (gtoh(ssp->nxm_u.nxm_active) != 0) - return (int) Tru64::KERN_NOT_RECEIVER; - - ssp->nxm_u.pth_id = attrp->pthid; - ssp->nxm_u.nxm_active = htog(uniq_val | 1); - - rad_state.copyOut(xc->getMemPtr()); - - Addr slot_state_addr = 0x12000 + sizeof(Tru64::nxm_config_info); - int slot_state_size = - process->numCpus() * sizeof(Tru64::nxm_slot_state_t); - - TypedBufferArg<Tru64::nxm_slot_state_t> - slot_state(slot_state_addr, - slot_state_size); - - slot_state.copyIn(xc->getMemPtr()); - - if (slot_state[thread_index] != Tru64::NXM_SLOT_AVAIL) { - cerr << "nxm_thread_createFunc: requested VP slot " - << thread_index << " not available!" << endl; - fatal(""); - } - - // XXX This should have an endian conversion but I think this code - // doesn't work anyway - slot_state[thread_index] = Tru64::NXM_SLOT_BOUND; - - slot_state.copyOut(xc->getMemPtr()); - - // Find a free simulator execution context. - for (int i = 0; i < process->numCpus(); ++i) { - ExecContext *xc = process->execContexts[i]; - - if (xc->status() == ExecContext::Suspended) { - // inactive context... grab it - init_exec_context(xc, attrp, uniq_val); - - // This is supposed to be a port number, but we'll try - // and get away with just sticking the thread index - // here. - *kidp = htog(thread_index); - kidp.copyOut(xc->getMemPtr()); - - return 0; - } - } - - // fell out of loop... no available inactive context - cerr << "nxm_thread_create: no idle contexts available." << endl; - abort(); - } else { - cerr << "nxm_thread_create: can't handle thread type " - << attrp->type << endl; - abort(); - } - - return 0; - } - - /// Thread idle call (like yield()). - static SyscallReturn - nxm_idleFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - return 0; - } - - /// Block thread. - static SyscallReturn - nxm_thread_blockFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - uint64_t tid = xc->getSyscallArg(0); - uint64_t secs = xc->getSyscallArg(1); - uint64_t flags = xc->getSyscallArg(2); - uint64_t action = xc->getSyscallArg(3); - uint64_t usecs = xc->getSyscallArg(4); - - cout << xc->getCpuPtr()->name() << ": nxm_thread_block " << tid << " " - << secs << " " << flags << " " << action << " " << usecs << endl; - - return 0; - } - - /// block. - static SyscallReturn - nxm_blockFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - Addr uaddr = xc->getSyscallArg(0); - uint64_t val = xc->getSyscallArg(1); - uint64_t secs = xc->getSyscallArg(2); - uint64_t usecs = xc->getSyscallArg(3); - uint64_t flags = xc->getSyscallArg(4); - - BaseCPU *cpu = xc->getCpuPtr(); - - cout << cpu->name() << ": nxm_block " - << hex << uaddr << dec << " " << val - << " " << secs << " " << usecs - << " " << flags << endl; - - return 0; - } - - /// Unblock thread. - static SyscallReturn - nxm_unblockFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - Addr uaddr = xc->getSyscallArg(0); - - cout << xc->getCpuPtr()->name() << ": nxm_unblock " - << hex << uaddr << dec << endl; - - return 0; - } - - /// Switch thread priority. - static SyscallReturn - swtch_priFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - // Attempts to switch to another runnable thread (if there is - // one). Returns false if there are no other threads to run - // (i.e., the thread can reasonably spin-wait) or true if there - // are other threads. - // - // Since we assume at most one "kernel" thread per CPU, it's - // always safe to return false here. - return 0; //false; - } - - - /// Activate exec context waiting on a channel. Just activate one - /// by default. - static int - activate_waiting_context(Addr uaddr, Process *process, - bool activate_all = false) - { - int num_activated = 0; - - list<Process::WaitRec>::iterator i = process->waitList.begin(); - list<Process::WaitRec>::iterator end = process->waitList.end(); - - while (i != end && (num_activated == 0 || activate_all)) { - if (i->waitChan == uaddr) { - // found waiting process: make it active - ExecContext *newCtx = i->waitingContext; - assert(newCtx->status() == ExecContext::Suspended); - newCtx->activate(); - - // get rid of this record - i = process->waitList.erase(i); - - ++num_activated; - } else { - ++i; - } - } - - return num_activated; - } - - /// M5 hacked-up lock acquire. - static void - m5_lock_mutex(Addr uaddr, Process *process, ExecContext *xc) - { - TypedBufferArg<uint64_t> lockp(uaddr); - - lockp.copyIn(xc->getMemPtr()); - - if (gtoh(*lockp) == 0) { - // lock is free: grab it - *lockp = htog(1); - lockp.copyOut(xc->getMemPtr()); - } else { - // lock is busy: disable until free - process->waitList.push_back(Process::WaitRec(uaddr, xc)); - xc->suspend(); - } - } - - /// M5 unlock call. - static void - m5_unlock_mutex(Addr uaddr, Process *process, ExecContext *xc) - { - TypedBufferArg<uint64_t> lockp(uaddr); - - lockp.copyIn(xc->getMemPtr()); - assert(*lockp != 0); - - // Check for a process waiting on the lock. - int num_waiting = activate_waiting_context(uaddr, process); - - // clear lock field if no waiting context is taking over the lock - if (num_waiting == 0) { - *lockp = 0; - lockp.copyOut(xc->getMemPtr()); - } - } - - /// Lock acquire syscall handler. - static SyscallReturn - m5_mutex_lockFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - Addr uaddr = xc->getSyscallArg(0); - - m5_lock_mutex(uaddr, process, xc); - - // Return 0 since we will always return to the user with the lock - // acquired. We will just keep the context inactive until that is - // true. - return 0; - } - - /// Try lock (non-blocking). - static SyscallReturn - m5_mutex_trylockFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - Addr uaddr = xc->getSyscallArg(0); - TypedBufferArg<uint64_t> lockp(uaddr); - - lockp.copyIn(xc->getMemPtr()); - - if (gtoh(*lockp) == 0) { - // lock is free: grab it - *lockp = htog(1); - lockp.copyOut(xc->getMemPtr()); - return 0; - } else { - return 1; - } - } - - /// Unlock syscall handler. - static SyscallReturn - m5_mutex_unlockFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - Addr uaddr = xc->getSyscallArg(0); - - m5_unlock_mutex(uaddr, process, xc); - - return 0; - } - - /// Signal ocndition. - static SyscallReturn - m5_cond_signalFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - Addr cond_addr = xc->getSyscallArg(0); - - // Wake up one process waiting on the condition variable. - activate_waiting_context(cond_addr, process); - - return 0; - } - - /// Wake up all processes waiting on the condition variable. - static SyscallReturn - m5_cond_broadcastFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - Addr cond_addr = xc->getSyscallArg(0); - - activate_waiting_context(cond_addr, process, true); - - return 0; - } - - /// Wait on a condition. - static SyscallReturn - m5_cond_waitFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - Addr cond_addr = xc->getSyscallArg(0); - Addr lock_addr = xc->getSyscallArg(1); - TypedBufferArg<uint64_t> condp(cond_addr); - TypedBufferArg<uint64_t> lockp(lock_addr); - - // user is supposed to acquire lock before entering - lockp.copyIn(xc->getMemPtr()); - assert(gtoh(*lockp) != 0); - - m5_unlock_mutex(lock_addr, process, xc); - - process->waitList.push_back(Process::WaitRec(cond_addr, xc)); - xc->suspend(); - - return 0; - } - - /// Thread exit. - static SyscallReturn - m5_thread_exitFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - assert(xc->status() == ExecContext::Active); - xc->deallocate(); - - return 0; - } - - /// Indirect syscall invocation (call #0). - static SyscallReturn - indirectSyscallFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) - { - int new_callnum = xc->getSyscallArg(0); - LiveProcess *lp = dynamic_cast<LiveProcess*>(process); - assert(lp); - - for (int i = 0; i < 5; ++i) - xc->setSyscallArg(i, xc->getSyscallArg(i+1)); - - - SyscallDesc *new_desc = lp->getDesc(new_callnum); - if (desc == NULL) - fatal("Syscall %d out of range", callnum); - - new_desc->doSyscall(new_callnum, process, xc); - - return 0; - } - -}; // class Tru64 - - -#endif // FULL_SYSTEM - -#endif // __TRU64_HH__ diff --git a/kern/tru64/tru64_events.cc b/kern/tru64/tru64_events.cc deleted file mode 100644 index 8f2be6d9b..000000000 --- a/kern/tru64/tru64_events.cc +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include "cpu/exec_context.hh" -#include "cpu/base.hh" -#include "kern/system_events.hh" -#include "kern/tru64/tru64_events.hh" -#include "kern/tru64/dump_mbuf.hh" -#include "kern/tru64/printf.hh" -#include "mem/functional/memory_control.hh" -#include "arch/arguments.hh" -#include "arch/isa_traits.hh" -#include "sim/system.hh" - -using namespace TheISA; - -//void SkipFuncEvent::process(ExecContext *xc); - -void -BadAddrEvent::process(ExecContext *xc) -{ - // The following gross hack is the equivalent function to the - // annotation for vmunix::badaddr in: - // simos/simulation/apps/tcl/osf/tlaser.tcl - - uint64_t a0 = xc->readIntReg(ArgumentReg0); - - if (!TheISA::IsK0Seg(a0) || - xc->getSystemPtr()->memctrl->badaddr( - TheISA::K0Seg2Phys(a0) & EV5::PAddrImplMask)) { - - DPRINTF(BADADDR, "badaddr arg=%#x bad\n", a0); - xc->setIntReg(ReturnValueReg, 0x1); - SkipFuncEvent::process(xc); - } - else - DPRINTF(BADADDR, "badaddr arg=%#x good\n", a0); -} - -void -PrintfEvent::process(ExecContext *xc) -{ - if (DTRACE(Printf)) { - DebugOut() << curTick << ": " << xc->getCpuPtr()->name() << ": "; - - AlphaArguments args(xc); - tru64::Printf(args); - } -} - -void -DebugPrintfEvent::process(ExecContext *xc) -{ - if (DTRACE(DebugPrintf)) { - if (!raw) - DebugOut() << curTick << ": " << xc->getCpuPtr()->name() << ": "; - - AlphaArguments args(xc); - tru64::Printf(args); - } -} - -void -DumpMbufEvent::process(ExecContext *xc) -{ - if (DTRACE(DebugPrintf)) { - AlphaArguments args(xc); - tru64::DumpMbuf(args); - } -} diff --git a/kern/tru64/tru64_events.hh b/kern/tru64/tru64_events.hh deleted file mode 100644 index 9b5bcfea2..000000000 --- a/kern/tru64/tru64_events.hh +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __TRU64_EVENTS_HH__ -#define __TRU64_EVENTS_HH__ - -#include <string> - -#include "cpu/pc_event.hh" -#include "kern/system_events.hh" - -class ExecContext; - -class BadAddrEvent : public SkipFuncEvent -{ - public: - BadAddrEvent(PCEventQueue *q, const std::string &desc, Addr addr) - : SkipFuncEvent(q, desc, addr) {} - virtual void process(ExecContext *xc); -}; - -class PrintfEvent : public PCEvent -{ - public: - PrintfEvent(PCEventQueue *q, const std::string &desc, Addr addr) - : PCEvent(q, desc, addr) {} - virtual void process(ExecContext *xc); -}; - -class DebugPrintfEvent : public PCEvent -{ - private: - bool raw; - - public: - DebugPrintfEvent(PCEventQueue *q, const std::string &desc, Addr addr, - bool r = false) - : PCEvent(q, desc, addr), raw(r) {} - virtual void process(ExecContext *xc); -}; - -class DebugPrintfrEvent : public DebugPrintfEvent -{ - public: - DebugPrintfrEvent(PCEventQueue *q, const std::string &desc, Addr addr) - : DebugPrintfEvent(q, desc, addr, true) - {} -}; - -class DumpMbufEvent : public PCEvent -{ - public: - DumpMbufEvent(PCEventQueue *q, const std::string &desc, Addr addr) - : PCEvent(q, desc, addr) {} - virtual void process(ExecContext *xc); -}; - -#endif // __TRU64_EVENTS_HH__ diff --git a/kern/tru64/tru64_syscalls.cc b/kern/tru64/tru64_syscalls.cc deleted file mode 100644 index 8aa57dbaa..000000000 --- a/kern/tru64/tru64_syscalls.cc +++ /dev/null @@ -1,438 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include "kern/tru64/tru64_syscalls.hh" - -namespace { - const char * - standard_strings[SystemCalls<Tru64>::StandardNumber] = { - "syscall", // 0 - "exit", // 1 - "fork", // 2 - "read", // 3 - "write", // 4 - "old_open", // 5 - "close", // 6 - "wait4", // 7 - "old_creat", // 8 - "link", // 9 - - "unlink", // 10 - "execv", // 11 - "chdir", // 12 - "fchdir", // 13 - "mknod", // 14 - "chmod", // 15 - "chown", // 16 - "obreak", // 17 - "pre_F64_getfsstat", // 18 - "lseek", // 19 - - "getpid", // 20 - "mount", // 21 - "unmount", // 22 - "setuid", // 23 - "getuid", // 24 - "exec_with_loader", // 25 - "ptrace", // 26 - "recvmsg", // 27 - "sendmsg", // 28 - "recvfrom", // 29 - - "accept", // 30 - "getpeername", // 31 - "getsockname", // 32 - "access", // 33 - "chflags", // 34 - "fchflags", // 35 - "sync", // 36 - "kill", // 37 - "old_stat", // 38 - "setpgid", // 39 - - "old_lstat", // 40 - "dup", // 41 - "pipe", // 42 - "set_program_attributes", // 43 - "profil", // 44 - "open", // 45 - "obsolete_osigaction", // 46 - "getgid", // 47 - "sigprocmask", // 48 - "getlogin", // 49 - - "setlogin", // 50 - "acct", // 51 - "sigpending", // 52 - "classcntl", // 53 - "ioctl", // 54 - "reboot", // 55 - "revoke", // 56 - "symlink", // 57 - "readlink", // 58 - "execve", // 59 - - "umask", // 60 - "chroot", // 61 - "old_fstat", // 62 - "getpgrp", // 63 - "getpagesize", // 64 - "mremap", // 65 - "vfork", // 66 - "pre_F64_stat", // 67 - "pre_F64_lstat", // 68 - "sbrk", // 69 - - "sstk", // 70 - "mmap", // 71 - "ovadvise", // 72 - "munmap", // 73 - "mprotect", // 74 - "madvise", // 75 - "old_vhangup", // 76 - "kmodcall", // 77 - "mincore", // 78 - "getgroups", // 79 - - "setgroups", // 80 - "old_getpgrp", // 81 - "setpgrp", // 82 - "setitimer", // 83 - "old_wait", // 84 - "table", // 85 - "getitimer", // 86 - "gethostname", // 87 - "sethostname", // 88 - "getdtablesize", // 89 - - "dup2", // 90 - "pre_F64_fstat", // 91 - "fcntl", // 92 - "select", // 93 - "poll", // 94 - "fsync", // 95 - "setpriority", // 96 - "socket", // 97 - "connect", // 98 - "old_accept", // 99 - - "getpriority", // 100 - "old_send", // 101 - "old_recv", // 102 - "sigreturn", // 103 - "bind", // 104 - "setsockopt", // 105 - "listen", // 106 - "plock", // 107 - "old_sigvec", // 108 - "old_sigblock", // 109 - - "old_sigsetmask", // 110 - "sigsuspend", // 111 - "sigstack", // 112 - "old_recvmsg", // 113 - "old_sendmsg", // 114 - "obsolete_vtrcae", // 115 - "gettimeofday", // 116 - "getrusage", // 117 - "getsockopt", // 118 - "numa_syscalls", // 119 - - "readv", // 120 - "writev", // 121 - "settimeofday", // 122 - "fchown", // 123 - "fchmod", // 124 - "old_recvfrom", // 125 - "setreuid", // 126 - "setregid", // 127 - "rename", // 128 - "truncate", // 129 - - "ftruncate", // 130 - "flock", // 131 - "setgid", // 132 - "sendto", // 133 - "shutdown", // 134 - "socketpair", // 135 - "mkdir", // 136 - "rmdir", // 137 - "utimes", // 138 - "obsolete_42_sigreturn", // 139 - - "adjtime", // 140 - "old_getpeername", // 141 - "gethostid", // 142 - "sethostid", // 143 - "getrlimit", // 144 - "setrlimit", // 145 - "old_killpg", // 146 - "setsid", // 147 - "quotactl", // 148 - "oldquota", // 149 - - "old_getsockname", // 150 - "pread", // 151 - "pwrite", // 152 - "pid_block", // 153 - "pid_unblock", // 154 - "signal_urti", // 155 - "sigaction", // 156 - "sigwaitprim", // 157 - "nfssvc", // 158 - "getdirentries", // 159 - - "pre_F64_statfs", // 160 - "pre_F64_fstatfs", // 161 - 0, // 162 - "async_daemon", // 163 - "getfh", // 164 - "getdomainname", // 165 - "setdomainname", // 166 - 0, // 167 - 0, // 168 - "exportfs", // 169 - - 0, // 170 - 0, // 171 - 0, // 172 - 0, // 173 - 0, // 174 - 0, // 175 - 0, // 176 - 0, // 177 - 0, // 178 - 0, // 179 - - 0, // 180 - "alt_plock", // 181 - 0, // 182 - 0, // 183 - "getmnt", // 184 - 0, // 185 - 0, // 186 - "alt_sigpending", // 187 - "alt_setsid", // 188 - 0, // 189 - - 0, // 190 - 0, // 191 - 0, // 192 - 0, // 193 - 0, // 194 - 0, // 195 - 0, // 196 - 0, // 197 - 0, // 198 - "swapon", // 199 - - "msgctl", // 200 - "msgget", // 201 - "msgrcv", // 202 - "msgsnd", // 203 - "semctl", // 204 - "semget", // 205 - "semop", // 206 - "uname", // 207 - "lchown", // 208 - "shmat", // 209 - - "shmctl", // 210 - "shmdt", // 211 - "shmget", // 212 - "mvalid", // 213 - "getaddressconf", // 214 - "msleep", // 215 - "mwakeup", // 216 - "msync", // 217 - "signal", // 218 - "utc_gettime", // 219 - - "utc_adjtime", // 220 - 0, // 221 - "security", // 222 - "kloadcall", // 223 - "stat", // 224 - "lstat", // 225 - "fstat", // 226 - "statfs", // 227 - "fstatfs", // 228 - "getfsstat", // 229 - - "gettimeofday64", // 230 - "settimeofday64", // 231 - 0, // 232 - "getpgid", // 233 - "getsid", // 234 - "sigaltstack", // 235 - "waitid", // 236 - "priocntlset", // 237 - "sigsendset", // 238 - "set_speculative", // 239 - - "msfs_syscall", // 240 - "sysinfo", // 241 - "uadmin", // 242 - "fuser", // 243 - "proplist_syscall", // 244 - "ntp_adjtime", // 245 - "ntp_gettime", // 246 - "pathconf", // 247 - "fpathconf", // 248 - "sync2", // 249 - - "uswitch", // 250 - "usleep_thread", // 251 - "audcntl", // 252 - "audgen", // 253 - "sysfs", // 254 - "subsys_info", // 255 - "getsysinfo", // 256 - "setsysinfo", // 257 - "afs_syscall", // 258 - "swapctl", // 259 - - "memcntl", // 260 - "fdatasync", // 261 - "oflock", // 262 - "_F64_readv", // 263 - "_F64_writev", // 264 - "cdslxlate", // 265 - "sendfile", // 266 - }; - - const char * - mach_strings[SystemCalls<Tru64>::MachNumber] = { - 0, // 0 - 0, // 1 - 0, // 2 - 0, // 3 - 0, // 4 - 0, // 5 - 0, // 6 - 0, // 7 - 0, // 8 - 0, // 9 - - "task_self", // 10 - "thread_reply", // 11 - "task_notify", // 12 - "thread_self", // 13 - 0, // 14 - 0, // 15 - 0, // 16 - 0, // 17 - 0, // 18 - 0, // 19 - - "msg_send_trap", // 20 - "msg_receive_trap", // 21 - "msg_rpc_trap", // 22 - 0, // 23 - "nxm_block", // 24 - "nxm_unblock", // 25 - 0, // 26 - 0, // 27 - 0, // 28 - "nxm_thread_destroy", // 29 - - "lw_wire", // 30 - "lw_unwire", // 31 - "nxm_thread_create", // 32 - "nxm_task_init", // 33 - 0, // 34 - "nxm_idle", // 35 - "nxm_wakeup_idle", // 36 - "nxm_set_pthid", // 37 - "nxm_thread_kill", // 38 - "nxm_thread_block", // 39 - - "nxm_thread_wakeup", // 40 - "init_process", // 41 - "nxm_get_binding", // 42 - "map_fd", // 43 - "nxm_resched", // 44 - "nxm_set_cancel", // 45 - "nxm_set_binding", // 46 - "stack_create", // 47 - "nxm_get_state", // 48 - "nxm_thread_suspend", // 49 - - "nxm_thread_resume", // 50 - "nxm_signal_check", // 51 - "htg_unix_syscall", // 52 - 0, // 53 - 0, // 54 - "host_self", // 55 - "host_priv_self", // 56 - 0, // 57 - 0, // 58 - "swtch_pri", // 59 - - "swtch", // 60 - "thread_switch", // 61 - "semop_fast", // 62 - "nxm_pshared_init", // 63 - "nxm_pshared_block", // 64 - "nxm_pshared_unblock", // 65 - "nxm_pshared_destroy", // 66 - "nxm_swtch_pri", // 67 - "lw_syscall", // 68 - 0, // 69 - - "mach_sctimes_0", // 70 - "mach_sctimes_1", // 71 - "mach_sctimes_2", // 72 - "mach_sctimes_3", // 73 - "mach_sctimes_4", // 74 - "mach_sctimes_5", // 75 - "mach_sctimes_6", // 76 - "mach_sctimes_7", // 77 - "mach_sctimes_8", // 78 - "mach_sctimes_9", // 79 - - "mach_sctimes_10", // 80 - "mach_sctimes_11", // 81 - "mach_sctimes_port_alloc_dealloc", // 82 - }; -} - -const char * -SystemCalls<Tru64>::name(int num) -{ - if (num >= Number) - return 0; - else if (num >= StandardNumber) - return mach_strings[num - StandardNumber]; - else if (num >= 0) - return standard_strings[num]; - else if (num > -MachNumber) - return mach_strings[-num]; - else - return 0; -} diff --git a/kern/tru64/tru64_syscalls.hh b/kern/tru64/tru64_syscalls.hh deleted file mode 100644 index 69fa9101c..000000000 --- a/kern/tru64/tru64_syscalls.hh +++ /dev/null @@ -1,359 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __KERN_TRU64_TRU64_SYSCALLS_HH__ -#define __KERN_TRU64_TRU64_SYSCALLS_HH__ - -#include "kern/tru64/tru64.hh" - -template <class OS> -class SystemCalls; - -template <> -class SystemCalls<Tru64> -{ - public: - enum { - syscall = 0, - exit = 1, - fork = 2, - read = 3, - write = 4, - old_open = 5, - close = 6, - wait4 = 7, - old_creat = 8, - link = 9, - unlink = 10, - execv = 11, - chdir = 12, - fchdir = 13, - mknod = 14, - chmod = 15, - chown = 16, - obreak = 17, - pre_F64_getfsstat = 18, - lseek = 19, - getpid = 20, - mount = 21, - unmount = 22, - setuid = 23, - getuid = 24, - exec_with_loader = 25, - ptrace = 26, - recvmsg = 27, - sendmsg = 28, - recvfrom = 29, - accept = 30, - getpeername = 31, - getsockname = 32, - access = 33, - chflags = 34, - fchflags = 35, - sync = 36, - kill = 37, - old_stat = 38, - setpgid = 39, - old_lstat = 40, - dup = 41, - pipe = 42, - set_program_attributes = 43, - profil = 44, - open = 45, - obsolete_osigaction = 46, - getgid = 47, - sigprocmask = 48, - getlogin = 49, - setlogin = 50, - acct = 51, - sigpending = 52, - classcntl = 53, - ioctl = 54, - reboot = 55, - revoke = 56, - symlink = 57, - readlink = 58, - execve = 59, - umask = 60, - chroot = 61, - old_fstat = 62, - getpgrp = 63, - getpagesize = 64, - mremap = 65, - vfork = 66, - pre_F64_stat = 67, - pre_F64_lstat = 68, - sbrk = 69, - sstk = 70, - mmap = 71, - ovadvise = 72, - munmap = 73, - mprotect = 74, - madvise = 75, - old_vhangup = 76, - kmodcall = 77, - mincore = 78, - getgroups = 79, - setgroups = 80, - old_getpgrp = 81, - setpgrp = 82, - setitimer = 83, - old_wait = 84, - table = 85, - getitimer = 86, - gethostname = 87, - sethostname = 88, - getdtablesize = 89, - dup2 = 90, - pre_F64_fstat = 91, - fcntl = 92, - select = 93, - poll = 94, - fsync = 95, - setpriority = 96, - socket = 97, - connect = 98, - old_accept = 99, - getpriority = 100, - old_send = 101, - old_recv = 102, - sigreturn = 103, - bind = 104, - setsockopt = 105, - listen = 106, - plock = 107, - old_sigvec = 108, - old_sigblock = 109, - old_sigsetmask = 110, - sigsuspend = 111, - sigstack = 112, - old_recvmsg = 113, - old_sendmsg = 114, - obsolete_vtrcae = 115, - gettimeofday = 116, - getrusage = 117, - getsockopt = 118, - numa_syscalls = 119, - readv = 120, - writev = 121, - settimeofday = 122, - fchown = 123, - fchmod = 124, - old_recvfrom = 125, - setreuid = 126, - setregid = 127, - rename = 128, - truncate = 129, - ftruncate = 130, - flock = 131, - setgid = 132, - sendto = 133, - shutdown = 134, - socketpair = 135, - mkdir = 136, - rmdir = 137, - utimes = 138, - obsolete_42_sigreturn = 139, - adjtime = 140, - old_getpeername = 141, - gethostid = 142, - sethostid = 143, - getrlimit = 144, - setrlimit = 145, - old_killpg = 146, - setsid = 147, - quotactl = 148, - oldquota = 149, - old_getsockname = 150, - pread = 151, - pwrite = 152, - pid_block = 153, - pid_unblock = 154, - signal_urti = 155, - sigaction = 156, - sigwaitprim = 157, - nfssvc = 158, - getdirentries = 159, - pre_F64_statfs = 160, - pre_F64_fstatfs = 161, - async_daemon = 163, - getfh = 164, - getdomainname = 165, - setdomainname = 166, - exportfs = 169, - alt_plock = 181, - getmnt = 184, - alt_sigpending = 187, - alt_setsid = 188, - swapon = 199, - msgctl = 200, - msgget = 201, - msgrcv = 202, - msgsnd = 203, - semctl = 204, - semget = 205, - semop = 206, - uname = 207, - lchown = 208, - shmat = 209, - shmctl = 210, - shmdt = 211, - shmget = 212, - mvalid = 213, - getaddressconf = 214, - msleep = 215, - mwakeup = 216, - msync = 217, - signal = 218, - utc_gettime = 219, - utc_adjtime = 220, - security = 222, - kloadcall = 223, - stat = 224, - lstat = 225, - fstat = 226, - statfs = 227, - fstatfs = 228, - getfsstat = 229, - gettimeofday64 = 230, - settimeofday64 = 231, - getpgid = 233, - getsid = 234, - sigaltstack = 235, - waitid = 236, - priocntlset = 237, - sigsendset = 238, - set_speculative = 239, - msfs_syscall = 240, - sysinfo = 241, - uadmin = 242, - fuser = 243, - proplist_syscall = 244, - ntp_adjtime = 245, - ntp_gettime = 246, - pathconf = 247, - fpathconf = 248, - sync2 = 249, - uswitch = 250, - usleep_thread = 251, - audcntl = 252, - audgen = 253, - sysfs = 254, - subsys_info = 255, - getsysinfo = 256, - setsysinfo = 257, - afs_syscall = 258, - swapctl = 259, - memcntl = 260, - fdatasync = 261, - oflock = 262, - _F64_readv = 263, - _F64_writev = 264, - cdslxlate = 265, - sendfile = 266, - StandardNumber - }; - - enum { - task_self = 10, - thread_reply = 11, - task_notify = 12, - thread_self = 13, - msg_send_trap = 20, - msg_receive_trap = 21, - msg_rpc_trap = 22, - nxm_block = 24, - nxm_unblock = 25, - nxm_thread_destroy = 29, - lw_wire = 30, - lw_unwire = 31, - nxm_thread_create = 32, - nxm_task_init = 33, - nxm_idle = 35, - nxm_wakeup_idle = 36, - nxm_set_pthid = 37, - nxm_thread_kill = 38, - nxm_thread_block = 39, - nxm_thread_wakeup = 40, - init_process = 41, - nxm_get_binding = 42, - map_fd = 43, - nxm_resched = 44, - nxm_set_cancel = 45, - nxm_set_binding = 46, - stack_create = 47, - nxm_get_state = 48, - nxm_thread_suspend = 49, - nxm_thread_resume = 50, - nxm_signal_check = 51, - htg_unix_syscall = 52, - host_self = 55, - host_priv_self = 56, - swtch_pri = 59, - swtch = 60, - thread_switch = 61, - semop_fast = 62, - nxm_pshared_init = 63, - nxm_pshared_block = 64, - nxm_pshared_unblock = 65, - nxm_pshared_destroy = 66, - nxm_swtch_pri = 67, - lw_syscall = 68, - mach_sctimes_0 = 70, - mach_sctimes_1 = 71, - mach_sctimes_2 = 72, - mach_sctimes_3 = 73, - mach_sctimes_4 = 74, - mach_sctimes_5 = 75, - mach_sctimes_6 = 76, - mach_sctimes_7 = 77, - mach_sctimes_8 = 78, - mach_sctimes_9 = 79, - mach_sctimes_10 = 80, - mach_sctimes_11 = 81, - mach_sctimes_port_alloc_dealloc = 82, - MachNumber - }; - - static const int Number = StandardNumber + MachNumber; - - static const char *name(int num); - - static bool validSyscallNumber(int num) { - return -MachNumber < num && num < StandardNumber; - } - - static int convert(int syscall_num) { - if (!validSyscallNumber(syscall_num)) - return -1; - - return syscall_num < 0 ? StandardNumber - syscall_num : syscall_num; - } -}; - -#endif // __KERN_TRU64_TRU64_SYSCALLS_HH__ diff --git a/mem/cache/prefetch/tagged_prefetcher_impl.hh b/mem/cache/prefetch/tagged_prefetcher_impl.hh deleted file mode 100644 index 6c27256a9..000000000 --- a/mem/cache/prefetch/tagged_prefetcher_impl.hh +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 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. - */ - -/** - * @file - * Describes a tagged prefetcher based on template policies. - */ - -#include "mem/cache/prefetch/tagged_prefetcher.hh" - -template <class TagStore, class Buffering> -TaggedPrefetcher<TagStore, Buffering>:: -TaggedPrefetcher(int size, bool pageStop, bool serialSquash, - bool cacheCheckPush, bool onlyData, - Tick latency, int degree) - :Prefetcher<TagStore, Buffering>(size, pageStop, serialSquash, - cacheCheckPush, onlyData), - latency(latency), degree(degree) -{ -} - -template <class TagStore, class Buffering> -void -TaggedPrefetcher<TagStore, Buffering>:: -calculatePrefetch(MemReqPtr &req, std::list<Addr> &addresses, - std::list<Tick> &delays) -{ - Addr blkAddr = req->paddr & ~(Addr)(this->blkSize-1); - - for (int d=1; d <= degree; d++) { - Addr newAddr = blkAddr + d*(this->blkSize); - if (this->pageStop && - (blkAddr & ~(TheISA::VMPageSize - 1)) != - (newAddr & ~(TheISA::VMPageSize - 1))) - { - //Spanned the page, so now stop - this->pfSpanPage += degree - d + 1; - return; - } - else - { - addresses.push_back(newAddr); - delays.push_back(latency); - } - } -} - - diff --git a/mem/config/prefetch.hh b/mem/config/prefetch.hh deleted file mode 100644 index 03eb570f0..000000000 --- a/mem/config/prefetch.hh +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * Central location to configure which prefetch types we want to build - * into the simulator. In the future, this should probably be - * autogenerated by some sort of configuration script. - */ -#define USE_TAGGED 1 //Be sure not to turn this off, it is also used for no - //prefetching case unless you always want to use a - //different prefetcher -//#define USE_STRIDED 1 -//#define USE_GHB 1 diff --git a/python/SConscript b/python/SConscript deleted file mode 100644 index a34d3f2d5..000000000 --- a/python/SConscript +++ /dev/null @@ -1,207 +0,0 @@ -# -*- mode:python -*- - -# 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. - -import os, os.path, re, sys - -Import('env') - -import scons_helper - -def WriteEmbeddedPyFile(target, source, path, name, ext, filename): - if isinstance(source, str): - source = file(source, 'r') - - if isinstance(target, str): - target = file(target, 'w') - - print >>target, "AddModule(%s, %s, %s, %s, '''\\" % \ - (`path`, `name`, `ext`, `filename`) - - for line in source: - line = line - # escape existing backslashes - line = line.replace('\\', '\\\\') - # escape existing triple quotes - line = line.replace("'''", r"\'\'\'") - - print >>target, line, - - print >>target, "''')" - print >>target - -def WriteCFile(target, source, name): - if isinstance(source, str): - source = file(source, 'r') - - if isinstance(target, str): - target = file(target, 'w') - - print >>target, 'const char %s_string[] = {' % name - - count = 0 - from array import array - try: - while True: - foo = array('B') - foo.fromfile(source, 10000) - l = [ str(i) for i in foo.tolist() ] - count += len(l) - for i in xrange(0,9999,20): - print >>target, ','.join(l[i:i+20]) + ',' - except EOFError: - l = [ str(i) for i in foo.tolist() ] - count += len(l) - for i in xrange(0,len(l),20): - print >>target, ','.join(l[i:i+20]) + ',' - print >>target, ','.join(l[i:]) + ',' - - print >>target, '};' - print >>target, 'const int %s_length = %d;' % (name, count) - print >>target - -def splitpath(path): - dir,file = os.path.split(path) - path = [] - assert(file) - while dir: - dir,base = os.path.split(dir) - path.insert(0, base) - return path, file - -def MakeEmbeddedPyFile(target, source, env): - target = file(str(target[0]), 'w') - - tree = {} - for src in source: - src = str(src) - path,pyfile = splitpath(src) - node = tree - for dir in path: - if not node.has_key(dir): - node[dir] = { } - node = node[dir] - - name,ext = pyfile.split('.') - if name == '__init__': - node['.hasinit'] = True - node[pyfile] = (src,name,ext,src) - - done = False - while not done: - done = True - for name,entry in tree.items(): - if not isinstance(entry, dict): continue - if entry.has_key('.hasinit'): continue - - done = False - del tree[name] - for key,val in entry.iteritems(): - if tree.has_key(key): - raise NameError, \ - "dir already has %s can't add it again" % key - tree[key] = val - - files = [] - def populate(node, path = []): - names = node.keys() - names.sort() - for name in names: - if name == '.hasinit': - continue - - entry = node[name] - if isinstance(entry, dict): - if not entry.has_key('.hasinit'): - raise NameError, 'package directory missing __init__.py' - populate(entry, path + [ name ]) - else: - pyfile,name,ext,filename = entry - files.append((pyfile, path, name, ext, filename)) - populate(tree) - - for pyfile, path, name, ext, filename in files: - WriteEmbeddedPyFile(target, pyfile, path, name, ext, filename) - -def MakeDefinesPyFile(target, source, env): - f = file(str(target[0]), 'w') - print >>f, "import __main__" - print >>f, "__main__.m5_build_env = ", - print >>f, source[0] - f.close() - -CFileCounter = 0 -def MakePythonCFile(target, source, env): - global CFileCounter - target = file(str(target[0]), 'w') - - print >>target, '''\ -#include "base/embedfile.hh" - -namespace { -''' - for src in source: - src = str(src) - fname = os.path.basename(src) - name = 'embedded_file%d' % CFileCounter - CFileCounter += 1 - WriteCFile(target, src, name) - print >>target, '''\ -EmbedMap %(name)s("%(fname)s", - %(name)s_string, %(name)s_length); - -''' % locals() - print >>target, '''\ - -/* namespace */ } -''' - -# base list of .py files to embed -embedded_py_files = [ '../util/pbs/jobfile.py' ] -# add all .py files in python/m5 -objpath = os.path.join(env['SRCDIR'], 'python', 'm5') -for root, dirs, files in os.walk(objpath, topdown=True): - for i,dir in enumerate(dirs): - if dir == 'SCCS': - del dirs[i] - break - - assert(root.startswith(objpath)) - for f in files: - if f.endswith('.py'): - embedded_py_files.append(os.path.join(root, f)) - -embedfile_hh = os.path.join(env['SRCDIR'], 'base/embedfile.hh') - -optionDict = dict([(opt, env[opt]) for opt in env.ExportOptions]) -env.Command('defines.py', Value(optionDict), MakeDefinesPyFile) - -env.Command('embedded_py.py', embedded_py_files, MakeEmbeddedPyFile) -env.Depends('embedded_py.cc', embedfile_hh) -env.Command('embedded_py.cc', - ['string_importer.py', 'defines.py', 'embedded_py.py'], - MakePythonCFile) diff --git a/python/m5/__init__.py b/python/m5/__init__.py deleted file mode 100644 index 9bb68a090..000000000 --- a/python/m5/__init__.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright (c) 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. - -import sys, os - -# define this here so we can use it right away if necessary -def panic(string): - print >>sys.stderr, 'panic:', string - sys.exit(1) - -def m5execfile(f, global_dict): - # copy current sys.path - oldpath = sys.path[:] - # push file's directory onto front of path - sys.path.insert(0, os.path.abspath(os.path.dirname(f))) - execfile(f, global_dict) - # restore original path - sys.path = oldpath - -# Prepend given directory to system module search path. -def AddToPath(path): - # if it's a relative path and we know what directory the current - # python script is in, make the path relative to that directory. - if not os.path.isabs(path) and sys.path[0]: - path = os.path.join(sys.path[0], path) - path = os.path.realpath(path) - # sys.path[0] should always refer to the current script's directory, - # so place the new dir right after that. - sys.path.insert(1, path) - -# find the m5 compile options: must be specified as a dict in -# __main__.m5_build_env. -import __main__ -if not hasattr(__main__, 'm5_build_env'): - panic("__main__ must define m5_build_env") - -# make a SmartDict out of the build options for our local use -import smartdict -build_env = smartdict.SmartDict() -build_env.update(__main__.m5_build_env) - -# make a SmartDict out of the OS environment too -env = smartdict.SmartDict() -env.update(os.environ) - -# import the main m5 config code -from config import * - -# import the built-in object definitions -from objects import * - diff --git a/python/m5/config.py b/python/m5/config.py deleted file mode 100644 index 1e25e0d09..000000000 --- a/python/m5/config.py +++ /dev/null @@ -1,1323 +0,0 @@ -# Copyright (c) 2004-2005 The Regents of The University of Michigan -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -from __future__ import generators -import os, re, sys, types, inspect - -import m5 -panic = m5.panic -from convert import * -from multidict import multidict - -noDot = False -try: - import pydot -except: - noDot = True - -class Singleton(type): - def __call__(cls, *args, **kwargs): - if hasattr(cls, '_instance'): - return cls._instance - - cls._instance = super(Singleton, cls).__call__(*args, **kwargs) - return cls._instance - -##################################################################### -# -# M5 Python Configuration Utility -# -# The basic idea is to write simple Python programs that build Python -# objects corresponding to M5 SimObjects for the desired simulation -# configuration. For now, the Python emits a .ini file that can be -# parsed by M5. In the future, some tighter integration between M5 -# and the Python interpreter may allow bypassing the .ini file. -# -# Each SimObject class in M5 is represented by a Python class with the -# same name. The Python inheritance tree mirrors the M5 C++ tree -# (e.g., SimpleCPU derives from BaseCPU in both cases, and all -# SimObjects inherit from a single SimObject base class). To specify -# an instance of an M5 SimObject in a configuration, the user simply -# instantiates the corresponding Python object. The parameters for -# that SimObject are given by assigning to attributes of the Python -# object, either using keyword assignment in the constructor or in -# separate assignment statements. For example: -# -# cache = BaseCache(size='64KB') -# cache.hit_latency = 3 -# cache.assoc = 8 -# -# The magic lies in the mapping of the Python attributes for SimObject -# classes to the actual SimObject parameter specifications. This -# allows parameter validity checking in the Python code. Continuing -# the example above, the statements "cache.blurfl=3" or -# "cache.assoc='hello'" would both result in runtime errors in Python, -# since the BaseCache object has no 'blurfl' parameter and the 'assoc' -# parameter requires an integer, respectively. This magic is done -# primarily by overriding the special __setattr__ method that controls -# assignment to object attributes. -# -# Once a set of Python objects have been instantiated in a hierarchy, -# calling 'instantiate(obj)' (where obj is the root of the hierarchy) -# will generate a .ini file. See simple-4cpu.py for an example -# (corresponding to m5-test/simple-4cpu.ini). -# -##################################################################### - -##################################################################### -# -# ConfigNode/SimObject classes -# -# The Python class hierarchy rooted by ConfigNode (which is the base -# class of SimObject, which in turn is the base class of all other M5 -# SimObject classes) has special attribute behavior. In general, an -# object in this hierarchy has three categories of attribute-like -# things: -# -# 1. Regular Python methods and variables. These must start with an -# underscore to be treated normally. -# -# 2. SimObject parameters. These values are stored as normal Python -# attributes, but all assignments to these attributes are checked -# against the pre-defined set of parameters stored in the class's -# _params dictionary. Assignments to attributes that do not -# correspond to predefined parameters, or that are not of the correct -# type, incur runtime errors. -# -# 3. Hierarchy children. The child nodes of a ConfigNode are stored -# in the node's _children dictionary, but can be accessed using the -# Python attribute dot-notation (just as they are printed out by the -# simulator). Children cannot be created using attribute assigment; -# they must be added by specifying the parent node in the child's -# constructor or using the '+=' operator. - -# The SimObject parameters are the most complex, for a few reasons. -# First, both parameter descriptions and parameter values are -# inherited. Thus parameter description lookup must go up the -# inheritance chain like normal attribute lookup, but this behavior -# must be explicitly coded since the lookup occurs in each class's -# _params attribute. Second, because parameter values can be set -# on SimObject classes (to implement default values), the parameter -# checking behavior must be enforced on class attribute assignments as -# well as instance attribute assignments. Finally, because we allow -# class specialization via inheritance (e.g., see the L1Cache class in -# the simple-4cpu.py example), we must do parameter checking even on -# class instantiation. To provide all these features, we use a -# metaclass to define most of the SimObject parameter behavior for -# this class hierarchy. -# -##################################################################### - -def isSimObject(value): - return isinstance(value, SimObject) - -def isSimObjSequence(value): - if not isinstance(value, (list, tuple)): - return False - - for val in value: - if not isNullPointer(val) and not isSimObject(val): - return False - - return True - -def isNullPointer(value): - return isinstance(value, NullSimObject) - -# The metaclass for ConfigNode (and thus for everything that derives -# from ConfigNode, including SimObject). This class controls how new -# classes that derive from ConfigNode are instantiated, and provides -# inherited class behavior (just like a class controls how instances -# of that class are instantiated, and provides inherited instance -# behavior). -class MetaSimObject(type): - # Attributes that can be set only at initialization time - init_keywords = { 'abstract' : types.BooleanType, - 'type' : types.StringType } - # Attributes that can be set any time - keywords = { 'check' : types.FunctionType, - 'children' : types.ListType } - - # __new__ is called before __init__, and is where the statements - # in the body of the class definition get loaded into the class's - # __dict__. We intercept this to filter out parameter assignments - # and only allow "private" attributes to be passed to the base - # __new__ (starting with underscore). - def __new__(mcls, name, bases, dict): - # Copy "private" attributes (including special methods such as __new__) - # to the official dict. Everything else goes in _init_dict to be - # filtered in __init__. - cls_dict = {} - for key,val in dict.items(): - if key.startswith('_'): - cls_dict[key] = val - del dict[key] - cls_dict['_init_dict'] = dict - return super(MetaSimObject, mcls).__new__(mcls, name, bases, cls_dict) - - # initialization - def __init__(cls, name, bases, dict): - super(MetaSimObject, cls).__init__(name, bases, dict) - - # initialize required attributes - cls._params = multidict() - cls._values = multidict() - cls._anon_subclass_counter = 0 - - # We don't support multiple inheritance. If you want to, you - # must fix multidict to deal with it properly. - if len(bases) > 1: - raise TypeError, "SimObjects do not support multiple inheritance" - - base = bases[0] - - if isinstance(base, MetaSimObject): - cls._params.parent = base._params - cls._values.parent = base._values - - # If your parent has a value in it that's a config node, clone - # it. Do this now so if we update any of the values' - # attributes we are updating the clone and not the original. - for key,val in base._values.iteritems(): - - # don't clone if (1) we're about to overwrite it with - # a local setting or (2) we've already cloned a copy - # from an earlier (more derived) base - if cls._init_dict.has_key(key) or cls._values.has_key(key): - continue - - if isSimObject(val): - cls._values[key] = val() - elif isSimObjSequence(val) and len(val): - cls._values[key] = [ v() for v in val ] - - # now process remaining _init_dict items - for key,val in cls._init_dict.items(): - if isinstance(val, (types.FunctionType, types.TypeType)): - type.__setattr__(cls, key, val) - - # param descriptions - elif isinstance(val, ParamDesc): - cls._new_param(key, val) - - # init-time-only keywords - elif cls.init_keywords.has_key(key): - cls._set_keyword(key, val, cls.init_keywords[key]) - - # default: use normal path (ends up in __setattr__) - else: - setattr(cls, key, val) - - def _set_keyword(cls, keyword, val, kwtype): - if not isinstance(val, kwtype): - raise TypeError, 'keyword %s has bad type %s (expecting %s)' % \ - (keyword, type(val), kwtype) - if isinstance(val, types.FunctionType): - val = classmethod(val) - type.__setattr__(cls, keyword, val) - - def _new_param(cls, name, value): - cls._params[name] = value - if hasattr(value, 'default'): - setattr(cls, name, value.default) - - # Set attribute (called on foo.attr = value when foo is an - # instance of class cls). - def __setattr__(cls, attr, value): - # normal processing for private attributes - if attr.startswith('_'): - type.__setattr__(cls, attr, value) - return - - if cls.keywords.has_key(attr): - cls._set_keyword(attr, value, cls.keywords[attr]) - return - - # must be SimObject param - param = cls._params.get(attr, None) - if param: - # It's ok: set attribute by delegating to 'object' class. - try: - cls._values[attr] = param.convert(value) - except Exception, e: - msg = "%s\nError setting param %s.%s to %s\n" % \ - (e, cls.__name__, attr, value) - e.args = (msg, ) - raise - # I would love to get rid of this - elif isSimObject(value) or isSimObjSequence(value): - cls._values[attr] = value - else: - raise AttributeError, \ - "Class %s has no parameter %s" % (cls.__name__, attr) - - def __getattr__(cls, attr): - if cls._values.has_key(attr): - return cls._values[attr] - - raise AttributeError, \ - "object '%s' has no attribute '%s'" % (cls.__name__, attr) - -# The ConfigNode class is the root of the special hierarchy. Most of -# the code in this class deals with the configuration hierarchy itself -# (parent/child node relationships). -class SimObject(object): - # Specify metaclass. Any class inheriting from SimObject will - # get this metaclass. - __metaclass__ = MetaSimObject - - def __init__(self, _value_parent = None, **kwargs): - self._children = {} - if _value_parent and type(_value_parent) != type(self): - # this was called as a type conversion rather than a clone - raise TypeError, "Cannot convert %s to %s" % \ - (_value_parent.__class__.__name__, self.__class__.__name__) - if not _value_parent: - _value_parent = self.__class__ - # clone values - self._values = multidict(_value_parent._values) - for key,val in _value_parent._values.iteritems(): - if isSimObject(val): - setattr(self, key, val()) - elif isSimObjSequence(val) and len(val): - setattr(self, key, [ v() for v in val ]) - # apply attribute assignments from keyword args, if any - for key,val in kwargs.iteritems(): - setattr(self, key, val) - - def __call__(self, **kwargs): - return self.__class__(_value_parent = self, **kwargs) - - def __getattr__(self, attr): - if self._values.has_key(attr): - return self._values[attr] - - raise AttributeError, "object '%s' has no attribute '%s'" \ - % (self.__class__.__name__, attr) - - # Set attribute (called on foo.attr = value when foo is an - # instance of class cls). - def __setattr__(self, attr, value): - # normal processing for private attributes - if attr.startswith('_'): - object.__setattr__(self, attr, value) - return - - # must be SimObject param - param = self._params.get(attr, None) - if param: - # It's ok: set attribute by delegating to 'object' class. - try: - value = param.convert(value) - except Exception, e: - msg = "%s\nError setting param %s.%s to %s\n" % \ - (e, self.__class__.__name__, attr, value) - e.args = (msg, ) - raise - # I would love to get rid of this - elif isSimObject(value) or isSimObjSequence(value): - pass - else: - raise AttributeError, "Class %s has no parameter %s" \ - % (self.__class__.__name__, attr) - - # clear out old child with this name, if any - self.clear_child(attr) - - if isSimObject(value): - value.set_path(self, attr) - elif isSimObjSequence(value): - value = SimObjVector(value) - [v.set_path(self, "%s%d" % (attr, i)) for i,v in enumerate(value)] - - self._values[attr] = value - - # this hack allows tacking a '[0]' onto parameters that may or may - # not be vectors, and always getting the first element (e.g. cpus) - def __getitem__(self, key): - if key == 0: - return self - raise TypeError, "Non-zero index '%s' to SimObject" % key - - # clear out children with given name, even if it's a vector - def clear_child(self, name): - if not self._children.has_key(name): - return - child = self._children[name] - if isinstance(child, SimObjVector): - for i in xrange(len(child)): - del self._children["s%d" % (name, i)] - del self._children[name] - - def add_child(self, name, value): - self._children[name] = value - - def set_path(self, parent, name): - if not hasattr(self, '_parent'): - self._parent = parent - self._name = name - parent.add_child(name, self) - - def path(self): - if not hasattr(self, '_parent'): - return 'root' - ppath = self._parent.path() - if ppath == 'root': - return self._name - return ppath + "." + self._name - - def __str__(self): - return self.path() - - def ini_str(self): - return self.path() - - def find_any(self, ptype): - if isinstance(self, ptype): - return self, True - - found_obj = None - for child in self._children.itervalues(): - if isinstance(child, ptype): - if found_obj != None and child != found_obj: - raise AttributeError, \ - 'parent.any matched more than one: %s %s' % \ - (found_obj.path, child.path) - found_obj = child - # search param space - for pname,pdesc in self._params.iteritems(): - if issubclass(pdesc.ptype, ptype): - match_obj = self._values[pname] - if found_obj != None and found_obj != match_obj: - raise AttributeError, \ - 'parent.any matched more than one: %s' % obj.path - found_obj = match_obj - return found_obj, found_obj != None - - def unproxy(self, base): - return self - - def print_ini(self): - print '[' + self.path() + ']' # .ini section header - - if hasattr(self, 'type') and not isinstance(self, ParamContext): - print 'type=%s' % self.type - - child_names = self._children.keys() - child_names.sort() - np_child_names = [c for c in child_names \ - if not isinstance(self._children[c], ParamContext)] - if len(np_child_names): - print 'children=%s' % ' '.join(np_child_names) - - param_names = self._params.keys() - param_names.sort() - for param in param_names: - value = self._values.get(param, None) - if value != None: - if isproxy(value): - try: - value = value.unproxy(self) - except: - print >> sys.stderr, \ - "Error in unproxying param '%s' of %s" % \ - (param, self.path()) - raise - setattr(self, param, value) - print '%s=%s' % (param, self._values[param].ini_str()) - - print # blank line between objects - - for child in child_names: - self._children[child].print_ini() - - # generate output file for 'dot' to display as a pretty graph. - # this code is currently broken. - def outputDot(self, dot): - label = "{%s|" % self.path - if isSimObject(self.realtype): - label += '%s|' % self.type - - if self.children: - # instantiate children in same order they were added for - # backward compatibility (else we can end up with cpu1 - # before cpu0). - for c in self.children: - dot.add_edge(pydot.Edge(self.path,c.path, style="bold")) - - simobjs = [] - for param in self.params: - try: - if param.value is None: - raise AttributeError, 'Parameter with no value' - - value = param.value - string = param.string(value) - except Exception, e: - msg = 'exception in %s:%s\n%s' % (self.name, param.name, e) - e.args = (msg, ) - raise - - if isSimObject(param.ptype) and string != "Null": - simobjs.append(string) - else: - label += '%s = %s\\n' % (param.name, string) - - for so in simobjs: - label += "|<%s> %s" % (so, so) - dot.add_edge(pydot.Edge("%s:%s" % (self.path, so), so, - tailport="w")) - label += '}' - dot.add_node(pydot.Node(self.path,shape="Mrecord",label=label)) - - # recursively dump out children - for c in self.children: - c.outputDot(dot) - -class ParamContext(SimObject): - pass - -##################################################################### -# -# Proxy object support. -# -##################################################################### - -class BaseProxy(object): - def __init__(self, search_self, search_up): - self._search_self = search_self - self._search_up = search_up - self._multiplier = None - - def __setattr__(self, attr, value): - if not attr.startswith('_'): - raise AttributeError, 'cannot set attribute on proxy object' - super(BaseProxy, self).__setattr__(attr, value) - - # support multiplying proxies by constants - def __mul__(self, other): - if not isinstance(other, (int, long, float)): - raise TypeError, "Proxy multiplier must be integer" - if self._multiplier == None: - self._multiplier = other - else: - # support chained multipliers - self._multiplier *= other - return self - - __rmul__ = __mul__ - - def _mulcheck(self, result): - if self._multiplier == None: - return result - return result * self._multiplier - - def unproxy(self, base): - obj = base - done = False - - if self._search_self: - result, done = self.find(obj) - - if self._search_up: - while not done: - try: obj = obj._parent - except: break - - result, done = self.find(obj) - - if not done: - raise AttributeError, "Can't resolve proxy '%s' from '%s'" % \ - (self.path(), base.path()) - - if isinstance(result, BaseProxy): - if result == self: - raise RuntimeError, "Cycle in unproxy" - result = result.unproxy(obj) - - return self._mulcheck(result) - - def getindex(obj, index): - if index == None: - return obj - try: - obj = obj[index] - except TypeError: - if index != 0: - raise - # if index is 0 and item is not subscriptable, just - # use item itself (so cpu[0] works on uniprocessors) - return obj - getindex = staticmethod(getindex) - - def set_param_desc(self, pdesc): - self._pdesc = pdesc - -class AttrProxy(BaseProxy): - def __init__(self, search_self, search_up, attr): - super(AttrProxy, self).__init__(search_self, search_up) - self._attr = attr - self._modifiers = [] - - def __getattr__(self, attr): - # python uses __bases__ internally for inheritance - if attr.startswith('_'): - return super(AttrProxy, self).__getattr__(self, attr) - if hasattr(self, '_pdesc'): - raise AttributeError, "Attribute reference on bound proxy" - self._modifiers.append(attr) - return self - - # support indexing on proxies (e.g., Self.cpu[0]) - def __getitem__(self, key): - if not isinstance(key, int): - raise TypeError, "Proxy object requires integer index" - self._modifiers.append(key) - return self - - def find(self, obj): - try: - val = getattr(obj, self._attr) - except: - return None, False - while isproxy(val): - val = val.unproxy(obj) - for m in self._modifiers: - if isinstance(m, str): - val = getattr(val, m) - elif isinstance(m, int): - val = val[m] - else: - assert("Item must be string or integer") - while isproxy(val): - val = val.unproxy(obj) - return val, True - - def path(self): - p = self._attr - for m in self._modifiers: - if isinstance(m, str): - p += '.%s' % m - elif isinstance(m, int): - p += '[%d]' % m - else: - assert("Item must be string or integer") - return p - -class AnyProxy(BaseProxy): - def find(self, obj): - return obj.find_any(self._pdesc.ptype) - - def path(self): - return 'any' - -def isproxy(obj): - if isinstance(obj, (BaseProxy, EthernetAddr)): - return True - elif isinstance(obj, (list, tuple)): - for v in obj: - if isproxy(v): - return True - return False - -class ProxyFactory(object): - def __init__(self, search_self, search_up): - self.search_self = search_self - self.search_up = search_up - - def __getattr__(self, attr): - if attr == 'any': - return AnyProxy(self.search_self, self.search_up) - else: - return AttrProxy(self.search_self, self.search_up, attr) - -# global objects for handling proxies -Parent = ProxyFactory(search_self = False, search_up = True) -Self = ProxyFactory(search_self = True, search_up = False) - -##################################################################### -# -# Parameter description classes -# -# The _params dictionary in each class maps parameter names to -# either a Param or a VectorParam object. These objects contain the -# parameter description string, the parameter type, and the default -# value (loaded from the PARAM section of the .odesc files). The -# _convert() method on these objects is used to force whatever value -# is assigned to the parameter to the appropriate type. -# -# Note that the default values are loaded into the class's attribute -# space when the parameter dictionary is initialized (in -# MetaConfigNode._setparams()); after that point they aren't used. -# -##################################################################### - -# Dummy base class to identify types that are legitimate for SimObject -# parameters. -class ParamValue(object): - - # default for printing to .ini file is regular string conversion. - # will be overridden in some cases - def ini_str(self): - return str(self) - - # allows us to blithely call unproxy() on things without checking - # if they're really proxies or not - def unproxy(self, base): - return self - -# Regular parameter description. -class ParamDesc(object): - def __init__(self, ptype_str, ptype, *args, **kwargs): - self.ptype_str = ptype_str - # remember ptype only if it is provided - if ptype != None: - self.ptype = ptype - - if args: - if len(args) == 1: - self.desc = args[0] - elif len(args) == 2: - self.default = args[0] - self.desc = args[1] - else: - raise TypeError, 'too many arguments' - - if kwargs.has_key('desc'): - assert(not hasattr(self, 'desc')) - self.desc = kwargs['desc'] - del kwargs['desc'] - - if kwargs.has_key('default'): - assert(not hasattr(self, 'default')) - self.default = kwargs['default'] - del kwargs['default'] - - if kwargs: - raise TypeError, 'extra unknown kwargs %s' % kwargs - - if not hasattr(self, 'desc'): - raise TypeError, 'desc attribute missing' - - def __getattr__(self, attr): - if attr == 'ptype': - try: - ptype = eval(self.ptype_str, m5.__dict__) - if not isinstance(ptype, type): - panic("Param qualifier is not a type: %s" % self.ptype) - self.ptype = ptype - return ptype - except NameError: - pass - raise AttributeError, "'%s' object has no attribute '%s'" % \ - (type(self).__name__, attr) - - def convert(self, value): - if isinstance(value, BaseProxy): - value.set_param_desc(self) - return value - if not hasattr(self, 'ptype') and isNullPointer(value): - # deferred evaluation of SimObject; continue to defer if - # we're just assigning a null pointer - return value - if isinstance(value, self.ptype): - return value - if isNullPointer(value) and issubclass(self.ptype, SimObject): - return value - return self.ptype(value) - -# Vector-valued parameter description. Just like ParamDesc, except -# that the value is a vector (list) of the specified type instead of a -# single value. - -class VectorParamValue(list): - def ini_str(self): - return ' '.join([v.ini_str() for v in self]) - - def unproxy(self, base): - return [v.unproxy(base) for v in self] - -class SimObjVector(VectorParamValue): - def print_ini(self): - for v in self: - v.print_ini() - -class VectorParamDesc(ParamDesc): - # Convert assigned value to appropriate type. If the RHS is not a - # list or tuple, it generates a single-element list. - def convert(self, value): - if isinstance(value, (list, tuple)): - # list: coerce each element into new list - tmp_list = [ ParamDesc.convert(self, v) for v in value ] - if isSimObjSequence(tmp_list): - return SimObjVector(tmp_list) - else: - return VectorParamValue(tmp_list) - else: - # singleton: leave it be (could coerce to a single-element - # list here, but for some historical reason we don't... - return ParamDesc.convert(self, value) - - -class ParamFactory(object): - def __init__(self, param_desc_class, ptype_str = None): - self.param_desc_class = param_desc_class - self.ptype_str = ptype_str - - def __getattr__(self, attr): - if self.ptype_str: - attr = self.ptype_str + '.' + attr - return ParamFactory(self.param_desc_class, attr) - - # E.g., Param.Int(5, "number of widgets") - def __call__(self, *args, **kwargs): - caller_frame = inspect.stack()[1][0] - ptype = None - try: - ptype = eval(self.ptype_str, - caller_frame.f_globals, caller_frame.f_locals) - if not isinstance(ptype, type): - raise TypeError, \ - "Param qualifier is not a type: %s" % ptype - except NameError: - # if name isn't defined yet, assume it's a SimObject, and - # try to resolve it later - pass - return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs) - -Param = ParamFactory(ParamDesc) -VectorParam = ParamFactory(VectorParamDesc) - -##################################################################### -# -# Parameter Types -# -# Though native Python types could be used to specify parameter types -# (the 'ptype' field of the Param and VectorParam classes), it's more -# flexible to define our own set of types. This gives us more control -# over how Python expressions are converted to values (via the -# __init__() constructor) and how these values are printed out (via -# the __str__() conversion method). Eventually we'll need these types -# to correspond to distinct C++ types as well. -# -##################################################################### - -# superclass for "numeric" parameter values, to emulate math -# operations in a type-safe way. e.g., a Latency times an int returns -# a new Latency object. -class NumericParamValue(ParamValue): - def __str__(self): - return str(self.value) - - def __float__(self): - return float(self.value) - - # hook for bounds checking - def _check(self): - return - - def __mul__(self, other): - newobj = self.__class__(self) - newobj.value *= other - newobj._check() - return newobj - - __rmul__ = __mul__ - - def __div__(self, other): - newobj = self.__class__(self) - newobj.value /= other - newobj._check() - return newobj - - def __sub__(self, other): - newobj = self.__class__(self) - newobj.value -= other - newobj._check() - return newobj - -class Range(ParamValue): - type = int # default; can be overridden in subclasses - def __init__(self, *args, **kwargs): - - def handle_kwargs(self, kwargs): - if 'end' in kwargs: - self.second = self.type(kwargs.pop('end')) - elif 'size' in kwargs: - self.second = self.first + self.type(kwargs.pop('size')) - 1 - else: - raise TypeError, "Either end or size must be specified" - - if len(args) == 0: - self.first = self.type(kwargs.pop('start')) - handle_kwargs(self, kwargs) - - elif len(args) == 1: - if kwargs: - self.first = self.type(args[0]) - handle_kwargs(self, kwargs) - elif isinstance(args[0], Range): - self.first = self.type(args[0].first) - self.second = self.type(args[0].second) - else: - self.first = self.type(0) - self.second = self.type(args[0]) - 1 - - elif len(args) == 2: - self.first = self.type(args[0]) - self.second = self.type(args[1]) - else: - raise TypeError, "Too many arguments specified" - - if kwargs: - raise TypeError, "too many keywords: %s" % kwargs.keys() - - def __str__(self): - return '%s:%s' % (self.first, self.second) - -# Metaclass for bounds-checked integer parameters. See CheckedInt. -class CheckedIntType(type): - def __init__(cls, name, bases, dict): - super(CheckedIntType, cls).__init__(name, bases, dict) - - # CheckedInt is an abstract base class, so we actually don't - # want to do any processing on it... the rest of this code is - # just for classes that derive from CheckedInt. - if name == 'CheckedInt': - return - - if not (hasattr(cls, 'min') and hasattr(cls, 'max')): - if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')): - panic("CheckedInt subclass %s must define either\n" \ - " 'min' and 'max' or 'size' and 'unsigned'\n" \ - % name); - if cls.unsigned: - cls.min = 0 - cls.max = 2 ** cls.size - 1 - else: - cls.min = -(2 ** (cls.size - 1)) - cls.max = (2 ** (cls.size - 1)) - 1 - -# Abstract superclass for bounds-checked integer parameters. This -# class is subclassed to generate parameter classes with specific -# bounds. Initialization of the min and max bounds is done in the -# metaclass CheckedIntType.__init__. -class CheckedInt(NumericParamValue): - __metaclass__ = CheckedIntType - - def _check(self): - if not self.min <= self.value <= self.max: - raise TypeError, 'Integer param out of bounds %d < %d < %d' % \ - (self.min, self.value, self.max) - - def __init__(self, value): - if isinstance(value, str): - self.value = toInteger(value) - elif isinstance(value, (int, long, float)): - self.value = long(value) - self._check() - -class Int(CheckedInt): size = 32; unsigned = False -class Unsigned(CheckedInt): size = 32; unsigned = True - -class Int8(CheckedInt): size = 8; unsigned = False -class UInt8(CheckedInt): size = 8; unsigned = True -class Int16(CheckedInt): size = 16; unsigned = False -class UInt16(CheckedInt): size = 16; unsigned = True -class Int32(CheckedInt): size = 32; unsigned = False -class UInt32(CheckedInt): size = 32; unsigned = True -class Int64(CheckedInt): size = 64; unsigned = False -class UInt64(CheckedInt): size = 64; unsigned = True - -class Counter(CheckedInt): size = 64; unsigned = True -class Tick(CheckedInt): size = 64; unsigned = True -class TcpPort(CheckedInt): size = 16; unsigned = True -class UdpPort(CheckedInt): size = 16; unsigned = True - -class Percent(CheckedInt): min = 0; max = 100 - -class Float(ParamValue, float): - pass - -class MemorySize(CheckedInt): - size = 64 - unsigned = True - def __init__(self, value): - if isinstance(value, MemorySize): - self.value = value.value - else: - self.value = toMemorySize(value) - self._check() - -class MemorySize32(CheckedInt): - size = 32 - unsigned = True - def __init__(self, value): - if isinstance(value, MemorySize): - self.value = value.value - else: - self.value = toMemorySize(value) - self._check() - -class Addr(CheckedInt): - size = 64 - unsigned = True - def __init__(self, value): - if isinstance(value, Addr): - self.value = value.value - else: - try: - self.value = toMemorySize(value) - except TypeError: - self.value = long(value) - self._check() - -class AddrRange(Range): - type = Addr - -# String-valued parameter. Just mixin the ParamValue class -# with the built-in str class. -class String(ParamValue,str): - pass - -# Boolean parameter type. Python doesn't let you subclass bool, since -# it doesn't want to let you create multiple instances of True and -# False. Thus this is a little more complicated than String. -class Bool(ParamValue): - def __init__(self, value): - try: - self.value = toBool(value) - except TypeError: - self.value = bool(value) - - def __str__(self): - return str(self.value) - - def ini_str(self): - if self.value: - return 'true' - return 'false' - -def IncEthernetAddr(addr, val = 1): - bytes = map(lambda x: int(x, 16), addr.split(':')) - bytes[5] += val - for i in (5, 4, 3, 2, 1): - val,rem = divmod(bytes[i], 256) - bytes[i] = rem - if val == 0: - break - bytes[i - 1] += val - assert(bytes[0] <= 255) - return ':'.join(map(lambda x: '%02x' % x, bytes)) - -class NextEthernetAddr(object): - addr = "00:90:00:00:00:01" - - def __init__(self, inc = 1): - self.value = NextEthernetAddr.addr - NextEthernetAddr.addr = IncEthernetAddr(NextEthernetAddr.addr, inc) - -class EthernetAddr(ParamValue): - def __init__(self, value): - if value == NextEthernetAddr: - self.value = value - return - - if not isinstance(value, str): - raise TypeError, "expected an ethernet address and didn't get one" - - bytes = value.split(':') - if len(bytes) != 6: - raise TypeError, 'invalid ethernet address %s' % value - - for byte in bytes: - if not 0 <= int(byte) <= 256: - raise TypeError, 'invalid ethernet address %s' % value - - self.value = value - - def unproxy(self, base): - if self.value == NextEthernetAddr: - self.addr = self.value().value - return self - - def __str__(self): - if self.value == NextEthernetAddr: - return self.addr - else: - return self.value - -# Special class for NULL pointers. Note the special check in -# make_param_value() above that lets these be assigned where a -# SimObject is required. -# only one copy of a particular node -class NullSimObject(object): - __metaclass__ = Singleton - - def __call__(cls): - return cls - - def _instantiate(self, parent = None, path = ''): - pass - - def ini_str(self): - return 'Null' - - def unproxy(self, base): - return self - - def set_path(self, parent, name): - pass - def __str__(self): - return 'Null' - -# The only instance you'll ever need... -Null = NULL = NullSimObject() - -# Enumerated types are a little more complex. The user specifies the -# type as Enum(foo) where foo is either a list or dictionary of -# alternatives (typically strings, but not necessarily so). (In the -# long run, the integer value of the parameter will be the list index -# or the corresponding dictionary value. For now, since we only check -# that the alternative is valid and then spit it into a .ini file, -# there's not much point in using the dictionary.) - -# What Enum() must do is generate a new type encapsulating the -# provided list/dictionary so that specific values of the parameter -# can be instances of that type. We define two hidden internal -# classes (_ListEnum and _DictEnum) to serve as base classes, then -# derive the new type from the appropriate base class on the fly. - - -# Metaclass for Enum types -class MetaEnum(type): - def __init__(cls, name, bases, init_dict): - if init_dict.has_key('map'): - if not isinstance(cls.map, dict): - raise TypeError, "Enum-derived class attribute 'map' " \ - "must be of type dict" - # build list of value strings from map - cls.vals = cls.map.keys() - cls.vals.sort() - elif init_dict.has_key('vals'): - if not isinstance(cls.vals, list): - raise TypeError, "Enum-derived class attribute 'vals' " \ - "must be of type list" - # build string->value map from vals sequence - cls.map = {} - for idx,val in enumerate(cls.vals): - cls.map[val] = idx - else: - raise TypeError, "Enum-derived class must define "\ - "attribute 'map' or 'vals'" - - super(MetaEnum, cls).__init__(name, bases, init_dict) - - def cpp_declare(cls): - s = 'enum %s {\n ' % cls.__name__ - s += ',\n '.join(['%s = %d' % (v,cls.map[v]) for v in cls.vals]) - s += '\n};\n' - return s - -# Base class for enum types. -class Enum(ParamValue): - __metaclass__ = MetaEnum - vals = [] - - def __init__(self, value): - if value not in self.map: - raise TypeError, "Enum param got bad value '%s' (not in %s)" \ - % (value, self.vals) - self.value = value - - def __str__(self): - return self.value - -ticks_per_sec = None - -# how big does a rounding error need to be before we warn about it? -frequency_tolerance = 0.001 # 0.1% - -# convert a floting-point # of ticks to integer, and warn if rounding -# discards too much precision -def tick_check(float_ticks): - if float_ticks == 0: - return 0 - int_ticks = int(round(float_ticks)) - err = (float_ticks - int_ticks) / float_ticks - if err > frequency_tolerance: - print >> sys.stderr, "Warning: rounding error > tolerance" - print >> sys.stderr, " %f rounded to %d" % (float_ticks, int_ticks) - #raise ValueError - return int_ticks - -def getLatency(value): - if isinstance(value, Latency) or isinstance(value, Clock): - return value.value - elif isinstance(value, Frequency) or isinstance(value, RootClock): - return 1 / value.value - elif isinstance(value, str): - try: - return toLatency(value) - except ValueError: - try: - return 1 / toFrequency(value) - except ValueError: - pass # fall through - raise ValueError, "Invalid Frequency/Latency value '%s'" % value - - -class Latency(NumericParamValue): - def __init__(self, value): - self.value = getLatency(value) - - def __getattr__(self, attr): - if attr in ('latency', 'period'): - return self - if attr == 'frequency': - return Frequency(self) - raise AttributeError, "Latency object has no attribute '%s'" % attr - - # convert latency to ticks - def ini_str(self): - return str(tick_check(self.value * ticks_per_sec)) - -class Frequency(NumericParamValue): - def __init__(self, value): - self.value = 1 / getLatency(value) - - def __getattr__(self, attr): - if attr == 'frequency': - return self - if attr in ('latency', 'period'): - return Latency(self) - raise AttributeError, "Frequency object has no attribute '%s'" % attr - - # convert frequency to ticks per period - def ini_str(self): - return self.period.ini_str() - -# Just like Frequency, except ini_str() is absolute # of ticks per sec (Hz). -# We can't inherit from Frequency because we don't want it to be directly -# assignable to a regular Frequency parameter. -class RootClock(ParamValue): - def __init__(self, value): - self.value = 1 / getLatency(value) - - def __getattr__(self, attr): - if attr == 'frequency': - return Frequency(self) - if attr in ('latency', 'period'): - return Latency(self) - raise AttributeError, "Frequency object has no attribute '%s'" % attr - - def ini_str(self): - return str(tick_check(self.value)) - -# A generic frequency and/or Latency value. Value is stored as a latency, -# but to avoid ambiguity this object does not support numeric ops (* or /). -# An explicit conversion to a Latency or Frequency must be made first. -class Clock(ParamValue): - def __init__(self, value): - self.value = getLatency(value) - - def __getattr__(self, attr): - if attr == 'frequency': - return Frequency(self) - if attr in ('latency', 'period'): - return Latency(self) - raise AttributeError, "Frequency object has no attribute '%s'" % attr - - def ini_str(self): - return self.period.ini_str() - -class NetworkBandwidth(float,ParamValue): - def __new__(cls, value): - val = toNetworkBandwidth(value) / 8.0 - return super(cls, NetworkBandwidth).__new__(cls, val) - - def __str__(self): - return str(self.val) - - def ini_str(self): - return '%f' % (ticks_per_sec / float(self)) - -class MemoryBandwidth(float,ParamValue): - def __new__(self, value): - val = toMemoryBandwidth(value) - return super(cls, MemoryBandwidth).__new__(cls, val) - - def __str__(self): - return str(self.val) - - def ini_str(self): - return '%f' % (ticks_per_sec / float(self)) - -# -# "Constants"... handy aliases for various values. -# - -# Some memory range specifications use this as a default upper bound. -MaxAddr = Addr.max -MaxTick = Tick.max -AllMemory = AddrRange(0, MaxAddr) - -##################################################################### - -# The final hook to generate .ini files. Called from configuration -# script once config is built. -def instantiate(root): - global ticks_per_sec - ticks_per_sec = float(root.clock.frequency) - root.print_ini() - noDot = True # temporary until we fix dot - if not noDot: - dot = pydot.Dot() - instance.outputDot(dot) - dot.orientation = "portrait" - dot.size = "8.5,11" - dot.ranksep="equally" - dot.rank="samerank" - dot.write("config.dot") - dot.write_ps("config.ps") - -# __all__ defines the list of symbols that get exported when -# 'from config import *' is invoked. Try to keep this reasonably -# short to avoid polluting other namespaces. -__all__ = ['SimObject', 'ParamContext', 'Param', 'VectorParam', - 'Parent', 'Self', - 'Enum', 'Bool', 'String', 'Float', - 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16', - 'Int32', 'UInt32', 'Int64', 'UInt64', - 'Counter', 'Addr', 'Tick', 'Percent', - 'TcpPort', 'UdpPort', 'EthernetAddr', - 'MemorySize', 'MemorySize32', - 'Latency', 'Frequency', 'RootClock', 'Clock', - 'NetworkBandwidth', 'MemoryBandwidth', - 'Range', 'AddrRange', 'MaxAddr', 'MaxTick', 'AllMemory', - 'Null', 'NULL', - 'NextEthernetAddr', 'instantiate'] - diff --git a/python/m5/convert.py b/python/m5/convert.py deleted file mode 100644 index 73181e985..000000000 --- a/python/m5/convert.py +++ /dev/null @@ -1,227 +0,0 @@ -# Copyright (c) 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. - -# metric prefixes -exa = 1.0e18 -peta = 1.0e15 -tera = 1.0e12 -giga = 1.0e9 -mega = 1.0e6 -kilo = 1.0e3 - -milli = 1.0e-3 -micro = 1.0e-6 -nano = 1.0e-9 -pico = 1.0e-12 -femto = 1.0e-15 -atto = 1.0e-18 - -# power of 2 prefixes -kibi = 1024 -mebi = kibi * 1024 -gibi = mebi * 1024 -tebi = gibi * 1024 -pebi = tebi * 1024 -exbi = pebi * 1024 - -# memory size configuration stuff -def toFloat(value): - if not isinstance(value, str): - raise TypeError, "wrong type '%s' should be str" % type(value) - - if value.endswith('Ei'): - return float(value[:-2]) * exbi - elif value.endswith('Pi'): - return float(value[:-2]) * pebi - elif value.endswith('Ti'): - return float(value[:-2]) * tebi - elif value.endswith('Gi'): - return float(value[:-2]) * gibi - elif value.endswith('Mi'): - return float(value[:-2]) * mebi - elif value.endswith('ki'): - return float(value[:-2]) * kibi - elif value.endswith('E'): - return float(value[:-1]) * exa - elif value.endswith('P'): - return float(value[:-1]) * peta - elif value.endswith('T'): - return float(value[:-1]) * tera - elif value.endswith('G'): - return float(value[:-1]) * giga - elif value.endswith('M'): - return float(value[:-1]) * mega - elif value.endswith('k'): - return float(value[:-1]) * kilo - elif value.endswith('m'): - return float(value[:-1]) * milli - elif value.endswith('u'): - return float(value[:-1]) * micro - elif value.endswith('n'): - return float(value[:-1]) * nano - elif value.endswith('p'): - return float(value[:-1]) * pico - elif value.endswith('f'): - return float(value[:-1]) * femto - else: - return float(value) - -def toInteger(value): - value = toFloat(value) - result = long(value) - if value != result: - raise ValueError, "cannot convert '%s' to integer" % value - - return result - -_bool_dict = { - 'true' : True, 't' : True, 'yes' : True, 'y' : True, '1' : True, - 'false' : False, 'f' : False, 'no' : False, 'n' : False, '0' : False - } - -def toBool(value): - if not isinstance(value, str): - raise TypeError, "wrong type '%s' should be str" % type(value) - - value = value.lower() - result = _bool_dict.get(value, None) - if result == None: - raise ValueError, "cannot convert '%s' to bool" % value - return result - -def toFrequency(value): - if not isinstance(value, str): - raise TypeError, "wrong type '%s' should be str" % type(value) - - if value.endswith('THz'): - return float(value[:-3]) * tera - elif value.endswith('GHz'): - return float(value[:-3]) * giga - elif value.endswith('MHz'): - return float(value[:-3]) * mega - elif value.endswith('kHz'): - return float(value[:-3]) * kilo - elif value.endswith('Hz'): - return float(value[:-2]) - - raise ValueError, "cannot convert '%s' to frequency" % value - -def toLatency(value): - if not isinstance(value, str): - raise TypeError, "wrong type '%s' should be str" % type(value) - - if value.endswith('ps'): - return float(value[:-2]) * pico - elif value.endswith('ns'): - return float(value[:-2]) * nano - elif value.endswith('us'): - return float(value[:-2]) * micro - elif value.endswith('ms'): - return float(value[:-2]) * milli - elif value.endswith('s'): - return float(value[:-1]) - - raise ValueError, "cannot convert '%s' to latency" % value - -def toClockPeriod(value): - """result is a clock period""" - - if not isinstance(value, str): - raise TypeError, "wrong type '%s' should be str" % type(value) - - try: - val = toFrequency(value) - if val != 0: - val = 1 / val - return val - except ValueError: - pass - - try: - val = toLatency(value) - return val - except ValueError: - pass - - raise ValueError, "cannot convert '%s' to clock period" % value - - -def toNetworkBandwidth(value): - if not isinstance(value, str): - raise TypeError, "wrong type '%s' should be str" % type(value) - - if value.endswith('Tbps'): - return float(value[:-4]) * tera - elif value.endswith('Gbps'): - return float(value[:-4]) * giga - elif value.endswith('Mbps'): - return float(value[:-4]) * mega - elif value.endswith('kbps'): - return float(value[:-4]) * kilo - elif value.endswith('bps'): - return float(value[:-3]) - else: - return float(value) - - raise ValueError, "cannot convert '%s' to network bandwidth" % value - -def toMemoryBandwidth(value): - if not isinstance(value, str): - raise TypeError, "wrong type '%s' should be str" % type(value) - - if value.endswith('PB/s'): - return float(value[:-4]) * pebi - elif value.endswith('TB/s'): - return float(value[:-4]) * tebi - elif value.endswith('GB/s'): - return float(value[:-4]) * gibi - elif value.endswith('MB/s'): - return float(value[:-4]) * mebi - elif value.endswith('kB/s'): - return float(value[:-4]) * kibi - elif value.endswith('B/s'): - return float(value[:-3]) - - raise ValueError, "cannot convert '%s' to memory bandwidth" % value - -def toMemorySize(value): - if not isinstance(value, str): - raise TypeError, "wrong type '%s' should be str" % type(value) - - if value.endswith('PB'): - return long(value[:-2]) * pebi - elif value.endswith('TB'): - return long(value[:-2]) * tebi - elif value.endswith('GB'): - return long(value[:-2]) * gibi - elif value.endswith('MB'): - return long(value[:-2]) * mebi - elif value.endswith('kB'): - return long(value[:-2]) * kibi - elif value.endswith('B'): - return long(value[:-1]) - - raise ValueError, "cannot convert '%s' to memory size" % value diff --git a/python/m5/multidict.py b/python/m5/multidict.py deleted file mode 100644 index fd40ebbbd..000000000 --- a/python/m5/multidict.py +++ /dev/null @@ -1,184 +0,0 @@ -# Copyright (c) 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. - -__all__ = [ 'multidict' ] - -class multidict(object): - __nodefault = object() - def __init__(self, parent = {}, **kwargs): - self.dict = dict(**kwargs) - self.parent = parent - self.deleted = {} - - def __str__(self): - return str(dict(self.items())) - - def __repr__(self): - return `dict(self.items())` - - def __contains__(self, key): - return self.dict.has_key(key) or self.parent.has_key(key) - - def __delitem__(self, key): - try: - del self.dict[key] - except KeyError, e: - if key in self.parent: - self.deleted[key] = True - else: - raise KeyError, e - - def __setitem__(self, key, value): - self.deleted.pop(key, False) - self.dict[key] = value - - def __getitem__(self, key): - try: - return self.dict[key] - except KeyError, e: - if not self.deleted.get(key, False) and key in self.parent: - return self.parent[key] - else: - raise KeyError, e - - def __len__(self): - return len(self.dict) + len(self.parent) - - def next(self): - for key,value in self.dict.items(): - yield key,value - - if self.parent: - for key,value in self.parent.next(): - if key not in self.dict and key not in self.deleted: - yield key,value - - def has_key(self, key): - return key in self - - def iteritems(self): - for item in self.next(): - yield item - - def items(self): - return [ item for item in self.next() ] - - def iterkeys(self): - for key,value in self.next(): - yield key - - def keys(self): - return [ key for key,value in self.next() ] - - def itervalues(self): - for key,value in self.next(): - yield value - - def values(self): - return [ value for key,value in self.next() ] - - def get(self, key, default=__nodefault): - try: - return self[key] - except KeyError, e: - if default != self.__nodefault: - return default - else: - raise KeyError, e - - def setdefault(self, key, default): - try: - return self[key] - except KeyError: - self.deleted.pop(key, False) - self.dict[key] = default - return default - - def _dump(self): - print 'multidict dump' - node = self - while isinstance(node, multidict): - print ' ', node.dict - node = node.parent - - def _dumpkey(self, key): - values = [] - node = self - while isinstance(node, multidict): - if key in node.dict: - values.append(node.dict[key]) - node = node.parent - print key, values - -if __name__ == '__main__': - test1 = multidict() - test2 = multidict(test1) - test3 = multidict(test2) - test4 = multidict(test3) - - test1['a'] = 'test1_a' - test1['b'] = 'test1_b' - test1['c'] = 'test1_c' - test1['d'] = 'test1_d' - test1['e'] = 'test1_e' - - test2['a'] = 'test2_a' - del test2['b'] - test2['c'] = 'test2_c' - del test1['a'] - - test2.setdefault('f', multidict) - - print 'test1>', test1.items() - print 'test2>', test2.items() - #print test1['a'] - print test1['b'] - print test1['c'] - print test1['d'] - print test1['e'] - - print test2['a'] - #print test2['b'] - print test2['c'] - print test2['d'] - print test2['e'] - - for key in test2.iterkeys(): - print key - - test2.get('g', 'foo') - #test2.get('b') - test2.get('b', 'bar') - test2.setdefault('b', 'blah') - print test1 - print test2 - print `test2` - - print len(test2) - - test3['a'] = [ 0, 1, 2, 3 ] - - print test4 diff --git a/python/m5/objects/AlphaConsole.py b/python/m5/objects/AlphaConsole.py deleted file mode 100644 index f8f034682..000000000 --- a/python/m5/objects/AlphaConsole.py +++ /dev/null @@ -1,9 +0,0 @@ -from m5 import * -from Device import PioDevice - -class AlphaConsole(PioDevice): - type = 'AlphaConsole' - cpu = Param.BaseCPU(Parent.any, "Processor") - disk = Param.SimpleDisk("Simple Disk") - sim_console = Param.SimConsole(Parent.any, "The Simulator Console") - system = Param.System(Parent.any, "system object") diff --git a/python/m5/objects/AlphaFullCPU.py b/python/m5/objects/AlphaFullCPU.py deleted file mode 100644 index d719bf783..000000000 --- a/python/m5/objects/AlphaFullCPU.py +++ /dev/null @@ -1,99 +0,0 @@ -from m5 import * -from BaseCPU import BaseCPU - -class DerivAlphaFullCPU(BaseCPU): - type = 'DerivAlphaFullCPU' - activity = Param.Unsigned("Initial count") - numThreads = Param.Unsigned("number of HW thread contexts") - - if not build_env['FULL_SYSTEM']: - mem = Param.FunctionalMemory(NULL, "memory") - - checker = Param.BaseCPU(NULL, "checker") - - cachePorts = Param.Unsigned("Cache Ports") - - decodeToFetchDelay = Param.Unsigned("Decode to fetch delay") - renameToFetchDelay = Param.Unsigned("Rename to fetch delay") - iewToFetchDelay = Param.Unsigned("Issue/Execute/Writeback to fetch " - "delay") - commitToFetchDelay = Param.Unsigned("Commit to fetch delay") - fetchWidth = Param.Unsigned("Fetch width") - - renameToDecodeDelay = Param.Unsigned("Rename to decode delay") - iewToDecodeDelay = Param.Unsigned("Issue/Execute/Writeback to decode " - "delay") - commitToDecodeDelay = Param.Unsigned("Commit to decode delay") - fetchToDecodeDelay = Param.Unsigned("Fetch to decode delay") - decodeWidth = Param.Unsigned("Decode width") - - iewToRenameDelay = Param.Unsigned("Issue/Execute/Writeback to rename " - "delay") - commitToRenameDelay = Param.Unsigned("Commit to rename delay") - decodeToRenameDelay = Param.Unsigned("Decode to rename delay") - renameWidth = Param.Unsigned("Rename width") - - commitToIEWDelay = Param.Unsigned("Commit to " - "Issue/Execute/Writeback delay") - renameToIEWDelay = Param.Unsigned("Rename to " - "Issue/Execute/Writeback delay") - issueToExecuteDelay = Param.Unsigned("Issue to execute delay (internal " - "to the IEW stage)") - issueWidth = Param.Unsigned("Issue width") - executeWidth = Param.Unsigned("Execute width") - executeIntWidth = Param.Unsigned("Integer execute width") - executeFloatWidth = Param.Unsigned("Floating point execute width") - executeBranchWidth = Param.Unsigned("Branch execute width") - executeMemoryWidth = Param.Unsigned("Memory execute width") - fuPool = Param.FUPool(NULL, "Functional Unit pool") - - iewToCommitDelay = Param.Unsigned("Issue/Execute/Writeback to commit " - "delay") - renameToROBDelay = Param.Unsigned("Rename to reorder buffer delay") - commitWidth = Param.Unsigned("Commit width") - squashWidth = Param.Unsigned("Squash width") - trapLatency = Param.Tick("Trap latency") - fetchTrapLatency = Param.Tick("Fetch trap latency") - - localPredictorSize = Param.Unsigned("Size of local predictor") - localCtrBits = Param.Unsigned("Bits per counter") - localHistoryTableSize = Param.Unsigned("Size of local history table") - localHistoryBits = Param.Unsigned("Bits for the local history") - globalPredictorSize = Param.Unsigned("Size of global predictor") - globalCtrBits = Param.Unsigned("Bits per counter") - globalHistoryBits = Param.Unsigned("Bits of history") - choicePredictorSize = Param.Unsigned("Size of choice predictor") - choiceCtrBits = Param.Unsigned("Bits of choice counters") - - BTBEntries = Param.Unsigned("Number of BTB entries") - BTBTagSize = Param.Unsigned("Size of the BTB tags, in bits") - - RASSize = Param.Unsigned("RAS size") - - LQEntries = Param.Unsigned("Number of load queue entries") - SQEntries = Param.Unsigned("Number of store queue entries") - LFSTSize = Param.Unsigned("Last fetched store table size") - SSITSize = Param.Unsigned("Store set ID table size") - - numRobs = Param.Unsigned("Number of Reorder Buffers"); - - numPhysIntRegs = Param.Unsigned("Number of physical integer registers") - numPhysFloatRegs = Param.Unsigned("Number of physical floating point " - "registers") - numIQEntries = Param.Unsigned("Number of instruction queue entries") - numROBEntries = Param.Unsigned("Number of reorder buffer entries") - - instShiftAmt = Param.Unsigned("Number of bits to shift instructions by") - - function_trace = Param.Bool(False, "Enable function trace") - function_trace_start = Param.Tick(0, "Cycle to start function trace") - - smtNumFetchingThreads = Param.Unsigned("SMT Number of Fetching Threads") - smtFetchPolicy = Param.String("SMT Fetch policy") - smtLSQPolicy = Param.String("SMT LSQ Sharing Policy") - smtLSQThreshold = Param.String("SMT LSQ Threshold Sharing Parameter") - smtIQPolicy = Param.String("SMT IQ Sharing Policy") - smtIQThreshold = Param.String("SMT IQ Threshold Sharing Parameter") - smtROBPolicy = Param.String("SMT ROB Sharing Policy") - smtROBThreshold = Param.String("SMT ROB Threshold Sharing Parameter") - smtCommitPolicy = Param.String("SMT Commit Policy") diff --git a/python/m5/objects/AlphaTLB.py b/python/m5/objects/AlphaTLB.py deleted file mode 100644 index 5edf8e13d..000000000 --- a/python/m5/objects/AlphaTLB.py +++ /dev/null @@ -1,13 +0,0 @@ -from m5 import * -class AlphaTLB(SimObject): - type = 'AlphaTLB' - abstract = True - size = Param.Int("TLB size") - -class AlphaDTB(AlphaTLB): - type = 'AlphaDTB' - size = 64 - -class AlphaITB(AlphaTLB): - type = 'AlphaITB' - size = 48 diff --git a/python/m5/objects/BadDevice.py b/python/m5/objects/BadDevice.py deleted file mode 100644 index 3fba4637d..000000000 --- a/python/m5/objects/BadDevice.py +++ /dev/null @@ -1,6 +0,0 @@ -from m5 import * -from Device import PioDevice - -class BadDevice(PioDevice): - type = 'BadDevice' - devicename = Param.String("Name of device to error on") diff --git a/python/m5/objects/BaseCPU.py b/python/m5/objects/BaseCPU.py deleted file mode 100644 index a90203729..000000000 --- a/python/m5/objects/BaseCPU.py +++ /dev/null @@ -1,29 +0,0 @@ -from m5 import * -class BaseCPU(SimObject): - type = 'BaseCPU' - abstract = True - icache = Param.BaseMem(NULL, "L1 instruction cache object") - dcache = Param.BaseMem(NULL, "L1 data cache object") - - if build_env['FULL_SYSTEM']: - dtb = Param.AlphaDTB("Data TLB") - itb = Param.AlphaITB("Instruction TLB") - mem = Param.FunctionalMemory("memory") - system = Param.System(Parent.any, "system object") - cpu_id = Param.Int(-1, "CPU identifier") - else: - workload = VectorParam.Process("processes to run") - - 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") - - defer_registration = Param.Bool(False, - "defer registration with system (for sampling)") - - clock = Param.Clock(Parent.clock, "clock speed") diff --git a/python/m5/objects/BaseCache.py b/python/m5/objects/BaseCache.py deleted file mode 100644 index 79d21572a..000000000 --- a/python/m5/objects/BaseCache.py +++ /dev/null @@ -1,65 +0,0 @@ -from m5 import * -from BaseMem import BaseMem - -class Prefetch(Enum): vals = ['none', 'tagged', 'stride', 'ghb'] - -class BaseCache(BaseMem): - type = 'BaseCache' - adaptive_compression = Param.Bool(False, - "Use an adaptive compression scheme") - assoc = Param.Int("associativity") - block_size = Param.Int("block size in bytes") - compressed_bus = Param.Bool(False, - "This cache connects to a compressed memory") - compression_latency = Param.Latency('0ns', - "Latency in cycles of compression algorithm") - do_copy = Param.Bool(False, "perform fast copies in the cache") - hash_delay = Param.Int(1, "time in cycles of hash access") - in_bus = Param.Bus(NULL, "incoming bus object") - lifo = Param.Bool(False, - "whether this NIC partition should use LIFO repl. policy") - max_miss_count = Param.Counter(0, - "number of misses to handle before calling exit") - mem_trace = Param.MemTraceWriter(NULL, - "memory trace writer to record accesses") - mshrs = Param.Int("number of MSHRs (max outstanding requests)") - out_bus = Param.Bus("outgoing bus object") - prioritizeRequests = Param.Bool(False, - "always service demand misses first") - protocol = Param.CoherenceProtocol(NULL, "coherence protocol to use") - repl = Param.Repl(NULL, "replacement policy") - size = Param.MemorySize("capacity in bytes") - split = Param.Bool(False, "whether or not this cache is split") - split_size = Param.Int(0, - "How many ways of the cache belong to CPU/LRU partition") - store_compressed = Param.Bool(False, - "Store compressed data in the cache") - subblock_size = Param.Int(0, - "Size of subblock in IIC used for compression") - tgts_per_mshr = Param.Int("max number of accesses per MSHR") - trace_addr = Param.Addr(0, "address to trace") - two_queue = Param.Bool(False, - "whether the lifo should have two queue replacement") - write_buffers = Param.Int(8, "number of write buffers") - prefetch_miss = Param.Bool(False, - "wheter you are using the hardware prefetcher from Miss stream") - prefetch_access = Param.Bool(False, - "wheter you are using the hardware prefetcher from Access stream") - prefetcher_size = Param.Int(100, - "Number of entries in the harware prefetch queue") - prefetch_past_page = Param.Bool(False, - "Allow prefetches to cross virtual page boundaries") - prefetch_serial_squash = Param.Bool(False, - "Squash prefetches with a later time on a subsequent miss") - prefetch_degree = Param.Int(1, - "Degree of the prefetch depth") - prefetch_latency = Param.Tick(10, - "Latency of the prefetcher") - prefetch_policy = Param.Prefetch('none', - "Type of prefetcher to use") - prefetch_cache_check_push = Param.Bool(True, - "Check if in cash on push or pop of prefetch queue") - prefetch_use_cpu_id = Param.Bool(True, - "Use the CPU ID to seperate calculations of prefetches") - prefetch_data_accesses_only = Param.Bool(False, - "Only prefetch on data not on instruction accesses") diff --git a/python/m5/objects/Bus.py b/python/m5/objects/Bus.py deleted file mode 100644 index 26509d7d2..000000000 --- a/python/m5/objects/Bus.py +++ /dev/null @@ -1,7 +0,0 @@ -from m5 import * -from BaseHier import BaseHier - -class Bus(BaseHier): - type = 'Bus' - clock = Param.Clock("bus frequency") - width = Param.Int("bus width in bytes") diff --git a/python/m5/objects/CoherenceProtocol.py b/python/m5/objects/CoherenceProtocol.py deleted file mode 100644 index 7013000d6..000000000 --- a/python/m5/objects/CoherenceProtocol.py +++ /dev/null @@ -1,7 +0,0 @@ -from m5 import * -class Coherence(Enum): vals = ['uni', 'msi', 'mesi', 'mosi', 'moesi'] - -class CoherenceProtocol(SimObject): - type = 'CoherenceProtocol' - do_upgrades = Param.Bool(True, "use upgrade transactions?") - protocol = Param.Coherence("name of coherence protocol") diff --git a/python/m5/objects/Device.py b/python/m5/objects/Device.py deleted file mode 100644 index d7ca014a9..000000000 --- a/python/m5/objects/Device.py +++ /dev/null @@ -1,35 +0,0 @@ -from m5 import * -from FunctionalMemory import FunctionalMemory - -# This device exists only because there are some devices that I don't -# want to have a Platform parameter because it would cause a cycle in -# the C++ that cannot be easily solved. -# -# The real solution to this problem is to pass the ParamXXX structure -# to the constructor, but with the express condition that SimObject -# parameter values are not to be available at construction time. If -# some further configuration must be done, it must be done during the -# initialization phase at which point all SimObject pointers will be -# valid. -class FooPioDevice(FunctionalMemory): - type = 'PioDevice' - abstract = True - addr = Param.Addr("Device Address") - mmu = Param.MemoryController(Parent.any, "Memory Controller") - pio_bus = Param.Bus(NULL, "Bus to attach to for PIO") - pio_latency = Param.Tick(1, "Programmed IO latency in bus cycles") - -class FooDmaDevice(FooPioDevice): - type = 'DmaDevice' - abstract = True - dma_bus = Param.Bus(Self.pio_bus, "Bus to attach to for DMA") - -class PioDevice(FooPioDevice): - type = 'PioDevice' - abstract = True - platform = Param.Platform(Parent.any, "Platform") - -class DmaDevice(PioDevice): - type = 'DmaDevice' - abstract = True - dma_bus = Param.Bus(Self.pio_bus, "Bus to attach to for DMA") diff --git a/python/m5/objects/DiskImage.py b/python/m5/objects/DiskImage.py deleted file mode 100644 index 0d55e9329..000000000 --- a/python/m5/objects/DiskImage.py +++ /dev/null @@ -1,15 +0,0 @@ -from m5 import * -class DiskImage(SimObject): - type = 'DiskImage' - abstract = True - image_file = Param.String("disk image file") - read_only = Param.Bool(False, "read only image") - -class RawDiskImage(DiskImage): - type = 'RawDiskImage' - -class CowDiskImage(DiskImage): - type = 'CowDiskImage' - child = Param.DiskImage("child image") - table_size = Param.Int(65536, "initial table size") - image_file = '' diff --git a/python/m5/objects/Ethernet.py b/python/m5/objects/Ethernet.py deleted file mode 100644 index 68b21b404..000000000 --- a/python/m5/objects/Ethernet.py +++ /dev/null @@ -1,119 +0,0 @@ -from m5 import * -from Device import DmaDevice -from Pci import PciDevice - -class EtherInt(SimObject): - type = 'EtherInt' - abstract = True - peer = Param.EtherInt(NULL, "peer interface") - -class EtherLink(SimObject): - type = 'EtherLink' - int1 = Param.EtherInt("interface 1") - int2 = Param.EtherInt("interface 2") - delay = Param.Latency('0us', "packet transmit delay") - delay_var = Param.Latency('0ns', "packet transmit delay variability") - speed = Param.NetworkBandwidth('1Gbps', "link speed") - dump = Param.EtherDump(NULL, "dump object") - -class EtherBus(SimObject): - type = 'EtherBus' - loopback = Param.Bool(True, "send packet back to the sending interface") - dump = Param.EtherDump(NULL, "dump object") - speed = Param.NetworkBandwidth('100Mbps', "bus speed in bits per second") - -class EtherTap(EtherInt): - type = 'EtherTap' - bufsz = Param.Int(10000, "tap buffer size") - dump = Param.EtherDump(NULL, "dump object") - port = Param.UInt16(3500, "tap port") - -class EtherDump(SimObject): - type = 'EtherDump' - file = Param.String("dump file") - maxlen = Param.Int(96, "max portion of packet data to dump") - -if build_env['ALPHA_TLASER']: - - class EtherDev(DmaDevice): - type = 'EtherDev' - hardware_address = Param.EthernetAddr(NextEthernetAddr, - "Ethernet Hardware Address") - - dma_data_free = Param.Bool(False, "DMA of Data is free") - dma_desc_free = Param.Bool(False, "DMA of Descriptors is free") - dma_read_delay = Param.Latency('0us', "fixed delay for dma reads") - dma_read_factor = Param.Latency('0us', "multiplier for dma reads") - dma_write_delay = Param.Latency('0us', "fixed delay for dma writes") - dma_write_factor = Param.Latency('0us', "multiplier for dma writes") - dma_no_allocate = Param.Bool(True, "Should we allocate cache on read") - - rx_filter = Param.Bool(True, "Enable Receive Filter") - rx_delay = Param.Latency('1us', "Receive Delay") - tx_delay = Param.Latency('1us', "Transmit Delay") - - intr_delay = Param.Latency('0us', "Interrupt Delay") - payload_bus = Param.Bus(NULL, "The IO Bus to attach to for payload") - physmem = Param.PhysicalMemory(Parent.any, "Physical Memory") - tlaser = Param.Turbolaser(Parent.any, "Turbolaser") - - class EtherDevInt(EtherInt): - type = 'EtherDevInt' - device = Param.EtherDev("Ethernet device of this interface") - -class EtherDevBase(PciDevice): - hardware_address = Param.EthernetAddr(NextEthernetAddr, - "Ethernet Hardware Address") - - clock = Param.Clock('0ns', "State machine processor frequency") - - physmem = Param.PhysicalMemory(Parent.any, "Physical Memory") - - hier = Param.HierParams(Parent.any, "Hierarchy global variables") - payload_bus = Param.Bus(NULL, "The IO Bus to attach to for payload") - dma_read_delay = Param.Latency('0us', "fixed delay for dma reads") - dma_read_factor = Param.Latency('0us', "multiplier for dma reads") - dma_write_delay = Param.Latency('0us', "fixed delay for dma writes") - dma_write_factor = Param.Latency('0us', "multiplier for dma writes") - dma_no_allocate = Param.Bool(True, "Should we allocate cache on read") - - rx_delay = Param.Latency('1us', "Receive Delay") - tx_delay = Param.Latency('1us', "Transmit Delay") - rx_fifo_size = Param.MemorySize('512kB', "max size of rx fifo") - tx_fifo_size = Param.MemorySize('512kB', "max size of tx fifo") - - rx_filter = Param.Bool(True, "Enable Receive Filter") - intr_delay = Param.Latency('10us', "Interrupt propagation delay") - rx_thread = Param.Bool(False, "dedicated kernel thread for transmit") - tx_thread = Param.Bool(False, "dedicated kernel threads for receive") - rss = Param.Bool(False, "Receive Side Scaling") - -class NSGigE(EtherDevBase): - type = 'NSGigE' - - dma_data_free = Param.Bool(False, "DMA of Data is free") - dma_desc_free = Param.Bool(False, "DMA of Descriptors is free") - - -class NSGigEInt(EtherInt): - type = 'NSGigEInt' - device = Param.NSGigE("Ethernet device of this interface") - -class Sinic(EtherDevBase): - type = 'Sinic' - - rx_max_copy = Param.MemorySize('1514B', "rx max copy") - tx_max_copy = Param.MemorySize('16kB', "tx max copy") - rx_max_intr = Param.UInt32(10, "max rx packets per interrupt") - rx_fifo_threshold = Param.MemorySize('384kB', "rx fifo high threshold") - rx_fifo_low_mark = Param.MemorySize('128kB', "rx fifo low threshold") - tx_fifo_high_mark = Param.MemorySize('384kB', "tx fifo high threshold") - tx_fifo_threshold = Param.MemorySize('128kB', "tx fifo low threshold") - virtual_count = Param.UInt32(1, "Virtualized SINIC") - zero_copy = Param.Bool(False, "Zero copy receive") - delay_copy = Param.Bool(False, "Delayed copy transmit") - virtual_addr = Param.Bool(False, "Virtual addressing") - -class SinicInt(EtherInt): - type = 'SinicInt' - device = Param.Sinic("Ethernet device of this interface") diff --git a/python/m5/objects/FUPool.py b/python/m5/objects/FUPool.py deleted file mode 100644 index 5eecfd12f..000000000 --- a/python/m5/objects/FUPool.py +++ /dev/null @@ -1,8 +0,0 @@ -from m5 import * -from FullCPU import OpType -from FullCPU import OpDesc -from FullCPU import FUDesc - -class FUPool(SimObject): - type = 'FUPool' - FUList = VectorParam.FUDesc("list of FU's for this pool") diff --git a/python/m5/objects/Ide.py b/python/m5/objects/Ide.py deleted file mode 100644 index 6855ec653..000000000 --- a/python/m5/objects/Ide.py +++ /dev/null @@ -1,15 +0,0 @@ -from m5 import * -from Pci import PciDevice - -class IdeID(Enum): vals = ['master', 'slave'] - -class IdeDisk(SimObject): - type = 'IdeDisk' - delay = Param.Latency('1us', "Fixed disk delay in microseconds") - driveID = Param.IdeID('master', "Drive ID") - image = Param.DiskImage("Disk image") - physmem = Param.PhysicalMemory(Parent.any, "Physical memory") - -class IdeController(PciDevice): - type = 'IdeController' - disks = VectorParam.IdeDisk("IDE disks attached to this controller") diff --git a/python/m5/objects/IntrControl.py b/python/m5/objects/IntrControl.py deleted file mode 100644 index 66c82c182..000000000 --- a/python/m5/objects/IntrControl.py +++ /dev/null @@ -1,4 +0,0 @@ -from m5 import * -class IntrControl(SimObject): - type = 'IntrControl' - cpu = Param.BaseCPU(Parent.any, "the cpu") diff --git a/python/m5/objects/MemTest.py b/python/m5/objects/MemTest.py deleted file mode 100644 index 34299faf0..000000000 --- a/python/m5/objects/MemTest.py +++ /dev/null @@ -1,19 +0,0 @@ -from m5 import * -class MemTest(SimObject): - type = 'MemTest' - cache = Param.BaseCache("L1 cache") - check_mem = Param.FunctionalMemory("check memory") - main_mem = Param.FunctionalMemory("hierarchical memory") - max_loads = Param.Counter("number of loads to execute") - memory_size = Param.Int(65536, "memory size") - percent_copies = Param.Percent(0, "target copy percentage") - percent_dest_unaligned = Param.Percent(50, - "percent of copy dest address that are unaligned") - percent_reads = Param.Percent(65, "target read percentage") - percent_source_unaligned = Param.Percent(50, - "percent of copy source address that are unaligned") - percent_uncacheable = Param.Percent(10, - "target uncacheable percentage") - progress_interval = Param.Counter(1000000, - "progress report interval (in accesses)") - trace_addr = Param.Addr(0, "address to trace") diff --git a/python/m5/objects/OzoneCPU.py b/python/m5/objects/OzoneCPU.py deleted file mode 100644 index 3fca61e28..000000000 --- a/python/m5/objects/OzoneCPU.py +++ /dev/null @@ -1,89 +0,0 @@ -from m5 import * -from BaseCPU import BaseCPU - -class DerivOzoneCPU(BaseCPU): - type = 'DerivOzoneCPU' - - numThreads = Param.Unsigned("number of HW thread contexts") - - if not build_env['FULL_SYSTEM']: - mem = Param.FunctionalMemory(NULL, "memory") - - checker = Param.BaseCPU("Checker CPU") - - width = Param.Unsigned("Width") - frontEndWidth = Param.Unsigned("Front end width") - backEndWidth = Param.Unsigned("Back end width") - backEndSquashLatency = Param.Unsigned("Back end squash latency") - backEndLatency = Param.Unsigned("Back end latency") - maxInstBufferSize = Param.Unsigned("Maximum instruction buffer size") - maxOutstandingMemOps = Param.Unsigned("Maximum number of outstanding memory operations") - decodeToFetchDelay = Param.Unsigned("Decode to fetch delay") - renameToFetchDelay = Param.Unsigned("Rename to fetch delay") - iewToFetchDelay = Param.Unsigned("Issue/Execute/Writeback to fetch " - "delay") - commitToFetchDelay = Param.Unsigned("Commit to fetch delay") - fetchWidth = Param.Unsigned("Fetch width") - - renameToDecodeDelay = Param.Unsigned("Rename to decode delay") - iewToDecodeDelay = Param.Unsigned("Issue/Execute/Writeback to decode " - "delay") - commitToDecodeDelay = Param.Unsigned("Commit to decode delay") - fetchToDecodeDelay = Param.Unsigned("Fetch to decode delay") - decodeWidth = Param.Unsigned("Decode width") - - iewToRenameDelay = Param.Unsigned("Issue/Execute/Writeback to rename " - "delay") - commitToRenameDelay = Param.Unsigned("Commit to rename delay") - decodeToRenameDelay = Param.Unsigned("Decode to rename delay") - renameWidth = Param.Unsigned("Rename width") - - commitToIEWDelay = Param.Unsigned("Commit to " - "Issue/Execute/Writeback delay") - renameToIEWDelay = Param.Unsigned("Rename to " - "Issue/Execute/Writeback delay") - issueToExecuteDelay = Param.Unsigned("Issue to execute delay (internal " - "to the IEW stage)") - issueWidth = Param.Unsigned("Issue width") - executeWidth = Param.Unsigned("Execute width") - executeIntWidth = Param.Unsigned("Integer execute width") - executeFloatWidth = Param.Unsigned("Floating point execute width") - executeBranchWidth = Param.Unsigned("Branch execute width") - executeMemoryWidth = Param.Unsigned("Memory execute width") - - iewToCommitDelay = Param.Unsigned("Issue/Execute/Writeback to commit " - "delay") - renameToROBDelay = Param.Unsigned("Rename to reorder buffer delay") - commitWidth = Param.Unsigned("Commit width") - squashWidth = Param.Unsigned("Squash width") - - localPredictorSize = Param.Unsigned("Size of local predictor") - localCtrBits = Param.Unsigned("Bits per counter") - localHistoryTableSize = Param.Unsigned("Size of local history table") - localHistoryBits = Param.Unsigned("Bits for the local history") - globalPredictorSize = Param.Unsigned("Size of global predictor") - globalCtrBits = Param.Unsigned("Bits per counter") - globalHistoryBits = Param.Unsigned("Bits of history") - choicePredictorSize = Param.Unsigned("Size of choice predictor") - choiceCtrBits = Param.Unsigned("Bits of choice counters") - - BTBEntries = Param.Unsigned("Number of BTB entries") - BTBTagSize = Param.Unsigned("Size of the BTB tags, in bits") - - RASSize = Param.Unsigned("RAS size") - - LQEntries = Param.Unsigned("Number of load queue entries") - SQEntries = Param.Unsigned("Number of store queue entries") - LFSTSize = Param.Unsigned("Last fetched store table size") - SSITSize = Param.Unsigned("Store set ID table size") - - numPhysIntRegs = Param.Unsigned("Number of physical integer registers") - numPhysFloatRegs = Param.Unsigned("Number of physical floating point " - "registers") - numIQEntries = Param.Unsigned("Number of instruction queue entries") - numROBEntries = Param.Unsigned("Number of reorder buffer entries") - - instShiftAmt = Param.Unsigned("Number of bits to shift instructions by") - - function_trace = Param.Bool(False, "Enable function trace") - function_trace_start = Param.Tick(0, "Cycle to start function trace") diff --git a/python/m5/objects/Pci.py b/python/m5/objects/Pci.py deleted file mode 100644 index 4124d0b92..000000000 --- a/python/m5/objects/Pci.py +++ /dev/null @@ -1,55 +0,0 @@ -from m5 import * -from Device import FooPioDevice, DmaDevice - -class PciConfigData(SimObject): - type = 'PciConfigData' - VendorID = Param.UInt16("Vendor ID") - DeviceID = Param.UInt16("Device ID") - Command = Param.UInt16(0, "Command") - Status = Param.UInt16(0, "Status") - Revision = Param.UInt8(0, "Device") - ProgIF = Param.UInt8(0, "Programming Interface") - SubClassCode = Param.UInt8(0, "Sub-Class Code") - ClassCode = Param.UInt8(0, "Class Code") - CacheLineSize = Param.UInt8(0, "System Cacheline Size") - LatencyTimer = Param.UInt8(0, "PCI Latency Timer") - HeaderType = Param.UInt8(0, "PCI Header Type") - BIST = Param.UInt8(0, "Built In Self Test") - - BAR0 = Param.UInt32(0x00, "Base Address Register 0") - BAR1 = Param.UInt32(0x00, "Base Address Register 1") - BAR2 = Param.UInt32(0x00, "Base Address Register 2") - BAR3 = Param.UInt32(0x00, "Base Address Register 3") - BAR4 = Param.UInt32(0x00, "Base Address Register 4") - BAR5 = Param.UInt32(0x00, "Base Address Register 5") - BAR0Size = Param.MemorySize32('0B', "Base Address Register 0 Size") - BAR1Size = Param.MemorySize32('0B', "Base Address Register 1 Size") - BAR2Size = Param.MemorySize32('0B', "Base Address Register 2 Size") - BAR3Size = Param.MemorySize32('0B', "Base Address Register 3 Size") - BAR4Size = Param.MemorySize32('0B', "Base Address Register 4 Size") - BAR5Size = Param.MemorySize32('0B', "Base Address Register 5 Size") - - CardbusCIS = Param.UInt32(0x00, "Cardbus Card Information Structure") - SubsystemID = Param.UInt16(0x00, "Subsystem ID") - SubsystemVendorID = Param.UInt16(0x00, "Subsystem Vendor ID") - ExpansionROM = Param.UInt32(0x00, "Expansion ROM Base Address") - InterruptLine = Param.UInt8(0x00, "Interrupt Line") - InterruptPin = Param.UInt8(0x00, "Interrupt Pin") - MaximumLatency = Param.UInt8(0x00, "Maximum Latency") - MinimumGrant = Param.UInt8(0x00, "Minimum Grant") - -class PciConfigAll(FooPioDevice): - type = 'PciConfigAll' - -class PciDevice(DmaDevice): - type = 'PciDevice' - abstract = True - addr = 0xffffffffL - pci_bus = Param.Int("PCI bus") - pci_dev = Param.Int("PCI device number") - pci_func = Param.Int("PCI function code") - configdata = Param.PciConfigData(Parent.any, "PCI Config data") - configspace = Param.PciConfigAll(Parent.any, "PCI Configspace") - -class PciFake(PciDevice): - type = 'PciFake' diff --git a/python/m5/objects/PhysicalMemory.py b/python/m5/objects/PhysicalMemory.py deleted file mode 100644 index f50937ee6..000000000 --- a/python/m5/objects/PhysicalMemory.py +++ /dev/null @@ -1,8 +0,0 @@ -from m5 import * -from FunctionalMemory import FunctionalMemory - -class PhysicalMemory(FunctionalMemory): - type = 'PhysicalMemory' - range = Param.AddrRange("Device Address") - file = Param.String('', "memory mapped file") - mmu = Param.MemoryController(Parent.any, "Memory Controller") diff --git a/python/m5/objects/Platform.py b/python/m5/objects/Platform.py deleted file mode 100644 index 4da0ffab4..000000000 --- a/python/m5/objects/Platform.py +++ /dev/null @@ -1,5 +0,0 @@ -from m5 import * -class Platform(SimObject): - type = 'Platform' - abstract = True - intrctrl = Param.IntrControl(Parent.any, "interrupt controller") diff --git a/python/m5/objects/Process.py b/python/m5/objects/Process.py deleted file mode 100644 index b4ccc1bec..000000000 --- a/python/m5/objects/Process.py +++ /dev/null @@ -1,17 +0,0 @@ -from m5 import * -class Process(SimObject): - type = 'Process' - abstract = True - output = Param.String('cout', 'filename for stdout/stderr') - -class LiveProcess(Process): - type = 'LiveProcess' - executable = Param.String('', "executable (overrides cmd[0] if set)") - cmd = VectorParam.String("command line (executable plus arguments)") - env = VectorParam.String('', "environment settings") - input = Param.String('cin', "filename for stdin") - -class EioProcess(Process): - type = 'EioProcess' - chkpt = Param.String('', "EIO checkpoint file name (optional)") - file = Param.String("EIO trace file name") diff --git a/python/m5/objects/Repl.py b/python/m5/objects/Repl.py deleted file mode 100644 index afd256082..000000000 --- a/python/m5/objects/Repl.py +++ /dev/null @@ -1,10 +0,0 @@ -from m5 import * -class Repl(SimObject): - type = 'Repl' - abstract = True - -class GenRepl(Repl): - type = 'GenRepl' - fresh_res = Param.Int("associativity") - num_pools = Param.Int("capacity in bytes") - pool_res = Param.Int("block size in bytes") diff --git a/python/m5/objects/Root.py b/python/m5/objects/Root.py deleted file mode 100644 index 23b13fc67..000000000 --- a/python/m5/objects/Root.py +++ /dev/null @@ -1,25 +0,0 @@ -from m5 import * -from HierParams import HierParams -from Serialize import Serialize -from Statistics import Statistics -from Trace import Trace -from ExeTrace import ExecutionTrace - -class Root(SimObject): - type = 'Root' - clock = Param.RootClock('200MHz', "tick frequency") - max_tick = Param.Tick('0', "maximum simulation ticks (0 = infinite)") - progress_interval = Param.Tick('0', - "print a progress message every n ticks (0 = never)") - output_file = Param.String('cout', "file to dump simulator output to") - checkpoint = Param.String('', "checkpoint file to load") -# hier = Param.HierParams(HierParams(do_data = False, do_events = True), -# "shared memory hierarchy parameters") -# stats = Param.Statistics(Statistics(), "statistics object") -# trace = Param.Trace(Trace(), "trace object") -# serialize = Param.Serialize(Serialize(), "checkpoint generation options") - hier = HierParams(do_data = False, do_events = True) - stats = Statistics() - trace = Trace() - exetrace = ExecutionTrace() - serialize = Serialize() diff --git a/python/m5/objects/SimConsole.py b/python/m5/objects/SimConsole.py deleted file mode 100644 index df3061908..000000000 --- a/python/m5/objects/SimConsole.py +++ /dev/null @@ -1,12 +0,0 @@ -from m5 import * -class ConsoleListener(SimObject): - type = 'ConsoleListener' - port = Param.TcpPort(3456, "listen port") - -class SimConsole(SimObject): - type = 'SimConsole' - append_name = Param.Bool(True, "append name() to filename") - intr_control = Param.IntrControl(Parent.any, "interrupt controller") - listener = Param.ConsoleListener("console listener") - number = Param.Int(0, "console number") - output = Param.String('console', "file to dump output to") diff --git a/python/m5/objects/SimpleDisk.py b/python/m5/objects/SimpleDisk.py deleted file mode 100644 index 48448e6e5..000000000 --- a/python/m5/objects/SimpleDisk.py +++ /dev/null @@ -1,5 +0,0 @@ -from m5 import * -class SimpleDisk(SimObject): - type = 'SimpleDisk' - disk = Param.DiskImage("Disk Image") - physmem = Param.PhysicalMemory(Parent.any, "Physical Memory") diff --git a/python/m5/objects/SimpleOzoneCPU.py b/python/m5/objects/SimpleOzoneCPU.py deleted file mode 100644 index 0d6403383..000000000 --- a/python/m5/objects/SimpleOzoneCPU.py +++ /dev/null @@ -1,86 +0,0 @@ -from m5 import * -from BaseCPU import BaseCPU - -class SimpleOzoneCPU(BaseCPU): - type = 'SimpleOzoneCPU' - - numThreads = Param.Unsigned("number of HW thread contexts") - - if not build_env['FULL_SYSTEM']: - mem = Param.FunctionalMemory(NULL, "memory") - - width = Param.Unsigned("Width") - frontEndWidth = Param.Unsigned("Front end width") - backEndWidth = Param.Unsigned("Back end width") - backEndSquashLatency = Param.Unsigned("Back end squash latency") - backEndLatency = Param.Unsigned("Back end latency") - maxInstBufferSize = Param.Unsigned("Maximum instruction buffer size") - decodeToFetchDelay = Param.Unsigned("Decode to fetch delay") - renameToFetchDelay = Param.Unsigned("Rename to fetch delay") - iewToFetchDelay = Param.Unsigned("Issue/Execute/Writeback to fetch " - "delay") - commitToFetchDelay = Param.Unsigned("Commit to fetch delay") - fetchWidth = Param.Unsigned("Fetch width") - - renameToDecodeDelay = Param.Unsigned("Rename to decode delay") - iewToDecodeDelay = Param.Unsigned("Issue/Execute/Writeback to decode " - "delay") - commitToDecodeDelay = Param.Unsigned("Commit to decode delay") - fetchToDecodeDelay = Param.Unsigned("Fetch to decode delay") - decodeWidth = Param.Unsigned("Decode width") - - iewToRenameDelay = Param.Unsigned("Issue/Execute/Writeback to rename " - "delay") - commitToRenameDelay = Param.Unsigned("Commit to rename delay") - decodeToRenameDelay = Param.Unsigned("Decode to rename delay") - renameWidth = Param.Unsigned("Rename width") - - commitToIEWDelay = Param.Unsigned("Commit to " - "Issue/Execute/Writeback delay") - renameToIEWDelay = Param.Unsigned("Rename to " - "Issue/Execute/Writeback delay") - issueToExecuteDelay = Param.Unsigned("Issue to execute delay (internal " - "to the IEW stage)") - issueWidth = Param.Unsigned("Issue width") - executeWidth = Param.Unsigned("Execute width") - executeIntWidth = Param.Unsigned("Integer execute width") - executeFloatWidth = Param.Unsigned("Floating point execute width") - executeBranchWidth = Param.Unsigned("Branch execute width") - executeMemoryWidth = Param.Unsigned("Memory execute width") - - iewToCommitDelay = Param.Unsigned("Issue/Execute/Writeback to commit " - "delay") - renameToROBDelay = Param.Unsigned("Rename to reorder buffer delay") - commitWidth = Param.Unsigned("Commit width") - squashWidth = Param.Unsigned("Squash width") - - localPredictorSize = Param.Unsigned("Size of local predictor") - localCtrBits = Param.Unsigned("Bits per counter") - localHistoryTableSize = Param.Unsigned("Size of local history table") - localHistoryBits = Param.Unsigned("Bits for the local history") - globalPredictorSize = Param.Unsigned("Size of global predictor") - globalCtrBits = Param.Unsigned("Bits per counter") - globalHistoryBits = Param.Unsigned("Bits of history") - choicePredictorSize = Param.Unsigned("Size of choice predictor") - choiceCtrBits = Param.Unsigned("Bits of choice counters") - - BTBEntries = Param.Unsigned("Number of BTB entries") - BTBTagSize = Param.Unsigned("Size of the BTB tags, in bits") - - RASSize = Param.Unsigned("RAS size") - - LQEntries = Param.Unsigned("Number of load queue entries") - SQEntries = Param.Unsigned("Number of store queue entries") - LFSTSize = Param.Unsigned("Last fetched store table size") - SSITSize = Param.Unsigned("Store set ID table size") - - numPhysIntRegs = Param.Unsigned("Number of physical integer registers") - numPhysFloatRegs = Param.Unsigned("Number of physical floating point " - "registers") - numIQEntries = Param.Unsigned("Number of instruction queue entries") - numROBEntries = Param.Unsigned("Number of reorder buffer entries") - - instShiftAmt = Param.Unsigned("Number of bits to shift instructions by") - - function_trace = Param.Bool(False, "Enable function trace") - function_trace_start = Param.Tick(0, "Cycle to start function trace") diff --git a/python/m5/objects/System.py b/python/m5/objects/System.py deleted file mode 100644 index e92c203e4..000000000 --- a/python/m5/objects/System.py +++ /dev/null @@ -1,19 +0,0 @@ -from m5 import * - -class System(SimObject): - type = 'System' - boot_cpu_frequency = Param.Frequency(Self.cpu[0].clock.frequency, - "boot processor frequency") - memctrl = Param.MemoryController(Parent.any, "memory controller") - physmem = Param.PhysicalMemory(Parent.any, "phsyical memory") - init_param = Param.UInt64(0, "numerical value to pass into simulator") - kernel = Param.String("file that contains the kernel code") - readfile = Param.String("", "file to read startup script from") - -class AlphaSystem(System): - type = 'AlphaSystem' - console = Param.String("file that contains the console code") - pal = Param.String("file that contains palcode") - boot_osflags = Param.String("a", "boot flags to pass to the kernel") - system_type = Param.UInt64("Type of system we are emulating") - system_rev = Param.UInt64("Revision of system we are emulating") diff --git a/python/m5/objects/Tsunami.py b/python/m5/objects/Tsunami.py deleted file mode 100644 index 5425f421f..000000000 --- a/python/m5/objects/Tsunami.py +++ /dev/null @@ -1,27 +0,0 @@ -from m5 import * -from Device import FooPioDevice -from Platform import Platform - -class Tsunami(Platform): - type = 'Tsunami' - pciconfig = Param.PciConfigAll("PCI configuration") - system = Param.System(Parent.any, "system") - -class TsunamiCChip(FooPioDevice): - type = 'TsunamiCChip' - tsunami = Param.Tsunami(Parent.any, "Tsunami") - -class IsaFake(FooPioDevice): - type = 'IsaFake' - size = Param.Addr("Size of address range") - -class TsunamiIO(FooPioDevice): - type = 'TsunamiIO' - time = Param.UInt64(1136073600, - "System time to use (0 for actual time, default is 1/1/06)") - tsunami = Param.Tsunami(Parent.any, "Tsunami") - frequency = Param.Frequency('1024Hz', "frequency of interrupts") - -class TsunamiPChip(FooPioDevice): - type = 'TsunamiPChip' - tsunami = Param.Tsunami(Parent.any, "Tsunami") diff --git a/python/m5/objects/Uart.py b/python/m5/objects/Uart.py deleted file mode 100644 index 6eda5cdb3..000000000 --- a/python/m5/objects/Uart.py +++ /dev/null @@ -1,16 +0,0 @@ -from m5 import * -from Device import PioDevice - -class Uart(PioDevice): - type = 'Uart' - abstract = True - console = Param.SimConsole(Parent.any, "The console") - size = Param.Addr(0x8, "Device size") - -class Uart8250(Uart): - type = 'Uart8250' - -if build_env['ALPHA_TLASER']: - class Uart8530(Uart): - type = 'Uart8530' - diff --git a/python/m5/smartdict.py b/python/m5/smartdict.py deleted file mode 100644 index cd38d7326..000000000 --- a/python/m5/smartdict.py +++ /dev/null @@ -1,152 +0,0 @@ -# Copyright (c) 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. - -# The SmartDict class fixes a couple of issues with using the content -# of os.environ or similar dicts of strings as Python variables: -# -# 1) Undefined variables should return False rather than raising KeyError. -# -# 2) String values of 'False', '0', etc., should evaluate to False -# (not just the empty string). -# -# #1 is solved by overriding __getitem__, and #2 is solved by using a -# proxy class for values and overriding __nonzero__ on the proxy. -# Everything else is just to (a) make proxies behave like normal -# values otherwise, (b) make sure any dict operation returns a proxy -# rather than a normal value, and (c) coerce values written to the -# dict to be strings. - - -from convert import * - -class Variable(str): - """Intelligent proxy class for SmartDict. Variable will use the - various convert functions to attempt to convert values to useable - types""" - def __int__(self): - return toInteger(str(self)) - def __long__(self): - return toLong(str(self)) - def __float__(self): - return toFloat(str(self)) - def __nonzero__(self): - return toBool(str(self)) - def convert(self, other): - t = type(other) - if t == bool: - return bool(self) - if t == int: - return int(self) - if t == long: - return long(self) - if t == float: - return float(self) - return str(self) - def __lt__(self, other): - return self.convert(other) < other - def __le__(self, other): - return self.convert(other) <= other - def __eq__(self, other): - return self.convert(other) == other - def __ne__(self, other): - return self.convert(other) != other - def __gt__(self, other): - return self.convert(other) > other - def __ge__(self, other): - return self.convert(other) >= other - - def __add__(self, other): - return self.convert(other) + other - def __sub__(self, other): - return self.convert(other) - other - def __mul__(self, other): - return self.convert(other) * other - def __div__(self, other): - return self.convert(other) / other - def __truediv__(self, other): - return self.convert(other) / other - - def __radd__(self, other): - return other + self.convert(other) - def __rsub__(self, other): - return other - self.convert(other) - def __rmul__(self, other): - return other * self.convert(other) - def __rdiv__(self, other): - return other / self.convert(other) - def __rtruediv__(self, other): - return other / self.convert(other) - -class UndefinedVariable(object): - """Placeholder class to represent undefined variables. Will - generally cause an exception whenever it is used, but evaluates to - zero for boolean truth testing such as in an if statement""" - def __nonzero__(self): - return False - -class SmartDict(dict): - """Dictionary class that holds strings, but intelligently converts - those strings to other types depending on their usage""" - - def __getitem__(self, key): - """returns a Variable proxy if the values exists in the database and - returns an UndefinedVariable otherwise""" - - if key in self: - return Variable(dict.get(self, key)) - else: - # Note that this does *not* change the contents of the dict, - # so that even after we call env['foo'] we still get a - # meaningful answer from "'foo' in env" (which - # calls dict.__contains__, which we do not override). - return UndefinedVariable() - - def __setitem__(self, key, item): - """intercept the setting of any variable so that we always - store strings in the dict""" - dict.__setitem__(self, key, str(item)) - - def values(self): - return [ Variable(v) for v in dict.values(self) ] - - def itervalues(self): - for value in dict.itervalues(self): - yield Variable(value) - - def items(self): - return [ (k, Variable(v)) for k,v in dict.items(self) ] - - def iteritems(self): - for key,value in dict.iteritems(self): - yield key, Variable(value) - - def get(self, key, default='False'): - return Variable(dict.get(self, key, str(default))) - - def setdefault(self, key, default='False'): - return Variable(dict.setdefault(self, key, str(default))) - -__all__ = [ 'SmartDict' ] diff --git a/sim/async.hh b/sim/async.hh deleted file mode 100644 index e0190a133..000000000 --- a/sim/async.hh +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __ASYNC_HH__ -#define __ASYNC_HH__ - -/// -/// @file sim/async.hh -/// This file defines flags used to handle asynchronous simulator events. -/// - -/// @name Asynchronous event flags. -/// To avoid races, signal handlers simply set these flags, which are -/// then checked in the main event loop. Defined in main.cc. -/// @note See the PollQueue object (in pollevent.hh) for the use of async_io and async_alarm. -//@{ -extern volatile bool async_event; ///< Some asynchronous event has happened. -extern volatile bool async_dump; ///< Async request to dump stats. -extern volatile bool async_exit; ///< Async request to exit simulator. -extern volatile bool async_io; ///< Async I/O request (SIGIO). -extern volatile bool async_alarm; ///< Async alarm event (SIGALRM). -//@} - -#endif // __ASYNC_HH__ diff --git a/sim/builder.cc b/sim/builder.cc deleted file mode 100644 index 7dc118985..000000000 --- a/sim/builder.cc +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include <assert.h> - -#include "base/inifile.hh" -#include "base/misc.hh" -#include "sim/builder.hh" -#include "sim/configfile.hh" -#include "sim/config_node.hh" -#include "sim/host.hh" -#include "sim/sim_object.hh" -#include "sim/root.hh" - -using namespace std; - -SimObjectBuilder::SimObjectBuilder(ConfigNode *_configNode) - : ParamContext(_configNode->getPath(), NoAutoInit), - configNode(_configNode) -{ -} - -SimObjectBuilder::~SimObjectBuilder() -{ -} - -/////////////////////////////////////////// -// -// SimObjectBuilder member definitions -// -/////////////////////////////////////////// - -// override ParamContext::parseParams() to check params based on -// instance name first. If not found, then check based on iniSection -// (as in default ParamContext implementation). -void -SimObjectBuilder::parseParams(IniFile &iniFile) -{ - iniFilePtr = &iniFile; // set object member - - ParamList::iterator i; - - for (i = paramList->begin(); i != paramList->end(); ++i) { - string string_value; - if (iniFile.find(iniSection, (*i)->name, string_value)) - (*i)->parse(string_value); - } -} - - -void -SimObjectBuilder::printErrorProlog(ostream &os) -{ - ccprintf(os, "Error creating object '%s' of type '%s':\n", - iniSection, configNode->getType()); -} - - -//////////////////////////////////////////////////////////////////////// -// -// SimObjectClass member definitions -// -//////////////////////////////////////////////////////////////////////// - -// Map of class names to SimObjectBuilder creation functions. Need to -// make this a pointer so we can force initialization on the first -// reference; otherwise, some SimObjectClass constructors may be invoked -// before the classMap constructor. -map<string,SimObjectClass::CreateFunc> *SimObjectClass::classMap = NULL; - -// SimObjectClass constructor: add mapping to classMap -SimObjectClass::SimObjectClass(const string &className, CreateFunc createFunc) -{ - if (classMap == NULL) - classMap = new map<string,SimObjectClass::CreateFunc>(); - - if ((*classMap)[className]) - panic("Error: simulation object class '%s' redefined\n", className); - - // add className --> createFunc to class map - (*classMap)[className] = createFunc; -} - - -// -// -SimObject * -SimObjectClass::createObject(IniFile &configDB, ConfigNode *configNode) -{ - const string &type = configNode->getType(); - - // look up className to get appropriate createFunc - if (classMap->find(type) == classMap->end()) - panic("Simulator object type '%s' not found.\n", type); - - - CreateFunc createFunc = (*classMap)[type]; - - // call createFunc with config hierarchy node to get object - // builder instance (context with parameters for object creation) - SimObjectBuilder *objectBuilder = (*createFunc)(configNode); - - assert(objectBuilder != NULL); - - // parse all parameters in context to generate parameter values - objectBuilder->parseParams(configDB); - - // now create the actual simulation object - SimObject *object = objectBuilder->create(); - - assert(object != NULL); - - // echo object parameters to stats file (for documenting the - // config used to generate the associated stats) - ccprintf(*configStream, "[%s]\n", object->name()); - ccprintf(*configStream, "type=%s\n", type); - objectBuilder->showParams(*configStream); - ccprintf(*configStream, "\n"); - - // done with the SimObjectBuilder now - delete objectBuilder; - - return object; -} - - -// -// static method: -// -void -SimObjectClass::describeAllClasses(ostream &os) -{ - map<string,CreateFunc>::iterator iter; - - for (iter = classMap->begin(); iter != classMap->end(); ++iter) { - const string &className = iter->first; - CreateFunc createFunc = iter->second; - - os << "[" << className << "]\n"; - - // create dummy object builder just to instantiate parameters - SimObjectBuilder *objectBuilder = (*createFunc)(NULL); - - // now get the object builder to describe ite params - objectBuilder->describeParams(os); - - os << endl; - - // done with the object builder now - delete objectBuilder; - } -} diff --git a/sim/builder.hh b/sim/builder.hh deleted file mode 100644 index b32e00e76..000000000 --- a/sim/builder.hh +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __BUILDER_HH__ -#define __BUILDER_HH__ - -#include <iosfwd> -#include <list> -#include <map> -#include <vector> - -#include "sim/param.hh" - -class SimObject; - -// -// A SimObjectBuilder serves as an evaluation context for a set of -// parameters that describe a specific instance of a SimObject. This -// evaluation context corresponds to a section in the .ini file (as -// with the base ParamContext) plus an optional node in the -// configuration hierarchy (the configNode member) for resolving -// SimObject references. SimObjectBuilder is an abstract superclass; -// derived classes specialize the class for particular subclasses of -// SimObject (e.g., BaseCache). -// -// For typical usage, see the definition of -// SimObjectClass::createObject(). -// -class SimObjectBuilder : public ParamContext -{ - private: - // The corresponding node in the configuration hierarchy. - // (optional: may be null if the created object is not in the - // hierarchy) - ConfigNode *configNode; - - public: - SimObjectBuilder(ConfigNode *_configNode); - - virtual ~SimObjectBuilder(); - - // call parse() on all params in this context to convert string - // representations to parameter values - virtual void parseParams(IniFile &iniFile); - - // parameter error prolog (override of ParamContext) - virtual void printErrorProlog(std::ostream &); - - // generate the name for this SimObject instance (derived from the - // configuration hierarchy node label and position) - virtual const std::string &getInstanceName() { return iniSection; } - - // return the configuration hierarchy node for this context. - virtual ConfigNode *getConfigNode() { return configNode; } - - // Create the actual SimObject corresponding to the parameter - // values in this context. This function is overridden in derived - // classes to call a specific constructor for a particular - // subclass of SimObject. - virtual SimObject *create() = 0; -}; - - -// -// Handy macros for initializing parameter members of classes derived -// from SimObjectBuilder. Assumes that the name of the parameter -// member object is the same as the textual parameter name seen by the -// user. (Note that '#p' is expanded by the preprocessor to '"p"'.) -// -#define INIT_PARAM(p, desc) p(this, #p, desc) -#define INIT_PARAM_DFLT(p, desc, dflt) p(this, #p, desc, dflt) - -// -// Initialize an enumeration variable... assumes that 'map' is the -// name of an array of mappings (char * for SimpleEnumParam, or -// EnumParamMap for MappedEnumParam). -// -#define INIT_ENUM_PARAM(p, desc, map) \ - p(this, #p, desc, map, sizeof(map)/sizeof(map[0])) -#define INIT_ENUM_PARAM_DFLT(p, desc, map, dflt) \ - p(this, #p, desc, map, sizeof(map)/sizeof(map[0]), dflt) - -// -// An instance of SimObjectClass corresponds to a class derived from -// SimObject. The SimObjectClass instance serves to bind the string -// name (found in the config file) to a function that creates an -// instance of the appropriate derived class. -// -// This would be much cleaner in Smalltalk or Objective-C, where types -// are first-class objects themselves. -// -class SimObjectClass -{ - public: - // Type CreateFunc is a pointer to a function that creates a new - // simulation object builder based on a .ini-file parameter - // section (specified by the first string argument), a unique name - // for the object (specified by the second string argument), and - // an optional config hierarchy node (specified by the third - // argument). A pointer to the new SimObjectBuilder is returned. - typedef SimObjectBuilder *(*CreateFunc)(ConfigNode *configNode); - - static std::map<std::string,CreateFunc> *classMap; - - // Constructor. For example: - // - // SimObjectClass baseCacheClass("BaseCache", newBaseCacheBuilder); - // - SimObjectClass(const std::string &className, CreateFunc createFunc); - - // create SimObject given name of class and pointer to - // configuration hierarchy node - static SimObject *createObject(IniFile &configDB, ConfigNode *configNode); - - // print descriptions of all parameters registered with all - // SimObject classes - static void describeAllClasses(std::ostream &os); -}; - -// -// Macros to encapsulate the magic of declaring & defining -// SimObjectBuilder and SimObjectClass objects -// - -#define BEGIN_DECLARE_SIM_OBJECT_PARAMS(OBJ_CLASS) \ -class OBJ_CLASS##Builder : public SimObjectBuilder \ -{ \ - public: - -#define END_DECLARE_SIM_OBJECT_PARAMS(OBJ_CLASS) \ - \ - OBJ_CLASS##Builder(ConfigNode *configNode); \ - virtual ~OBJ_CLASS##Builder() {} \ - \ - OBJ_CLASS *create(); \ -}; - -#define BEGIN_INIT_SIM_OBJECT_PARAMS(OBJ_CLASS) \ -OBJ_CLASS##Builder::OBJ_CLASS##Builder(ConfigNode *configNode) \ - : SimObjectBuilder(configNode), - - -#define END_INIT_SIM_OBJECT_PARAMS(OBJ_CLASS) \ -{ \ -} - -#define CREATE_SIM_OBJECT(OBJ_CLASS) \ -OBJ_CLASS *OBJ_CLASS##Builder::create() - -#define REGISTER_SIM_OBJECT(CLASS_NAME, OBJ_CLASS) \ -SimObjectBuilder * \ -new##OBJ_CLASS##Builder(ConfigNode *configNode) \ -{ \ - return new OBJ_CLASS##Builder(configNode); \ -} \ - \ -SimObjectClass the##OBJ_CLASS##Class(CLASS_NAME, \ - new##OBJ_CLASS##Builder); \ - \ -/* see param.hh */ \ -DEFINE_SIM_OBJECT_CLASS_NAME(CLASS_NAME, OBJ_CLASS) - - -#endif // __BUILDER_HH__ diff --git a/sim/byteswap.hh b/sim/byteswap.hh deleted file mode 100644 index c5d8801ab..000000000 --- a/sim/byteswap.hh +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (c) 2004 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. - */ - -//The purpose of this file is to provide endainness conversion utility -//functions. Depending on the endianness of the guest system, either -//the LittleEndianGuest or BigEndianGuest namespace is used. - -#ifndef __SIM_BYTE_SWAP_HH__ -#define __SIM_BYTE_SWAP_HH__ - -#include "sim/host.hh" - -// This lets us figure out what the byte order of the host system is -#if defined(linux) -#include <endian.h> -#else -#include <machine/endian.h> -#endif - -//These functions actually perform the swapping for parameters -//of various bit lengths -static inline uint64_t -swap_byte64(uint64_t x) -{ - return (uint64_t)((((uint64_t)(x) & 0xff) << 56) | - ((uint64_t)(x) & 0xff00ULL) << 40 | - ((uint64_t)(x) & 0xff0000ULL) << 24 | - ((uint64_t)(x) & 0xff000000ULL) << 8 | - ((uint64_t)(x) & 0xff00000000ULL) >> 8 | - ((uint64_t)(x) & 0xff0000000000ULL) >> 24 | - ((uint64_t)(x) & 0xff000000000000ULL) >> 40 | - ((uint64_t)(x) & 0xff00000000000000ULL) >> 56) ; -} - -static inline uint32_t -swap_byte32(uint32_t x) -{ - return (uint32_t)(((uint32_t)(x) & 0xff) << 24 | - ((uint32_t)(x) & 0xff00) << 8 | ((uint32_t)(x) & 0xff0000) >> 8 | - ((uint32_t)(x) & 0xff000000) >> 24); - -} - -static inline uint16_t -swap_byte16(uint16_t x) -{ - return (uint16_t)(((uint16_t)(x) & 0xff) << 8 | - ((uint16_t)(x) & 0xff00) >> 8); -} - -//This lets the compiler figure out how to call the swap_byte functions above -//for different data types. -static inline uint64_t swap_byte(uint64_t x) {return swap_byte64(x);} -static inline int64_t swap_byte(int64_t x) {return swap_byte64((uint64_t)x);} -static inline uint32_t swap_byte(uint32_t x) {return swap_byte32(x);} -static inline int32_t swap_byte(int32_t x) {return swap_byte32((uint32_t)x);} -#if defined(__APPLE__) -static inline long swap_byte(long x) {return swap_byte32((long)x);} -static inline unsigned long swap_byte(unsigned long x) - { return swap_byte32((unsigned long)x);} -#endif -static inline uint16_t swap_byte(uint16_t x) {return swap_byte32(x);} -static inline int16_t swap_byte(int16_t x) {return swap_byte16((uint16_t)x);} -static inline uint8_t swap_byte(uint8_t x) {return x;} -static inline int8_t swap_byte(int8_t x) {return x;} -static inline double swap_byte(double x) {return swap_byte64((uint64_t)x);} -static inline float swap_byte(float x) {return swap_byte32((uint32_t)x);} - -//The conversion functions with fixed endianness on both ends don't need to -//be in a namespace -template <typename T> static inline T betole(T value) {return swap_byte(value);} -template <typename T> static inline T letobe(T value) {return swap_byte(value);} - -//For conversions not involving the guest system, we can define the functions -//conditionally based on the BYTE_ORDER macro and outside of the namespaces -#if BYTE_ORDER == BIG_ENDIAN -template <typename T> static inline T htole(T value) {return swap_byte(value);} -template <typename T> static inline T letoh(T value) {return swap_byte(value);} -template <typename T> static inline T htobe(T value) {return value;} -template <typename T> static inline T betoh(T value) {return value;} -#elif BYTE_ORDER == LITTLE_ENDIAN -template <typename T> static inline T htole(T value) {return value;} -template <typename T> static inline T letoh(T value) {return value;} -template <typename T> static inline T htobe(T value) {return swap_byte(value);} -template <typename T> static inline T betoh(T value) {return swap_byte(value);} -#else - #error Invalid Endianess -#endif - -namespace BigEndianGuest -{ - template <typename T> - static inline T gtole(T value) {return betole(value);} - template <typename T> - static inline T letog(T value) {return letobe(value);} - template <typename T> - static inline T gtobe(T value) {return value;} - template <typename T> - static inline T betog(T value) {return value;} - template <typename T> - static inline T htog(T value) {return htobe(value);} - template <typename T> - static inline T gtoh(T value) {return betoh(value);} -} - -namespace LittleEndianGuest -{ - template <typename T> - static inline T gtole(T value) {return value;} - template <typename T> - static inline T letog(T value) {return value;} - template <typename T> - static inline T gtobe(T value) {return letobe(value);} - template <typename T> - static inline T betog(T value) {return betole(value);} - template <typename T> - static inline T htog(T value) {return htole(value);} - template <typename T> - static inline T gtoh(T value) {return letoh(value);} -} -#endif // __SIM_BYTE_SWAP_HH__ diff --git a/sim/debug.cc b/sim/debug.cc deleted file mode 100644 index 09e5346a8..000000000 --- a/sim/debug.cc +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include <sys/types.h> -#include <signal.h> -#include <unistd.h> - -#include <string> -#include <vector> - -#include "sim/debug.hh" -#include "sim/eventq.hh" -#include "sim/param.hh" -#include "sim/sim_events.hh" - -using namespace std; - -void -debug_break() -{ -#ifndef NDEBUG - kill(getpid(), SIGTRAP); -#else - cprintf("debug_break suppressed, compiled with NDEBUG\n"); -#endif -} - -// -// Debug event: place a breakpoint on the process function and -// schedule the event to break at a particular cycle -// -class DebugBreakEvent : public Event -{ - public: - - DebugBreakEvent(EventQueue *q, Tick _when); - - void process(); // process event - virtual const char *description(); -}; - -// -// constructor: schedule at specified time -// -DebugBreakEvent::DebugBreakEvent(EventQueue *q, Tick _when) - : Event(q, Debug_Break_Pri) -{ - setFlags(AutoDelete); - schedule(_when); -} - -// -// handle debug event: set debugger breakpoint on this function -// -void -DebugBreakEvent::process() -{ - debug_break(); -} - - -const char * -DebugBreakEvent::description() -{ - return "debug break"; -} - -// -// Parameter context for global debug options -// -class DebugContext : public ParamContext -{ - public: - DebugContext(const string &_iniSection) - : ParamContext(_iniSection) {} - void checkParams(); -}; - -DebugContext debugParams("debug"); - -VectorParam<Tick> break_cycles(&debugParams, "break_cycles", - "cycle(s) to create breakpoint events"); - -void -DebugContext::checkParams() -{ - if (break_cycles.isValid()) { - vector<Tick> &cycles = break_cycles; - - vector<Tick>::iterator i = cycles.begin(); - vector<Tick>::iterator end = cycles.end(); - - for (; i < end; ++i) - new DebugBreakEvent(&mainEventQueue, *i); - } -} - -// -// handy function to schedule DebugBreakEvent on main event queue -// (callable from debugger) -// -extern "C" void sched_break_cycle(Tick when) -{ - new DebugBreakEvent(&mainEventQueue, when); -} - -extern "C" void eventq_dump() -{ - mainEventQueue.dump(); -} - diff --git a/sim/debug.hh b/sim/debug.hh deleted file mode 100644 index 75b261d80..000000000 --- a/sim/debug.hh +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __DEBUG_HH__ -#define __DEBUG_HH__ - -void debug_break(); - -#endif // __DEBUG_HH__ diff --git a/sim/eventq.cc b/sim/eventq.cc deleted file mode 100644 index 0884db994..000000000 --- a/sim/eventq.cc +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright (c) 2000-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. - */ - -#include <assert.h> - -#include <iostream> -#include <string> -#include <sstream> -#include <vector> - -#include "cpu/smt.hh" -#include "base/misc.hh" - -#include "sim/eventq.hh" -#include "base/trace.hh" -#include "sim/root.hh" - -using namespace std; - -// -// Main Event Queue -// -// Events on this queue are processed at the *beginning* of each -// cycle, before the pipeline simulation is performed. -// -EventQueue mainEventQueue("MainEventQueue"); - -void -EventQueue::insert(Event *event) -{ - if (head == NULL || event->when() < head->when() || - (event->when() == head->when() && - event->priority() <= head->priority())) { - event->next = head; - head = event; - } else { - Event *prev = head; - Event *curr = head->next; - - while (curr) { - if (event->when() <= curr->when() && - (event->when() < curr->when() || - event->priority() <= curr->priority())) - break; - - prev = curr; - curr = curr->next; - } - - event->next = curr; - prev->next = event; - } -} - -void -EventQueue::remove(Event *event) -{ - if (head == NULL) - return; - - if (head == event){ - head = event->next; - return; - } - - Event *prev = head; - Event *curr = head->next; - while (curr && curr != event) { - prev = curr; - curr = curr->next; - } - - if (curr == event) - prev->next = curr->next; -} - -void -EventQueue::serviceOne() -{ - Event *event = head; - event->clearFlags(Event::Scheduled); - head = event->next; - - // handle action - if (!event->squashed()) - event->process(); - else - event->clearFlags(Event::Squashed); - - if (event->getFlags(Event::AutoDelete) && !event->scheduled()) - delete event; -} - - -void -Event::serialize(std::ostream &os) -{ - SERIALIZE_SCALAR(_when); - SERIALIZE_SCALAR(_priority); - SERIALIZE_ENUM(_flags); -} - - -void -Event::unserialize(Checkpoint *cp, const string §ion) -{ - if (scheduled()) - deschedule(); - - UNSERIALIZE_SCALAR(_when); - UNSERIALIZE_SCALAR(_priority); - - // need to see if original event was in a scheduled, unsquashed - // state, but don't want to restore those flags in the current - // object itself (since they aren't immediately true) - UNSERIALIZE_ENUM(_flags); - bool wasScheduled = (_flags & Scheduled) && !(_flags & Squashed); - _flags &= ~(Squashed | Scheduled); - - if (wasScheduled) { - DPRINTF(Config, "rescheduling at %d\n", _when); - schedule(_when); - } -} - -void -EventQueue::serialize(ostream &os) -{ - std::list<Event *> eventPtrs; - - int numEvents = 0; - Event *event = head; - while (event) { - if (event->getFlags(Event::AutoSerialize)) { - eventPtrs.push_back(event); - paramOut(os, csprintf("event%d", numEvents++), event->name()); - } - event = event->next; - } - - SERIALIZE_SCALAR(numEvents); - - for (std::list<Event *>::iterator it=eventPtrs.begin(); - it != eventPtrs.end(); ++it) { - (*it)->nameOut(os); - (*it)->serialize(os); - } -} - -void -EventQueue::unserialize(Checkpoint *cp, const std::string §ion) -{ - int numEvents; - UNSERIALIZE_SCALAR(numEvents); - - std::string eventName; - for (int i = 0; i < numEvents; i++) { - // get the pointer value associated with the event - paramIn(cp, section, csprintf("event%d", i), eventName); - - // create the event based on its pointer value - Serializable::create(cp, eventName); - } -} - -void -EventQueue::dump() -{ - cprintf("============================================================\n"); - cprintf("EventQueue Dump (cycle %d)\n", curTick); - cprintf("------------------------------------------------------------\n"); - - if (empty()) - cprintf("<No Events>\n"); - else { - Event *event = head; - while (event) { - event->dump(); - event = event->next; - } - } - - cprintf("============================================================\n"); -} - -extern "C" -void -dumpMainQueue() -{ - mainEventQueue.dump(); -} - - -const char * -Event::description() -{ - return "generic"; -} - -#if TRACING_ON -void -Event::trace(const char *action) -{ - // This DPRINTF is unconditional because calls to this function - // are protected by an 'if (DTRACE(Event))' in the inlined Event - // methods. - // - // This is just a default implementation for derived classes where - // it's not worth doing anything special. If you want to put a - // more informative message in the trace, override this method on - // the particular subclass where you have the information that - // needs to be printed. - DPRINTFN("%s event %s @ %d\n", description(), action, when()); -} -#endif - -void -Event::dump() -{ - cprintf("Event (%s)\n", description()); - cprintf("Flags: %#x\n", _flags); -#if TRACING_ON - cprintf("Created: %d\n", when_created); -#endif - if (scheduled()) { -#if TRACING_ON - cprintf("Scheduled at %d\n", when_scheduled); -#endif - cprintf("Scheduled for %d, priority %d\n", when(), _priority); - } - else { - cprintf("Not Scheduled\n"); - } -} diff --git a/sim/eventq.hh b/sim/eventq.hh deleted file mode 100644 index 5fc73bb53..000000000 --- a/sim/eventq.hh +++ /dev/null @@ -1,407 +0,0 @@ -/* - * Copyright (c) 2000-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. - */ - -/* @file - * EventQueue interfaces - */ - -#ifndef __SIM_EVENTQ_HH__ -#define __SIM_EVENTQ_HH__ - -#include <assert.h> - -#include <algorithm> -#include <map> -#include <string> -#include <vector> - -#include "sim/host.hh" // for Tick - -#include "base/fast_alloc.hh" -#include "base/trace.hh" -#include "sim/serialize.hh" - -class EventQueue; // forward declaration - -////////////////////// -// -// Main Event Queue -// -// Events on this queue are processed at the *beginning* of each -// cycle, before the pipeline simulation is performed. -// -// defined in eventq.cc -// -////////////////////// -extern EventQueue mainEventQueue; - - -/* - * An item on an event queue. The action caused by a given - * event is specified by deriving a subclass and overriding the - * process() member function. - */ -class Event : public Serializable, public FastAlloc -{ - friend class EventQueue; - - private: - /// queue to which this event belongs (though it may or may not be - /// scheduled on this queue yet) - EventQueue *queue; - - Event *next; - - Tick _when; //!< timestamp when event should be processed - int _priority; //!< event priority - char _flags; - - protected: - enum Flags { - None = 0x0, - Squashed = 0x1, - Scheduled = 0x2, - AutoDelete = 0x4, - AutoSerialize = 0x8 - }; - - bool getFlags(Flags f) const { return (_flags & f) == f; } - void setFlags(Flags f) { _flags |= f; } - void clearFlags(Flags f) { _flags &= ~f; } - - protected: - EventQueue *theQueue() const { return queue; } - -#if TRACING_ON - Tick when_created; //!< Keep track of creation time For debugging - Tick when_scheduled; //!< Keep track of creation time For debugging - - virtual void trace(const char *action); //!< trace event activity -#else - void trace(const char *) {} -#endif - - unsigned annotated_value; - - public: - - /// Event priorities, to provide tie-breakers for events scheduled - /// at the same cycle. Most events are scheduled at the default - /// priority; these values are used to control events that need to - /// be ordered within a cycle. - enum Priority { - /// Breakpoints should happen before anything else, so we - /// don't miss any action when debugging. - Debug_Break_Pri = -100, - - /// For some reason "delayed" inter-cluster writebacks are - /// scheduled before regular writebacks (which have default - /// priority). Steve? - Delayed_Writeback_Pri = -1, - - /// Default is zero for historical reasons. - Default_Pri = 0, - - /// CPU switches schedule the new CPU's tick event for the - /// same cycle (after unscheduling the old CPU's tick event). - /// The switch needs to come before any tick events to make - /// sure we don't tick both CPUs in the same cycle. - CPU_Switch_Pri = 31, - - /// Serailization needs to occur before tick events also, so - /// that a serialize/unserialize is identical to an on-line - /// CPU switch. - Serialize_Pri = 32, - - /// CPU ticks must come after other associated CPU events - /// (such as writebacks). - CPU_Tick_Pri = 50, - - /// Statistics events (dump, reset, etc.) come after - /// everything else, but before exit. - Stat_Event_Pri = 90, - - /// If we want to exit on this cycle, it's the very last thing - /// we do. - Sim_Exit_Pri = 100 - }; - - /* - * Event constructor - * @param queue that the event gets scheduled on - */ - Event(EventQueue *q, Priority p = Default_Pri) - : queue(q), next(NULL), _priority(p), _flags(None), -#if TRACING_ON - when_created(curTick), when_scheduled(0), -#endif - annotated_value(0) - { - } - - ~Event() {} - - virtual const std::string name() const { - return csprintf("Event_%x", (uintptr_t)this); - } - - /// Determine if the current event is scheduled - bool scheduled() const { return getFlags(Scheduled); } - - /// Schedule the event with the current priority or default priority - void schedule(Tick t); - - /// Reschedule the event with the current priority - void reschedule(Tick t); - - /// Remove the event from the current schedule - void deschedule(); - - /// Return a C string describing the event. This string should - /// *not* be dynamically allocated; just a const char array - /// describing the event class. - virtual const char *description(); - - /// Dump the current event data - void dump(); - - /* - * This member function is invoked when the event is processed - * (occurs). There is no default implementation; each subclass - * must provide its own implementation. The event is not - * automatically deleted after it is processed (to allow for - * statically allocated event objects). - * - * If the AutoDestroy flag is set, the object is deleted once it - * is processed. - */ - virtual void process() = 0; - - void annotate(unsigned value) { annotated_value = value; }; - unsigned annotation() { return annotated_value; } - - /// Squash the current event - void squash() { setFlags(Squashed); } - - /// Check whether the event is squashed - bool squashed() { return getFlags(Squashed); } - - /// Get the time that the event is scheduled - Tick when() const { return _when; } - - /// Get the event priority - int priority() const { return _priority; } - - struct priority_compare : - public std::binary_function<Event *, Event *, bool> - { - bool operator()(const Event *l, const Event *r) const { - return l->when() >= r->when() || l->priority() >= r->priority(); - } - }; - - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); -}; - -template <class T, void (T::* F)()> -void -DelayFunction(Tick when, T *object) -{ - class DelayEvent : public Event - { - private: - T *object; - - public: - DelayEvent(Tick when, T *o) - : Event(&mainEventQueue), object(o) - { setFlags(this->AutoDestroy); schedule(when); } - void process() { (object->*F)(); } - const char *description() { return "delay"; } - }; - - new DelayEvent(when, object); -} - -template <class T, void (T::* F)()> -class EventWrapper : public Event -{ - private: - T *object; - - public: - EventWrapper(T *obj, bool del = false, EventQueue *q = &mainEventQueue, - Priority p = Default_Pri) - : Event(q, p), object(obj) - { - if (del) - setFlags(AutoDelete); - } - void process() { (object->*F)(); } -}; - -/* - * Queue of events sorted in time order - */ -class EventQueue : public Serializable -{ - protected: - std::string objName; - - private: - Event *head; - - void insert(Event *event); - void remove(Event *event); - - public: - - // constructor - EventQueue(const std::string &n) - : objName(n), head(NULL) - {} - - virtual const std::string name() const { return objName; } - - // schedule the given event on this queue - void schedule(Event *ev); - void deschedule(Event *ev); - void reschedule(Event *ev); - - Tick nextTick() { return head->when(); } - void serviceOne(); - - // process all events up to the given timestamp. we inline a - // quick test to see if there are any events to process; if so, - // call the internal out-of-line version to process them all. - void serviceEvents(Tick when) { - while (!empty()) { - if (nextTick() > when) - break; - - /** - * @todo this assert is a good bug catcher. I need to - * make it true again. - */ - //assert(head->when() >= when && "event scheduled in the past"); - serviceOne(); - } - } - - // default: process all events up to 'now' (curTick) - void serviceEvents() { serviceEvents(curTick); } - - // return true if no events are queued - bool empty() { return head == NULL; } - - void dump(); - - Tick nextEventTime() { return empty() ? curTick : head->when(); } - - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); -}; - - -////////////////////// -// -// inline functions -// -// can't put these inside declaration due to circular dependence -// between Event and EventQueue classes. -// -////////////////////// - -// schedule at specified time (place on event queue specified via -// constructor) -inline void -Event::schedule(Tick t) -{ - assert(!scheduled()); - assert(t >= curTick); - - setFlags(Scheduled); -#if TRACING_ON - when_scheduled = curTick; -#endif - _when = t; - queue->schedule(this); -} - -inline void -Event::deschedule() -{ - assert(scheduled()); - - clearFlags(Squashed); - clearFlags(Scheduled); - queue->deschedule(this); -} - -inline void -Event::reschedule(Tick t) -{ - assert(scheduled()); - clearFlags(Squashed); - -#if TRACING_ON - when_scheduled = curTick; -#endif - _when = t; - queue->reschedule(this); -} - -inline void -EventQueue::schedule(Event *event) -{ - insert(event); - if (DTRACE(Event)) - event->trace("scheduled"); -} - -inline void -EventQueue::deschedule(Event *event) -{ - remove(event); - if (DTRACE(Event)) - event->trace("descheduled"); -} - -inline void -EventQueue::reschedule(Event *event) -{ - remove(event); - insert(event); - if (DTRACE(Event)) - event->trace("rescheduled"); -} - - - -#endif // __SIM_EVENTQ_HH__ diff --git a/sim/faults.cc b/sim/faults.cc deleted file mode 100644 index 701384989..000000000 --- a/sim/faults.cc +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include "sim/faults.hh" -#include "cpu/exec_context.hh" -#include "cpu/base.hh" - -#if !FULL_SYSTEM -void FaultBase::invoke(ExecContext * xc) -{ - fatal("fault (%s) detected @ PC 0x%08p", name(), xc->readPC()); -} -#else -void FaultBase::invoke(ExecContext * xc) -{ - DPRINTF(Fault, "Fault %s at PC: %#x\n", name(), xc->readPC()); - xc->getCpuPtr()->recordEvent(csprintf("Fault %s", name())); - - assert(!xc->misspeculating()); -} -#endif diff --git a/sim/faults.hh b/sim/faults.hh deleted file mode 100644 index 18601e8f1..000000000 --- a/sim/faults.hh +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __FAULTS_HH__ -#define __FAULTS_HH__ - -#include "base/refcnt.hh" -#include "sim/stats.hh" -#include "config/full_system.hh" - -class ExecContext; -class FaultBase; -typedef RefCountingPtr<FaultBase> Fault; - -typedef const char * FaultName; -typedef Stats::Scalar<> FaultStat; - -// Each class has it's name statically define in _name, -// and has a virtual function to access it's name. -// The function is necessary because otherwise, all objects -// which are being accessed cast as a FaultBase * (namely -// all faults returned using the Fault type) will use the -// generic FaultBase name. - -class FaultBase : public RefCounted -{ - public: - virtual FaultName name() = 0; -#if FULL_SYSTEM - virtual void invoke(ExecContext * xc); -#else - virtual void invoke(ExecContext * xc); -#endif -// template<typename T> -// bool isA() {return dynamic_cast<T *>(this);} - virtual bool isMachineCheckFault() {return false;} - virtual bool isAlignmentFault() {return false;} -}; - -FaultBase * const NoFault = 0; - -#endif // __FAULTS_HH__ diff --git a/sim/host.hh b/sim/host.hh deleted file mode 100644 index f7e64f23c..000000000 --- a/sim/host.hh +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 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. - */ - -/** - * @file - * Defines host-dependent types: - * Counter, Tick, and (indirectly) {int,uint}{8,16,32,64}_t. - */ - -#ifndef __HOST_HH__ -#define __HOST_HH__ - -#include <inttypes.h> - -/** uint64_t constant */ -#define ULL(N) ((uint64_t)N##ULL) -/** int64_t constant */ -#define LL(N) (((int64_t)N##LL) - -/** Statistics counter type. Not much excuse for not using a 64-bit - * integer here, but if you're desperate and only run short - * simulations you could make this 32 bits. - */ -typedef int64_t Counter; - -/** - * Clock cycle count type. - * @note using an unsigned breaks the cache. - */ -typedef int64_t Tick; - -/** - * Address type - * This will probably be moved somewhere else in the near future. - * This should be at least as big as the biggest address width in use - * in the system, which will probably be 64 bits. - */ -typedef uint64_t Addr; - -#endif // __HOST_H__ diff --git a/sim/main.cc b/sim/main.cc deleted file mode 100644 index 6f6143506..000000000 --- a/sim/main.cc +++ /dev/null @@ -1,429 +0,0 @@ -/* - * Copyright (c) 2000-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. - */ - -/// -/// @file sim/main.cc -/// -#include <sys/types.h> -#include <sys/stat.h> -#include <errno.h> -#include <libgen.h> -#include <stdlib.h> -#include <signal.h> - -#include <list> -#include <string> -#include <vector> - -#include "base/copyright.hh" -#include "base/embedfile.hh" -#include "base/inifile.hh" -#include "base/misc.hh" -#include "base/output.hh" -#include "base/pollevent.hh" -#include "base/statistics.hh" -#include "base/str.hh" -#include "base/time.hh" -#include "cpu/base.hh" -#include "cpu/smt.hh" -#include "python/pyconfig.hh" -#include "sim/async.hh" -#include "sim/builder.hh" -#include "sim/configfile.hh" -#include "sim/host.hh" -#include "sim/sim_events.hh" -#include "sim/sim_exit.hh" -#include "sim/sim_object.hh" -#include "sim/stat_control.hh" -#include "sim/stats.hh" -#include "sim/root.hh" - -using namespace std; - -// See async.h. -volatile bool async_event = false; -volatile bool async_dump = false; -volatile bool async_dumpreset = false; -volatile bool async_exit = false; -volatile bool async_io = false; -volatile bool async_alarm = false; - -/// Stats signal handler. -void -dumpStatsHandler(int sigtype) -{ - async_event = true; - async_dump = true; -} - -void -dumprstStatsHandler(int sigtype) -{ - async_event = true; - async_dumpreset = true; -} - -/// Exit signal handler. -void -exitNowHandler(int sigtype) -{ - async_event = true; - async_exit = true; -} - -/// Abort signal handler. -void -abortHandler(int sigtype) -{ - cerr << "Program aborted at cycle " << curTick << endl; - -#if TRACING_ON - // dump trace buffer, if there is one - Trace::theLog.dump(cerr); -#endif -} - -/// Simulator executable name -char *myProgName = ""; - -/// Show brief help message. -void -showBriefHelp(ostream &out) -{ - char *prog = basename(myProgName); - - ccprintf(out, "Usage:\n"); - ccprintf(out, -"%s [-d <dir>] [-E <var>[=<val>]] [-I <dir>] [-P <python>]\n" -" [--<var>=<val>] <config file>\n" -"\n" -" -d set the output directory to <dir>\n" -" -E set the environment variable <var> to <val> (or 'True')\n" -" -I add the directory <dir> to python's path\n" -" -P execute <python> directly in the configuration\n" -" --var=val set the python variable <var> to '<val>'\n" -" <configfile> config file name (ends in .py)\n\n", - prog); - - ccprintf(out, "%s -X\n -X extract embedded files\n\n", prog); - ccprintf(out, "%s -h\n -h print short help\n\n", prog); -} - -/// Print welcome message. -void -sayHello(ostream &out) -{ - extern const char *compileDate; // from date.cc - - ccprintf(out, "M5 Simulator System\n"); - // display copyright - ccprintf(out, "%s\n", briefCopyright); - ccprintf(out, "M5 compiled on %d\n", compileDate); - - char *host = getenv("HOSTNAME"); - if (!host) - host = getenv("HOST"); - - if (host) - ccprintf(out, "M5 executing on %s\n", host); - - ccprintf(out, "M5 simulation started %s\n", Time::start); -} - -/// -/// Echo the command line for posterity in such a way that it can be -/// used to rerun the same simulation (given the same .ini files). -/// -void -echoCommandLine(int argc, char **argv, ostream &out) -{ - out << "command line: " << argv[0]; - for (int i = 1; i < argc; i++) { - string arg(argv[i]); - - out << ' '; - - // If the arg contains spaces, we need to quote it. - // The rest of this is overkill to make it look purty. - - // print dashes first outside quotes - int non_dash_pos = arg.find_first_not_of("-"); - out << arg.substr(0, non_dash_pos); // print dashes - string body = arg.substr(non_dash_pos); // the rest - - // if it's an assignment, handle the lhs & rhs separately - int eq_pos = body.find("="); - if (eq_pos == string::npos) { - out << quote(body); - } - else { - string lhs(body.substr(0, eq_pos)); - string rhs(body.substr(eq_pos + 1)); - - out << quote(lhs) << "=" << quote(rhs); - } - } - out << endl << endl; -} - -char * -getOptionString(int &index, int argc, char **argv) -{ - char *option = argv[index] + 2; - if (*option != '\0') - return option; - - // We didn't find an argument, it must be in the next variable. - if (++index >= argc) - panic("option string for option '%s' not found", argv[index - 1]); - - return argv[index]; -} - -int -main(int argc, char **argv) -{ - // Save off program name - myProgName = argv[0]; - - signal(SIGFPE, SIG_IGN); // may occur on misspeculated paths - signal(SIGTRAP, SIG_IGN); - signal(SIGUSR1, dumpStatsHandler); // dump intermediate stats - signal(SIGUSR2, dumprstStatsHandler); // dump and reset stats - signal(SIGINT, exitNowHandler); // dump final stats and exit - signal(SIGABRT, abortHandler); - - bool configfile_found = false; - PythonConfig pyconfig; - string outdir; - - if (argc < 2) { - showBriefHelp(cerr); - exit(1); - } - - sayHello(cerr); - - // Parse command-line options. - // Since most of the complex options are handled through the - // config database, we don't mess with getopts, and just parse - // manually. - for (int i = 1; i < argc; ++i) { - char *arg_str = argv[i]; - - // if arg starts with '--', parse as a special python option - // of the format --<python var>=<string value>, if the arg - // starts with '-', it should be a simulator option with a - // format similar to getopt. In any other case, treat the - // option as a configuration file name and load it. - if (arg_str[0] == '-' && arg_str[1] == '-') { - string str = &arg_str[2]; - string var, val; - - if (!split_first(str, var, val, '=')) - panic("Could not parse configuration argument '%s'\n" - "Expecting --<variable>=<value>\n", arg_str); - - pyconfig.setVariable(var, val); - } else if (arg_str[0] == '-') { - char *option; - string var, val; - - // switch on second char - switch (arg_str[1]) { - case 'd': - outdir = getOptionString(i, argc, argv); - break; - - case 'h': - showBriefHelp(cerr); - exit(1); - - case 'E': - option = getOptionString(i, argc, argv); - if (!split_first(option, var, val, '=')) - val = "True"; - - if (setenv(var.c_str(), val.c_str(), true) == -1) - panic("setenv: %s\n", strerror(errno)); - break; - - case 'I': - option = getOptionString(i, argc, argv); - pyconfig.addPath(option); - break; - - case 'P': - option = getOptionString(i, argc, argv); - pyconfig.writeLine(option); - break; - - case 'X': { - list<EmbedFile> lst; - EmbedMap::all(lst); - list<EmbedFile>::iterator i = lst.begin(); - list<EmbedFile>::iterator end = lst.end(); - - while (i != end) { - cprintf("Embedded File: %s\n", i->name); - cout.write(i->data, i->length); - ++i; - } - - return 0; - } - - default: - showBriefHelp(cerr); - panic("invalid argument '%s'\n", arg_str); - } - } else { - string file(arg_str); - string base, ext; - - if (!split_last(file, base, ext, '.') || ext != "py") - panic("Config file '%s' must end in '.py'\n", file); - - pyconfig.load(file); - configfile_found = true; - } - } - - if (outdir.empty()) { - char *env = getenv("OUTPUT_DIR"); - outdir = env ? env : "."; - } - - simout.setDirectory(outdir); - - char *env = getenv("CONFIG_OUTPUT"); - if (!env) - env = "config.out"; - configStream = simout.find(env); - - if (!configfile_found) - panic("no configuration file specified!"); - - // The configuration database is now complete; start processing it. - IniFile inifile; - if (!pyconfig.output(inifile)) - panic("Error processing python code"); - - // Initialize statistics database - Stats::InitSimStats(); - - // Now process the configuration hierarchy and create the SimObjects. - ConfigHierarchy configHierarchy(inifile); - configHierarchy.build(); - configHierarchy.createSimObjects(); - - // Parse and check all non-config-hierarchy parameters. - ParamContext::parseAllContexts(inifile); - ParamContext::checkAllContexts(); - - // Print hello message to stats file if it's actually a file. If - // it's not (i.e. it's cout or cerr) then we already did it above. - if (simout.isFile(*outputStream)) - sayHello(*outputStream); - - // Echo command line and all parameter settings to stats file as well. - echoCommandLine(argc, argv, *outputStream); - ParamContext::showAllContexts(*configStream); - - // Do a second pass to finish initializing the sim objects - SimObject::initAll(); - - // Restore checkpointed state, if any. - configHierarchy.unserializeSimObjects(); - - // Done processing the configuration database. - // Check for unreferenced entries. - if (inifile.printUnreferenced()) - panic("unreferenced sections/entries in the intermediate ini file"); - - SimObject::regAllStats(); - - // uncomment the following to get PC-based execution-time profile -#ifdef DO_PROFILE - init_profile((char *)&_init, (char *)&_fini); -#endif - - // Check to make sure that the stats package is properly initialized - Stats::check(); - - // Reset to put the stats in a consistent state. - Stats::reset(); - - warn("Entering event queue. Starting simulation...\n"); - SimStartup(); - while (!mainEventQueue.empty()) { - assert(curTick <= mainEventQueue.nextTick() && - "event scheduled in the past"); - - // forward current cycle to the time of the first event on the - // queue - curTick = mainEventQueue.nextTick(); - mainEventQueue.serviceOne(); - - if (async_event) { - async_event = false; - if (async_dump) { - async_dump = false; - - using namespace Stats; - SetupEvent(Dump, curTick); - } - - if (async_dumpreset) { - async_dumpreset = false; - - using namespace Stats; - SetupEvent(Dump | Reset, curTick); - } - - if (async_exit) { - async_exit = false; - new SimExitEvent("User requested STOP"); - } - - if (async_io || async_alarm) { - async_io = false; - async_alarm = false; - pollQueue.service(); - } - } - } - - // This should never happen... every conceivable way for the - // simulation to terminate (hit max cycles/insts, signal, - // simulated system halts/exits) generates an exit event, so we - // should never run out of events on the queue. - exitNow("no events on event loop! All CPUs must be idle.", 1); - - return 0; -} diff --git a/sim/param.cc b/sim/param.cc deleted file mode 100644 index bc81881d3..000000000 --- a/sim/param.cc +++ /dev/null @@ -1,794 +0,0 @@ -/* - * 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. - */ - -#include <algorithm> -#include <cassert> -#include <cstdio> -#include <list> -#include <string> -#include <vector> - -#include "base/inifile.hh" -#include "base/misc.hh" -#include "base/range.hh" -#include "base/str.hh" -#include "base/trace.hh" -#include "sim/config_node.hh" -#include "sim/configfile.hh" -#include "sim/param.hh" -#include "sim/sim_object.hh" - -using namespace std; - - -//////////////////////////////////////////////////////////////////////// -// -// BaseParam member definitions -// -//////////////////////////////////////////////////////////////////////// - -void -BaseParam::die(const string &err) const -{ - context->printErrorProlog(cerr); - cerr << " parameter '" << name << "': " - << err << endl; - abort(); -} - - -//////////////////////////////////////////////////////////////////////// -// -// Param<T> and VectorParam<T> member definitions -// -// We implement parsing & displaying values for various parameter -// types T using a set of overloaded functions: -// -// - parseParam(string s, T &value) parses s into value -// - showParam(ostream &os, T &value) displays value on os -// -// By making these independent functions, we can reuse the same code -// for type T in both Param<T> and VectorParam<T>. -// -// For enum types, the parseParam function requires additional -// arguments, in which case we must specialize the Param<T>::parse and -// VectorParam<T>::parse calls as well. -// -// Type-specific instances come first, followed by more generic -// templated versions and their instantiations. -// -//////////////////////////////////////////////////////////////////////// - -// -// The base implementations use to_number for parsing and '<<' for -// displaying, suitable for integer types. -// -template <class T> -bool -parseParam(const string &s, T &value) -{ - return to_number(s, value); -} - -template <class T> -void -showParam(ostream &os, T const &value) -{ - os << value; -} - -// -// Template specializations: -// - char (8-bit integer) -// - floating-point types -// - bool -// - string -// - -// Treat 8-bit ints (chars) as ints on output, not as chars -template <> -void -showParam(ostream &os, const char &value) -{ - os << (int)value; -} - - -template <> -void -showParam(ostream &os, const unsigned char &value) -{ - os << (unsigned int)value; -} - - -// Use sscanf() for FP types as to_number() only handles integers -template <> -bool -parseParam(const string &s, float &value) -{ - return (sscanf(s.c_str(), "%f", &value) == 1); -} - -template <> -bool -parseParam(const string &s, double &value) -{ - return (sscanf(s.c_str(), "%lf", &value) == 1); -} - -// Be flexible about what we take for bool -template <> -bool -parseParam(const string &s, bool &value) -{ - const string &ls = to_lower(s); - - if (ls == "true" || ls == "t" || ls == "yes" || ls == "y" || ls == "1") { - value = true; - return true; - } - - if (ls == "false" || ls == "f" || ls == "no" || ls == "n" || ls == "0") { - value = false; - return true; - } - - return false; -} - -// Display bools as strings -template <> -void -showParam(ostream &os, const bool &value) -{ - os << (value ? "true" : "false"); -} - - -// String requires no processing to speak of -template <> -bool -parseParam(const string &s, string &value) -{ - value = s; - return true; -} - -template <> -bool -parseParam(const string &s, Range<uint32_t> &value) -{ - value = s; - return value.valid(); -} - -template <> -bool -parseParam(const string &s, Range<uint64_t> &value) -{ - value = s; - return value.valid(); -} - -// -// End of parseParam/showParam definitions. Now we move on to -// incorporate them into the Param/VectorParam parse() and showValue() -// methods. -// - -// These definitions for Param<T>::parse and VectorParam<T>::parse -// work for any type for which parseParam() takes only two arguments -// (i.e., all the fundamental types like int, bool, etc.), thanks to -// overloading. -template <class T> -void -Param<T>::parse(const string &s) -{ - if (parseParam(s, value)) { - wasSet = true; - } - else { - string err("could not parse \""); - - err += s; - err += "\""; - - die(err); - } -} - -template <class T> -void -VectorParam<T>::parse(const string &s) -{ - if (s.empty()) { - wasSet = true; - return; - } - - vector<string> tokens; - - tokenize(tokens, s, ' '); - - value.resize(tokens.size()); - - for (int i = 0; i < tokens.size(); i++) { - // need to parse into local variable to handle vector<bool>, - // for which operator[] returns a special reference class - // that's not the same as 'bool&', (since it's a packed - // vector) - T scalar_value; - if (!parseParam(tokens[i], scalar_value)) { - string err("could not parse \""); - - err += s; - err += "\""; - - die(err); - } - - // assign parsed value to vector - value[i] = scalar_value; - } - - wasSet = true; -} - -// These definitions for Param<T>::showValue() and -// VectorParam<T>::showValue() work for any type where showParam() -// takes only two arguments (i.e., everything but the SimpleEnum and -// MappedEnum classes). -template <class T> -void -Param<T>::showValue(ostream &os) const -{ - showParam(os, value); -} - -template <class T> -void -VectorParam<T>::showValue(ostream &os) const -{ - for (int i = 0; i < value.size(); i++) { - if (i != 0) { - os << " "; - } - showParam(os, value[i]); - } -} - - -#ifdef INSURE_BUILD -#define INSTANTIATE_PARAM_TEMPLATES(type, typestr) \ -void Param<type>::showType(ostream &os) const { os << typestr; } \ -void VectorParam<type>::showType(ostream &os) const { \ - os << "vector of " << typestr; \ -} \ -template Param<type>; \ -template VectorParam<type>; - -#else -// instantiate all four methods (parse/show, scalar/vector) for basic -// types that can use the above templates -#define INSTANTIATE_PARAM_TEMPLATES(type, typestr) \ -template bool parseParam<type>(const string &s, type &value); \ -template void showParam<type>(ostream &os, type const &value); \ -template void Param<type>::parse(const string &); \ -template void VectorParam<type>::parse(const string &); \ -template void Param<type>::showValue(ostream &) const; \ -template void VectorParam<type>::showValue(ostream &) const; \ -template <> void Param<type>::showType(ostream &os) const { os << typestr; } \ -template <> void VectorParam<type>::showType(ostream &os) const { \ - os << "vector of " << typestr; \ -} -#endif - -INSTANTIATE_PARAM_TEMPLATES(unsigned long long, "ull") -INSTANTIATE_PARAM_TEMPLATES(signed long long, "sll") -INSTANTIATE_PARAM_TEMPLATES(unsigned long, "uns long") -INSTANTIATE_PARAM_TEMPLATES(signed long, "long") -INSTANTIATE_PARAM_TEMPLATES(unsigned int, "uns") -INSTANTIATE_PARAM_TEMPLATES(signed int, "int") -INSTANTIATE_PARAM_TEMPLATES(unsigned short, "uns short") -INSTANTIATE_PARAM_TEMPLATES(signed short, "short") -INSTANTIATE_PARAM_TEMPLATES(unsigned char, "uns char") -INSTANTIATE_PARAM_TEMPLATES(signed char, "char") - -INSTANTIATE_PARAM_TEMPLATES(float, "float") -INSTANTIATE_PARAM_TEMPLATES(double, "double") - -INSTANTIATE_PARAM_TEMPLATES(bool, "bool") -INSTANTIATE_PARAM_TEMPLATES(string, "string") - -INSTANTIATE_PARAM_TEMPLATES(Range<uint64_t>, "uint64 range") -INSTANTIATE_PARAM_TEMPLATES(Range<uint32_t>, "uint32 range") - -#undef INSTANTIATE_PARAM_TEMPLATES - -// -// SimpleEnumParam & MappedEnumParam must specialize their parse(), -// showValue(), and showType() methods. -// - -// -// SimpleEnumParam & SimpleEnumVectorParam -// -bool -parseEnumParam(const char *const *map, const int num_values, - const string &s, int &value) -{ - for (int i = 0; i < num_values; ++i) { - if (s == map[i]) { - value = i; - return true; - } - } - - return false; -} - -void -showEnumParam(ostream &os, - const char *const *map, const int num_values, - int value) -{ - assert(0 <= value && value < num_values); - os << map[value]; -} - -void -showEnumType(ostream &os, - const char *const *map, const int num_values) -{ - os << "{" << map[0]; - for (int i = 1; i < num_values; ++i) - os << "," << map[i]; - - os << "}"; -} - - -// -// MappedEnumParam & MappedEnumVectorParam -// -bool -parseEnumParam(const EnumParamMap *map, const int num_values, - const string &s, int &value) -{ - for (int i = 0; i < num_values; ++i) { - if (s == map[i].name) { - value = map[i].value; - return true; - } - } - - return false; -} - -void -showEnumParam(ostream &os, - const EnumParamMap *map, const int num_values, - int value) -{ - for (int i = 0; i < num_values; ++i) { - if (value == map[i].value) { - os << map[i].name; - return; - } - } - - // if we can't find a reverse mapping just print the int value - os << value; -} - -void -showEnumType(ostream &os, - const EnumParamMap *map, const int num_values) -{ - os << "{" << map[0].name; - for (int i = 1; i < num_values; ++i) - os << "," << map[i].name; - - os << "}"; -} - - -template <class Map> -void -EnumParam<Map>::parse(const string &s) -{ - if (parseEnumParam(map, num_values, s, value)) { - wasSet = true; - } else { - string err("no match for enum string \""); - - err += s; - err += "\""; - - die(err); - } -} - -template <class Map> -void -EnumVectorParam<Map>::parse(const string &s) -{ - vector<string> tokens; - - if (s.empty()) { - wasSet = true; - return; - } - - tokenize(tokens, s, ' '); - - value.resize(tokens.size()); - - for (int i = 0; i < tokens.size(); i++) { - if (!parseEnumParam(map, num_values, tokens[i], value[i])) { - string err("no match for enum string \""); - - err += s; - err += "\""; - - die(err); - } - } - - wasSet = true; -} - -template <class Map> -void -EnumParam<Map>::showValue(ostream &os) const -{ - showEnumParam(os, map, num_values, value); -} - -template <class Map> -void -EnumVectorParam<Map>::showValue(ostream &os) const -{ - for (int i = 0; i < value.size(); i++) { - if (i != 0) { - os << " "; - } - showEnumParam(os, map, num_values, value[i]); - } -} - -template <class Map> -void -EnumParam<Map>::showType(ostream &os) const -{ - showEnumType(os, map, num_values); -} - -template <class Map> -void -EnumVectorParam<Map>::showType(ostream &os) const -{ - os << "vector of"; - showEnumType(os, map, num_values); -} - -template class EnumParam<const char *>; -template class EnumVectorParam<const char *>; - -template class EnumParam<EnumParamMap>; -template class EnumVectorParam<EnumParamMap>; - -//////////////////////////////////////////////////////////////////////// -// -// SimObjectBaseParam methods -// -//////////////////////////////////////////////////////////////////////// - -bool -parseSimObjectParam(ParamContext *context, const string &s, SimObject *&value) -{ - SimObject *obj; - - if (to_lower(s) == "null") { - // explicitly set to null by user; assume that's OK - obj = NULL; - } - else { - obj = context->resolveSimObject(s); - - if (obj == NULL) - return false; - } - - value = obj; - return true; -} - - -void -SimObjectBaseParam::showValue(ostream &os, SimObject *value) const -{ - os << (value ? value->name() : "null"); -} - -void -SimObjectBaseParam::parse(const string &s, SimObject *&value) -{ - if (parseSimObjectParam(context, s, value)) { - wasSet = true; - } - else { - string err("could not resolve object name \""); - - err += s; - err += "\""; - - die(err); - } -} - -void -SimObjectBaseParam::parse(const string &s, vector<SimObject *>&value) -{ - vector<string> tokens; - - tokenize(tokens, s, ' '); - - value.resize(tokens.size()); - - for (int i = 0; i < tokens.size(); i++) { - if (!parseSimObjectParam(context, tokens[i], value[i])) { - string err("could not resolve object name \""); - - err += s; - err += "\""; - - die(err); - } - } - - wasSet = true; -} - -//////////////////////////////////////////////////////////////////////// -// -// ParamContext member definitions -// -//////////////////////////////////////////////////////////////////////// - -list<ParamContext *> *ParamContext::ctxList = NULL; - -ParamContext::ParamContext(const string &_iniSection, InitPhase _initPhase) - : iniFilePtr(NULL), // initialized on call to parseParams() - iniSection(_iniSection), paramList(NULL), - initPhase(_initPhase) -{ - // Put this context on global list for initialization - if (initPhase != NoAutoInit) { - if (ctxList == NULL) - ctxList = new list<ParamContext *>(); - - // keep list sorted by ascending initPhase values - list<ParamContext *>::iterator i = ctxList->begin(); - list<ParamContext *>::iterator end = ctxList->end(); - for (; i != end; ++i) { - if (initPhase <= (*i)->initPhase) { - // found where we want to insert - break; - } - } - // (fall through case: insert at end) - ctxList->insert(i, this); - } -} - - -void -ParamContext::addParam(BaseParam *param) -{ - getParamList()->push_back(param); -} - - -void -ParamContext::parseParams(IniFile &iniFile) -{ - iniFilePtr = &iniFile; // set object member - - ParamList::iterator i; - - for (i = getParamList()->begin(); i != getParamList()->end(); ++i) { - string string_value; - - if (iniFile.find(iniSection, (*i)->name, string_value)) - (*i)->parse(string_value); - } -} - - -// Check parameter values for validity & consistency. Default -// implementation is no-op; derive subclass & override to add -// actual functionality here. -void -ParamContext::checkParams() -{ - // nada -} - - -// Clean up context-related objects at end of execution. Default -// implementation is no-op; derive subclass & override to add actual -// functionality here. -void -ParamContext::cleanup() -{ - // nada -} - - -void -ParamContext::describeParams(ostream &os) -{ - ParamList::iterator i; - - for (i = getParamList()->begin(); i != getParamList()->end(); ++i) { - BaseParam *p = *i; - - os << p->name << " ("; - p->showType(os); - os << "): " << p->description << "\n"; - } -} - - - -void -ParamContext::showParams(ostream &os) -{ - ParamList::iterator i; - - for (i = getParamList()->begin(); i != getParamList()->end(); ++i) { - BaseParam *p = *i; - - if (p->isValid()) { - os << p->name << "="; - p->showValue(os); - os << endl; - } - else { - os << "// "<< p->name << " not specified" << endl; - } - } -} - - -void -ParamContext::printErrorProlog(ostream &os) -{ - os << "Parameter error in section [" << iniSection << "]: " << endl; -} - -// -// Resolve an object name to a SimObject pointer. The object will be -// created as a side-effect if necessary. If the name contains a -// colon (e.g., "iq:IQ"), then the object is local (invisible to -// outside this context). If there is no colon, the name needs to be -// resolved through the configuration hierarchy (only possible for -// SimObjectBuilder objects, which return non-NULL for configNode()). -// -SimObject * -ParamContext::resolveSimObject(const string &name) -{ - ConfigNode *n = getConfigNode(); - return n ? n->resolveSimObject(name) : NULL; -} - - -// -// static method: call parseParams() on all registered contexts -// -void -ParamContext::parseAllContexts(IniFile &iniFile) -{ - list<ParamContext *>::iterator iter; - - for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) { - ParamContext *pc = *iter; - - pc->parseParams(iniFile); - } -} - - -// -// static method: call checkParams() on all registered contexts -// -void -ParamContext::checkAllContexts() -{ - list<ParamContext *>::iterator iter; - - for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) { - ParamContext *pc = *iter; - - pc->checkParams(); - } -} - - -// -// static method: call showParams() on all registered contexts -// -void -ParamContext::showAllContexts(ostream &os) -{ - list<ParamContext *>::iterator iter; - - for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) { - ParamContext *pc = *iter; - - os << "[" << pc->iniSection << "]" << endl; - pc->showParams(os); - os << endl; - } -} - - -// -// static method: call cleanup() on all registered contexts -// -void -ParamContext::cleanupAllContexts() -{ - list<ParamContext *>::iterator iter; - - for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) { - ParamContext *pc = *iter; - - pc->cleanup(); - } -} - - -// -// static method: call describeParams() on all registered contexts -// -void -ParamContext::describeAllContexts(ostream &os) -{ - list<ParamContext *>::iterator iter; - - for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) { - ParamContext *pc = *iter; - - os << "[" << pc->iniSection << "]\n"; - pc->describeParams(os); - os << endl; - } -} diff --git a/sim/param.hh b/sim/param.hh deleted file mode 100644 index 4a1b8bda1..000000000 --- a/sim/param.hh +++ /dev/null @@ -1,788 +0,0 @@ -/* - * 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. - */ - -#ifndef __SIM_PARAM_HH__ -#define __SIM_PARAM_HH__ - -#include <iostream> -#include <list> -#include <string> -#include <vector> - -#include "sim/configfile.hh" -#include "sim/startup.hh" - -// forward decls -class BaseParam; -class SimObject; - -// -// The context of a parameter definition... usually a subclass of -// SimObjectBuilder (which derives from ParamContext), but abstracted -// here to support more global simulator control parameters as well. -// -class ParamContext : protected StartupCallback -{ - private: - - // static list of all ParamContext objects, built as a side effect - // of the ParamContext constructor - static std::list<ParamContext *> *ctxList; - - protected: - - // .ini file (database) for parameter lookup... initialized on call - // to parseParams() - IniFile *iniFilePtr; - - // .ini file section for parameter lookup - const std::string iniSection; - - typedef std::vector<BaseParam *> ParamList; - - // list of parameters defined in this context - ParamList *paramList; - - ParamList *getParamList() { - if (!paramList) - paramList = new ParamList; - return paramList; - } - - public: - - /// Initialization phases for ParamContext objects. - enum InitPhase { - NoAutoInit = -1, ///< Don't initialize at all... params - /// will be parsed later (used by - /// SimObjectBuilder, which parses - /// params in SimObject::create(). - OutputInitPhase = 0, ///< Output stream initialization - TraceInitPhase = 1, ///< Trace context initialization: - /// depends on output streams, but - /// needs to come before others so we - /// can use tracing in other - /// ParamContext init code - StatsInitPhase = 2, ///< Stats output initialization - DefaultInitPhase = 3 ///< Everything else - }; - - /// Records the initialization phase for this ParamContext. - InitPhase initPhase; - - /// Constructor. - /// @param _iniSection Name of .ini section corresponding to this context. - /// @param _initPhase Initialization phase (see InitPhase). - ParamContext(const std::string &_iniSection, - InitPhase _initPhase = DefaultInitPhase); - - virtual ~ParamContext() {} - - // add a parameter to the context... called from the parameter - // object's constructor (see BaseParam::BaseParam()) - void addParam(BaseParam *); - - // call parse() on all params in this context to convert string - // representations to parameter values - virtual void parseParams(IniFile &iniFile); - - // Check parameter values for validity & consistency. Default - // implementation is no-op; derive subclass & override to add - // actual functionality here - virtual void checkParams(); - - // Clean up at end of execution: close file descriptors, etc. - // Default implementation is no-op; derive subclass & override to - // add actual functionality here - virtual void cleanup(); - - // dump parameter descriptions - void describeParams(std::ostream &); - - // Display the parameters & values used - void showParams(std::ostream &); - - // print context information for parameter error - virtual void printErrorProlog(std::ostream &); - - // resolve a SimObject name in this context to an object pointer. - virtual SimObject *resolveSimObject(const std::string &name); - - // generate the name for this instance of this context (used as a - // prefix to create unique names in resolveSimObject() - virtual const std::string &getInstanceName() { return iniSection; } - - // return the configuration hierarchy node for this context. Bare - // ParamContext objects have no corresponding node, so the default - // implementation returns NULL. - virtual ConfigNode *getConfigNode() { return NULL; } - - // Parse all parameters registered with all ParamContext objects. - static void parseAllContexts(IniFile &iniFile); - - // Check all parameters registered with all ParamContext objects. - // (calls checkParams() on each) - static void checkAllContexts(); - - // Print all parameter values on indicated ostream. - static void showAllContexts(std::ostream &os); - - // Clean up all registered ParamContext objects. (calls cleanup() - // on each) - static void cleanupAllContexts(); - - // print descriptions of all parameters registered with all - // ParamContext objects - static void describeAllContexts(std::ostream &os); -}; - - -// -// Base class for all parameter objects -// -class BaseParam -{ - public: - - ParamContext *context; - std::string name; - std::string description; // text description for help message - bool wasSet; // true if parameter was set by user - bool hasDefault; // true if parameter has default value - - BaseParam(ParamContext *_context, const std::string &_name, - const std::string &_description, bool _hasDefault) - : context(_context), name(_name), description(_description), - wasSet(false), hasDefault(_hasDefault) - { - context->addParam(this); - } - - virtual ~BaseParam() {} - - // a parameter is valid only if its value was set by the user or - // it has a default value - bool isValid() const - { - return (wasSet || hasDefault); - } - - // set value by parsing string - virtual void parse(const std::string &s) = 0; - - // display value to stream - virtual void showValue(std::ostream &) const = 0; - - // display type to stream - virtual void showType(std::ostream &) const = 0; - - // signal parse or usage error - virtual void die(const std::string &err) const; -}; - -// -// Template classes to specialize parameters to specific types. -// -// Param<T> is for single-valued (scalar) parameters of type T. -// VectorParam<T> is for multi-valued (vector) parameters of type T. -// These are specified in the .ini file as a space-delimited list of -// arguments. -// -template <class T> -class Param : public BaseParam -{ - protected: - - T value; - - public: - - // Param with default value: set value to default - Param(ParamContext *context, - const std::string &name, const std::string &description, T dfltValue) - : BaseParam(context, name, description, true), - value(dfltValue) - { - } - - // Param with no default value: leave value uninitialized - Param(ParamContext *context, - const std::string &name, const std::string &description) - : BaseParam(context, name, description, false) - { - } - - virtual ~Param() {} - - operator T&() - { - // if we attempt to reference an invalid parameter (i.e., one - // with no default value that was not set by the user), die. - if (!isValid()) - die("not found"); - return value; - } - - // display value to stream - virtual void showValue(std::ostream &os) const; - - // display type to stream - virtual void showType(std::ostream &) const; - - // set value by parsing string - virtual void parse(const std::string &s); -}; - - -// -// Template class for vector-valued parameters (lists) -// -template <class T> -class VectorParam : public BaseParam -{ - protected: - - std::vector<T> value; - - public: - - typedef typename std::vector<T>::size_type size_type; - - // Param with default value: set value to default - VectorParam(ParamContext *context, const std::string &name, - const std::string &description, - const std::vector<T> &dfltValue) - : BaseParam(context, name, description, true), - value(dfltValue) - { - } - - // Param with no default value: leave value uninitialized - VectorParam(ParamContext *context, - const std::string &name, const std::string &description) - : BaseParam(context, name, description, false) - { - } - - virtual ~VectorParam() {} - - // basic vector access methods - size_type size() const - { - if (!isValid()) - die("not found"); - return value.size(); - } - - const T &operator[](size_type n) const - { - if (!isValid()) - die("not found"); - return value[n]; - } - - // return reference to value vector - operator std::vector<T>&() - { - if (!isValid()) - die("not found"); - return value; - } - - // display value to stream - virtual void showValue(std::ostream &os) const; - - // display type to stream - virtual void showType(std::ostream &) const; - - // set value by parsing string - virtual void parse(const std::string &s); -}; - -// -// Specialization of Param<int> and VectorParam<int> to handle -// enumerated types is done in two ways, using SimpleEnumParam and -// MappedEnumParam (and their vector counterparts, -// SimpleEnumVectorParam and MappedEnumVectorParam). SimpleEnumParam -// takes an array of strings and maps them to integers based on array -// index. MappedEnumParam takes an array of string-to-int mappings, -// allowing for mapping strings to non-contiguous integer values, or -// mapping multiple strings to the same integer value. -// -// Both SimpleEnumParam and MappedEnumParam are implemented using a -// single template class, EnumParam<Map>, which takes the type of the map -// as a parameter (const char * or EnumParamMap). Similarly, -// SimpleEnumVectorParam and MappedEnumVectorParam are both -// implemented using EnumVectorParam<Map>. -// -template <class Map> -class EnumParam : public Param<int> -{ - const int num_values; - const Map *map; - - public: - - // Param with default value: set value to default - EnumParam(ParamContext *context, - const std::string &name, const std::string &description, - const Map *_map, int _num_values, - int dfltValue) - : Param<int>(context, name, description, dfltValue), - num_values(_num_values), map(_map) - { - } - - // Param with no default value: leave value uninitialized - EnumParam(ParamContext *context, - const std::string &name, const std::string &description, - const Map *_map, int _num_values) - : Param<int>(context, name, description), - num_values(_num_values), map(_map) - { - } - - virtual ~EnumParam() {} - - // display value to stream - virtual void showValue(std::ostream &os) const; - - // display type to stream - virtual void showType(std::ostream &) const; - - // set value by parsing string - virtual void parse(const std::string &s); -}; - -// -// Vector counterpart to SimpleEnumParam -// -template <class Map> -class EnumVectorParam : public VectorParam<int> -{ - const int num_values; - const Map *map; - - public: - - // Param with default value: set value to default - EnumVectorParam(ParamContext *context, - const std::string &name, const std::string &description, - const Map *_map, int _num_values, - std::vector<int> &dfltValue) - : VectorParam<int>(context, name, description, dfltValue), - num_values(_num_values), map(_map) - { - } - - // Param with no default value: leave value uninitialized - EnumVectorParam(ParamContext *context, - const std::string &name, const std::string &description, - const Map *_map, int _num_values) - : VectorParam<int>(context, name, description), - num_values(_num_values), map(_map) - { - } - - virtual ~EnumVectorParam() {} - - // display value to stream - virtual void showValue(std::ostream &os) const; - - // display type to stream - virtual void showType(std::ostream &) const; - - // set value by parsing string - virtual void parse(const std::string &s); -}; - -// Specialize EnumParam for a particular enumeration type ENUM -// (automates casting to get value of enum type) - -template <class ENUM> -class SimpleEnumParam : public EnumParam<const char *> -{ - public: - - SimpleEnumParam(ParamContext *context, - const std::string &name, const std::string &description, - const char **_map, int _num_values, - ENUM dfltValue) - : EnumParam<const char *>(context, name, description, - _map, _num_values, (int)dfltValue) - { - } - - SimpleEnumParam(ParamContext *context, - const std::string &name, const std::string &description, - const char **_map, int _num_values) - : EnumParam<const char *>(context, name, description, - _map, _num_values) - { - } - - operator ENUM() const - { - if (!isValid()) - die("not found"); - return (ENUM)value; - } -}; - - -// Specialize EnumParam for a particular enumeration type ENUM -// (automates casting to get value of enum type) - -template <class ENUM> -class SimpleEnumVectorParam : public EnumVectorParam<const char *> -{ - public: - - // skip default value constructor: too much pain to convert - // vector<ENUM> initializer to vector<int> - - - SimpleEnumVectorParam(ParamContext *context, - const std::string &name, - const std::string &description, - const char **_map, int _num_values) - : EnumVectorParam<const char *>(context, name, description, - _map, _num_values) - { - } - - ENUM operator[](size_type n) - { - if (!isValid()) - die("not found"); - return (ENUM)value[n]; - } -}; - - -// -// Handle enums via string-to-int map (see comment above). -// - -// An array of string-to-int mappings must be supplied using the -// following type. -typedef struct { - const char *name; - int value; -} EnumParamMap; - -// Specialize EnumParam for a particular enumeration type ENUM -// (automates casting to get value of enum type) - -template <class ENUM> -class MappedEnumParam : public EnumParam<EnumParamMap> -{ - public: - - MappedEnumParam(ParamContext *context, - const std::string &name, const std::string &description, - const EnumParamMap *_map, int _num_values, - ENUM dfltValue) - : EnumParam<EnumParamMap>(context, name, description, - _map, _num_values, (int)dfltValue) - { - } - - MappedEnumParam(ParamContext *context, - const std::string &name, const std::string &description, - const EnumParamMap *_map, int _num_values) - : EnumParam<EnumParamMap>(context, name, description, - _map, _num_values) - { - } - - operator ENUM() - { - if (!isValid()) - die("not found"); - return (ENUM)value[this->n]; - } -}; - - -// Specialize EnumParam for a particular enumeration type ENUM -// (automates casting to get value of enum type) - -template <class ENUM> -class MappedEnumVectorParam : public EnumVectorParam<EnumParamMap> -{ - public: - - // skip default value constructor: too much pain to convert - // vector<ENUM> initializer to vector<int> - - - MappedEnumVectorParam(ParamContext *context, - const std::string &name, - const std::string &description, - const EnumParamMap *_map, int _num_values) - : EnumVectorParam<EnumParamMap>(context, name, description, - _map, _num_values) - { - } - - ENUM operator[](size_type n) - { - if (!isValid()) - die("not found"); - return (ENUM)value[n]; - } -}; - - -// -// Parameters that point to other simulation objects (e.g. caches, -// busses, etc.) are handled by specializing SimObjectBaseParam to the -// specific subtype. The main purpose of SimObjectBaseParam is to -// provide a place to stick several helper functions common to all -// SimObject-derived parameters. -// -class SimObjectBaseParam : public BaseParam -{ - public: - - SimObjectBaseParam(ParamContext *context, const std::string &name, - const std::string &description, bool hasDefault) - : BaseParam(context, name, description, hasDefault) - { - } - - virtual ~SimObjectBaseParam() {} - - // helper function for SimObjectParam<T>::showValue() - void showValue(std::ostream &os, SimObject *obj) const; - - // helper function for SimObjectParam<T>::parse() - void parse(const std::string &s, SimObject *&value); - - // helper function for SimObjectParam<T>::parse() - void parse(const std::string &s, std::vector<SimObject *>&value_vec); -}; - - -// -// Parameter to a specific type of SimObject. Note that T must be a -// pointer to a class derived from SimObject (e.g., <CPU *>). -// - -template <class T> class SimObjectParam; - -template <class T> -class SimObjectParam<T *> : public SimObjectBaseParam -{ - protected: - - T *value; - - public: - - // initialization w/o default - SimObjectParam(ParamContext *context, - const std::string &name, const std::string &description) - : SimObjectBaseParam(context, name, description, false) - { - } - - // initialization wit=h default - SimObjectParam(ParamContext *context, - const std::string &name, const std::string &description, - T *dfltValue) - : SimObjectBaseParam(context, name, description, true), - value(dfltValue) - { - } - - virtual ~SimObjectParam() {} - - // convert to pointer - operator T*() - { - if (!isValid()) - die("not found"); - return value; - } - - T *operator->() const - { - if (!isValid()) - die("not found"); - return value; - } - - // display value to stream - virtual void showValue(std::ostream &os) const - { - SimObjectBaseParam::showValue(os, value); - } - - // display type to stream: see REGISTER_SIM_OBJECT macro in - // sim_object.hh for declaration - virtual void showType(std::ostream &os) const; - - // set value by parsing string - virtual void parse(const std::string &s) - { - SimObject *so_ptr; - // first parse to generic SimObject * - SimObjectBaseParam::parse(s, so_ptr); - // now dynamic_cast to specific derived type - value = dynamic_cast<T *>(so_ptr); - // check for failure of dynamic_cast - if (value == NULL && so_ptr != NULL) - die("not of appropriate type"); - } -}; - - -// -// Vector counterpart to SimObjectParam<T> -// - -template <class T> class SimObjectVectorParam; - -template <class T> -class SimObjectVectorParam<T *> : public SimObjectBaseParam -{ - protected: - - std::vector<T *> value; - - public: - - typedef typename std::vector<T *>::size_type size_type; - - SimObjectVectorParam(ParamContext *context, - const std::string &name, - const std::string &description) - : SimObjectBaseParam(context, name, description, false) - { - } - - SimObjectVectorParam(ParamContext *context, - const std::string &name, - const std::string &description, - std::vector<T *> dfltValue) - : SimObjectBaseParam(context, name, description, true), - value(dfltValue) - { - } - - virtual ~SimObjectVectorParam() {} - - // basic vector access methods - size_type size() const - { - if (!isValid()) - die("not found"); - return value.size(); - } - - T *&operator[](size_type n) - { - if (!isValid()) - die("not found"); - return value[n]; - } - - // return reference to value vector - operator std::vector<T *>&() - { - if (!isValid()) - die("not found"); - return value; - } - - // display value to stream - virtual void showValue(std::ostream &os) const - { - for (int i = 0; i < value.size(); i++) { - if (i != 0) - os << " "; - SimObjectBaseParam::showValue(os, value[i]); - } - } - - // display type to stream: see - virtual void showType(std::ostream &os) const; - - // set value by parsing string - virtual void parse(const std::string &s) - { - std::vector<SimObject *> so_ptr_vec; - // first parse to generic SimObject * vector (from SimObjectBaseParam) - SimObjectBaseParam::parse(s, so_ptr_vec); - - value.resize(so_ptr_vec.size()); - - for (int i = 0; i < so_ptr_vec.size(); ++i) { - // now dynamic_cast to specific derived type - value[i] = dynamic_cast<T *>(so_ptr_vec[i]); - // check for failure of dynamic_cast - if (value[i] == NULL && so_ptr_vec[i] != NULL) - die("not of appropriate type"); - } - } -}; - -// -// Macro to define showType() methods for SimObjectParam & -// SimObjectVectorParam. Can't do this automatically as it requires a -// string name for the type, which you can't get from a template -// argument. For concrete derived SimObject types, this macro is -// automatically invoked by REGISTER_SIM_OBJECT() (see sim_object.hh). -// -#define DEFINE_SIM_OBJECT_CLASS_NAME(CLASS_NAME, OBJ_CLASS) \ -template<> \ -void \ -SimObjectParam<OBJ_CLASS *>::showType(std::ostream &os) const \ -{ \ - os << CLASS_NAME; \ -} \ - \ -template<> \ -void \ -SimObjectVectorParam<OBJ_CLASS *>::showType(std::ostream &os) const \ -{ \ - os << "vector of " << CLASS_NAME; \ -} - - -// -// Declarations for low-level parsing & displaying functions. These -// are used internally, but should not be used directly by clients of -// the parameter mechanism, but are declared here so they can be -// shared with the serialization code (see sim/serialize.cc). -template <class T> bool parseParam(const std::string &str, T &data); -template <class T> void showParam(std::ostream &os, const T &data); - -#endif // _SIM_PARAM_HH_ diff --git a/sim/process.cc b/sim/process.cc deleted file mode 100644 index a84a4f7ba..000000000 --- a/sim/process.cc +++ /dev/null @@ -1,446 +0,0 @@ -/* - * 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. - */ - -#include <unistd.h> -#include <fcntl.h> - -#include <cstdio> -#include <string> - -#include "base/intmath.hh" -#include "base/loader/object_file.hh" -#include "base/loader/symtab.hh" -#include "base/statistics.hh" -#include "config/full_system.hh" -#include "cpu/cpu_exec_context.hh" -#include "cpu/exec_context.hh" -#include "cpu/smt.hh" -#include "encumbered/cpu/full/thread.hh" -#include "encumbered/eio/eio.hh" -#include "encumbered/mem/functional/main.hh" -#include "sim/builder.hh" -#include "sim/process.hh" -#include "sim/stats.hh" -#include "sim/syscall_emul.hh" - -#include "arch/process.hh" - -using namespace std; -using namespace TheISA; - -// -// The purpose of this code is to fake the loader & syscall mechanism -// when there's no OS: thus there's no resone to use it in FULL_SYSTEM -// mode when we do have an OS -// -#if FULL_SYSTEM -#error "process.cc not compatible with FULL_SYSTEM" -#endif - -// current number of allocated processes -int num_processes = 0; - -Process::Process(const string &nm, - int stdin_fd, // initial I/O descriptors - int stdout_fd, - int stderr_fd) - : SimObject(nm) -{ - // allocate memory space - memory = new MainMemory(nm + ".MainMem"); - - // allocate initial register file - init_regs = new RegFile; - memset(init_regs, 0, sizeof(RegFile)); - - cpuXC = new CPUExecContext(init_regs); - - // initialize first 3 fds (stdin, stdout, stderr) - fd_map[STDIN_FILENO] = stdin_fd; - fd_map[STDOUT_FILENO] = stdout_fd; - fd_map[STDERR_FILENO] = stderr_fd; - - // mark remaining fds as free - for (int i = 3; i <= MAX_FD; ++i) { - fd_map[i] = -1; - } - - mmap_start = mmap_end = 0; - nxm_start = nxm_end = 0; - // other parameters will be initialized when the program is loaded -} - -void -Process::regStats() -{ - using namespace Stats; - - num_syscalls - .name(name() + ".PROG:num_syscalls") - .desc("Number of system calls") - ; -} - -// -// static helper functions -// -int -Process::openInputFile(const string &filename) -{ - int fd = open(filename.c_str(), O_RDONLY); - - if (fd == -1) { - perror(NULL); - cerr << "unable to open \"" << filename << "\" for reading\n"; - fatal("can't open input file"); - } - - return fd; -} - - -int -Process::openOutputFile(const string &filename) -{ - int fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0774); - - if (fd == -1) { - perror(NULL); - cerr << "unable to open \"" << filename << "\" for writing\n"; - fatal("can't open output file"); - } - - return fd; -} - - -int -Process::registerExecContext(ExecContext *xc) -{ - // add to list - int myIndex = execContexts.size(); - execContexts.push_back(xc); - - if (myIndex == 0) { - // copy process's initial regs struct - // Hack for now to copy init regs - xc->copyArchRegs(cpuXC->getProxy()); - } - - // return CPU number to caller and increment available CPU count - return myIndex; -} - -void -Process::startup() -{ - if (execContexts.empty()) - return; - - // first exec context for this process... initialize & enable - ExecContext *xc = execContexts[0]; - - // mark this context as active so it will start ticking. - xc->activate(0); -} - -void -Process::replaceExecContext(ExecContext *xc, int xcIndex) -{ - if (xcIndex >= execContexts.size()) { - panic("replaceExecContext: bad xcIndex, %d >= %d\n", - xcIndex, execContexts.size()); - } - - execContexts[xcIndex] = xc; -} - -// map simulator fd sim_fd to target fd tgt_fd -void -Process::dup_fd(int sim_fd, int tgt_fd) -{ - if (tgt_fd < 0 || tgt_fd > MAX_FD) - panic("Process::dup_fd tried to dup past MAX_FD (%d)", tgt_fd); - - fd_map[tgt_fd] = sim_fd; -} - - -// generate new target fd for sim_fd -int -Process::alloc_fd(int sim_fd) -{ - // in case open() returns an error, don't allocate a new fd - if (sim_fd == -1) - return -1; - - // find first free target fd - for (int free_fd = 0; free_fd < MAX_FD; ++free_fd) { - if (fd_map[free_fd] == -1) { - fd_map[free_fd] = sim_fd; - return free_fd; - } - } - - panic("Process::alloc_fd: out of file descriptors!"); -} - - -// free target fd (e.g., after close) -void -Process::free_fd(int tgt_fd) -{ - if (fd_map[tgt_fd] == -1) - warn("Process::free_fd: request to free unused fd %d", tgt_fd); - - fd_map[tgt_fd] = -1; -} - - -// look up simulator fd for given target fd -int -Process::sim_fd(int tgt_fd) -{ - if (tgt_fd > MAX_FD) - return -1; - - return fd_map[tgt_fd]; -} - - - -// -// need to declare these here since there is no concrete Process type -// that can be constructed (i.e., no REGISTER_SIM_OBJECT() macro call, -// which is where these get declared for concrete types). -// -DEFINE_SIM_OBJECT_CLASS_NAME("Process", Process) - - -//////////////////////////////////////////////////////////////////////// -// -// LiveProcess member definitions -// -//////////////////////////////////////////////////////////////////////// - - -static void -copyStringArray(vector<string> &strings, Addr array_ptr, Addr data_ptr, - FunctionalMemory *memory) -{ - Addr data_ptr_swap; - for (int i = 0; i < strings.size(); ++i) { - data_ptr_swap = htog(data_ptr); - memory->access(Write, array_ptr, &data_ptr_swap, sizeof(Addr)); - memory->writeString(data_ptr, strings[i].c_str()); - array_ptr += sizeof(Addr); - data_ptr += strings[i].size() + 1; - } - // add NULL terminator - data_ptr = 0; - memory->access(Write, array_ptr, &data_ptr, sizeof(Addr)); -} - -LiveProcess::LiveProcess(const string &nm, ObjectFile *objFile, - int stdin_fd, int stdout_fd, int stderr_fd, - vector<string> &argv, vector<string> &envp) - : Process(nm, stdin_fd, stdout_fd, stderr_fd) -{ - prog_fname = argv[0]; - - prog_entry = objFile->entryPoint(); - text_base = objFile->textBase(); - text_size = objFile->textSize(); - data_base = objFile->dataBase(); - data_size = objFile->dataSize() + objFile->bssSize(); - brk_point = roundUp(data_base + data_size, VMPageSize); - - // load object file into target memory - objFile->loadSections(memory); - - // load up symbols, if any... these may be used for debugging or - // profiling. - if (!debugSymbolTable) { - debugSymbolTable = new SymbolTable(); - if (!objFile->loadGlobalSymbols(debugSymbolTable) || - !objFile->loadLocalSymbols(debugSymbolTable)) { - // didn't load any symbols - delete debugSymbolTable; - debugSymbolTable = NULL; - } - } - - // Set up stack. On Alpha, stack goes below text section. This - // code should get moved to some architecture-specific spot. - stack_base = text_base - (409600+4096); - - // Set up region for mmaps. Tru64 seems to start just above 0 and - // grow up from there. - mmap_start = mmap_end = 0x10000; - - // Set pointer for next thread stack. Reserve 8M for main stack. - next_thread_stack_base = stack_base - (8 * 1024 * 1024); - - // Calculate how much space we need for arg & env arrays. - int argv_array_size = sizeof(Addr) * (argv.size() + 1); - int envp_array_size = sizeof(Addr) * (envp.size() + 1); - int arg_data_size = 0; - for (int i = 0; i < argv.size(); ++i) { - arg_data_size += argv[i].size() + 1; - } - int env_data_size = 0; - for (int i = 0; i < envp.size(); ++i) { - env_data_size += envp[i].size() + 1; - } - - int space_needed = - argv_array_size + envp_array_size + arg_data_size + env_data_size; - // for SimpleScalar compatibility - if (space_needed < 16384) - space_needed = 16384; - - // set bottom of stack - stack_min = stack_base - space_needed; - // align it - stack_min &= ~7; - stack_size = stack_base - stack_min; - - // map out initial stack contents - Addr argv_array_base = stack_min + sizeof(uint64_t); // room for argc - Addr envp_array_base = argv_array_base + argv_array_size; - Addr arg_data_base = envp_array_base + envp_array_size; - Addr env_data_base = arg_data_base + arg_data_size; - - // write contents to stack - uint64_t argc = argv.size(); - argc = htog(argc); - memory->access(Write, stack_min, &argc, sizeof(uint64_t)); - - copyStringArray(argv, argv_array_base, arg_data_base, memory); - copyStringArray(envp, envp_array_base, env_data_base, memory); - - cpuXC->setIntReg(ArgumentReg0, argc); - cpuXC->setIntReg(ArgumentReg1, argv_array_base); - cpuXC->setIntReg(StackPointerReg, stack_min); - cpuXC->setIntReg(GlobalPointerReg, objFile->globalPointer()); - cpuXC->setPC(prog_entry); - cpuXC->setNextPC(prog_entry + sizeof(MachInst)); -} - -void -LiveProcess::syscall(ExecContext *xc) -{ - num_syscalls++; - - int64_t callnum = xc->readIntReg(SyscallNumReg); - - SyscallDesc *desc = getDesc(callnum); - if (desc == NULL) - fatal("Syscall %d out of range", callnum); - - desc->doSyscall(callnum, this, xc); -} - -LiveProcess * -LiveProcess::create(const string &nm, - int stdin_fd, int stdout_fd, int stderr_fd, - string executable, - vector<string> &argv, vector<string> &envp) -{ - LiveProcess *process = NULL; - ObjectFile *objFile = createObjectFile(executable); - if (objFile == NULL) { - fatal("Can't load object file %s", executable); - } - - // set up syscall emulation pointer for the current ISA - process = createProcess(nm, objFile, - stdin_fd, stdout_fd, stderr_fd, - argv, envp); - - delete objFile; - - if (process == NULL) - fatal("Unknown error creating process object."); - - return process; -} - - - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(LiveProcess) - - VectorParam<string> cmd; - Param<string> executable; - Param<string> input; - Param<string> output; - VectorParam<string> env; - -END_DECLARE_SIM_OBJECT_PARAMS(LiveProcess) - - -BEGIN_INIT_SIM_OBJECT_PARAMS(LiveProcess) - - INIT_PARAM(cmd, "command line (executable plus arguments)"), - INIT_PARAM(executable, "executable (overrides cmd[0] if set)"), - INIT_PARAM(input, "filename for stdin (dflt: use sim stdin)"), - INIT_PARAM(output, "filename for stdout/stderr (dflt: use sim stdout)"), - INIT_PARAM(env, "environment settings") - -END_INIT_SIM_OBJECT_PARAMS(LiveProcess) - - -CREATE_SIM_OBJECT(LiveProcess) -{ - string in = input; - string out = output; - - // initialize file descriptors to default: same as simulator - int stdin_fd, stdout_fd, stderr_fd; - - if (in == "stdin" || in == "cin") - stdin_fd = STDIN_FILENO; - else - stdin_fd = Process::openInputFile(input); - - if (out == "stdout" || out == "cout") - stdout_fd = STDOUT_FILENO; - else if (out == "stderr" || out == "cerr") - stdout_fd = STDERR_FILENO; - else - stdout_fd = Process::openOutputFile(out); - - stderr_fd = (stdout_fd != STDOUT_FILENO) ? stdout_fd : STDERR_FILENO; - - return LiveProcess::create(getInstanceName(), - stdin_fd, stdout_fd, stderr_fd, - (string)executable == "" ? cmd[0] : executable, - cmd, env); -} - -REGISTER_SIM_OBJECT("LiveProcess", LiveProcess) diff --git a/sim/process.hh b/sim/process.hh deleted file mode 100644 index 3a48f128c..000000000 --- a/sim/process.hh +++ /dev/null @@ -1,219 +0,0 @@ -/* - * 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. - */ - -#ifndef __PROCESS_HH__ -#define __PROCESS_HH__ - -// -// The purpose of this code is to fake the loader & syscall mechanism -// when there's no OS: thus there's no reason to use it in FULL_SYSTEM -// mode when we do have an OS. -// -#include "config/full_system.hh" - -#if !FULL_SYSTEM - -#include <vector> - -#include "arch/isa_traits.hh" -#include "sim/sim_object.hh" -#include "sim/stats.hh" -#include "base/statistics.hh" -#include "base/trace.hh" - -class CPUExecContext; -class ExecContext; -class FunctionalMemory; -class SyscallDesc; -class Process : public SimObject -{ - protected: - typedef TheISA::RegFile RegFile; - typedef TheISA::MachInst MachInst; - public: - - // have we initialized an execution context from this process? If - // yes, subsequent contexts are assumed to be for dynamically - // created threads and are not initialized. - bool initialContextLoaded; - - // execution contexts associated with this process - std::vector<ExecContext *> execContexts; - - // number of CPUs (esxec contexts, really) assigned to this process. - unsigned int numCpus() { return execContexts.size(); } - - // record of blocked context - struct WaitRec - { - Addr waitChan; - ExecContext *waitingContext; - - WaitRec(Addr chan, ExecContext *ctx) - : waitChan(chan), waitingContext(ctx) - { - } - }; - - // list of all blocked contexts - std::list<WaitRec> waitList; - - RegFile *init_regs; // initial register contents - CPUExecContext *cpuXC; // XC to hold the init_regs - - Addr text_base; // text (code) segment base - unsigned text_size; // text (code) size in bytes - - Addr data_base; // initialized data segment base - unsigned data_size; // initialized data + bss size in bytes - - Addr brk_point; // top of the data segment - - Addr stack_base; // stack segment base (highest address) - unsigned stack_size; // initial stack size - Addr stack_min; // lowest address accessed on the stack - - // addr to use for next stack region (for multithreaded apps) - Addr next_thread_stack_base; - - // Base of region for mmaps (when user doesn't specify an address). - Addr mmap_start; - Addr mmap_end; - - // Base of region for nxm data - Addr nxm_start; - Addr nxm_end; - - std::string prog_fname; // file name - Addr prog_entry; // entry point (initial PC) - - Stats::Scalar<> num_syscalls; // number of syscalls executed - - - protected: - // constructor - Process(const std::string &nm, - int stdin_fd, // initial I/O descriptors - int stdout_fd, - int stderr_fd); - - // post initialization startup - virtual void startup(); - - protected: - FunctionalMemory *memory; - - private: - // file descriptor remapping support - static const int MAX_FD = 256; // max legal fd value - int fd_map[MAX_FD+1]; - - public: - // static helper functions to generate file descriptors for constructor - static int openInputFile(const std::string &filename); - static int openOutputFile(const std::string &filename); - - // override of virtual SimObject method: register statistics - virtual void regStats(); - - // register an execution context for this process. - // returns xc's cpu number (index into execContexts[]) - int registerExecContext(ExecContext *xc); - - - void replaceExecContext(ExecContext *xc, int xcIndex); - - // map simulator fd sim_fd to target fd tgt_fd - void dup_fd(int sim_fd, int tgt_fd); - - // generate new target fd for sim_fd - int alloc_fd(int sim_fd); - - // free target fd (e.g., after close) - void free_fd(int tgt_fd); - - // look up simulator fd for given target fd - int sim_fd(int tgt_fd); - - // is this a valid instruction fetch address? - bool validInstAddr(Addr addr) - { - return (text_base <= addr && - addr < text_base + text_size && - !(addr & (sizeof(MachInst)-1))); - } - - // is this a valid address? (used to filter data fetches) - // note that we just assume stack size <= 16MB - // this may be alpha-specific - bool validDataAddr(Addr addr) - { - return ((data_base <= addr && addr < brk_point) || - (next_thread_stack_base <= addr && addr < stack_base) || - (text_base <= addr && addr < (text_base + text_size)) || - (mmap_start <= addr && addr < mmap_end) || - (nxm_start <= addr && addr < nxm_end)); - } - - virtual void syscall(ExecContext *xc) = 0; - - virtual FunctionalMemory *getMemory() { return memory; } -}; - -// -// "Live" process with system calls redirected to host system -// -class ObjectFile; -class LiveProcess : public Process -{ - protected: - LiveProcess(const std::string &nm, ObjectFile *objFile, - int stdin_fd, int stdout_fd, int stderr_fd, - std::vector<std::string> &argv, - std::vector<std::string> &envp); - - public: - // this function is used to create the LiveProcess object, since - // we can't tell which subclass of LiveProcess to use until we - // open and look at the object file. - static LiveProcess *create(const std::string &nm, - int stdin_fd, int stdout_fd, int stderr_fd, - std::string executable, - std::vector<std::string> &argv, - std::vector<std::string> &envp); - - virtual void syscall(ExecContext *xc); - - virtual SyscallDesc* getDesc(int callnum) { panic("Must be implemented."); } - -}; - - -#endif // !FULL_SYSTEM - -#endif // __PROCESS_HH__ diff --git a/sim/pseudo_inst.cc b/sim/pseudo_inst.cc deleted file mode 100644 index 2d737c0a2..000000000 --- a/sim/pseudo_inst.cc +++ /dev/null @@ -1,291 +0,0 @@ -/* - * 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. - */ - -#include <errno.h> -#include <fcntl.h> -#include <unistd.h> -#include <cstdio> - -#include <string> - -#include "sim/pseudo_inst.hh" -#include "arch/vtophys.hh" -#include "cpu/base.hh" -#include "cpu/sampler/sampler.hh" -#include "cpu/exec_context.hh" -#include "cpu/quiesce_event.hh" -#include "kern/kernel_stats.hh" -#include "sim/param.hh" -#include "sim/serialize.hh" -#include "sim/sim_exit.hh" -#include "sim/stat_control.hh" -#include "sim/stats.hh" -#include "sim/system.hh" -#include "sim/debug.hh" -#include "sim/vptr.hh" - -using namespace std; - -extern Sampler *SampCPU; - -using namespace Stats; -using namespace TheISA; - -namespace AlphaPseudo -{ - bool doStatisticsInsts; - bool doCheckpointInsts; - bool doQuiesce; - - void - arm(ExecContext *xc) - { - if (xc->getKernelStats()) - xc->getKernelStats()->arm(); - } - - void - quiesce(ExecContext *xc) - { - if (!doQuiesce) - return; - - xc->suspend(); - if (xc->getKernelStats()) - xc->getKernelStats()->quiesce(); - } - - void - quiesceNs(ExecContext *xc, uint64_t ns) - { - if (!doQuiesce || ns == 0) - return; - - EndQuiesceEvent *quiesceEvent = xc->getQuiesceEvent(); - - if (quiesceEvent->scheduled()) - quiesceEvent->reschedule(curTick + Clock::Int::ns * ns); - else - quiesceEvent->schedule(curTick + Clock::Int::ns * ns); - - xc->suspend(); - if (xc->getKernelStats()) - xc->getKernelStats()->quiesce(); - } - - void - quiesceCycles(ExecContext *xc, uint64_t cycles) - { - if (!doQuiesce || cycles == 0) - return; - - EndQuiesceEvent *quiesceEvent = xc->getQuiesceEvent(); - - if (quiesceEvent->scheduled()) - quiesceEvent->reschedule(curTick + - xc->getCpuPtr()->cycles(cycles)); - else - quiesceEvent->schedule(curTick + - xc->getCpuPtr()->cycles(cycles)); - - xc->suspend(); - if (xc->getKernelStats()) - xc->getKernelStats()->quiesce(); - } - - uint64_t - quiesceTime(ExecContext *xc) - { - return (xc->readLastActivate() - xc->readLastSuspend()) / Clock::Int::ns; - } - - void - ivlb(ExecContext *xc) - { - if (xc->getKernelStats()) - xc->getKernelStats()->ivlb(); - } - - void - ivle(ExecContext *xc) - { - } - - void - m5exit_old(ExecContext *xc) - { - SimExit(curTick, "m5_exit_old instruction encountered"); - } - - void - m5exit(ExecContext *xc, Tick delay) - { - Tick when = curTick + delay * Clock::Int::ns; - SimExit(when, "m5_exit instruction encountered"); - } - - void - resetstats(ExecContext *xc, Tick delay, Tick period) - { - if (!doStatisticsInsts) - return; - - - Tick when = curTick + delay * Clock::Int::ns; - Tick repeat = period * Clock::Int::ns; - - using namespace Stats; - SetupEvent(Reset, when, repeat); - } - - void - dumpstats(ExecContext *xc, Tick delay, Tick period) - { - if (!doStatisticsInsts) - return; - - - Tick when = curTick + delay * Clock::Int::ns; - Tick repeat = period * Clock::Int::ns; - - using namespace Stats; - SetupEvent(Dump, when, repeat); - } - - void - addsymbol(ExecContext *xc, Addr addr, Addr symbolAddr) - { - char symb[100]; - CopyString(xc, symb, symbolAddr, 100); - std::string symbol(symb); - - DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr); - - xc->getSystemPtr()->kernelSymtab->insert(addr,symbol); - } - - void - dumpresetstats(ExecContext *xc, Tick delay, Tick period) - { - if (!doStatisticsInsts) - return; - - - Tick when = curTick + delay * Clock::Int::ns; - Tick repeat = period * Clock::Int::ns; - - using namespace Stats; - SetupEvent(Dump|Reset, when, repeat); - } - - void - m5checkpoint(ExecContext *xc, Tick delay, Tick period) - { - if (!doCheckpointInsts) - return; - - - Tick when = curTick + delay * Clock::Int::ns; - Tick repeat = period * Clock::Int::ns; - - Checkpoint::setup(when, repeat); - } - - uint64_t - readfile(ExecContext *xc, Addr vaddr, uint64_t len, uint64_t offset) - { - const string &file = xc->getCpuPtr()->system->params()->readfile; - if (file.empty()) { - return ULL(0); - } - - uint64_t result = 0; - - int fd = ::open(file.c_str(), O_RDONLY, 0); - if (fd < 0) - panic("could not open file %s\n", file); - - if (::lseek(fd, offset, SEEK_SET) < 0) - panic("could not seek: %s", strerror(errno)); - - char *buf = new char[len]; - char *p = buf; - while (len > 0) { - int bytes = ::read(fd, p, len); - if (bytes <= 0) - break; - - p += bytes; - result += bytes; - len -= bytes; - } - - close(fd); - CopyIn(xc, vaddr, buf, result); - delete [] buf; - return result; - } - - class Context : public ParamContext - { - public: - Context(const string §ion) : ParamContext(section) {} - void checkParams(); - }; - - Context context("pseudo_inst"); - - Param<bool> __quiesce(&context, "quiesce", - "enable quiesce instructions", - true); - Param<bool> __statistics(&context, "statistics", - "enable statistics pseudo instructions", - true); - Param<bool> __checkpoint(&context, "checkpoint", - "enable checkpoint pseudo instructions", - true); - - void - Context::checkParams() - { - doQuiesce = __quiesce; - doStatisticsInsts = __statistics; - doCheckpointInsts = __checkpoint; - } - - void debugbreak(ExecContext *xc) - { - debug_break(); - } - - void switchcpu(ExecContext *xc) - { - if (SampCPU) - SampCPU->switchCPUs(); - } -} diff --git a/sim/pseudo_inst.hh b/sim/pseudo_inst.hh deleted file mode 100644 index 4dd427c99..000000000 --- a/sim/pseudo_inst.hh +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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. - */ - -class ExecContext; - -//We need the "Tick" data type from here -#include "sim/host.hh" -//We need the "Addr" data type from here -#include "arch/isa_traits.hh" - -namespace AlphaPseudo -{ - /** - * @todo these externs are only here for a hack in fullCPU::takeOver... - */ - extern bool doStatisticsInsts; - extern bool doCheckpointInsts; - extern bool doQuiesce; - - void arm(ExecContext *xc); - void quiesce(ExecContext *xc); - void quiesceNs(ExecContext *xc, uint64_t ns); - void quiesceCycles(ExecContext *xc, uint64_t cycles); - uint64_t quiesceTime(ExecContext *xc); - void ivlb(ExecContext *xc); - void ivle(ExecContext *xc); - void m5exit(ExecContext *xc, Tick delay); - void m5exit_old(ExecContext *xc); - void resetstats(ExecContext *xc, Tick delay, Tick period); - void dumpstats(ExecContext *xc, Tick delay, Tick period); - void dumpresetstats(ExecContext *xc, Tick delay, Tick period); - void m5checkpoint(ExecContext *xc, Tick delay, Tick period); - uint64_t readfile(ExecContext *xc, Addr vaddr, uint64_t len, uint64_t offset); - void debugbreak(ExecContext *xc); - void switchcpu(ExecContext *xc); - void addsymbol(ExecContext *xc, Addr addr, Addr symbolAddr); -} diff --git a/sim/root.cc b/sim/root.cc deleted file mode 100644 index 6348ec104..000000000 --- a/sim/root.cc +++ /dev/null @@ -1,156 +0,0 @@ -/* - * 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. - */ - -#include <cstring> -#include <fstream> -#include <list> -#include <string> -#include <vector> - -#include "base/misc.hh" -#include "base/output.hh" -#include "sim/builder.hh" -#include "sim/host.hh" -#include "sim/sim_events.hh" -#include "sim/sim_object.hh" -#include "sim/root.hh" - -using namespace std; - -Tick curTick = 0; -ostream *outputStream; -ostream *configStream; - -/// The simulated frequency of curTick. (This is only here for a short time) -Tick ticksPerSecond; - -namespace Clock { -/// The simulated frequency of curTick. (In ticks per second) -Tick Frequency; - -namespace Float { -double s; -double ms; -double us; -double ns; -double ps; - -double Hz; -double kHz; -double MHz; -double GHZ; -/* namespace Float */ } - -namespace Int { -Tick s; -Tick ms; -Tick us; -Tick ns; -Tick ps; -/* namespace Float */ } - -/* namespace Clock */ } - - -// Dummy Object -class Root : public SimObject -{ - private: - Tick max_tick; - Tick progress_interval; - - public: - Root(const std::string &name, Tick maxtick, Tick pi) - : SimObject(name), max_tick(maxtick), progress_interval(pi) - {} - - virtual void startup(); -}; - -void -Root::startup() -{ - if (max_tick != 0) - new SimExitEvent(curTick + max_tick, "reached maximum cycle count"); - - if (progress_interval != 0) - new ProgressEvent(&mainEventQueue, progress_interval); -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(Root) - - Param<Tick> clock; - Param<Tick> max_tick; - Param<Tick> progress_interval; - Param<string> output_file; - -END_DECLARE_SIM_OBJECT_PARAMS(Root) - -BEGIN_INIT_SIM_OBJECT_PARAMS(Root) - - INIT_PARAM(clock, "tick frequency"), - INIT_PARAM(max_tick, "maximum simulation time"), - INIT_PARAM(progress_interval, "print a progress message"), - INIT_PARAM(output_file, "file to dump simulator output to") - -END_INIT_SIM_OBJECT_PARAMS(Root) - -CREATE_SIM_OBJECT(Root) -{ - static bool created = false; - if (created) - panic("only one root object allowed!"); - - created = true; - - outputStream = simout.find(output_file); - Root *root = new Root(getInstanceName(), max_tick, progress_interval); - - using namespace Clock; - Frequency = clock; - Float::s = static_cast<double>(Frequency); - Float::ms = Float::s / 1.0e3; - Float::us = Float::s / 1.0e6; - Float::ns = Float::s / 1.0e9; - Float::ps = Float::s / 1.0e12; - - Float::Hz = 1.0 / Float::s; - Float::kHz = 1.0 / Float::ms; - Float::MHz = 1.0 / Float::us; - Float::GHZ = 1.0 / Float::ns; - - Int::s = Frequency; - Int::ms = Int::s / 1000; - Int::us = Int::ms / 1000; - Int::ns = Int::us / 1000; - Int::ps = Int::ns / 1000; - - return root; -} - -REGISTER_SIM_OBJECT("Root", Root) diff --git a/sim/serialize.cc b/sim/serialize.cc deleted file mode 100644 index c4ef124bb..000000000 --- a/sim/serialize.cc +++ /dev/null @@ -1,484 +0,0 @@ -/* - * 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. - */ - -#include <sys/time.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <errno.h> - -#include <fstream> -#include <list> -#include <string> -#include <vector> - -#include "base/inifile.hh" -#include "base/misc.hh" -#include "base/output.hh" -#include "base/str.hh" -#include "base/trace.hh" -#include "sim/config_node.hh" -#include "sim/eventq.hh" -#include "sim/param.hh" -#include "sim/serialize.hh" -#include "sim/sim_events.hh" -#include "sim/sim_exit.hh" -#include "sim/sim_object.hh" - -using namespace std; - -int Serializable::ckptMaxCount = 0; -int Serializable::ckptCount = 0; -int Serializable::ckptPrevCount = -1; - -void -Serializable::nameOut(ostream &os) -{ - os << "\n[" << name() << "]\n"; -} - -void -Serializable::nameOut(ostream &os, const string &_name) -{ - os << "\n[" << _name << "]\n"; -} - -template <class T> -void -paramOut(ostream &os, const std::string &name, const T ¶m) -{ - os << name << "="; - showParam(os, param); - os << "\n"; -} - - -template <class T> -void -paramIn(Checkpoint *cp, const std::string §ion, - const std::string &name, T ¶m) -{ - std::string str; - if (!cp->find(section, name, str) || !parseParam(str, param)) { - fatal("Can't unserialize '%s:%s'\n", section, name); - } -} - - -template <class T> -void -arrayParamOut(ostream &os, const std::string &name, - const T *param, int size) -{ - os << name << "="; - if (size > 0) - showParam(os, param[0]); - for (int i = 1; i < size; ++i) { - os << " "; - showParam(os, param[i]); - } - os << "\n"; -} - - -template <class T> -void -arrayParamIn(Checkpoint *cp, const std::string §ion, - const std::string &name, T *param, int size) -{ - std::string str; - if (!cp->find(section, name, str)) { - fatal("Can't unserialize '%s:%s'\n", section, name); - } - - // code below stolen from VectorParam<T>::parse(). - // it would be nice to unify these somehow... - - vector<string> tokens; - - tokenize(tokens, str, ' '); - - // Need this if we were doing a vector - // value.resize(tokens.size()); - - if (tokens.size() != size) { - fatal("Array size mismatch on %s:%s'\n", section, name); - } - - for (int i = 0; i < tokens.size(); i++) { - // need to parse into local variable to handle vector<bool>, - // for which operator[] returns a special reference class - // that's not the same as 'bool&', (since it's a packed - // vector) - T scalar_value; - if (!parseParam(tokens[i], scalar_value)) { - string err("could not parse \""); - - err += str; - err += "\""; - - fatal(err); - } - - // assign parsed value to vector - param[i] = scalar_value; - } -} - - -void -objParamIn(Checkpoint *cp, const std::string §ion, - const std::string &name, Serializable * ¶m) -{ - if (!cp->findObj(section, name, param)) { - fatal("Can't unserialize '%s:%s'\n", section, name); - } -} - - -#define INSTANTIATE_PARAM_TEMPLATES(type) \ -template void \ -paramOut(ostream &os, const std::string &name, type const ¶m); \ -template void \ -paramIn(Checkpoint *cp, const std::string §ion, \ - const std::string &name, type & param); \ -template void \ -arrayParamOut(ostream &os, const std::string &name, \ - type const *param, int size); \ -template void \ -arrayParamIn(Checkpoint *cp, const std::string §ion, \ - const std::string &name, type *param, int size); - -INSTANTIATE_PARAM_TEMPLATES(signed char) -INSTANTIATE_PARAM_TEMPLATES(unsigned char) -INSTANTIATE_PARAM_TEMPLATES(signed short) -INSTANTIATE_PARAM_TEMPLATES(unsigned short) -INSTANTIATE_PARAM_TEMPLATES(signed int) -INSTANTIATE_PARAM_TEMPLATES(unsigned int) -INSTANTIATE_PARAM_TEMPLATES(signed long) -INSTANTIATE_PARAM_TEMPLATES(unsigned long) -INSTANTIATE_PARAM_TEMPLATES(signed long long) -INSTANTIATE_PARAM_TEMPLATES(unsigned long long) -INSTANTIATE_PARAM_TEMPLATES(bool) -INSTANTIATE_PARAM_TEMPLATES(string) - - -///////////////////////////// - -/// Container for serializing global variables (not associated with -/// any serialized object). -class Globals : public Serializable -{ - public: - const string name() const; - void serialize(ostream &os); - void unserialize(Checkpoint *cp); -}; - -/// The one and only instance of the Globals class. -Globals globals; - -const string -Globals::name() const -{ - return "Globals"; -} - -void -Globals::serialize(ostream &os) -{ - nameOut(os); - SERIALIZE_SCALAR(curTick); - - nameOut(os, "MainEventQueue"); - mainEventQueue.serialize(os); -} - -void -Globals::unserialize(Checkpoint *cp) -{ - const string §ion = name(); - UNSERIALIZE_SCALAR(curTick); - - mainEventQueue.unserialize(cp, "MainEventQueue"); -} - -void -Serializable::serializeAll() -{ - string dir = Checkpoint::dir(); - if (mkdir(dir.c_str(), 0775) == -1 && errno != EEXIST) - fatal("couldn't mkdir %s\n", dir); - - string cpt_file = dir + Checkpoint::baseFilename; - ofstream outstream(cpt_file.c_str()); - time_t t = time(NULL); - outstream << "// checkpoint generated: " << ctime(&t); - - globals.serialize(outstream); - SimObject::serializeAll(outstream); - - assert(Serializable::ckptPrevCount + 1 == Serializable::ckptCount); - Serializable::ckptPrevCount++; - if (ckptMaxCount && ++ckptCount >= ckptMaxCount) - SimExit(curTick + 1, "Maximum number of checkpoints dropped"); - -} - - -void -Serializable::unserializeGlobals(Checkpoint *cp) -{ - globals.unserialize(cp); -} - - -class SerializeEvent : public Event -{ - protected: - Tick repeat; - - public: - SerializeEvent(Tick _when, Tick _repeat); - virtual void process(); - virtual void serialize(std::ostream &os) - { - panic("Cannot serialize the SerializeEvent"); - } - -}; - -SerializeEvent::SerializeEvent(Tick _when, Tick _repeat) - : Event(&mainEventQueue, Serialize_Pri), repeat(_repeat) -{ - setFlags(AutoDelete); - schedule(_when); -} - -void -SerializeEvent::process() -{ - Serializable::serializeAll(); - if (repeat) - schedule(curTick + repeat); -} - -const char *Checkpoint::baseFilename = "m5.cpt"; - -static string checkpointDirBase; - -string -Checkpoint::dir() -{ - // use csprintf to insert curTick into directory name if it - // appears to have a format placeholder in it. - return (checkpointDirBase.find("%") != string::npos) ? - csprintf(checkpointDirBase, curTick) : checkpointDirBase; -} - -void -Checkpoint::setup(Tick when, Tick period) -{ - new SerializeEvent(when, period); -} - -class SerializeParamContext : public ParamContext -{ - private: - SerializeEvent *event; - - public: - SerializeParamContext(const string §ion); - ~SerializeParamContext(); - void checkParams(); -}; - -SerializeParamContext serialParams("serialize"); - -Param<string> serialize_dir(&serialParams, "dir", - "dir to stick checkpoint in " - "(sprintf format with cycle #)"); - -Param<Counter> serialize_cycle(&serialParams, - "cycle", - "cycle to serialize", - 0); - -Param<Counter> serialize_period(&serialParams, - "period", - "period to repeat serializations", - 0); - -Param<int> serialize_count(&serialParams, "count", - "maximum number of checkpoints to drop"); - -SerializeParamContext::SerializeParamContext(const string §ion) - : ParamContext(section), event(NULL) -{ } - -SerializeParamContext::~SerializeParamContext() -{ -} - -void -SerializeParamContext::checkParams() -{ - checkpointDirBase = simout.resolve(serialize_dir); - - // guarantee that directory ends with a '/' - if (checkpointDirBase[checkpointDirBase.size() - 1] != '/') - checkpointDirBase += "/"; - - if (serialize_cycle > 0) - Checkpoint::setup(serialize_cycle, serialize_period); - - Serializable::ckptMaxCount = serialize_count; -} - -void -debug_serialize() -{ - Serializable::serializeAll(); -} - -void -debug_serialize(Tick when) -{ - new SerializeEvent(when, 0); -} - -//////////////////////////////////////////////////////////////////////// -// -// SerializableClass member definitions -// -//////////////////////////////////////////////////////////////////////// - -// Map of class names to SerializableBuilder creation functions. -// Need to make this a pointer so we can force initialization on the -// first reference; otherwise, some SerializableClass constructors -// may be invoked before the classMap constructor. -map<string,SerializableClass::CreateFunc> *SerializableClass::classMap = 0; - -// SerializableClass constructor: add mapping to classMap -SerializableClass::SerializableClass(const string &className, - CreateFunc createFunc) -{ - if (classMap == NULL) - classMap = new map<string,SerializableClass::CreateFunc>(); - - if ((*classMap)[className]) - { - cerr << "Error: simulation object class " << className << " redefined" - << endl; - fatal(""); - } - - // add className --> createFunc to class map - (*classMap)[className] = createFunc; -} - - -// -// -Serializable * -SerializableClass::createObject(Checkpoint *cp, - const std::string §ion) -{ - string className; - - if (!cp->find(section, "type", className)) { - fatal("Serializable::create: no 'type' entry in section '%s'.\n", - section); - } - - CreateFunc createFunc = (*classMap)[className]; - - if (createFunc == NULL) { - fatal("Serializable::create: no create function for class '%s'.\n", - className); - } - - Serializable *object = createFunc(cp, section); - - assert(object != NULL); - - return object; -} - - -Serializable * -Serializable::create(Checkpoint *cp, const std::string §ion) -{ - Serializable *object = SerializableClass::createObject(cp, section); - object->unserialize(cp, section); - return object; -} - - -Checkpoint::Checkpoint(const std::string &cpt_dir, const std::string &path, - const ConfigNode *_configNode) - : db(new IniFile), basePath(path), configNode(_configNode), cptDir(cpt_dir) -{ - string filename = cpt_dir + "/" + Checkpoint::baseFilename; - if (!db->load(filename)) { - fatal("Can't load checkpoint file '%s'\n", filename); - } -} - - -bool -Checkpoint::find(const std::string §ion, const std::string &entry, - std::string &value) -{ - return db->find(section, entry, value); -} - - -bool -Checkpoint::findObj(const std::string §ion, const std::string &entry, - Serializable *&value) -{ - string path; - - if (!db->find(section, entry, path)) - return false; - - if ((value = configNode->resolveSimObject(path)) != NULL) - return true; - - if ((value = objMap[path]) != NULL) - return true; - - return false; -} - - -bool -Checkpoint::sectionExists(const std::string §ion) -{ - return db->sectionExists(section); -} diff --git a/sim/serialize.hh b/sim/serialize.hh deleted file mode 100644 index d8f5f8fc5..000000000 --- a/sim/serialize.hh +++ /dev/null @@ -1,243 +0,0 @@ -/* - * 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. - */ - -/* @file - * Serialization Interface Declarations - */ - -#ifndef __SERIALIZE_HH__ -#define __SERIALIZE_HH__ - - -#include <list> -#include <iostream> -#include <map> - -#include "sim/host.hh" -#include "sim/configfile.hh" - -class Serializable; -class Checkpoint; - -template <class T> -void paramOut(std::ostream &os, const std::string &name, const T ¶m); - -template <class T> -void paramIn(Checkpoint *cp, const std::string §ion, - const std::string &name, T ¶m); - -template <class T> -void arrayParamOut(std::ostream &os, const std::string &name, - const T *param, int size); - -template <class T> -void arrayParamIn(Checkpoint *cp, const std::string §ion, - const std::string &name, T *param, int size); - -void -objParamIn(Checkpoint *cp, const std::string §ion, - const std::string &name, Serializable * ¶m); - - -// -// These macros are streamlined to use in serialize/unserialize -// functions. It's assumed that serialize() has a parameter 'os' for -// the ostream, and unserialize() has parameters 'cp' and 'section'. -#define SERIALIZE_SCALAR(scalar) paramOut(os, #scalar, scalar) - -#define UNSERIALIZE_SCALAR(scalar) paramIn(cp, section, #scalar, scalar) - -// ENUMs are like SCALARs, but we cast them to ints on the way out -#define SERIALIZE_ENUM(scalar) paramOut(os, #scalar, (int)scalar) - -#define UNSERIALIZE_ENUM(scalar) \ - do { \ - int tmp; \ - paramIn(cp, section, #scalar, tmp); \ - scalar = (typeof(scalar))tmp; \ - } while (0) - -#define SERIALIZE_ARRAY(member, size) \ - arrayParamOut(os, #member, member, size) - -#define UNSERIALIZE_ARRAY(member, size) \ - arrayParamIn(cp, section, #member, member, size) - -#define SERIALIZE_OBJPTR(objptr) paramOut(os, #objptr, (objptr)->name()) - -#define UNSERIALIZE_OBJPTR(objptr) \ - do { \ - Serializable *sptr; \ - objParamIn(cp, section, #objptr, sptr); \ - objptr = dynamic_cast<typeof(objptr)>(sptr); \ - } while (0) - -/* - * Basic support for object serialization. - */ -class Serializable -{ - protected: - void nameOut(std::ostream &os); - void nameOut(std::ostream &os, const std::string &_name); - - public: - Serializable() {} - virtual ~Serializable() {} - - // manditory virtual function, so objects must provide names - virtual const std::string name() const = 0; - - virtual void serialize(std::ostream &os) {} - virtual void unserialize(Checkpoint *cp, const std::string §ion) {} - - static Serializable *create(Checkpoint *cp, - const std::string §ion); - - static int ckptCount; - static int ckptMaxCount; - static int ckptPrevCount; - static void serializeAll(); - static void unserializeGlobals(Checkpoint *cp); -}; - -// -// A SerializableBuilder serves as an evaluation context for a set of -// parameters that describe a specific instance of a Serializable. This -// evaluation context corresponds to a section in the .ini file (as -// with the base ParamContext) plus an optional node in the -// configuration hierarchy (the configNode member) for resolving -// Serializable references. SerializableBuilder is an abstract superclass; -// derived classes specialize the class for particular subclasses of -// Serializable (e.g., BaseCache). -// -// For typical usage, see the definition of -// SerializableClass::createObject(). -// -class SerializableBuilder -{ - public: - - SerializableBuilder() {} - - virtual ~SerializableBuilder() {} - - // Create the actual Serializable corresponding to the parameter - // values in this context. This function is overridden in derived - // classes to call a specific constructor for a particular - // subclass of Serializable. - virtual Serializable *create() = 0; -}; - -// -// An instance of SerializableClass corresponds to a class derived from -// Serializable. The SerializableClass instance serves to bind the string -// name (found in the config file) to a function that creates an -// instance of the appropriate derived class. -// -// This would be much cleaner in Smalltalk or Objective-C, where types -// are first-class objects themselves. -// -class SerializableClass -{ - public: - - // Type CreateFunc is a pointer to a function that creates a new - // simulation object builder based on a .ini-file parameter - // section (specified by the first string argument), a unique name - // for the object (specified by the second string argument), and - // an optional config hierarchy node (specified by the third - // argument). A pointer to the new SerializableBuilder is returned. - typedef Serializable *(*CreateFunc)(Checkpoint *cp, - const std::string §ion); - - static std::map<std::string,CreateFunc> *classMap; - - // Constructor. For example: - // - // SerializableClass baseCacheSerializableClass("BaseCacheSerializable", - // newBaseCacheSerializableBuilder); - // - SerializableClass(const std::string &className, CreateFunc createFunc); - - // create Serializable given name of class and pointer to - // configuration hierarchy node - static Serializable *createObject(Checkpoint *cp, - const std::string §ion); -}; - -// -// Macros to encapsulate the magic of declaring & defining -// SerializableBuilder and SerializableClass objects -// - -#define REGISTER_SERIALIZEABLE(CLASS_NAME, OBJ_CLASS) \ -SerializableClass the##OBJ_CLASS##Class(CLASS_NAME, \ - OBJ_CLASS::createForUnserialize); - -class Checkpoint -{ - private: - - IniFile *db; - const std::string basePath; - const ConfigNode *configNode; - std::map<std::string, Serializable*> objMap; - - public: - Checkpoint(const std::string &cpt_dir, const std::string &path, - const ConfigNode *_configNode); - - const std::string cptDir; - - bool find(const std::string §ion, const std::string &entry, - std::string &value); - - bool findObj(const std::string §ion, const std::string &entry, - Serializable *&value); - - bool sectionExists(const std::string §ion); - - // The following static functions have to do with checkpoint - // creation rather than restoration. This class makes a handy - // namespace for them though. - - // Export current checkpoint directory name so other objects can - // derive filenames from it (e.g., memory). The return value is - // guaranteed to end in '/' so filenames can be directly appended. - // This function is only valid while a checkpoint is being created. - static std::string dir(); - - // Filename for base checkpoint file within directory. - static const char *baseFilename; - - // Set up a checkpoint creation event or series of events. - static void setup(Tick when, Tick period = 0); -}; - -#endif // __SERIALIZE_HH__ diff --git a/sim/sim_events.cc b/sim/sim_events.cc deleted file mode 100644 index c2bdca9df..000000000 --- a/sim/sim_events.cc +++ /dev/null @@ -1,148 +0,0 @@ -/* - * 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. - */ - -#include <string> - -#include "base/callback.hh" -#include "base/hostinfo.hh" -#include "sim/eventq.hh" -#include "sim/param.hh" -#include "sim/sim_events.hh" -#include "sim/sim_exit.hh" -#include "sim/startup.hh" -#include "sim/stats.hh" - -using namespace std; - -// -// handle termination event -// -void -SimExitEvent::process() -{ - // This event does not autodelete because exitNow may be called, - // and the function will never be allowed to finish. - if (theQueue() == &mainEventQueue) { - string _cause = cause; - int _code = code; - delete this; - exitNow(_cause, _code); - } else { - new SimExitEvent(cause, code); - delete this; - } -} - - -const char * -SimExitEvent::description() -{ - return "simulation termination"; -} - -// -// constructor: automatically schedules at specified time -// -CountedExitEvent::CountedExitEvent(EventQueue *q, const std::string &_cause, - Tick _when, int &_downCounter) - : Event(q, Sim_Exit_Pri), - cause(_cause), - downCounter(_downCounter) -{ - // catch stupid mistakes - assert(downCounter > 0); - - schedule(_when); -} - - -// -// handle termination event -// -void -CountedExitEvent::process() -{ - if (--downCounter == 0) { - new SimExitEvent(cause, 0); - } -} - - -const char * -CountedExitEvent::description() -{ - return "counted exit"; -} - -#ifdef CHECK_SWAP_CYCLES -new CheckSwapEvent(&mainEventQueue, CHECK_SWAP_CYCLES); -#endif - -void -CheckSwapEvent::process() -{ - /* Check the amount of free swap space */ - long swap; - - /* returns free swap in KBytes */ - swap = procInfo("/proc/meminfo", "SwapFree:"); - - if (swap < 1000) - ccprintf(cerr, "\a\a\aWarning! Swap space is low (%d)\n", swap); - - if (swap < 100) { - cerr << "\a\aAborting Simulation! Inadequate swap space!\n\n"; - new SimExitEvent("Lack of swap space"); - } - - schedule(curTick + interval); -} - -const char * -CheckSwapEvent::description() -{ - return "check swap"; -} - -// -// handle progress event: print message and reschedule -// -void -ProgressEvent::process() -{ - DPRINTFN("ProgressEvent\n"); - // reschedule for next interval - schedule(curTick + interval); -} - - -const char * -ProgressEvent::description() -{ - return "progress message"; -} diff --git a/sim/sim_events.hh b/sim/sim_events.hh deleted file mode 100644 index c93914457..000000000 --- a/sim/sim_events.hh +++ /dev/null @@ -1,126 +0,0 @@ -/* - * 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. - */ - -#ifndef __SIM_SIM_EVENTS_HH__ -#define __SIM_SIM_EVENTS_HH__ - -#include "sim/eventq.hh" - -// -// Event to terminate simulation at a particular cycle/instruction -// -class SimExitEvent : public Event -{ - private: - // string explaining why we're terminating - std::string cause; - int code; - - public: - SimExitEvent(const std::string &_cause, int c = 0) - : Event(&mainEventQueue, Sim_Exit_Pri), cause(_cause), - code(c) - { schedule(curTick); } - - SimExitEvent(Tick _when, const std::string &_cause, int c = 0) - : Event(&mainEventQueue, Sim_Exit_Pri), cause(_cause), - code(c) - { schedule(_when); } - - SimExitEvent(EventQueue *q, const std::string &_cause, int c = 0) - : Event(q, Sim_Exit_Pri), cause(_cause), code(c) - { schedule(curTick); } - - SimExitEvent(EventQueue *q, Tick _when, const std::string &_cause, - int c = 0) - : Event(q, Sim_Exit_Pri), cause(_cause), code(c) - { schedule(_when); } - - void process(); // process event - - virtual const char *description(); -}; - -// -// Event class to terminate simulation after 'n' related events have -// occurred using a shared counter: used to terminate when *all* -// threads have reached a particular instruction count -// -class CountedExitEvent : public Event -{ - private: - std::string cause; // string explaining why we're terminating - int &downCounter; // decrement & terminate if zero - - public: - CountedExitEvent(EventQueue *q, const std::string &_cause, - Tick _when, int &_downCounter); - - void process(); // process event - - virtual const char *description(); -}; - -// -// Event to check swap usage -// -class CheckSwapEvent : public Event -{ - private: - int interval; - - public: - CheckSwapEvent(EventQueue *q, int ival) - : Event(q), interval(ival) - { schedule(curTick + interval); } - - void process(); // process event - - virtual const char *description(); -}; - -// -// Progress event: print out cycle every so often so we know we're -// making forward progress. -// -class ProgressEvent : public Event -{ - protected: - Tick interval; - - public: - ProgressEvent(EventQueue *q, Tick ival) - : Event(q), interval(ival) - { schedule(curTick + interval); } - - void process(); // process event - - virtual const char *description(); -}; - -#endif // __SIM_SIM_EVENTS_HH__ diff --git a/sim/sim_exit.hh b/sim/sim_exit.hh deleted file mode 100644 index f14256933..000000000 --- a/sim/sim_exit.hh +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __SIM_EXIT_HH__ -#define __SIM_EXIT_HH__ - -#include <string> - -#include "sim/host.hh" - -class Callback; - -void registerExitCallback(Callback *); - -void exitNow(const std::string &cause, int exit_code); -void exitNow(const char *cause, int exit_code); -void SimExit(Tick when, const char *message); - -#endif // __SIM_EXIT_HH__ diff --git a/sim/sim_object.cc b/sim/sim_object.cc deleted file mode 100644 index f34e17fe6..000000000 --- a/sim/sim_object.cc +++ /dev/null @@ -1,231 +0,0 @@ -/* - * 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. - */ - -#include <assert.h> - -#include "base/callback.hh" -#include "base/inifile.hh" -#include "base/match.hh" -#include "base/misc.hh" -#include "base/trace.hh" -#include "base/stats/events.hh" -#include "sim/configfile.hh" -#include "sim/host.hh" -#include "sim/sim_object.hh" -#include "sim/stats.hh" -#include "sim/param.hh" - -using namespace std; - - -//////////////////////////////////////////////////////////////////////// -// -// SimObject member definitions -// -//////////////////////////////////////////////////////////////////////// - -// -// static list of all SimObjects, used for initialization etc. -// -SimObject::SimObjectList SimObject::simObjectList; - -namespace Stats { - extern ObjectMatch event_ignore; -} - -// -// SimObject constructor: used to maintain static simObjectList -// -SimObject::SimObject(Params *p) - : _params(p) -{ -#ifdef DEBUG - doDebugBreak = false; -#endif - - doRecordEvent = !Stats::event_ignore.match(name()); - simObjectList.push_back(this); -} - -// -// SimObject constructor: used to maintain static simObjectList -// -SimObject::SimObject(const string &_name) - : _params(new Params) -{ - _params->name = _name; -#ifdef DEBUG - doDebugBreak = false; -#endif - - doRecordEvent = !Stats::event_ignore.match(name()); - simObjectList.push_back(this); -} - -void -SimObject::init() -{ -} - -// -// no default statistics, so nothing to do in base implementation -// -void -SimObject::regStats() -{ -} - -void -SimObject::regFormulas() -{ -} - -void -SimObject::resetStats() -{ -} - -// -// static function: -// call regStats() on all SimObjects and then regFormulas() on all -// SimObjects. -// -struct SimObjectResetCB : public Callback -{ - virtual void process() { SimObject::resetAllStats(); } -}; - -namespace { - static SimObjectResetCB StatResetCB; -} - -void -SimObject::regAllStats() -{ - SimObjectList::iterator i; - SimObjectList::iterator end = simObjectList.end(); - - /** - * @todo change cprintfs to DPRINTFs - */ - for (i = simObjectList.begin(); i != end; ++i) { -#ifdef STAT_DEBUG - cprintf("registering stats for %s\n", (*i)->name()); -#endif - (*i)->regStats(); - } - - for (i = simObjectList.begin(); i != end; ++i) { -#ifdef STAT_DEBUG - cprintf("registering formulas for %s\n", (*i)->name()); -#endif - (*i)->regFormulas(); - } - - Stats::registerResetCallback(&StatResetCB); -} - -// -// static function: call init() on all SimObjects. -// -void -SimObject::initAll() -{ - SimObjectList::iterator i = simObjectList.begin(); - SimObjectList::iterator end = simObjectList.end(); - - for (; i != end; ++i) { - SimObject *obj = *i; - obj->init(); - } -} - -// -// static function: call resetStats() on all SimObjects. -// -void -SimObject::resetAllStats() -{ - SimObjectList::iterator i = simObjectList.begin(); - SimObjectList::iterator end = simObjectList.end(); - - for (; i != end; ++i) { - SimObject *obj = *i; - obj->resetStats(); - } -} - -// -// static function: serialize all SimObjects. -// -void -SimObject::serializeAll(ostream &os) -{ - SimObjectList::reverse_iterator ri = simObjectList.rbegin(); - SimObjectList::reverse_iterator rend = simObjectList.rend(); - - for (; ri != rend; ++ri) { - SimObject *obj = *ri; - obj->nameOut(os); - obj->serialize(os); - } -} - -#ifdef DEBUG -// -// static function: flag which objects should have the debugger break -// -void -SimObject::debugObjectBreak(const string &objs) -{ - SimObjectList::const_iterator i = simObjectList.begin(); - SimObjectList::const_iterator end = simObjectList.end(); - - ObjectMatch match(objs); - for (; i != end; ++i) { - SimObject *obj = *i; - obj->doDebugBreak = match.match(obj->name()); - } -} - -extern "C" -void -debugObjectBreak(const char *objs) -{ - SimObject::debugObjectBreak(string(objs)); -} -#endif - -void -SimObject::recordEvent(const std::string &stat) -{ - if (doRecordEvent) - Stats::recordEvent(stat); -} - -DEFINE_SIM_OBJECT_CLASS_NAME("SimObject", SimObject) diff --git a/sim/sim_object.hh b/sim/sim_object.hh deleted file mode 100644 index 59d9daf45..000000000 --- a/sim/sim_object.hh +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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. - */ - -/* @file - * User Console Definitions - */ - -#ifndef __SIM_OBJECT_HH__ -#define __SIM_OBJECT_HH__ - -#include <map> -#include <list> -#include <vector> -#include <iostream> - -#include "sim/serialize.hh" -#include "sim/startup.hh" - -/* - * Abstract superclass for simulation objects. Represents things that - * correspond to physical components and can be specified via the - * config file (CPUs, caches, etc.). - */ -class SimObject : public Serializable, protected StartupCallback -{ - public: - struct Params { - std::string name; - }; - - protected: - Params *_params; - - public: - const Params *params() const { return _params; } - - private: - friend class Serializer; - - typedef std::vector<SimObject *> SimObjectList; - - // list of all instantiated simulation objects - static SimObjectList simObjectList; - - public: - SimObject(Params *_params); - SimObject(const std::string &_name); - - virtual ~SimObject() {} - - virtual const std::string name() const { return params()->name; } - - // initialization pass of all objects. - // Gets invoked after construction, before unserialize. - virtual void init(); - static void initAll(); - - // register statistics for this object - virtual void regStats(); - virtual void regFormulas(); - virtual void resetStats(); - - // static: call reg_stats on all SimObjects - static void regAllStats(); - - // static: call resetStats on all SimObjects - static void resetAllStats(); - - // static: call nameOut() & serialize() on all SimObjects - static void serializeAll(std::ostream &); - -#ifdef DEBUG - public: - bool doDebugBreak; - static void debugObjectBreak(const std::string &objs); -#endif - - public: - bool doRecordEvent; - void recordEvent(const std::string &stat); -}; - -#endif // __SIM_OBJECT_HH__ diff --git a/sim/startup.cc b/sim/startup.cc deleted file mode 100644 index 683e6c746..000000000 --- a/sim/startup.cc +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <list> - -#include "base/misc.hh" -#include "sim/debug.hh" -#include "sim/startup.hh" - -typedef std::list<StartupCallback *> startupq_t; - -startupq_t *startupq = NULL; - -StartupCallback::StartupCallback() -{ - if (startupq == NULL) - startupq = new startupq_t; - startupq->push_back(this); -} - -StartupCallback::~StartupCallback() -{ - startupq->remove(this); -} - -void StartupCallback::startup() { } - -void -SimStartup() -{ - startupq_t::iterator i = startupq->begin(); - startupq_t::iterator end = startupq->end(); - - while (i != end) { - (*i)->startup(); - ++i; - } -} diff --git a/sim/startup.hh b/sim/startup.hh deleted file mode 100644 index 3c9b654f1..000000000 --- a/sim/startup.hh +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __SIM_STARTUP_HH__ -#define __SIM_STARTUP_HH__ - -struct StartupCallback -{ - StartupCallback(); - virtual ~StartupCallback(); - virtual void startup(); -}; - -void SimStartup(); - -#endif // __SIM_STARTUP_HH__ diff --git a/sim/stat_control.cc b/sim/stat_control.cc deleted file mode 100644 index 85c405b7f..000000000 --- a/sim/stat_control.cc +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// This file will contain default statistics for the simulator that -// don't really belong to a specific simulator object - -#include <fstream> -#include <iostream> -#include <list> - -#include "base/callback.hh" -#include "base/hostinfo.hh" -#include "base/statistics.hh" -#include "base/str.hh" -#include "base/time.hh" -#include "base/stats/output.hh" -#include "cpu/base.hh" -#include "sim/eventq.hh" -#include "sim/sim_object.hh" -#include "sim/stat_control.hh" -#include "sim/root.hh" - -using namespace std; - -Stats::Formula hostInstRate; -Stats::Formula hostTickRate; -Stats::Value hostMemory; -Stats::Value hostSeconds; - -Stats::Value simTicks; -Stats::Value simInsts; -Stats::Value simFreq; -Stats::Formula simSeconds; - -namespace Stats { - -Time statTime(true); -Tick startTick; -Tick lastDump(0); - -class SimTicksReset : public Callback -{ - public: - void process() - { - statTime.set(); - startTick = curTick; - } -}; - -double -statElapsedTime() -{ - Time now(true); - Time elapsed = now - statTime; - return elapsed(); -} - -Tick -statElapsedTicks() -{ - return curTick - startTick; -} - -SimTicksReset simTicksReset; - -void -InitSimStats() -{ - simInsts - .functor(BaseCPU::numSimulatedInstructions) - .name("sim_insts") - .desc("Number of instructions simulated") - .precision(0) - .prereq(simInsts) - ; - - simSeconds - .name("sim_seconds") - .desc("Number of seconds simulated") - ; - - simFreq - .scalar(Clock::Frequency) - .name("sim_freq") - .desc("Frequency of simulated ticks") - ; - - simTicks - .functor(statElapsedTicks) - .name("sim_ticks") - .desc("Number of ticks simulated") - ; - - hostInstRate - .name("host_inst_rate") - .desc("Simulator instruction rate (inst/s)") - .precision(0) - .prereq(simInsts) - ; - - hostMemory - .functor(memUsage) - .name("host_mem_usage") - .desc("Number of bytes of host memory used") - .prereq(hostMemory) - ; - - hostSeconds - .functor(statElapsedTime) - .name("host_seconds") - .desc("Real time elapsed on the host") - .precision(2) - ; - - hostTickRate - .name("host_tick_rate") - .desc("Simulator tick rate (ticks/s)") - .precision(0) - ; - - simSeconds = simTicks / simFreq; - hostInstRate = simInsts / hostSeconds; - hostTickRate = simTicks / hostSeconds; - - registerResetCallback(&simTicksReset); -} - -class StatEvent : public Event -{ - protected: - int flags; - Tick repeat; - - public: - StatEvent(int _flags, Tick _when, Tick _repeat); - virtual void process(); - virtual const char *description(); -}; - -StatEvent::StatEvent(int _flags, Tick _when, Tick _repeat) - : Event(&mainEventQueue, Stat_Event_Pri), - flags(_flags), repeat(_repeat) -{ - setFlags(AutoDelete); - schedule(_when); -} - -const char * -StatEvent::description() -{ - return "Statistics dump and/or reset"; -} - -void -StatEvent::process() -{ - if (flags & Stats::Dump) - DumpNow(); - - if (flags & Stats::Reset) - reset(); - - if (repeat) - schedule(curTick + repeat); -} - -list<Output *> OutputList; - -void -DumpNow() -{ - assert(lastDump <= curTick); - if (lastDump == curTick) - return; - lastDump = curTick; - - list<Output *>::iterator i = OutputList.begin(); - list<Output *>::iterator end = OutputList.end(); - for (; i != end; ++i) { - Output *output = *i; - if (!output->valid()) - continue; - - output->output(); - } -} - -void -SetupEvent(int flags, Tick when, Tick repeat) -{ - new StatEvent(flags, when, repeat); -} - -/* namespace Stats */ } - -extern "C" void -debugDumpStats() -{ - Stats::DumpNow(); -} - diff --git a/sim/stat_control.hh b/sim/stat_control.hh deleted file mode 100644 index a22ce76af..000000000 --- a/sim/stat_control.hh +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __SIM_STAT_CONTROL_HH__ -#define __SIM_STAT_CONTROL_HH__ - -#include <fstream> -#include <list> - -namespace Stats { - -enum { - Reset = 0x1, - Dump = 0x2 -}; - -class Output; -extern std::list<Output *> OutputList; - -void DumpNow(); -void SetupEvent(int flags, Tick when, Tick repeat = 0); - -void InitSimStats(); - -/* namespace Stats */ } - -#endif // __SIM_STAT_CONTROL_HH__ diff --git a/sim/stats.hh b/sim/stats.hh deleted file mode 100644 index 8e97d041f..000000000 --- a/sim/stats.hh +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __SIM_STATS_HH__ -#define __SIM_STATS_HH__ - -#include "base/statistics.hh" - -extern Stats::Formula simSeconds; -extern Stats::Value simTicks; - -#endif // __SIM_SIM_STATS_HH__ diff --git a/sim/syscall_emul.cc b/sim/syscall_emul.cc deleted file mode 100644 index 00168b025..000000000 --- a/sim/syscall_emul.cc +++ /dev/null @@ -1,441 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include <fcntl.h> -#include <unistd.h> - -#include <string> -#include <iostream> - -#include "sim/syscall_emul.hh" -#include "base/trace.hh" -#include "cpu/exec_context.hh" -#include "cpu/base.hh" -#include "sim/process.hh" - -#include "sim/sim_events.hh" - -using namespace std; -using namespace TheISA; - -void -SyscallDesc::doSyscall(int callnum, Process *process, ExecContext *xc) -{ - DPRINTFR(SyscallVerbose, "%s: syscall %s called\n", - xc->getCpuPtr()->name(), name); - - SyscallReturn retval = (*funcPtr)(this, callnum, process, xc); - - DPRINTFR(SyscallVerbose, "%s: syscall %s returns %d\n", - xc->getCpuPtr()->name(), name, retval.value()); - - if (!(flags & SyscallDesc::SuppressReturnValue)) - xc->setSyscallReturn(retval); -} - - -SyscallReturn -unimplementedFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - fatal("syscall %s (#%d) unimplemented.", desc->name, callnum); -} - - -SyscallReturn -ignoreFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - warn("ignoring syscall %s(%d, %d, ...)", desc->name, - xc->getSyscallArg(0), xc->getSyscallArg(1)); - - return 0; -} - - -SyscallReturn -exitFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - new SimExitEvent("syscall caused exit", xc->getSyscallArg(0) & 0xff); - - return 1; -} - - -SyscallReturn -getpagesizeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) -{ - return (int)VMPageSize; -} - - -SyscallReturn -obreakFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) -{ - // change brk addr to first arg - Addr new_brk = xc->getSyscallArg(0); - if (new_brk != 0) - { - p->brk_point = xc->getSyscallArg(0); - } - DPRINTF(SyscallVerbose, "Break Point changed to: %#X\n", p->brk_point); - return p->brk_point; -} - - -SyscallReturn -closeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) -{ - int target_fd = xc->getSyscallArg(0); - int status = close(p->sim_fd(target_fd)); - if (status >= 0) - p->free_fd(target_fd); - return status; -} - - -SyscallReturn -readFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) -{ - int fd = p->sim_fd(xc->getSyscallArg(0)); - int nbytes = xc->getSyscallArg(2); - BufferArg bufArg(xc->getSyscallArg(1), nbytes); - - int bytes_read = read(fd, bufArg.bufferPtr(), nbytes); - - if (bytes_read != -1) - bufArg.copyOut(xc->getMemPtr()); - - return bytes_read; -} - -SyscallReturn -writeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) -{ - int fd = p->sim_fd(xc->getSyscallArg(0)); - int nbytes = xc->getSyscallArg(2); - BufferArg bufArg(xc->getSyscallArg(1), nbytes); - - bufArg.copyIn(xc->getMemPtr()); - - int bytes_written = write(fd, bufArg.bufferPtr(), nbytes); - - fsync(fd); - - return bytes_written; -} - - -SyscallReturn -lseekFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) -{ - int fd = p->sim_fd(xc->getSyscallArg(0)); - uint64_t offs = xc->getSyscallArg(1); - int whence = xc->getSyscallArg(2); - - off_t result = lseek(fd, offs, whence); - - return (result == (off_t)-1) ? -errno : result; -} - - -SyscallReturn -munmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) -{ - // given that we don't really implement mmap, munmap is really easy - return 0; -} - - -const char *hostname = "m5.eecs.umich.edu"; - -SyscallReturn -gethostnameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) -{ - int name_len = xc->getSyscallArg(1); - BufferArg name(xc->getSyscallArg(0), name_len); - - strncpy((char *)name.bufferPtr(), hostname, name_len); - - name.copyOut(xc->getMemPtr()); - - return 0; -} - -SyscallReturn -unlinkFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) -{ - string path; - - if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault) - return (TheISA::IntReg)-EFAULT; - - int result = unlink(path.c_str()); - return (result == -1) ? -errno : result; -} - -SyscallReturn -renameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) -{ - string old_name; - - if (xc->getMemPtr()->readString(old_name, xc->getSyscallArg(0)) != NoFault) - return -EFAULT; - - string new_name; - - if (xc->getMemPtr()->readString(new_name, xc->getSyscallArg(1)) != NoFault) - return -EFAULT; - - int64_t result = rename(old_name.c_str(), new_name.c_str()); - return (result == -1) ? -errno : result; -} - -SyscallReturn -truncateFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) -{ - string path; - - if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault) - return -EFAULT; - - off_t length = xc->getSyscallArg(1); - - int result = truncate(path.c_str(), length); - return (result == -1) ? -errno : result; -} - -SyscallReturn -ftruncateFunc(SyscallDesc *desc, int num, Process *process, ExecContext *xc) -{ - int fd = process->sim_fd(xc->getSyscallArg(0)); - - if (fd < 0) - return -EBADF; - - off_t length = xc->getSyscallArg(1); - - int result = ftruncate(fd, length); - return (result == -1) ? -errno : result; -} - -SyscallReturn -chownFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) -{ - string path; - - if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault) - return -EFAULT; - - /* XXX endianess */ - uint32_t owner = xc->getSyscallArg(1); - uid_t hostOwner = owner; - uint32_t group = xc->getSyscallArg(2); - gid_t hostGroup = group; - - int result = chown(path.c_str(), hostOwner, hostGroup); - return (result == -1) ? -errno : result; -} - -SyscallReturn -fchownFunc(SyscallDesc *desc, int num, Process *process, ExecContext *xc) -{ - int fd = process->sim_fd(xc->getSyscallArg(0)); - - if (fd < 0) - return -EBADF; - - /* XXX endianess */ - uint32_t owner = xc->getSyscallArg(1); - uid_t hostOwner = owner; - uint32_t group = xc->getSyscallArg(2); - gid_t hostGroup = group; - - int result = fchown(fd, hostOwner, hostGroup); - return (result == -1) ? -errno : result; -} - - -SyscallReturn -fcntlFunc(SyscallDesc *desc, int num, Process *process, - ExecContext *xc) -{ - int fd = xc->getSyscallArg(0); - - if (fd < 0 || process->sim_fd(fd) < 0) - return -EBADF; - - int cmd = xc->getSyscallArg(1); - switch (cmd) { - case 0: // F_DUPFD - // if we really wanted to support this, we'd need to do it - // in the target fd space. - warn("fcntl(%d, F_DUPFD) not supported, error returned\n", fd); - return -EMFILE; - - case 1: // F_GETFD (get close-on-exec flag) - case 2: // F_SETFD (set close-on-exec flag) - return 0; - - case 3: // F_GETFL (get file flags) - case 4: // F_SETFL (set file flags) - // not sure if this is totally valid, but we'll pass it through - // to the underlying OS - warn("fcntl(%d, %d) passed through to host\n", fd, cmd); - return fcntl(process->sim_fd(fd), cmd); - // return 0; - - case 7: // F_GETLK (get lock) - case 8: // F_SETLK (set lock) - case 9: // F_SETLKW (set lock and wait) - // don't mess with file locking... just act like it's OK - warn("File lock call (fcntl(%d, %d)) ignored.\n", fd, cmd); - return 0; - - default: - warn("Unknown fcntl command %d\n", cmd); - return 0; - } -} - -SyscallReturn -pipePseudoFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - int fds[2], sim_fds[2]; - int pipe_retval = pipe(fds); - - if (pipe_retval < 0) { - // error - return pipe_retval; - } - - sim_fds[0] = process->alloc_fd(fds[0]); - sim_fds[1] = process->alloc_fd(fds[1]); - - // Alpha Linux convention for pipe() is that fd[0] is returned as - // the return value of the function, and fd[1] is returned in r20. - xc->setIntReg(SyscallPseudoReturnReg, sim_fds[1]); - return sim_fds[0]; -} - - -SyscallReturn -getpidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - // Make up a PID. There's no interprocess communication in - // fake_syscall mode, so there's no way for a process to know it's - // not getting a unique value. - - xc->setIntReg(SyscallPseudoReturnReg, 99); - return 100; -} - - -SyscallReturn -getuidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - // Make up a UID and EUID... it shouldn't matter, and we want the - // simulation to be deterministic. - - // EUID goes in r20. - xc->setIntReg(SyscallPseudoReturnReg, 100); //EUID - return 100; // UID -} - - -SyscallReturn -getgidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - // Get current group ID. EGID goes in r20. - xc->setIntReg(SyscallPseudoReturnReg, 100); //EGID - return 100; -} - - -SyscallReturn -setuidFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - // can't fathom why a benchmark would call this. - warn("Ignoring call to setuid(%d)\n", xc->getSyscallArg(0)); - return 0; -} - -SyscallReturn -getpidFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - // Make up a PID. There's no interprocess communication in - // fake_syscall mode, so there's no way for a process to know it's - // not getting a unique value. - - xc->setIntReg(SyscallPseudoReturnReg, 99); //PID - return 100; -} - -SyscallReturn -getppidFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - return 99; -} - -SyscallReturn -getuidFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - return 100; // UID -} - -SyscallReturn -geteuidFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - return 100; // UID -} - -SyscallReturn -getgidFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - return 100; -} - -SyscallReturn -getegidFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - return 100; -} - - diff --git a/sim/syscall_emul.hh b/sim/syscall_emul.hh deleted file mode 100644 index 35129bcb4..000000000 --- a/sim/syscall_emul.hh +++ /dev/null @@ -1,832 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef __SIM_SYSCALL_EMUL_HH__ -#define __SIM_SYSCALL_EMUL_HH__ - -#define BSD_HOST (defined(__APPLE__) || defined(__OpenBSD__) || \ - defined(__FreeBSD__)) - -/// -/// @file syscall_emul.hh -/// -/// This file defines objects used to emulate syscalls from the target -/// application on the host machine. - -#include <errno.h> -#include <string> -#ifdef __CYGWIN32__ -#include <sys/fcntl.h> // for O_BINARY -#endif -#include <sys/uio.h> - -#include "base/intmath.hh" // for RoundUp -#include "mem/functional/functional.hh" -#include "arch/isa_traits.hh" // for Addr - -#include "base/trace.hh" -#include "cpu/exec_context.hh" -#include "sim/process.hh" - -/// -/// System call descriptor. -/// -class SyscallDesc { - - public: - - /// Typedef for target syscall handler functions. - typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num, - Process *, ExecContext *); - - const char *name; //!< Syscall name (e.g., "open"). - FuncPtr funcPtr; //!< Pointer to emulation function. - int flags; //!< Flags (see Flags enum). - - /// Flag values for controlling syscall behavior. - enum Flags { - /// Don't set return regs according to funcPtr return value. - /// Used for syscalls with non-standard return conventions - /// that explicitly set the ExecContext regs (e.g., - /// sigreturn). - SuppressReturnValue = 1 - }; - - /// Constructor. - SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0) - : name(_name), funcPtr(_funcPtr), flags(_flags) - { - } - - /// Emulate the syscall. Public interface for calling through funcPtr. - void doSyscall(int callnum, Process *proc, ExecContext *xc); -}; - - -class BaseBufferArg { - - public: - - BaseBufferArg(Addr _addr, int _size) : addr(_addr), size(_size) - { - bufPtr = new uint8_t[size]; - // clear out buffer: in case we only partially populate this, - // and then do a copyOut(), we want to make sure we don't - // introduce any random junk into the simulated address space - memset(bufPtr, 0, size); - } - - virtual ~BaseBufferArg() { delete [] bufPtr; } - - // - // copy data into simulator space (read from target memory) - // - virtual bool copyIn(FunctionalMemory *mem) - { - mem->access(Read, addr, bufPtr, size); - return true; // no EFAULT detection for now - } - - // - // copy data out of simulator space (write to target memory) - // - virtual bool copyOut(FunctionalMemory *mem) - { - mem->access(Write, addr, bufPtr, size); - return true; // no EFAULT detection for now - } - - protected: - Addr addr; - int size; - uint8_t *bufPtr; -}; - - -class BufferArg : public BaseBufferArg -{ - public: - BufferArg(Addr _addr, int _size) : BaseBufferArg(_addr, _size) { } - void *bufferPtr() { return bufPtr; } -}; - -template <class T> -class TypedBufferArg : public BaseBufferArg -{ - public: - // user can optionally specify a specific number of bytes to - // allocate to deal with those structs that have variable-size - // arrays at the end - TypedBufferArg(Addr _addr, int _size = sizeof(T)) - : BaseBufferArg(_addr, _size) - { } - - // type case - operator T*() { return (T *)bufPtr; } - - // dereference operators - T &operator*() { return *((T *)bufPtr); } - T* operator->() { return (T *)bufPtr; } - T &operator[](int i) { return ((T *)bufPtr)[i]; } -}; - -////////////////////////////////////////////////////////////////////// -// -// The following emulation functions are generic enough that they -// don't need to be recompiled for different emulated OS's. They are -// defined in sim/syscall_emul.cc. -// -////////////////////////////////////////////////////////////////////// - - -/// Handler for unimplemented syscalls that we haven't thought about. -SyscallReturn unimplementedFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Handler for unimplemented syscalls that we never intend to -/// implement (signal handling, etc.) and should not affect the correct -/// behavior of the program. Print a warning only if the appropriate -/// trace flag is enabled. Return success to the target program. -SyscallReturn ignoreFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target exit() handler: terminate simulation. -SyscallReturn exitFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target getpagesize() handler. -SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target obreak() handler: set brk address. -SyscallReturn obreakFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target close() handler. -SyscallReturn closeFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target read() handler. -SyscallReturn readFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target write() handler. -SyscallReturn writeFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target lseek() handler. -SyscallReturn lseekFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target munmap() handler. -SyscallReturn munmapFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target gethostname() handler. -SyscallReturn gethostnameFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target unlink() handler. -SyscallReturn unlinkFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target rename() handler. -SyscallReturn renameFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - - -/// Target truncate() handler. -SyscallReturn truncateFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - - -/// Target ftruncate() handler. -SyscallReturn ftruncateFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - - -/// Target chown() handler. -SyscallReturn chownFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - - -/// Target fchown() handler. -SyscallReturn fchownFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target fnctl() handler. -SyscallReturn fcntlFunc(SyscallDesc *desc, int num, - Process *process, ExecContext *xc); - -/// Target setuid() handler. -SyscallReturn setuidFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target getpid() handler. -SyscallReturn getpidFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target getuid() handler. -SyscallReturn getuidFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target getgid() handler. -SyscallReturn getgidFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target getppid() handler. -SyscallReturn getppidFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target geteuid() handler. -SyscallReturn geteuidFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target getegid() handler. -SyscallReturn getegidFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - - - -/// Pseudo Funcs - These functions use a different return convension, -/// returning a second value in a register other than the normal return register -SyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, - Process *process, ExecContext *xc); - -/// Target getpidPseudo() handler. -SyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target getuidPseudo() handler. -SyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - -/// Target getgidPseudo() handler. -SyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, - Process *p, ExecContext *xc); - - -/// This struct is used to build an target-OS-dependent table that -/// maps the target's open() flags to the host open() flags. -struct OpenFlagTransTable { - int tgtFlag; //!< Target system flag value. - int hostFlag; //!< Corresponding host system flag value. -}; - - - -/// A readable name for 1,000,000, for converting microseconds to seconds. -const int one_million = 1000000; - -/// Approximate seconds since the epoch (1/1/1970). About a billion, -/// by my reckoning. We want to keep this a constant (not use the -/// real-world time) to keep simulations repeatable. -const unsigned seconds_since_epoch = 1000000000; - -/// Helper function to convert current elapsed time to seconds and -/// microseconds. -template <class T1, class T2> -void -getElapsedTime(T1 &sec, T2 &usec) -{ - int elapsed_usecs = curTick / Clock::Int::us; - sec = elapsed_usecs / one_million; - usec = elapsed_usecs % one_million; -} - -////////////////////////////////////////////////////////////////////// -// -// The following emulation functions are generic, but need to be -// templated to account for differences in types, constants, etc. -// -////////////////////////////////////////////////////////////////////// - -/// Target ioctl() handler. For the most part, programs call ioctl() -/// only to find out if their stdout is a tty, to determine whether to -/// do line or block buffering. -template <class OS> -SyscallReturn -ioctlFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - int fd = xc->getSyscallArg(0); - unsigned req = xc->getSyscallArg(1); - - DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req); - - if (fd < 0 || process->sim_fd(fd) < 0) { - // doesn't map to any simulator fd: not a valid target fd - return -EBADF; - } - - switch (req) { - case OS::TIOCISATTY: - case OS::TIOCGETP: - case OS::TIOCSETP: - case OS::TIOCSETN: - case OS::TIOCSETC: - case OS::TIOCGETC: - case OS::TIOCGETS: - case OS::TIOCGETA: - return -ENOTTY; - - default: - fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ 0x%llx\n", - fd, req, xc->readPC()); - } -} - -/// Target open() handler. -template <class OS> -SyscallReturn -openFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - std::string path; - - if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault) - return -EFAULT; - - if (path == "/dev/sysdev0") { - // This is a memory-mapped high-resolution timer device on Alpha. - // We don't support it, so just punt. - warn("Ignoring open(%s, ...)\n", path); - return -ENOENT; - } - - int tgtFlags = xc->getSyscallArg(1); - int mode = xc->getSyscallArg(2); - int hostFlags = 0; - - // translate open flags - for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { - if (tgtFlags & OS::openFlagTable[i].tgtFlag) { - tgtFlags &= ~OS::openFlagTable[i].tgtFlag; - hostFlags |= OS::openFlagTable[i].hostFlag; - } - } - - // any target flags left? - if (tgtFlags != 0) - warn("Syscall: open: cannot decode flags 0x%x", tgtFlags); - -#ifdef __CYGWIN32__ - hostFlags |= O_BINARY; -#endif - - DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str()); - - // open the file - int fd = open(path.c_str(), hostFlags, mode); - - return (fd == -1) ? -errno : process->alloc_fd(fd); -} - - -/// Target chmod() handler. -template <class OS> -SyscallReturn -chmodFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - std::string path; - - if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault) - return -EFAULT; - - uint32_t mode = xc->getSyscallArg(1); - mode_t hostMode = 0; - - // XXX translate mode flags via OS::something??? - hostMode = mode; - - // do the chmod - int result = chmod(path.c_str(), hostMode); - if (result < 0) - return -errno; - - return 0; -} - - -/// Target fchmod() handler. -template <class OS> -SyscallReturn -fchmodFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - int fd = xc->getSyscallArg(0); - if (fd < 0 || process->sim_fd(fd) < 0) { - // doesn't map to any simulator fd: not a valid target fd - return -EBADF; - } - - uint32_t mode = xc->getSyscallArg(1); - mode_t hostMode = 0; - - // XXX translate mode flags via OS::someting??? - hostMode = mode; - - // do the fchmod - int result = fchmod(process->sim_fd(fd), hostMode); - if (result < 0) - return -errno; - - return 0; -} - - -/// Target stat() handler. -template <class OS> -SyscallReturn -statFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - std::string path; - - if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault) - return -EFAULT; - - struct stat hostBuf; - int result = stat(path.c_str(), &hostBuf); - - if (result < 0) - return -errno; - - OS::copyOutStatBuf(xc->getMemPtr(), xc->getSyscallArg(1), &hostBuf); - - return 0; -} - - -/// Target fstat64() handler. -template <class OS> -SyscallReturn -fstat64Func(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - int fd = xc->getSyscallArg(0); - if (fd < 0 || process->sim_fd(fd) < 0) { - // doesn't map to any simulator fd: not a valid target fd - return -EBADF; - } - -#if BSD_HOST - struct stat hostBuf; - int result = fstat(process->sim_fd(fd), &hostBuf); -#else - struct stat64 hostBuf; - int result = fstat64(process->sim_fd(fd), &hostBuf); -#endif - - if (result < 0) - return -errno; - - OS::copyOutStat64Buf(xc->getMemPtr(), fd, xc->getSyscallArg(1), &hostBuf); - - return 0; -} - - -/// Target lstat() handler. -template <class OS> -SyscallReturn -lstatFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - std::string path; - - if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault) - return -EFAULT; - - struct stat hostBuf; - int result = lstat(path.c_str(), &hostBuf); - - if (result < 0) - return -errno; - - OS::copyOutStatBuf(xc->getMemPtr(), xc->getSyscallArg(1), &hostBuf); - - return 0; -} - -/// Target lstat64() handler. -template <class OS> -SyscallReturn -lstat64Func(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - std::string path; - - if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault) - return -EFAULT; - -#if BSD_HOST - struct stat hostBuf; - int result = lstat(path.c_str(), &hostBuf); -#else - struct stat64 hostBuf; - int result = lstat64(path.c_str(), &hostBuf); -#endif - - if (result < 0) - return -errno; - - OS::copyOutStat64Buf(xc->getMemPtr(), -1, xc->getSyscallArg(1), &hostBuf); - - return 0; -} - -/// Target fstat() handler. -template <class OS> -SyscallReturn -fstatFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - int fd = process->sim_fd(xc->getSyscallArg(0)); - - DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd); - - if (fd < 0) - return -EBADF; - - struct stat hostBuf; - int result = fstat(fd, &hostBuf); - - if (result < 0) - return -errno; - - OS::copyOutStatBuf(xc->getMemPtr(), xc->getSyscallArg(1), &hostBuf); - return 0; -} - - -/// Target statfs() handler. -template <class OS> -SyscallReturn -statfsFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - std::string path; - - if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault) - return -EFAULT; - - struct statfs hostBuf; - int result = statfs(path.c_str(), &hostBuf); - - if (result < 0) - return -errno; - - OS::copyOutStatfsBuf(xc->getMemPtr(), xc->getSyscallArg(1), &hostBuf); - - return 0; -} - - -/// Target fstatfs() handler. -template <class OS> -SyscallReturn -fstatfsFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - int fd = process->sim_fd(xc->getSyscallArg(0)); - - if (fd < 0) - return -EBADF; - - struct statfs hostBuf; - int result = fstatfs(fd, &hostBuf); - - if (result < 0) - return -errno; - - OS::copyOutStatfsBuf(xc->getMemPtr(), xc->getSyscallArg(1), &hostBuf); - - return 0; -} - - -/// Target writev() handler. -template <class OS> -SyscallReturn -writevFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - int fd = xc->getSyscallArg(0); - if (fd < 0 || process->sim_fd(fd) < 0) { - // doesn't map to any simulator fd: not a valid target fd - return -EBADF; - } - - uint64_t tiov_base = xc->getSyscallArg(1); - size_t count = xc->getSyscallArg(2); - struct iovec hiov[count]; - for (int i = 0; i < count; ++i) - { - typename OS::tgt_iovec tiov; - xc->getMemPtr()->access(Read, tiov_base + i*sizeof(typename OS::tgt_iovec), - &tiov, sizeof(typename OS::tgt_iovec)); - hiov[i].iov_len = gtoh(tiov.iov_len); - hiov[i].iov_base = new char [hiov[i].iov_len]; - xc->getMemPtr()->access(Read, gtoh(tiov.iov_base), - hiov[i].iov_base, hiov[i].iov_len); - } - - int result = writev(process->sim_fd(fd), hiov, count); - - for (int i = 0; i < count; ++i) - { - delete [] (char *)hiov[i].iov_base; - } - - if (result < 0) - return -errno; - - return 0; -} - - -/// Target mmap() handler. -/// -/// We don't really handle mmap(). If the target is mmaping an -/// anonymous region or /dev/zero, we can get away with doing basically -/// nothing (since memory is initialized to zero and the simulator -/// doesn't really check addresses anyway). Always print a warning, -/// since this could be seriously broken if we're not mapping -/// /dev/zero. -// -/// Someday we should explicitly check for /dev/zero in open, flag the -/// file descriptor, and fail (or implement!) a non-anonymous mmap to -/// anything else. -template <class OS> -SyscallReturn -mmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) -{ - Addr start = xc->getSyscallArg(0); - uint64_t length = xc->getSyscallArg(1); - // int prot = xc->getSyscallArg(2); - int flags = xc->getSyscallArg(3); - // int fd = p->sim_fd(xc->getSyscallArg(4)); - // int offset = xc->getSyscallArg(5); - - if (start == 0) { - // user didn't give an address... pick one from our "mmap region" - start = p->mmap_end; - p->mmap_end += roundUp(length, TheISA::VMPageSize); - if (p->nxm_start != 0) { - //If we have an nxm space, make sure we haven't colided - assert(p->mmap_end < p->nxm_start); - } - } - - if (!(flags & OS::TGT_MAP_ANONYMOUS)) { - warn("allowing mmap of file @ fd %d. " - "This will break if not /dev/zero.", xc->getSyscallArg(4)); - } - - return start; -} - -/// Target getrlimit() handler. -template <class OS> -SyscallReturn -getrlimitFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - unsigned resource = xc->getSyscallArg(0); - TypedBufferArg<typename OS::rlimit> rlp(xc->getSyscallArg(1)); - - switch (resource) { - case OS::TGT_RLIMIT_STACK: - // max stack size in bytes: make up a number (2MB for now) - rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; - rlp->rlim_cur = htog(rlp->rlim_cur); - rlp->rlim_max = htog(rlp->rlim_max); - break; - - default: - std::cerr << "getrlimitFunc: unimplemented resource " << resource - << std::endl; - abort(); - break; - } - - rlp.copyOut(xc->getMemPtr()); - return 0; -} - -/// Target gettimeofday() handler. -template <class OS> -SyscallReturn -gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - TypedBufferArg<typename OS::timeval> tp(xc->getSyscallArg(0)); - - getElapsedTime(tp->tv_sec, tp->tv_usec); - tp->tv_sec += seconds_since_epoch; - tp->tv_sec = htog(tp->tv_sec); - tp->tv_usec = htog(tp->tv_usec); - - tp.copyOut(xc->getMemPtr()); - - return 0; -} - - -/// Target utimes() handler. -template <class OS> -SyscallReturn -utimesFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - std::string path; - - if (xc->getMemPtr()->readString(path, xc->getSyscallArg(0)) != NoFault) - return -EFAULT; - - TypedBufferArg<typename OS::timeval [2]> tp(xc->getSyscallArg(1)); - tp.copyIn(xc->getMemPtr()); - - struct timeval hostTimeval[2]; - for (int i = 0; i < 2; ++i) - { - hostTimeval[i].tv_sec = gtoh((*tp)[i].tv_sec); - hostTimeval[i].tv_usec = gtoh((*tp)[i].tv_usec); - } - int result = utimes(path.c_str(), hostTimeval); - - if (result < 0) - return -errno; - - return 0; -} -/// Target getrusage() function. -template <class OS> -SyscallReturn -getrusageFunc(SyscallDesc *desc, int callnum, Process *process, - ExecContext *xc) -{ - int who = xc->getSyscallArg(0); // THREAD, SELF, or CHILDREN - TypedBufferArg<typename OS::rusage> rup(xc->getSyscallArg(1)); - - if (who != OS::TGT_RUSAGE_SELF) { - // don't really handle THREAD or CHILDREN, but just warn and - // plow ahead - warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", - who); - } - - getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); - rup->ru_utime.tv_sec = htog(rup->ru_utime.tv_sec); - rup->ru_utime.tv_usec = htog(rup->ru_utime.tv_usec); - - rup->ru_stime.tv_sec = 0; - rup->ru_stime.tv_usec = 0; - rup->ru_maxrss = 0; - rup->ru_ixrss = 0; - rup->ru_idrss = 0; - rup->ru_isrss = 0; - rup->ru_minflt = 0; - rup->ru_majflt = 0; - rup->ru_nswap = 0; - rup->ru_inblock = 0; - rup->ru_oublock = 0; - rup->ru_msgsnd = 0; - rup->ru_msgrcv = 0; - rup->ru_nsignals = 0; - rup->ru_nvcsw = 0; - rup->ru_nivcsw = 0; - - rup.copyOut(xc->getMemPtr()); - - return 0; -} - -#endif // __SIM_SYSCALL_EMUL_HH__ diff --git a/sim/system.cc b/sim/system.cc deleted file mode 100644 index 7f5b54c6b..000000000 --- a/sim/system.cc +++ /dev/null @@ -1,171 +0,0 @@ -#include "base/loader/object_file.hh" -#include "base/loader/symtab.hh" -#include "base/remote_gdb.hh" -#include "cpu/exec_context.hh" -#include "kern/kernel_stats.hh" -#include "mem/functional/memory_control.hh" -#include "mem/functional/physical.hh" -#include "arch/vtophys.hh" -#include "sim/builder.hh" -#include "arch/isa_traits.hh" -#include "sim/byteswap.hh" -#include "sim/system.hh" -#include "base/trace.hh" - -using namespace std; -using namespace TheISA; - -vector<System *> System::systemList; - -int System::numSystemsRunning = 0; - -System::System(Params *p) - : SimObject(p->name), memctrl(p->memctrl), physmem(p->physmem), - init_param(p->init_param), numcpus(0), _params(p) -{ - // add self to global system list - systemList.push_back(this); - - kernelSymtab = new SymbolTable; - debugSymbolTable = new SymbolTable; - - /** - * Load the kernel code into memory - */ - // Load kernel code - kernel = createObjectFile(params()->kernel_path); - if (kernel == NULL) - fatal("Could not load kernel file %s", params()->kernel_path); - - // Load program sections into memory - kernel->loadSections(physmem, true); - - // setup entry points - kernelStart = kernel->textBase(); - kernelEnd = kernel->bssBase() + kernel->bssSize(); - kernelEntry = kernel->entryPoint(); - - // load symbols - if (!kernel->loadGlobalSymbols(kernelSymtab)) - panic("could not load kernel symbols\n"); - - if (!kernel->loadLocalSymbols(kernelSymtab)) - panic("could not load kernel local symbols\n"); - - if (!kernel->loadGlobalSymbols(debugSymbolTable)) - panic("could not load kernel symbols\n"); - - if (!kernel->loadLocalSymbols(debugSymbolTable)) - panic("could not load kernel local symbols\n"); - - DPRINTF(Loader, "Kernel start = %#x\n", kernelStart); - DPRINTF(Loader, "Kernel end = %#x\n", kernelEnd); - DPRINTF(Loader, "Kernel entry = %#x\n", kernelEntry); - DPRINTF(Loader, "Kernel loaded...\n"); - - // increment the number of running systms - numSystemsRunning++; -} - -System::~System() -{ - delete kernelSymtab; - delete kernel; -} - - - - -int rgdb_wait = -1; - -int -System::registerExecContext(ExecContext *xc, int id) -{ - if (id == -1) { - for (id = 0; id < execContexts.size(); id++) { - if (!execContexts[id]) - break; - } - } - - if (execContexts.size() <= id) - execContexts.resize(id + 1); - - if (execContexts[id]) - panic("Cannot have two CPUs with the same id (%d)\n", id); - - execContexts[id] = xc; - numcpus++; - - RemoteGDB *rgdb = new RemoteGDB(this, xc); - GDBListener *gdbl = new GDBListener(rgdb, 7000 + id); - gdbl->listen(); - /** - * Uncommenting this line waits for a remote debugger to connect - * to the simulator before continuing. - */ - if (rgdb_wait != -1 && rgdb_wait == id) - gdbl->accept(); - - if (remoteGDB.size() <= id) { - remoteGDB.resize(id + 1); - } - - remoteGDB[id] = rgdb; - - return id; -} - -void -System::startup() -{ - int i; - for (i = 0; i < execContexts.size(); i++) - execContexts[i]->activate(0); -} - -void -System::replaceExecContext(ExecContext *xc, int id) -{ - if (id >= execContexts.size()) { - panic("replaceExecContext: bad id, %d >= %d\n", - id, execContexts.size()); - } - - execContexts[id] = xc; - remoteGDB[id]->replaceExecContext(xc); -} - -void -System::serialize(ostream &os) -{ - kernelSymtab->serialize("kernel_symtab", os); -} - - -void -System::unserialize(Checkpoint *cp, const string §ion) -{ - kernelSymtab->unserialize("kernel_symtab", cp, section); -} - -void -System::printSystems() -{ - vector<System *>::iterator i = systemList.begin(); - vector<System *>::iterator end = systemList.end(); - for (; i != end; ++i) { - System *sys = *i; - cerr << "System " << sys->name() << ": " << hex << sys << endl; - } -} - -extern "C" -void -printSystems() -{ - System::printSystems(); -} - -DEFINE_SIM_OBJECT_CLASS_NAME("System", System) - diff --git a/sim/system.hh b/sim/system.hh deleted file mode 100644 index 2156747fb..000000000 --- a/sim/system.hh +++ /dev/null @@ -1,187 +0,0 @@ -/* - * 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. - */ - -#ifndef __SYSTEM_HH__ -#define __SYSTEM_HH__ - -#include <string> -#include <vector> - -#include "base/statistics.hh" -#include "base/loader/symtab.hh" -#include "cpu/pc_event.hh" -#include "kern/system_events.hh" -#include "sim/sim_object.hh" - -class BaseCPU; -class ExecContext; -class GDBListener; -class MemoryController; -class ObjectFile; -class PhysicalMemory; -class Platform; -class RemoteGDB; - -class System : public SimObject -{ - public: - MemoryController *memctrl; - PhysicalMemory *physmem; - Platform *platform; - PCEventQueue pcEventQueue; - uint64_t init_param; - - std::vector<ExecContext *> execContexts; - int numcpus; - - int getNumCPUs() - { - if (numcpus != execContexts.size()) - panic("cpu array not fully populated!"); - - return numcpus; - } - - /** kernel symbol table */ - SymbolTable *kernelSymtab; - - /** Object pointer for the kernel code */ - ObjectFile *kernel; - - /** Begining of kernel code */ - Addr kernelStart; - - /** End of kernel code */ - Addr kernelEnd; - - /** Entry point in the kernel to start at */ - Addr kernelEntry; - - protected: - - /** - * Fix up an address used to match PCs for hooking simulator - * events on to target function executions. See comment in - * system.cc for details. - */ - virtual Addr fixFuncEventAddr(Addr addr) = 0; - - /** - * Add a function-based event to the given function, to be looked - * up in the specified symbol table. - */ - template <class T> - T *System::addFuncEvent(SymbolTable *symtab, const char *lbl) - { - Addr addr = 0; // initialize only to avoid compiler warning - - if (symtab->findAddress(lbl, addr)) { - T *ev = new T(&pcEventQueue, lbl, fixFuncEventAddr(addr)); - return ev; - } - - return NULL; - } - - /** Add a function-based event to kernel code. */ - template <class T> - T *System::addKernelFuncEvent(const char *lbl) - { - return addFuncEvent<T>(kernelSymtab, lbl); - } - - public: - std::vector<RemoteGDB *> remoteGDB; - std::vector<GDBListener *> gdbListen; - virtual bool breakpoint() = 0; - - public: - struct Params - { - std::string name; - Tick boot_cpu_frequency; - MemoryController *memctrl; - PhysicalMemory *physmem; - uint64_t init_param; - - std::string kernel_path; - std::string readfile; - }; - - protected: - Params *_params; - - public: - System(Params *p); - ~System(); - - void startup(); - - const Params *params() const { return (const Params *)_params; } - - public: - /** - * Returns the addess the kernel starts at. - * @return address the kernel starts at - */ - Addr getKernelStart() const { return kernelStart; } - - /** - * Returns the addess the kernel ends at. - * @return address the kernel ends at - */ - Addr getKernelEnd() const { return kernelEnd; } - - /** - * Returns the addess the entry point to the kernel code. - * @return entry point of the kernel code - */ - Addr getKernelEntry() const { return kernelEntry; } - - int registerExecContext(ExecContext *xc, int xcIndex); - void replaceExecContext(ExecContext *xc, int xcIndex); - - void serialize(std::ostream &os); - void unserialize(Checkpoint *cp, const std::string §ion); - - public: - //////////////////////////////////////////// - // - // STATIC GLOBAL SYSTEM LIST - // - //////////////////////////////////////////// - - static std::vector<System *> systemList; - static int numSystemsRunning; - - static void printSystems(); - - -}; - -#endif // __SYSTEM_HH__ diff --git a/sim/vptr.hh b/sim/vptr.hh deleted file mode 100644 index 0ec452f25..000000000 --- a/sim/vptr.hh +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2004-2005 The Regents of The University of Michigan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer; - * redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution; - * neither the name of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __ARCH_ALPHA_VPTR_HH__ -#define __ARCH_ALPHA_VPTR_HH__ - -#include "arch/vtophys.hh" -#include "arch/isa_traits.hh" - -class ExecContext; - -template <class T> -class VPtr -{ - public: - typedef T Type; - - private: - ExecContext *xc; - Addr ptr; - - public: - ExecContext *GetXC() const { return xc; } - Addr GetPointer() const { return ptr; } - - public: - explicit VPtr(ExecContext *_xc, Addr p = 0) : xc(_xc), ptr(p) { } - template <class U> - VPtr(const VPtr<U> &vp) : xc(vp.GetXC()), ptr(vp.GetPointer()) {} - ~VPtr() {} - - bool operator!() const - { - return ptr == 0; - } - - VPtr<T> operator+(int offset) - { - VPtr<T> ptr(*this); - ptr += offset; - - return ptr; - } - - const VPtr<T> &operator+=(int offset) - { - ptr += offset; - assert((ptr & (TheISA::PageBytes - 1)) + sizeof(T) - < TheISA::PageBytes); - - return *this; - } - - const VPtr<T> &operator=(Addr p) - { - assert((p & (TheISA::PageBytes - 1)) + sizeof(T) - < TheISA::PageBytes); - ptr = p; - - return *this; - } - - template <class U> - const VPtr<T> &operator=(const VPtr<U> &vp) - { - xc = vp.GetXC(); - ptr = vp.GetPointer(); - - return *this; - } - - operator T *() - { - void *addr = vtomem(xc, ptr, sizeof(T)); - return (T *)addr; - } - - T *operator->() - { - void *addr = vtomem(xc, ptr, sizeof(T)); - return (T *)addr; - } - - T &operator*() - { - void *addr = vtomem(xc, ptr, sizeof(T)); - return *(T *)addr; - } -}; - -#endif // __ARCH_ALPHA_VPTR_HH__ diff --git a/Doxyfile b/src/Doxyfile index 38116f6b0..38116f6b0 100644 --- a/Doxyfile +++ b/src/Doxyfile diff --git a/src/SConscript b/src/SConscript new file mode 100644 index 000000000..a1c18711c --- /dev/null +++ b/src/SConscript @@ -0,0 +1,398 @@ +# -*- mode:python -*- + +# 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: Steve Reinhardt + +import os +import sys +from os.path import isdir + +# This file defines how to build a particular configuration of M5 +# based on variable settings in the 'env' build environment. + +# Import build environment variable from SConstruct. +Import('env') + +################################################### +# +# Define needed sources. +# +################################################### + +# Base sources used by all configurations. + +base_sources = Split(''' + base/circlebuf.cc + base/cprintf.cc + base/fast_alloc.cc + base/fifo_buffer.cc + base/hostinfo.cc + base/hybrid_pred.cc + base/inifile.cc + base/intmath.cc + base/match.cc + base/misc.cc + base/output.cc + base/pollevent.cc + base/range.cc + base/random.cc + base/sat_counter.cc + base/serializer.cc + base/socket.cc + base/statistics.cc + base/str.cc + base/time.cc + base/trace.cc + base/traceflags.cc + base/userinfo.cc + base/compression/lzss_compression.cc + base/loader/aout_object.cc + base/loader/ecoff_object.cc + base/loader/elf_object.cc + base/loader/object_file.cc + base/loader/symtab.cc + base/stats/events.cc + base/stats/statdb.cc + base/stats/visit.cc + base/stats/text.cc + + cpu/activity.cc + cpu/base.cc + cpu/cpuevent.cc + cpu/exetrace.cc + cpu/op_class.cc + cpu/pc_event.cc + cpu/quiesce_event.cc + cpu/static_inst.cc + cpu/sampler/sampler.cc + cpu/simple_thread.cc + cpu/thread_state.cc + + encumbered/cpu/full/fu_pool.cc + + mem/bridge.cc + mem/bus.cc + mem/connector.cc + mem/mem_object.cc + mem/packet.cc + mem/physical.cc + mem/port.cc + + sim/builder.cc + sim/configfile.cc + sim/debug.cc + sim/eventq.cc + sim/faults.cc + sim/main.cc + python/swig/main_wrap.cc + sim/param.cc + sim/profile.cc + sim/root.cc + sim/serialize.cc + sim/sim_events.cc + sim/sim_object.cc + sim/startup.cc + sim/stat_context.cc + sim/stat_control.cc + sim/system.cc + sim/trace_context.cc + ''') + +# Old FullCPU sources +full_cpu_sources = Split(''' + encumbered/cpu/full/bpred.cc + encumbered/cpu/full/commit.cc + encumbered/cpu/full/cpu.cc + encumbered/cpu/full/create_vector.cc + encumbered/cpu/full/cv_spec_state.cc + encumbered/cpu/full/dd_queue.cc + encumbered/cpu/full/dep_link.cc + encumbered/cpu/full/dispatch.cc + encumbered/cpu/full/dyn_inst.cc + encumbered/cpu/full/execute.cc + encumbered/cpu/full/fetch.cc + encumbered/cpu/full/floss_reasons.cc + encumbered/cpu/full/fu_pool.cc + encumbered/cpu/full/inst_fifo.cc + encumbered/cpu/full/instpipe.cc + encumbered/cpu/full/issue.cc + encumbered/cpu/full/ls_queue.cc + encumbered/cpu/full/machine_queue.cc + encumbered/cpu/full/pipetrace.cc + encumbered/cpu/full/readyq.cc + encumbered/cpu/full/reg_info.cc + encumbered/cpu/full/rob_station.cc + encumbered/cpu/full/spec_memory.cc + encumbered/cpu/full/spec_state.cc + encumbered/cpu/full/storebuffer.cc + encumbered/cpu/full/writeback.cc + encumbered/cpu/full/iq/iq_station.cc + encumbered/cpu/full/iq/iqueue.cc + encumbered/cpu/full/iq/segmented/chain_info.cc + encumbered/cpu/full/iq/segmented/chain_wire.cc + encumbered/cpu/full/iq/segmented/iq_seg.cc + encumbered/cpu/full/iq/segmented/iq_segmented.cc + encumbered/cpu/full/iq/segmented/seg_chain.cc + encumbered/cpu/full/iq/seznec/iq_seznec.cc + encumbered/cpu/full/iq/standard/iq_standard.cc + ''') + +trace_reader_sources = Split(''' + cpu/trace/reader/mem_trace_reader.cc + cpu/trace/reader/ibm_reader.cc + cpu/trace/reader/itx_reader.cc + cpu/trace/reader/m5_reader.cc + cpu/trace/opt_cpu.cc + cpu/trace/trace_cpu.cc + ''') + + + +# MySql sources +mysql_sources = Split(''' + base/mysql.cc + base/stats/mysql.cc + ''') + +# Full-system sources +full_system_sources = Split(''' + base/crc.cc + base/inet.cc + base/remote_gdb.cc + + cpu/intr_control.cc + cpu/profile.cc + + dev/alpha_console.cc + dev/baddev.cc + dev/disk_image.cc + dev/etherbus.cc + dev/etherdump.cc + dev/etherint.cc + dev/etherlink.cc + dev/etherpkt.cc + dev/ethertap.cc + dev/ide_ctrl.cc + dev/ide_disk.cc + dev/io_device.cc + dev/isa_fake.cc + dev/ns_gige.cc + dev/pciconfigall.cc + dev/pcidev.cc + dev/pcifake.cc + dev/pktfifo.cc + dev/platform.cc + dev/simconsole.cc + dev/simple_disk.cc + dev/sinic.cc + dev/tsunami.cc + dev/tsunami_cchip.cc + dev/tsunami_io.cc + dev/tsunami_fake.cc + dev/tsunami_pchip.cc + + dev/uart.cc + dev/uart8250.cc + + kern/kernel_stats.cc + kern/system_events.cc + kern/linux/events.cc + kern/linux/linux_syscalls.cc + kern/linux/printk.cc + + mem/vport.cc + + sim/pseudo_inst.cc + ''') + + +if env['TARGET_ISA'] == 'alpha': + full_system_sources += Split(''' + kern/tru64/dump_mbuf.cc + kern/tru64/printf.cc + kern/tru64/tru64_events.cc + kern/tru64/tru64_syscalls.cc + ''') + +# turbolaser encumbered sources +turbolaser_sources = Split(''' + encumbered/dev/dma.cc + encumbered/dev/etherdev.cc + encumbered/dev/scsi.cc + encumbered/dev/scsi_ctrl.cc + encumbered/dev/scsi_disk.cc + encumbered/dev/scsi_none.cc + encumbered/dev/tlaser_clock.cc + encumbered/dev/tlaser_ipi.cc + encumbered/dev/tlaser_mbox.cc + encumbered/dev/tlaser_mc146818.cc + encumbered/dev/tlaser_node.cc + encumbered/dev/tlaser_pcia.cc + encumbered/dev/tlaser_pcidev.cc + encumbered/dev/tlaser_serial.cc + encumbered/dev/turbolaser.cc + encumbered/dev/uart8530.cc + ''') + +# Syscall emulation (non-full-system) sources +syscall_emulation_sources = Split(''' + mem/translating_port.cc + mem/page_table.cc + sim/process.cc + sim/syscall_emul.cc + ''') + +#if env['TARGET_ISA'] == 'alpha': +# syscall_emulation_sources += Split(''' +# kern/tru64/tru64.cc +# ''') + +alpha_eio_sources = Split(''' + encumbered/eio/exolex.cc + encumbered/eio/libexo.cc + encumbered/eio/eio.cc + ''') + +if env['TARGET_ISA'] == 'ALPHA_ISA': + syscall_emulation_sources += alpha_eio_sources + +memtest_sources = Split(''' + cpu/memtest/memtest.cc + ''') + +# Include file paths are rooted in this directory. SCons will +# automatically expand '.' to refer to both the source directory and +# the corresponding build directory to pick up generated include +# files. +env.Append(CPPPATH=Dir('.')) + +# Add a flag defining what THE_ISA should be for all compilation +env.Append(CPPDEFINES=[('THE_ISA','%s_ISA' % env['TARGET_ISA'].upper())]) + +arch_sources = SConscript('arch/SConscript', exports = 'env') + +cpu_sources = SConscript('cpu/SConscript', exports = 'env') + +# This is outside of cpu/SConscript since the source directory isn't +# underneath 'cpu'. +if 'FullCPU' in env['CPU_MODELS']: + cpu_sources += full_cpu_sources + +# Set up complete list of sources based on configuration. +sources = base_sources + arch_sources + cpu_sources + +if env['FULL_SYSTEM']: + sources += full_system_sources + if env['ALPHA_TLASER']: + sources += turbolaser_sources +else: + sources += syscall_emulation_sources + +if env['USE_MYSQL']: + sources += mysql_sources + +for opt in env.ExportOptions: + env.ConfigFile(opt) + +################################################### +# +# Special build rules. +# +################################################### + +# base/traceflags.{cc,hh} are generated from base/traceflags.py. +# $TARGET.base will expand to "<build-dir>/base/traceflags". +env.Command(Split('base/traceflags.hh base/traceflags.cc'), + 'base/traceflags.py', + 'python $SOURCE $TARGET.base') + +SConscript('python/SConscript', exports = ['env']) + +# This function adds the specified sources to the given build +# environment, and returns a list of all the corresponding SCons +# Object nodes (including an extra one for date.cc). We explicitly +# add the Object nodes so we can set up special dependencies for +# date.cc. +def make_objs(sources, env): + objs = [env.Object(s) for s in sources] + # make date.cc depend on all other objects so it always gets + # recompiled whenever anything else does + date_obj = env.Object('base/date.cc') + env.Depends(date_obj, objs) + objs.append(date_obj) + return objs + +################################################### +# +# Define binaries. Each different build type (debug, opt, etc.) gets +# a slightly different build environment. +# +################################################### + +# List of constructed environments to pass back to SConstruct +envList = [] + +# Function to create a new build environment as clone of current +# environment 'env' with modified object suffix and optional stripped +# binary. Additional keyword arguments are appended to corresponding +# build environment vars. +def makeEnv(label, objsfx, strip = False, **kwargs): + newEnv = env.Copy(OBJSUFFIX=objsfx) + newEnv.Label = label + newEnv.Append(**kwargs) + exe = 'm5.' + label # final executable + bin = exe + '.bin' # executable w/o appended Python zip archive + newEnv.Program(bin, make_objs(sources, newEnv)) + if strip: + stripped_bin = bin + '.stripped' + newEnv.Command(stripped_bin, bin, 'strip $SOURCE -o $TARGET') + bin = stripped_bin + targets = newEnv.Concat(exe, [bin, 'python/m5py.zip']) + newEnv.M5Binary = targets[0] + envList.append(newEnv) + +# Debug binary +makeEnv('debug', '.do', + CCFLAGS = Split('-g3 -gdwarf-2 -O0'), + CPPDEFINES = 'DEBUG') + +# Optimized binary +makeEnv('opt', '.o', + CCFLAGS = Split('-g -O3')) + +# "Fast" binary +makeEnv('fast', '.fo', strip = True, + CCFLAGS = Split('-O3'), + CPPDEFINES = 'NDEBUG') + +# Profiled binary +makeEnv('prof', '.po', + CCFLAGS = Split('-O3 -g -pg'), + LINKFLAGS = '-pg') + +Return('envList') diff --git a/src/arch/SConscript b/src/arch/SConscript new file mode 100644 index 000000000..c90694a68 --- /dev/null +++ b/src/arch/SConscript @@ -0,0 +1,151 @@ +# -*- 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 os.path + +# Import build environment variable from SConstruct. +Import('env') + +# Right now there are no source files immediately in this directory +sources = [] + +################################################################# +# +# ISA "switch header" generation. +# +# Auto-generate arch headers that include the right ISA-specific +# header based on the setting of THE_ISA preprocessor variable. +# +################################################################# + +# List of headers to generate +isa_switch_hdrs = Split(''' + arguments.hh + constants.hh + faults.hh + isa_traits.hh + process.hh + regfile.hh + stacktrace.hh + tlb.hh + types.hh + utility.hh + vtophys.hh + ''') + +# Generate the header. target[0] is the full path of the output +# header to generate. 'source' is a dummy variable, since we get the +# list of ISAs from env['ALL_ISA_LIST']. +def gen_switch_hdr(target, source, env): + fname = str(target[0]) + basename = os.path.basename(fname) + f = open(fname, 'w') + f.write('#include "arch/isa_specific.hh"\n') + cond = '#if' + for isa in env['ALL_ISA_LIST']: + f.write('%s THE_ISA == %s_ISA\n#include "arch/%s/%s"\n' + % (cond, isa.upper(), isa, basename)) + cond = '#elif' + f.write('#else\n#error "THE_ISA not set"\n#endif\n') + f.close() + return 0 + +# String to print when generating header +def gen_switch_hdr_string(target, source, env): + return "Generating ISA switch header " + str(target[0]) + +# Build SCons Action object. 'varlist' specifies env vars that this +# action depends on; when env['ALL_ISA_LIST'] changes these actions +# should get re-executed. +switch_hdr_action = Action(gen_switch_hdr, gen_switch_hdr_string, + varlist=['ALL_ISA_LIST']) + +# Instantiate actions for each header +for hdr in isa_switch_hdrs: + env.Command(hdr, [], switch_hdr_action) + +################################################################# +# +# Include architecture-specific files. +# +################################################################# + +# +# Build a SCons scanner for ISA files +# +import SCons.Scanner + +isa_scanner = SCons.Scanner.Classic("ISAScan", + [".isa", ".ISA"], + "SRCDIR", + r'^\s*##include\s+"([\w/.-]*)"') + +env.Append(SCANNERS = isa_scanner) + +# +# Now create a Builder object that uses isa_parser.py to generate C++ +# output from the ISA description (*.isa) files. +# + +# Convert to File node to fix path +isa_parser = File('isa_parser.py') +cpu_models_file = File('../cpu/cpu_models.py') + +# This sucks in the defintions of the CpuModel objects. +execfile(cpu_models_file.srcnode().abspath) + +# Several files are generated from the ISA description. +# We always get the basic decoder and header file. +isa_desc_gen_files = Split('decoder.cc decoder.hh') +# We also get an execute file for each selected CPU model. +isa_desc_gen_files += [CpuModel.dict[cpu].filename + for cpu in env['CPU_MODELS']] + +# The emitter patches up the sources & targets to include the +# autogenerated files as targets and isa parser itself as a source. +def isa_desc_emitter(target, source, env): + return (isa_desc_gen_files, [isa_parser, cpu_models_file] + source) + +# Pieces are in place, so create the builder. +isa_desc_builder = Builder(action='python2.4 $SOURCES $TARGET.dir $CPU_MODELS', + emitter = isa_desc_emitter) + +env.Append(BUILDERS = { 'ISADesc' : isa_desc_builder }) + +# +# Now include other ISA-specific sources from the ISA subdirectories. +# + +isa = env['TARGET_ISA'] # someday this may be a list of ISAs + +# Let the target architecture define what additional sources it needs +sources += SConscript(os.path.join(isa, 'SConscript'), exports = 'env') + +Return('sources') diff --git a/src/arch/alpha/SConscript b/src/arch/alpha/SConscript new file mode 100644 index 000000000..216c88cc7 --- /dev/null +++ b/src/arch/alpha/SConscript @@ -0,0 +1,96 @@ +# -*- mode:python -*- + +# Copyright (c) 2004-2005 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black +# Steve Reinhardt + +import os +import sys +from os.path import isdir + +# This file defines how to build a particular configuration of M5 +# based on variable settings in the 'env' build environment. + +# Import build environment variable from SConstruct. +Import('env') + +################################################### +# +# Define needed sources. +# +################################################### + +# Base sources used by all configurations. +base_sources = Split(''' + faults.cc + isa_traits.cc + ''') + +# Full-system sources +full_system_sources = Split(''' + tlb.cc + arguments.cc + ev5.cc + osfpal.cc + stacktrace.cc + vtophys.cc + system.cc + freebsd/system.cc + linux/system.cc + tru64/system.cc + ''') + + +# Syscall emulation (non-full-system) sources +syscall_emulation_sources = Split(''' + linux/linux.cc + linux/process.cc + tru64/tru64.cc + tru64/process.cc + process.cc + ''') + +# Set up complete list of sources based on configuration. +sources = base_sources + +if env['FULL_SYSTEM']: + sources += full_system_sources +else: + sources += syscall_emulation_sources + +# Convert file names to SCons File objects. This takes care of the +# path relative to the top of the directory tree. +sources = [File(s) for s in sources] + +# Add in files generated by the ISA description. +isa_desc_files = env.ISADesc('isa/main.isa') +# Only non-header files need to be compiled. +isa_desc_sources = [f for f in isa_desc_files if not f.path.endswith('.hh')] +sources += isa_desc_sources + +Return('sources') diff --git a/src/arch/alpha/aout_machdep.h b/src/arch/alpha/aout_machdep.h new file mode 100644 index 000000000..58991256a --- /dev/null +++ b/src/arch/alpha/aout_machdep.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 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 Reinhardt + * Nathan Binkert + */ + +#ifndef __AOUT_MACHDEP_H__ +#define __AOUT_MACHDEP_H__ + +/// +/// Funky Alpha 64-bit a.out header used for PAL code. +/// +struct aout_exechdr { + uint16_t magic; ///< magic number + uint16_t vstamp; ///< version stamp? + uint16_t bldrev; ///< ??? + uint16_t padcell; ///< padding + uint64_t tsize; ///< text segment size + uint64_t dsize; ///< data segment size + uint64_t bsize; ///< bss segment size + uint64_t entry; ///< entry point + uint64_t text_start; ///< text base address + uint64_t data_start; ///< data base address + uint64_t bss_start; ///< bss base address + uint32_t gprmask; ///< GPR mask (unused, AFAIK) + uint32_t fprmask; ///< FPR mask (unused, AFAIK) + uint64_t gp_value; ///< global pointer reg value +}; + +#define AOUT_LDPGSZ 8192 + +#define N_GETMAGIC(ex) ((ex).magic) + +#define N_BADMAX + +#define N_TXTADDR(ex) ((ex).text_start) +#define N_DATADDR(ex) ((ex).data_start) +#define N_BSSADDR(ex) ((ex).bss_start) + +#define N_TXTOFF(ex) \ + (N_GETMAGIC(ex) == ZMAGIC ? 0 : sizeof(struct aout_exechdr)) + +#define N_DATOFF(ex) N_ALIGN(ex, N_TXTOFF(ex) + (ex).tsize) + +#endif /* !__AOUT_MACHDEP_H__*/ diff --git a/src/arch/alpha/arguments.cc b/src/arch/alpha/arguments.cc new file mode 100644 index 000000000..9f9002003 --- /dev/null +++ b/src/arch/alpha/arguments.cc @@ -0,0 +1,70 @@ +/* + * Copyright (c) 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: Nathan Binkert + */ + +#include "arch/alpha/arguments.hh" +#include "arch/alpha/vtophys.hh" +#include "cpu/thread_context.hh" +#include "mem/vport.hh" + +using namespace AlphaISA; + +AlphaArguments::Data::~Data() +{ + while (!data.empty()) { + delete [] data.front(); + data.pop_front(); + } +} + +char * +AlphaArguments::Data::alloc(size_t size) +{ + char *buf = new char[size]; + data.push_back(buf); + return buf; +} + +uint64_t +AlphaArguments::getArg(bool fp) +{ + if (number < 6) { + if (fp) + return tc->readFloatRegBits(16 + number); + else + return tc->readIntReg(16 + number); + } else { + Addr sp = tc->readIntReg(30); + VirtualPort *vp = tc->getVirtPort(tc); + uint64_t arg = vp->read<uint64_t>(sp + (number-6) * sizeof(uint64_t)); + tc->delVirtPort(vp); + return arg; + } +} + diff --git a/src/arch/alpha/arguments.hh b/src/arch/alpha/arguments.hh new file mode 100644 index 000000000..d977d48d6 --- /dev/null +++ b/src/arch/alpha/arguments.hh @@ -0,0 +1,149 @@ +/* + * Copyright (c) 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: Nathan Binkert + */ + +#ifndef __ARCH_ALPHA_ARGUMENTS_HH__ +#define __ARCH_ALPHA_ARGUMENTS_HH__ + +#include <assert.h> + +#include "arch/alpha/vtophys.hh" +#include "base/refcnt.hh" +#include "sim/host.hh" + +class ThreadContext; + +namespace AlphaISA { + +class AlphaArguments +{ + protected: + ThreadContext *tc; + int number; + uint64_t getArg(bool fp = false); + + protected: + class Data : public RefCounted + { + public: + Data(){} + ~Data(); + + private: + std::list<char *> data; + + public: + char *alloc(size_t size); + }; + + RefCountingPtr<Data> data; + + public: + AlphaArguments(ThreadContext *ctx, int n = 0) + : tc(ctx), number(n), data(NULL) + { assert(number >= 0); data = new Data;} + AlphaArguments(const AlphaArguments &args) + : tc(args.tc), number(args.number), data(args.data) {} + ~AlphaArguments() {} + + ThreadContext *getThreadContext() const { return tc; } + + const AlphaArguments &operator=(const AlphaArguments &args) { + tc = args.tc; + number = args.number; + data = args.data; + return *this; + } + + AlphaArguments &operator++() { + ++number; + assert(number >= 0); + return *this; + } + + AlphaArguments operator++(int) { + AlphaArguments args = *this; + ++number; + assert(number >= 0); + return args; + } + + AlphaArguments &operator--() { + --number; + assert(number >= 0); + return *this; + } + + AlphaArguments operator--(int) { + AlphaArguments args = *this; + --number; + assert(number >= 0); + return args; + } + + const AlphaArguments &operator+=(int index) { + number += index; + assert(number >= 0); + return *this; + } + + const AlphaArguments &operator-=(int index) { + number -= index; + assert(number >= 0); + return *this; + } + + AlphaArguments operator[](int index) { + return AlphaArguments(tc, index); + } + + template <class T> + operator T() { + assert(sizeof(T) <= sizeof(uint64_t)); + T data = static_cast<T>(getArg()); + return data; + } + + template <class T> + operator T *() { + T *buf = (T *)data->alloc(sizeof(T)); + CopyData(tc, buf, getArg(), sizeof(T)); + return buf; + } + + operator char *() { + char *buf = data->alloc(2048); + CopyStringOut(tc, buf, getArg(), 2048); + return buf; + } +}; + +}; // namespace AlphaISA + +#endif // __ARCH_ALPHA_ARGUMENTS_HH__ diff --git a/arch/alpha/ecoff_machdep.h b/src/arch/alpha/ecoff_machdep.h index 9341b8ff7..9341b8ff7 100644 --- a/arch/alpha/ecoff_machdep.h +++ b/src/arch/alpha/ecoff_machdep.h diff --git a/src/arch/alpha/ev5.cc b/src/arch/alpha/ev5.cc new file mode 100644 index 000000000..7d6894733 --- /dev/null +++ b/src/arch/alpha/ev5.cc @@ -0,0 +1,587 @@ +/* + * 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: Steve Reinhardt + * Nathan Binkert + */ + +#include "arch/alpha/tlb.hh" +#include "arch/alpha/isa_traits.hh" +#include "arch/alpha/osfpal.hh" +#include "base/kgdb.h" +#include "base/remote_gdb.hh" +#include "base/stats/events.hh" +#include "config/full_system.hh" +#include "cpu/base.hh" +#include "cpu/simple_thread.hh" +#include "cpu/thread_context.hh" +#include "kern/kernel_stats.hh" +#include "sim/debug.hh" +#include "sim/sim_exit.hh" + +#if FULL_SYSTEM + +using namespace EV5; + +//////////////////////////////////////////////////////////////////////// +// +// Machine dependent functions +// +void +AlphaISA::initCPU(ThreadContext *tc, int cpuId) +{ + initIPRs(tc, cpuId); + + tc->setIntReg(16, cpuId); + tc->setIntReg(0, cpuId); + + tc->setPC(tc->readMiscReg(IPR_PAL_BASE) + (new ResetFault)->vect()); + tc->setNextPC(tc->readPC() + sizeof(MachInst)); +} + +//////////////////////////////////////////////////////////////////////// +// +// +// +void +AlphaISA::initIPRs(ThreadContext *tc, int cpuId) +{ + for (int i = 0; i < NumInternalProcRegs; ++i) { + tc->setMiscReg(i, 0); + } + + tc->setMiscReg(IPR_PAL_BASE, PalBase); + tc->setMiscReg(IPR_MCSR, 0x6); + tc->setMiscReg(IPR_PALtemp16, cpuId); +} + + +template <class CPU> +void +AlphaISA::processInterrupts(CPU *cpu) +{ + //Check if there are any outstanding interrupts + //Handle the interrupts + int ipl = 0; + int summary = 0; + + cpu->checkInterrupts = false; + + if (cpu->readMiscReg(IPR_ASTRR)) + panic("asynchronous traps not implemented\n"); + + if (cpu->readMiscReg(IPR_SIRR)) { + for (int i = INTLEVEL_SOFTWARE_MIN; + i < INTLEVEL_SOFTWARE_MAX; i++) { + if (cpu->readMiscReg(IPR_SIRR) & (ULL(1) << i)) { + // See table 4-19 of the 21164 hardware reference + ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1; + summary |= (ULL(1) << i); + } + } + } + + uint64_t interrupts = cpu->intr_status(); + + if (interrupts) { + for (int i = INTLEVEL_EXTERNAL_MIN; + i < INTLEVEL_EXTERNAL_MAX; i++) { + if (interrupts & (ULL(1) << i)) { + // See table 4-19 of the 21164 hardware reference + ipl = i; + summary |= (ULL(1) << i); + } + } + } + + if (ipl && ipl > cpu->readMiscReg(IPR_IPLR)) { + cpu->setMiscReg(IPR_ISR, summary); + cpu->setMiscReg(IPR_INTID, ipl); + cpu->trap(new InterruptFault); + DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", + cpu->readMiscReg(IPR_IPLR), ipl, summary); + } + +} + +template <class CPU> +void +AlphaISA::zeroRegisters(CPU *cpu) +{ + // Insure ISA semantics + // (no longer very clean due to the change in setIntReg() in the + // cpu model. Consider changing later.) + cpu->thread->setIntReg(ZeroReg, 0); + cpu->thread->setFloatReg(ZeroReg, 0.0); +} + +Fault +SimpleThread::hwrei() +{ + if (!inPalMode()) + return new UnimplementedOpcodeFault; + + setNextPC(readMiscReg(AlphaISA::IPR_EXC_ADDR)); + + if (!misspeculating()) { + if (kernelStats) + kernelStats->hwrei(); + + cpu->checkInterrupts = true; + } + + // FIXME: XXX check for interrupts? XXX + return NoFault; +} + +int +AlphaISA::MiscRegFile::getInstAsid() +{ + return EV5::ITB_ASN_ASN(ipr[IPR_ITB_ASN]); +} + +int +AlphaISA::MiscRegFile::getDataAsid() +{ + return EV5::DTB_ASN_ASN(ipr[IPR_DTB_ASN]); +} + +AlphaISA::MiscReg +AlphaISA::MiscRegFile::readIpr(int idx, Fault &fault, ThreadContext *tc) +{ + uint64_t retval = 0; // return value, default 0 + + switch (idx) { + case AlphaISA::IPR_PALtemp0: + case AlphaISA::IPR_PALtemp1: + case AlphaISA::IPR_PALtemp2: + case AlphaISA::IPR_PALtemp3: + case AlphaISA::IPR_PALtemp4: + case AlphaISA::IPR_PALtemp5: + case AlphaISA::IPR_PALtemp6: + case AlphaISA::IPR_PALtemp7: + case AlphaISA::IPR_PALtemp8: + case AlphaISA::IPR_PALtemp9: + case AlphaISA::IPR_PALtemp10: + case AlphaISA::IPR_PALtemp11: + case AlphaISA::IPR_PALtemp12: + case AlphaISA::IPR_PALtemp13: + case AlphaISA::IPR_PALtemp14: + case AlphaISA::IPR_PALtemp15: + case AlphaISA::IPR_PALtemp16: + case AlphaISA::IPR_PALtemp17: + case AlphaISA::IPR_PALtemp18: + case AlphaISA::IPR_PALtemp19: + case AlphaISA::IPR_PALtemp20: + case AlphaISA::IPR_PALtemp21: + case AlphaISA::IPR_PALtemp22: + case AlphaISA::IPR_PALtemp23: + case AlphaISA::IPR_PAL_BASE: + + case AlphaISA::IPR_IVPTBR: + case AlphaISA::IPR_DC_MODE: + case AlphaISA::IPR_MAF_MODE: + case AlphaISA::IPR_ISR: + case AlphaISA::IPR_EXC_ADDR: + case AlphaISA::IPR_IC_PERR_STAT: + case AlphaISA::IPR_DC_PERR_STAT: + case AlphaISA::IPR_MCSR: + case AlphaISA::IPR_ASTRR: + case AlphaISA::IPR_ASTER: + case AlphaISA::IPR_SIRR: + case AlphaISA::IPR_ICSR: + case AlphaISA::IPR_ICM: + case AlphaISA::IPR_DTB_CM: + case AlphaISA::IPR_IPLR: + case AlphaISA::IPR_INTID: + case AlphaISA::IPR_PMCTR: + // no side-effect + retval = ipr[idx]; + break; + + case AlphaISA::IPR_CC: + retval |= ipr[idx] & ULL(0xffffffff00000000); + retval |= tc->getCpuPtr()->curCycle() & ULL(0x00000000ffffffff); + break; + + case AlphaISA::IPR_VA: + retval = ipr[idx]; + break; + + case AlphaISA::IPR_VA_FORM: + case AlphaISA::IPR_MM_STAT: + case AlphaISA::IPR_IFAULT_VA_FORM: + case AlphaISA::IPR_EXC_MASK: + case AlphaISA::IPR_EXC_SUM: + retval = ipr[idx]; + break; + + case AlphaISA::IPR_DTB_PTE: + { + AlphaISA::PTE &pte = tc->getDTBPtr()->index(!tc->misspeculating()); + + retval |= ((u_int64_t)pte.ppn & ULL(0x7ffffff)) << 32; + retval |= ((u_int64_t)pte.xre & ULL(0xf)) << 8; + retval |= ((u_int64_t)pte.xwe & ULL(0xf)) << 12; + retval |= ((u_int64_t)pte.fonr & ULL(0x1)) << 1; + retval |= ((u_int64_t)pte.fonw & ULL(0x1))<< 2; + retval |= ((u_int64_t)pte.asma & ULL(0x1)) << 4; + retval |= ((u_int64_t)pte.asn & ULL(0x7f)) << 57; + } + break; + + // write only registers + case AlphaISA::IPR_HWINT_CLR: + case AlphaISA::IPR_SL_XMIT: + case AlphaISA::IPR_DC_FLUSH: + case AlphaISA::IPR_IC_FLUSH: + case AlphaISA::IPR_ALT_MODE: + case AlphaISA::IPR_DTB_IA: + case AlphaISA::IPR_DTB_IAP: + case AlphaISA::IPR_ITB_IA: + case AlphaISA::IPR_ITB_IAP: + fault = new UnimplementedOpcodeFault; + break; + + default: + // invalid IPR + fault = new UnimplementedOpcodeFault; + break; + } + + return retval; +} + +#ifdef DEBUG +// Cause the simulator to break when changing to the following IPL +int break_ipl = -1; +#endif + +Fault +AlphaISA::MiscRegFile::setIpr(int idx, uint64_t val, ThreadContext *tc) +{ + uint64_t old; + + if (tc->misspeculating()) + return NoFault; + + switch (idx) { + case AlphaISA::IPR_PALtemp0: + case AlphaISA::IPR_PALtemp1: + case AlphaISA::IPR_PALtemp2: + case AlphaISA::IPR_PALtemp3: + case AlphaISA::IPR_PALtemp4: + case AlphaISA::IPR_PALtemp5: + case AlphaISA::IPR_PALtemp6: + case AlphaISA::IPR_PALtemp7: + case AlphaISA::IPR_PALtemp8: + case AlphaISA::IPR_PALtemp9: + case AlphaISA::IPR_PALtemp10: + case AlphaISA::IPR_PALtemp11: + case AlphaISA::IPR_PALtemp12: + case AlphaISA::IPR_PALtemp13: + case AlphaISA::IPR_PALtemp14: + case AlphaISA::IPR_PALtemp15: + case AlphaISA::IPR_PALtemp16: + case AlphaISA::IPR_PALtemp17: + case AlphaISA::IPR_PALtemp18: + case AlphaISA::IPR_PALtemp19: + case AlphaISA::IPR_PALtemp20: + case AlphaISA::IPR_PALtemp21: + case AlphaISA::IPR_PALtemp22: + case AlphaISA::IPR_PAL_BASE: + case AlphaISA::IPR_IC_PERR_STAT: + case AlphaISA::IPR_DC_PERR_STAT: + case AlphaISA::IPR_PMCTR: + // write entire quad w/ no side-effect + ipr[idx] = val; + break; + + case AlphaISA::IPR_CC_CTL: + // This IPR resets the cycle counter. We assume this only + // happens once... let's verify that. + assert(ipr[idx] == 0); + ipr[idx] = 1; + break; + + case AlphaISA::IPR_CC: + // This IPR only writes the upper 64 bits. It's ok to write + // all 64 here since we mask out the lower 32 in rpcc (see + // isa_desc). + ipr[idx] = val; + break; + + case AlphaISA::IPR_PALtemp23: + // write entire quad w/ no side-effect + old = ipr[idx]; + ipr[idx] = val; + if (tc->getKernelStats()) + tc->getKernelStats()->context(old, val, tc); + break; + + case AlphaISA::IPR_DTB_PTE: + // write entire quad w/ no side-effect, tag is forthcoming + ipr[idx] = val; + break; + + case AlphaISA::IPR_EXC_ADDR: + // second least significant bit in PC is always zero + ipr[idx] = val & ~2; + break; + + case AlphaISA::IPR_ASTRR: + case AlphaISA::IPR_ASTER: + // only write least significant four bits - privilege mask + ipr[idx] = val & 0xf; + break; + + case AlphaISA::IPR_IPLR: +#ifdef DEBUG + if (break_ipl != -1 && break_ipl == (val & 0x1f)) + debug_break(); +#endif + + // only write least significant five bits - interrupt level + ipr[idx] = val & 0x1f; + if (tc->getKernelStats()) + tc->getKernelStats()->swpipl(ipr[idx]); + break; + + case AlphaISA::IPR_DTB_CM: + if (val & 0x18) { + if (tc->getKernelStats()) + tc->getKernelStats()->mode(Kernel::user, tc); + } else { + if (tc->getKernelStats()) + tc->getKernelStats()->mode(Kernel::kernel, tc); + } + + case AlphaISA::IPR_ICM: + // only write two mode bits - processor mode + ipr[idx] = val & 0x18; + break; + + case AlphaISA::IPR_ALT_MODE: + // only write two mode bits - processor mode + ipr[idx] = val & 0x18; + break; + + case AlphaISA::IPR_MCSR: + // more here after optimization... + ipr[idx] = val; + break; + + case AlphaISA::IPR_SIRR: + // only write software interrupt mask + ipr[idx] = val & 0x7fff0; + break; + + case AlphaISA::IPR_ICSR: + ipr[idx] = val & ULL(0xffffff0300); + break; + + case AlphaISA::IPR_IVPTBR: + case AlphaISA::IPR_MVPTBR: + ipr[idx] = val & ULL(0xffffffffc0000000); + break; + + case AlphaISA::IPR_DC_TEST_CTL: + ipr[idx] = val & 0x1ffb; + break; + + case AlphaISA::IPR_DC_MODE: + case AlphaISA::IPR_MAF_MODE: + ipr[idx] = val & 0x3f; + break; + + case AlphaISA::IPR_ITB_ASN: + ipr[idx] = val & 0x7f0; + break; + + case AlphaISA::IPR_DTB_ASN: + ipr[idx] = val & ULL(0xfe00000000000000); + break; + + case AlphaISA::IPR_EXC_SUM: + case AlphaISA::IPR_EXC_MASK: + // any write to this register clears it + ipr[idx] = 0; + break; + + case AlphaISA::IPR_INTID: + case AlphaISA::IPR_SL_RCV: + case AlphaISA::IPR_MM_STAT: + case AlphaISA::IPR_ITB_PTE_TEMP: + case AlphaISA::IPR_DTB_PTE_TEMP: + // read-only registers + return new UnimplementedOpcodeFault; + + case AlphaISA::IPR_HWINT_CLR: + case AlphaISA::IPR_SL_XMIT: + case AlphaISA::IPR_DC_FLUSH: + case AlphaISA::IPR_IC_FLUSH: + // the following are write only + ipr[idx] = val; + break; + + case AlphaISA::IPR_DTB_IA: + // really a control write + ipr[idx] = 0; + + tc->getDTBPtr()->flushAll(); + break; + + case AlphaISA::IPR_DTB_IAP: + // really a control write + ipr[idx] = 0; + + tc->getDTBPtr()->flushProcesses(); + break; + + case AlphaISA::IPR_DTB_IS: + // really a control write + ipr[idx] = val; + + tc->getDTBPtr()->flushAddr(val, + DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN])); + break; + + case AlphaISA::IPR_DTB_TAG: { + struct AlphaISA::PTE pte; + + // FIXME: granularity hints NYI... + if (DTB_PTE_GH(ipr[AlphaISA::IPR_DTB_PTE]) != 0) + panic("PTE GH field != 0"); + + // write entire quad + ipr[idx] = val; + + // construct PTE for new entry + pte.ppn = DTB_PTE_PPN(ipr[AlphaISA::IPR_DTB_PTE]); + pte.xre = DTB_PTE_XRE(ipr[AlphaISA::IPR_DTB_PTE]); + pte.xwe = DTB_PTE_XWE(ipr[AlphaISA::IPR_DTB_PTE]); + pte.fonr = DTB_PTE_FONR(ipr[AlphaISA::IPR_DTB_PTE]); + pte.fonw = DTB_PTE_FONW(ipr[AlphaISA::IPR_DTB_PTE]); + pte.asma = DTB_PTE_ASMA(ipr[AlphaISA::IPR_DTB_PTE]); + pte.asn = DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN]); + + // insert new TAG/PTE value into data TLB + tc->getDTBPtr()->insert(val, pte); + } + break; + + case AlphaISA::IPR_ITB_PTE: { + struct AlphaISA::PTE pte; + + // FIXME: granularity hints NYI... + if (ITB_PTE_GH(val) != 0) + panic("PTE GH field != 0"); + + // write entire quad + ipr[idx] = val; + + // construct PTE for new entry + pte.ppn = ITB_PTE_PPN(val); + pte.xre = ITB_PTE_XRE(val); + pte.xwe = 0; + pte.fonr = ITB_PTE_FONR(val); + pte.fonw = ITB_PTE_FONW(val); + pte.asma = ITB_PTE_ASMA(val); + pte.asn = ITB_ASN_ASN(ipr[AlphaISA::IPR_ITB_ASN]); + + // insert new TAG/PTE value into data TLB + tc->getITBPtr()->insert(ipr[AlphaISA::IPR_ITB_TAG], pte); + } + break; + + case AlphaISA::IPR_ITB_IA: + // really a control write + ipr[idx] = 0; + + tc->getITBPtr()->flushAll(); + break; + + case AlphaISA::IPR_ITB_IAP: + // really a control write + ipr[idx] = 0; + + tc->getITBPtr()->flushProcesses(); + break; + + case AlphaISA::IPR_ITB_IS: + // really a control write + ipr[idx] = val; + + tc->getITBPtr()->flushAddr(val, + ITB_ASN_ASN(ipr[AlphaISA::IPR_ITB_ASN])); + break; + + default: + // invalid IPR + return new UnimplementedOpcodeFault; + } + + // no error... + return NoFault; +} + +void +AlphaISA::copyIprs(ThreadContext *src, ThreadContext *dest) +{ + for (int i = IPR_Base_DepTag; i < NumInternalProcRegs; ++i) { + dest->setMiscReg(i, src->readMiscReg(i)); + } +} + +/** + * Check for special simulator handling of specific PAL calls. + * If return value is false, actual PAL call will be suppressed. + */ +bool +SimpleThread::simPalCheck(int palFunc) +{ + if (kernelStats) + kernelStats->callpal(palFunc, tc); + + switch (palFunc) { + case PAL::halt: + halt(); + if (--System::numSystemsRunning == 0) + exitSimLoop("all cpus halted"); + break; + + case PAL::bpt: + case PAL::bugchk: + if (system->breakpoint()) + return false; + break; + } + + return true; +} + +#endif // FULL_SYSTEM diff --git a/src/arch/alpha/ev5.hh b/src/arch/alpha/ev5.hh new file mode 100644 index 000000000..4dd225786 --- /dev/null +++ b/src/arch/alpha/ev5.hh @@ -0,0 +1,125 @@ +/* + * 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: Steve Reinhardt + * Nathan Binkert + * Ali Saidi + */ + +#ifndef __ARCH_ALPHA_EV5_HH__ +#define __ARCH_ALPHA_EV5_HH__ + +#include "config/alpha_tlaser.hh" +#include "arch/alpha/isa_traits.hh" + +namespace EV5 { + +//It seems like a safe assumption EV5 only applies to alpha +using namespace AlphaISA; + +#if ALPHA_TLASER +const uint64_t AsnMask = ULL(0x7f); +#else +const uint64_t AsnMask = ULL(0xff); +#endif + +const int VAddrImplBits = 43; +const Addr VAddrImplMask = (ULL(1) << VAddrImplBits) - 1; +const Addr VAddrUnImplMask = ~VAddrImplMask; +inline Addr VAddrImpl(Addr a) { return a & VAddrImplMask; } +inline Addr VAddrVPN(Addr a) { return a >> AlphaISA::PageShift; } +inline Addr VAddrOffset(Addr a) { return a & AlphaISA::PageOffset; } +inline Addr VAddrSpaceEV5(Addr a) { return a >> 41 & 0x3; } +inline Addr VAddrSpaceEV6(Addr a) { return a >> 41 & 0x7f; } + +#if ALPHA_TLASER +inline bool PAddrIprSpace(Addr a) { return a >= ULL(0xFFFFF00000); } +const int PAddrImplBits = 40; +#else +inline bool PAddrIprSpace(Addr a) { return a >= ULL(0xFFFFFF00000); } +const int PAddrImplBits = 44; // for Tsunami +#endif +const Addr PAddrImplMask = (ULL(1) << PAddrImplBits) - 1; +const Addr PAddrUncachedBit39 = ULL(0x8000000000); +const Addr PAddrUncachedBit40 = ULL(0x10000000000); +const Addr PAddrUncachedBit43 = ULL(0x80000000000); +const Addr PAddrUncachedMask = ULL(0x807ffffffff); // Clear PA<42:35> +inline Addr Phys2K0Seg(Addr addr) +{ +#if !ALPHA_TLASER + if (addr & PAddrUncachedBit43) { + addr &= PAddrUncachedMask; + addr |= PAddrUncachedBit40; + } +#endif + return addr | AlphaISA::K0SegBase; +} + +inline int DTB_ASN_ASN(uint64_t reg) { return reg >> 57 & AsnMask; } +inline Addr DTB_PTE_PPN(uint64_t reg) +{ return reg >> 32 & (ULL(1) << PAddrImplBits - AlphaISA::PageShift) - 1; } +inline int DTB_PTE_XRE(uint64_t reg) { return reg >> 8 & 0xf; } +inline int DTB_PTE_XWE(uint64_t reg) { return reg >> 12 & 0xf; } +inline int DTB_PTE_FONR(uint64_t reg) { return reg >> 1 & 0x1; } +inline int DTB_PTE_FONW(uint64_t reg) { return reg >> 2 & 0x1; } +inline int DTB_PTE_GH(uint64_t reg) { return reg >> 5 & 0x3; } +inline int DTB_PTE_ASMA(uint64_t reg) { return reg >> 4 & 0x1; } + +inline int ITB_ASN_ASN(uint64_t reg) { return reg >> 4 & AsnMask; } +inline Addr ITB_PTE_PPN(uint64_t reg) +{ return reg >> 32 & (ULL(1) << PAddrImplBits - AlphaISA::PageShift) - 1; } +inline int ITB_PTE_XRE(uint64_t reg) { return reg >> 8 & 0xf; } +inline bool ITB_PTE_FONR(uint64_t reg) { return reg >> 1 & 0x1; } +inline bool ITB_PTE_FONW(uint64_t reg) { return reg >> 2 & 0x1; } +inline int ITB_PTE_GH(uint64_t reg) { return reg >> 5 & 0x3; } +inline bool ITB_PTE_ASMA(uint64_t reg) { return reg >> 4 & 0x1; } + +inline uint64_t MCSR_SP(uint64_t reg) { return reg >> 1 & 0x3; } + +inline bool ICSR_SDE(uint64_t reg) { return reg >> 30 & 0x1; } +inline int ICSR_SPE(uint64_t reg) { return reg >> 28 & 0x3; } +inline bool ICSR_FPE(uint64_t reg) { return reg >> 26 & 0x1; } + +inline uint64_t ALT_MODE_AM(uint64_t reg) { return reg >> 3 & 0x3; } +inline uint64_t DTB_CM_CM(uint64_t reg) { return reg >> 3 & 0x3; } +inline uint64_t ICM_CM(uint64_t reg) { return reg >> 3 & 0x3; } + +const uint64_t MM_STAT_BAD_VA_MASK = ULL(0x0020); +const uint64_t MM_STAT_DTB_MISS_MASK = ULL(0x0010); +const uint64_t MM_STAT_FONW_MASK = ULL(0x0008); +const uint64_t MM_STAT_FONR_MASK = ULL(0x0004); +const uint64_t MM_STAT_ACV_MASK = ULL(0x0002); +const uint64_t MM_STAT_WR_MASK = ULL(0x0001); +inline int Opcode(AlphaISA::MachInst inst) { return inst >> 26 & 0x3f; } +inline int Ra(AlphaISA::MachInst inst) { return inst >> 21 & 0x1f; } + +const Addr PalBase = 0x4000; +const Addr PalMax = 0x10000; + +/* namespace EV5 */ } + +#endif // __ARCH_ALPHA_EV5_HH__ diff --git a/src/arch/alpha/faults.cc b/src/arch/alpha/faults.cc new file mode 100644 index 000000000..8493223ff --- /dev/null +++ b/src/arch/alpha/faults.cc @@ -0,0 +1,179 @@ +/* + * Copyright (c) 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: Gabe Black + * Kevin Lim + */ + +#include "arch/alpha/faults.hh" +#include "cpu/thread_context.hh" +#include "cpu/base.hh" +#include "base/trace.hh" +#if FULL_SYSTEM +#include "arch/alpha/ev5.hh" +#endif + +namespace AlphaISA +{ + +FaultName MachineCheckFault::_name = "mchk"; +FaultVect MachineCheckFault::_vect = 0x0401; +FaultStat MachineCheckFault::_count; + +FaultName AlignmentFault::_name = "unalign"; +FaultVect AlignmentFault::_vect = 0x0301; +FaultStat AlignmentFault::_count; + +FaultName ResetFault::_name = "reset"; +FaultVect ResetFault::_vect = 0x0001; +FaultStat ResetFault::_count; + +FaultName ArithmeticFault::_name = "arith"; +FaultVect ArithmeticFault::_vect = 0x0501; +FaultStat ArithmeticFault::_count; + +FaultName InterruptFault::_name = "interrupt"; +FaultVect InterruptFault::_vect = 0x0101; +FaultStat InterruptFault::_count; + +FaultName NDtbMissFault::_name = "dtb_miss_single"; +FaultVect NDtbMissFault::_vect = 0x0201; +FaultStat NDtbMissFault::_count; + +FaultName PDtbMissFault::_name = "dtb_miss_double"; +FaultVect PDtbMissFault::_vect = 0x0281; +FaultStat PDtbMissFault::_count; + +FaultName DtbPageFault::_name = "dfault"; +FaultVect DtbPageFault::_vect = 0x0381; +FaultStat DtbPageFault::_count; + +FaultName DtbAcvFault::_name = "dfault"; +FaultVect DtbAcvFault::_vect = 0x0381; +FaultStat DtbAcvFault::_count; + +FaultName DtbAlignmentFault::_name = "unalign"; +FaultVect DtbAlignmentFault::_vect = 0x0301; +FaultStat DtbAlignmentFault::_count; + +FaultName ItbMissFault::_name = "itbmiss"; +FaultVect ItbMissFault::_vect = 0x0181; +FaultStat ItbMissFault::_count; + +FaultName ItbPageFault::_name = "itbmiss"; +FaultVect ItbPageFault::_vect = 0x0181; +FaultStat ItbPageFault::_count; + +FaultName ItbAcvFault::_name = "iaccvio"; +FaultVect ItbAcvFault::_vect = 0x0081; +FaultStat ItbAcvFault::_count; + +FaultName UnimplementedOpcodeFault::_name = "opdec"; +FaultVect UnimplementedOpcodeFault::_vect = 0x0481; +FaultStat UnimplementedOpcodeFault::_count; + +FaultName FloatEnableFault::_name = "fen"; +FaultVect FloatEnableFault::_vect = 0x0581; +FaultStat FloatEnableFault::_count; + +FaultName PalFault::_name = "pal"; +FaultVect PalFault::_vect = 0x2001; +FaultStat PalFault::_count; + +FaultName IntegerOverflowFault::_name = "intover"; +FaultVect IntegerOverflowFault::_vect = 0x0501; +FaultStat IntegerOverflowFault::_count; + +#if FULL_SYSTEM + +void AlphaFault::invoke(ThreadContext * tc) +{ + FaultBase::invoke(tc); + countStat()++; + + // exception restart address + if (setRestartAddress() || !tc->inPalMode()) + tc->setMiscReg(AlphaISA::IPR_EXC_ADDR, tc->readPC()); + + if (skipFaultingInstruction()) { + // traps... skip faulting instruction. + tc->setMiscReg(AlphaISA::IPR_EXC_ADDR, + tc->readMiscReg(AlphaISA::IPR_EXC_ADDR) + 4); + } + + tc->setPC(tc->readMiscReg(AlphaISA::IPR_PAL_BASE) + vect()); + tc->setNextPC(tc->readPC() + sizeof(MachInst)); +} + +void ArithmeticFault::invoke(ThreadContext * tc) +{ + FaultBase::invoke(tc); + panic("Arithmetic traps are unimplemented!"); +} + +void DtbFault::invoke(ThreadContext * tc) +{ + // Set fault address and flags. Even though we're modeling an + // EV5, we use the EV6 technique of not latching fault registers + // on VPTE loads (instead of locking the registers until IPR_VA is + // read, like the EV5). The EV6 approach is cleaner and seems to + // work with EV5 PAL code, but not the other way around. + if (!tc->misspeculating() + && !(reqFlags & VPTE) && !(reqFlags & NO_FAULT)) { + // set VA register with faulting address + tc->setMiscReg(AlphaISA::IPR_VA, vaddr); + + // set MM_STAT register flags + tc->setMiscReg(AlphaISA::IPR_MM_STAT, + (((EV5::Opcode(tc->getInst()) & 0x3f) << 11) + | ((EV5::Ra(tc->getInst()) & 0x1f) << 6) + | (flags & 0x3f))); + + // set VA_FORM register with faulting formatted address + tc->setMiscReg(AlphaISA::IPR_VA_FORM, + tc->readMiscReg(AlphaISA::IPR_MVPTBR) | (vaddr.vpn() << 3)); + } + + AlphaFault::invoke(tc); +} + +void ItbFault::invoke(ThreadContext * tc) +{ + if (!tc->misspeculating()) { + tc->setMiscReg(AlphaISA::IPR_ITB_TAG, pc); + tc->setMiscReg(AlphaISA::IPR_IFAULT_VA_FORM, + tc->readMiscReg(AlphaISA::IPR_IVPTBR) | + (AlphaISA::VAddr(pc).vpn() << 3)); + } + + AlphaFault::invoke(tc); +} + +#endif + +} // namespace AlphaISA + diff --git a/src/arch/alpha/faults.hh b/src/arch/alpha/faults.hh new file mode 100644 index 000000000..f952cf9d6 --- /dev/null +++ b/src/arch/alpha/faults.hh @@ -0,0 +1,355 @@ +/* + * Copyright (c) 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: Gabe Black + * Kevin Lim + */ + +#ifndef __ALPHA_FAULTS_HH__ +#define __ALPHA_FAULTS_HH__ + +#include "arch/alpha/isa_traits.hh" +#include "sim/faults.hh" + +// The design of the "name" and "vect" functions is in sim/faults.hh + +namespace AlphaISA +{ + +typedef const Addr FaultVect; + +class AlphaFault : public FaultBase +{ + protected: + virtual bool skipFaultingInstruction() {return false;} + virtual bool setRestartAddress() {return true;} + public: +#if FULL_SYSTEM + void invoke(ThreadContext * tc); +#endif + virtual FaultVect vect() = 0; + virtual FaultStat & countStat() = 0; +}; + +class MachineCheckFault : public AlphaFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} + bool isMachineCheckFault() {return true;} +}; + +class AlignmentFault : public AlphaFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} + bool isAlignmentFault() {return true;} +}; + +static inline Fault genMachineCheckFault() +{ + return new MachineCheckFault; +} + +static inline Fault genAlignmentFault() +{ + return new AlignmentFault; +} + +class ResetFault : public AlphaFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class ArithmeticFault : public AlphaFault +{ + protected: + bool skipFaultingInstruction() {return true;} + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +#if FULL_SYSTEM + void invoke(ThreadContext * tc); +#endif +}; + +class InterruptFault : public AlphaFault +{ + protected: + bool setRestartAddress() {return false;} + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class DtbFault : public AlphaFault +{ +#if FULL_SYSTEM + private: + AlphaISA::VAddr vaddr; + uint32_t reqFlags; + uint64_t flags; + public: + DtbFault(AlphaISA::VAddr _vaddr, uint32_t _reqFlags, uint64_t _flags) + : vaddr(_vaddr), reqFlags(_reqFlags), flags(_flags) + { } +#endif + FaultName name() = 0; + FaultVect vect() = 0; + FaultStat & countStat() = 0; +#if FULL_SYSTEM + void invoke(ThreadContext * tc); +#endif +}; + +class NDtbMissFault : public DtbFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: +#if FULL_SYSTEM + NDtbMissFault(AlphaISA::VAddr vaddr, uint32_t reqFlags, uint64_t flags) + : DtbFault(vaddr, reqFlags, flags) + { } +#endif + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class PDtbMissFault : public DtbFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: +#if FULL_SYSTEM + PDtbMissFault(AlphaISA::VAddr vaddr, uint32_t reqFlags, uint64_t flags) + : DtbFault(vaddr, reqFlags, flags) + { } +#endif + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class DtbPageFault : public DtbFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: +#if FULL_SYSTEM + DtbPageFault(AlphaISA::VAddr vaddr, uint32_t reqFlags, uint64_t flags) + : DtbFault(vaddr, reqFlags, flags) + { } +#endif + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class DtbAcvFault : public DtbFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: +#if FULL_SYSTEM + DtbAcvFault(AlphaISA::VAddr vaddr, uint32_t reqFlags, uint64_t flags) + : DtbFault(vaddr, reqFlags, flags) + { } +#endif + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class DtbAlignmentFault : public DtbFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: +#if FULL_SYSTEM + DtbAlignmentFault(AlphaISA::VAddr vaddr, uint32_t reqFlags, uint64_t flags) + : DtbFault(vaddr, reqFlags, flags) + { } +#endif + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class ItbFault : public AlphaFault +{ + private: + Addr pc; + public: + ItbFault(Addr _pc) + : pc(_pc) + { } + FaultName name() = 0; + FaultVect vect() = 0; + FaultStat & countStat() = 0; +#if FULL_SYSTEM + void invoke(ThreadContext * tc); +#endif +}; + +class ItbMissFault : public ItbFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + ItbMissFault(Addr pc) + : ItbFault(pc) + { } + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class ItbPageFault : public ItbFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + ItbPageFault(Addr pc) + : ItbFault(pc) + { } + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class ItbAcvFault : public ItbFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + ItbAcvFault(Addr pc) + : ItbFault(pc) + { } + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class UnimplementedOpcodeFault : public AlphaFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class FloatEnableFault : public AlphaFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class PalFault : public AlphaFault +{ + protected: + bool skipFaultingInstruction() {return true;} + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class IntegerOverflowFault : public AlphaFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +} // AlphaISA namespace + +#endif // __FAULTS_HH__ diff --git a/src/arch/alpha/freebsd/system.cc b/src/arch/alpha/freebsd/system.cc new file mode 100644 index 000000000..7cf68e0db --- /dev/null +++ b/src/arch/alpha/freebsd/system.cc @@ -0,0 +1,148 @@ +/* + * 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: Ben Nash + */ + +/** + * @file + * Modifications for the FreeBSD kernel. + * Based on kern/linux/linux_system.cc. + * + */ + +#include "arch/alpha/system.hh" +#include "arch/alpha/freebsd/system.hh" +#include "base/loader/symtab.hh" +#include "cpu/thread_context.hh" +#include "mem/physical.hh" +#include "mem/port.hh" +#include "arch/isa_traits.hh" +#include "sim/builder.hh" +#include "sim/byteswap.hh" +#include "arch/vtophys.hh" + +#define TIMER_FREQUENCY 1193180 + +using namespace std; +using namespace AlphaISA; + +FreebsdAlphaSystem::FreebsdAlphaSystem(Params *p) + : AlphaSystem(p) +{ + /** + * Any time DELAY is called just skip the function. + * Shouldn't we actually emulate the delay? + */ + skipDelayEvent = addKernelFuncEvent<SkipFuncEvent>("DELAY"); + skipCalibrateClocks = + addKernelFuncEvent<SkipCalibrateClocksEvent>("calibrate_clocks"); +} + + +FreebsdAlphaSystem::~FreebsdAlphaSystem() +{ + delete skipDelayEvent; + delete skipCalibrateClocks; +} + + +void +FreebsdAlphaSystem::doCalibrateClocks(ThreadContext *tc) +{ + Addr ppc_vaddr = 0; + Addr timer_vaddr = 0; + + ppc_vaddr = (Addr)tc->readIntReg(ArgumentReg1); + timer_vaddr = (Addr)tc->readIntReg(ArgumentReg2); + + virtPort.write(ppc_vaddr, (uint32_t)Clock::Frequency); + virtPort.write(timer_vaddr, (uint32_t)TIMER_FREQUENCY); +} + + +void +FreebsdAlphaSystem::SkipCalibrateClocksEvent::process(ThreadContext *tc) +{ + SkipFuncEvent::process(tc); + ((FreebsdAlphaSystem *)tc->getSystemPtr())->doCalibrateClocks(tc); +} + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(FreebsdAlphaSystem) + + Param<Tick> boot_cpu_frequency; + SimObjectParam<PhysicalMemory *> physmem; + + Param<string> kernel; + Param<string> console; + Param<string> pal; + + Param<string> boot_osflags; + Param<string> readfile; + Param<unsigned int> init_param; + + Param<uint64_t> system_type; + Param<uint64_t> system_rev; + +END_DECLARE_SIM_OBJECT_PARAMS(FreebsdAlphaSystem) + +BEGIN_INIT_SIM_OBJECT_PARAMS(FreebsdAlphaSystem) + + INIT_PARAM(boot_cpu_frequency, "Frequency of the boot CPU"), + INIT_PARAM(physmem, "phsyical memory"), + INIT_PARAM(kernel, "file that contains the kernel code"), + INIT_PARAM(console, "file that contains the console code"), + INIT_PARAM(pal, "file that contains palcode"), + INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot", + "a"), + INIT_PARAM_DFLT(readfile, "file to read startup script from", ""), + INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0), + INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 34), + INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10) + +END_INIT_SIM_OBJECT_PARAMS(FreebsdAlphaSystem) + +CREATE_SIM_OBJECT(FreebsdAlphaSystem) +{ + AlphaSystem::Params *p = new AlphaSystem::Params; + p->name = getInstanceName(); + p->boot_cpu_frequency = boot_cpu_frequency; + p->physmem = physmem; + p->kernel_path = kernel; + p->console_path = console; + p->palcode = pal; + p->boot_osflags = boot_osflags; + p->init_param = init_param; + p->readfile = readfile; + p->system_type = system_type; + p->system_rev = system_rev; + return new FreebsdAlphaSystem(p); +} + +REGISTER_SIM_OBJECT("FreebsdAlphaSystem", FreebsdAlphaSystem) + diff --git a/src/arch/alpha/freebsd/system.hh b/src/arch/alpha/freebsd/system.hh new file mode 100644 index 000000000..e0d874e8f --- /dev/null +++ b/src/arch/alpha/freebsd/system.hh @@ -0,0 +1,58 @@ +/* + * 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: Ben Nash + */ + +#ifndef __KERN_FREEBSD_FREEBSD_SYSTEM_HH__ +#define __KERN_FREEBSD_FREEBSD_SYSTEM_HH__ + +#include "kern/system_events.hh" + +class FreebsdAlphaSystem : public AlphaSystem +{ + private: + class SkipCalibrateClocksEvent : public SkipFuncEvent + { + public: + SkipCalibrateClocksEvent(PCEventQueue *q, const std::string &desc, + Addr addr) + : SkipFuncEvent(q, desc, addr) {} + virtual void process(ThreadContext *tc); + }; + + SkipFuncEvent *skipDelayEvent; + SkipCalibrateClocksEvent *skipCalibrateClocks; + + public: + FreebsdAlphaSystem(Params *p); + ~FreebsdAlphaSystem(); + void doCalibrateClocks(ThreadContext *tc); + +}; + +#endif // __KERN_FREEBSD_FREEBSD_SYSTEM_HH__ diff --git a/src/arch/alpha/isa/branch.isa b/src/arch/alpha/isa/branch.isa new file mode 100644 index 000000000..7438e7e18 --- /dev/null +++ b/src/arch/alpha/isa/branch.isa @@ -0,0 +1,266 @@ +// -*- mode:c++ -*- + +// Copyright (c) 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 Reinhardt + +//////////////////////////////////////////////////////////////////// +// +// Control transfer instructions +// + +output header {{ + + /** + * Base class for instructions whose disassembly is not purely a + * function of the machine instruction (i.e., it depends on the + * PC). This class overrides the disassemble() method to check + * the PC and symbol table values before re-using a cached + * disassembly string. This is necessary for branches and jumps, + * where the disassembly string includes the target address (which + * may depend on the PC and/or symbol table). + */ + class PCDependentDisassembly : public AlphaStaticInst + { + protected: + /// Cached program counter from last disassembly + mutable Addr cachedPC; + /// Cached symbol table pointer from last disassembly + mutable const SymbolTable *cachedSymtab; + + /// Constructor + PCDependentDisassembly(const char *mnem, ExtMachInst _machInst, + OpClass __opClass) + : AlphaStaticInst(mnem, _machInst, __opClass), + cachedPC(0), cachedSymtab(0) + { + } + + const std::string & + disassemble(Addr pc, const SymbolTable *symtab) const; + }; + + /** + * Base class for branches (PC-relative control transfers), + * conditional or unconditional. + */ + class Branch : public PCDependentDisassembly + { + protected: + /// Displacement to target address (signed). + int32_t disp; + + /// Constructor. + Branch(const char *mnem, ExtMachInst _machInst, OpClass __opClass) + : PCDependentDisassembly(mnem, _machInst, __opClass), + disp(BRDISP << 2) + { + } + + Addr branchTarget(Addr branchPC) const; + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; + + /** + * Base class for jumps (register-indirect control transfers). In + * the Alpha ISA, these are always unconditional. + */ + class Jump : public PCDependentDisassembly + { + protected: + + /// Displacement to target address (signed). + int32_t disp; + + public: + /// Constructor + Jump(const char *mnem, ExtMachInst _machInst, OpClass __opClass) + : PCDependentDisassembly(mnem, _machInst, __opClass), + disp(BRDISP) + { + } + + Addr branchTarget(ThreadContext *tc) const; + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; +}}; + +output decoder {{ + Addr + Branch::branchTarget(Addr branchPC) const + { + return branchPC + 4 + disp; + } + + Addr + Jump::branchTarget(ThreadContext *tc) const + { + Addr NPC = tc->readPC() + 4; + uint64_t Rb = tc->readIntReg(_srcRegIdx[0]); + return (Rb & ~3) | (NPC & 1); + } + + const std::string & + PCDependentDisassembly::disassemble(Addr pc, + const SymbolTable *symtab) const + { + if (!cachedDisassembly || + pc != cachedPC || symtab != cachedSymtab) + { + if (cachedDisassembly) + delete cachedDisassembly; + + cachedDisassembly = + new std::string(generateDisassembly(pc, symtab)); + cachedPC = pc; + cachedSymtab = symtab; + } + + return *cachedDisassembly; + } + + std::string + Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + std::stringstream ss; + + ccprintf(ss, "%-10s ", mnemonic); + + // There's only one register arg (RA), but it could be + // either a source (the condition for conditional + // branches) or a destination (the link reg for + // unconditional branches) + if (_numSrcRegs > 0) { + printReg(ss, _srcRegIdx[0]); + ss << ","; + } + else if (_numDestRegs > 0) { + printReg(ss, _destRegIdx[0]); + ss << ","; + } + +#ifdef SS_COMPATIBLE_DISASSEMBLY + if (_numSrcRegs == 0 && _numDestRegs == 0) { + printReg(ss, 31); + ss << ","; + } +#endif + + Addr target = pc + 4 + disp; + + std::string str; + if (symtab && symtab->findSymbol(target, str)) + ss << str; + else + ccprintf(ss, "0x%x", target); + + return ss.str(); + } + + std::string + Jump::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + std::stringstream ss; + + ccprintf(ss, "%-10s ", mnemonic); + +#ifdef SS_COMPATIBLE_DISASSEMBLY + if (_numDestRegs == 0) { + printReg(ss, 31); + ss << ","; + } +#endif + + if (_numDestRegs > 0) { + printReg(ss, _destRegIdx[0]); + ss << ","; + } + + ccprintf(ss, "(r%d)", RB); + + return ss.str(); + } +}}; + +def template JumpOrBranchDecode {{ + return (RA == 31) + ? (StaticInst *)new %(class_name)s(machInst) + : (StaticInst *)new %(class_name)sAndLink(machInst); +}}; + +def format CondBranch(code) {{ + code = 'bool cond;\n' + code + '\nif (cond) NPC = NPC + disp;\n'; + iop = InstObjParams(name, Name, 'Branch', CodeBlock(code), + ('IsDirectControl', 'IsCondControl')) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + +let {{ +def UncondCtrlBase(name, Name, base_class, npc_expr, flags): + # Declare basic control transfer w/o link (i.e. link reg is R31) + nolink_code = 'NPC = %s;\n' % npc_expr + nolink_iop = InstObjParams(name, Name, base_class, + CodeBlock(nolink_code), flags) + header_output = BasicDeclare.subst(nolink_iop) + decoder_output = BasicConstructor.subst(nolink_iop) + exec_output = BasicExecute.subst(nolink_iop) + + # Generate declaration of '*AndLink' version, append to decls + link_code = 'Ra = NPC & ~3;\n' + nolink_code + link_iop = InstObjParams(name, Name + 'AndLink', base_class, + CodeBlock(link_code), flags) + header_output += BasicDeclare.subst(link_iop) + decoder_output += BasicConstructor.subst(link_iop) + exec_output += BasicExecute.subst(link_iop) + + # need to use link_iop for the decode template since it is expecting + # the shorter version of class_name (w/o "AndLink") + + return (header_output, decoder_output, + JumpOrBranchDecode.subst(nolink_iop), exec_output) +}}; + +def format UncondBranch(*flags) {{ + flags += ('IsUncondControl', 'IsDirectControl') + (header_output, decoder_output, decode_block, exec_output) = \ + UncondCtrlBase(name, Name, 'Branch', 'NPC + disp', flags) +}}; + +def format Jump(*flags) {{ + flags += ('IsUncondControl', 'IsIndirectControl') + (header_output, decoder_output, decode_block, exec_output) = \ + UncondCtrlBase(name, Name, 'Jump', '(Rb & ~3) | (NPC & 1)', flags) +}}; + + diff --git a/src/arch/alpha/isa/decoder.isa b/src/arch/alpha/isa/decoder.isa new file mode 100644 index 000000000..fbdb119b6 --- /dev/null +++ b/src/arch/alpha/isa/decoder.isa @@ -0,0 +1,826 @@ +// -*- mode:c++ -*- + +// 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 + +//////////////////////////////////////////////////////////////////// +// +// The actual decoder specification +// + +decode OPCODE default Unknown::unknown() { + + format LoadAddress { + 0x08: lda({{ Ra = Rb + disp; }}); + 0x09: ldah({{ Ra = Rb + (disp << 16); }}); + } + + format LoadOrNop { + 0x0a: ldbu({{ Ra.uq = Mem.ub; }}); + 0x0c: ldwu({{ Ra.uq = Mem.uw; }}); + 0x0b: ldq_u({{ Ra = Mem.uq; }}, ea_code = {{ EA = (Rb + disp) & ~7; }}); + 0x23: ldt({{ Fa = Mem.df; }}); + 0x2a: ldl_l({{ Ra.sl = Mem.sl; }}, mem_flags = LOCKED); + 0x2b: ldq_l({{ Ra.uq = Mem.uq; }}, mem_flags = LOCKED); + 0x20: MiscPrefetch::copy_load({{ EA = Ra; }}, + {{ fault = xc->copySrcTranslate(EA); }}, + inst_flags = [IsMemRef, IsLoad, IsCopy]); + } + + format LoadOrPrefetch { + 0x28: ldl({{ Ra.sl = Mem.sl; }}); + 0x29: ldq({{ Ra.uq = Mem.uq; }}, pf_flags = EVICT_NEXT); + // IsFloating flag on lds gets the prefetch to disassemble + // using f31 instead of r31... funcitonally it's unnecessary + 0x22: lds({{ Fa.uq = s_to_t(Mem.ul); }}, + pf_flags = PF_EXCLUSIVE, inst_flags = IsFloating); + } + + format Store { + 0x0e: stb({{ Mem.ub = Ra<7:0>; }}); + 0x0d: stw({{ Mem.uw = Ra<15:0>; }}); + 0x2c: stl({{ Mem.ul = Ra<31:0>; }}); + 0x2d: stq({{ Mem.uq = Ra.uq; }}); + 0x0f: stq_u({{ Mem.uq = Ra.uq; }}, {{ EA = (Rb + disp) & ~7; }}); + 0x26: sts({{ Mem.ul = t_to_s(Fa.uq); }}); + 0x27: stt({{ Mem.df = Fa; }}); + 0x24: MiscPrefetch::copy_store({{ EA = Rb; }}, + {{ fault = xc->copy(EA); }}, + inst_flags = [IsMemRef, IsStore, IsCopy]); + } + + format StoreCond { + 0x2e: stl_c({{ Mem.ul = Ra<31:0>; }}, + {{ + uint64_t tmp = write_result; + // see stq_c + Ra = (tmp == 0 || tmp == 1) ? tmp : Ra; + }}, mem_flags = LOCKED, inst_flags = IsStoreConditional); + 0x2f: stq_c({{ Mem.uq = Ra; }}, + {{ + uint64_t tmp = write_result; + // If the write operation returns 0 or 1, then + // this was a conventional store conditional, + // and the value indicates the success/failure + // of the operation. If another value is + // returned, then this was a Turbolaser + // mailbox access, and we don't update the + // result register at all. + Ra = (tmp == 0 || tmp == 1) ? tmp : Ra; + }}, mem_flags = LOCKED, inst_flags = IsStoreConditional); + } + + format IntegerOperate { + + 0x10: decode INTFUNC { // integer arithmetic operations + + 0x00: addl({{ Rc.sl = Ra.sl + Rb_or_imm.sl; }}); + 0x40: addlv({{ + uint32_t tmp = Ra.sl + Rb_or_imm.sl; + // signed overflow occurs when operands have same sign + // and sign of result does not match. + if (Ra.sl<31:> == Rb_or_imm.sl<31:> && tmp<31:> != Ra.sl<31:>) + fault = new IntegerOverflowFault; + Rc.sl = tmp; + }}); + 0x02: s4addl({{ Rc.sl = (Ra.sl << 2) + Rb_or_imm.sl; }}); + 0x12: s8addl({{ Rc.sl = (Ra.sl << 3) + Rb_or_imm.sl; }}); + + 0x20: addq({{ Rc = Ra + Rb_or_imm; }}); + 0x60: addqv({{ + uint64_t tmp = Ra + Rb_or_imm; + // signed overflow occurs when operands have same sign + // and sign of result does not match. + if (Ra<63:> == Rb_or_imm<63:> && tmp<63:> != Ra<63:>) + fault = new IntegerOverflowFault; + Rc = tmp; + }}); + 0x22: s4addq({{ Rc = (Ra << 2) + Rb_or_imm; }}); + 0x32: s8addq({{ Rc = (Ra << 3) + Rb_or_imm; }}); + + 0x09: subl({{ Rc.sl = Ra.sl - Rb_or_imm.sl; }}); + 0x49: sublv({{ + uint32_t tmp = Ra.sl - Rb_or_imm.sl; + // signed overflow detection is same as for add, + // except we need to look at the *complemented* + // sign bit of the subtrahend (Rb), i.e., if the initial + // signs are the *same* then no overflow can occur + if (Ra.sl<31:> != Rb_or_imm.sl<31:> && tmp<31:> != Ra.sl<31:>) + fault = new IntegerOverflowFault; + Rc.sl = tmp; + }}); + 0x0b: s4subl({{ Rc.sl = (Ra.sl << 2) - Rb_or_imm.sl; }}); + 0x1b: s8subl({{ Rc.sl = (Ra.sl << 3) - Rb_or_imm.sl; }}); + + 0x29: subq({{ Rc = Ra - Rb_or_imm; }}); + 0x69: subqv({{ + uint64_t tmp = Ra - Rb_or_imm; + // signed overflow detection is same as for add, + // except we need to look at the *complemented* + // sign bit of the subtrahend (Rb), i.e., if the initial + // signs are the *same* then no overflow can occur + if (Ra<63:> != Rb_or_imm<63:> && tmp<63:> != Ra<63:>) + fault = new IntegerOverflowFault; + Rc = tmp; + }}); + 0x2b: s4subq({{ Rc = (Ra << 2) - Rb_or_imm; }}); + 0x3b: s8subq({{ Rc = (Ra << 3) - Rb_or_imm; }}); + + 0x2d: cmpeq({{ Rc = (Ra == Rb_or_imm); }}); + 0x6d: cmple({{ Rc = (Ra.sq <= Rb_or_imm.sq); }}); + 0x4d: cmplt({{ Rc = (Ra.sq < Rb_or_imm.sq); }}); + 0x3d: cmpule({{ Rc = (Ra.uq <= Rb_or_imm.uq); }}); + 0x1d: cmpult({{ Rc = (Ra.uq < Rb_or_imm.uq); }}); + + 0x0f: cmpbge({{ + int hi = 7; + int lo = 0; + uint64_t tmp = 0; + for (int i = 0; i < 8; ++i) { + tmp |= (Ra.uq<hi:lo> >= Rb_or_imm.uq<hi:lo>) << i; + hi += 8; + lo += 8; + } + Rc = tmp; + }}); + } + + 0x11: decode INTFUNC { // integer logical operations + + 0x00: and({{ Rc = Ra & Rb_or_imm; }}); + 0x08: bic({{ Rc = Ra & ~Rb_or_imm; }}); + 0x20: bis({{ Rc = Ra | Rb_or_imm; }}); + 0x28: ornot({{ Rc = Ra | ~Rb_or_imm; }}); + 0x40: xor({{ Rc = Ra ^ Rb_or_imm; }}); + 0x48: eqv({{ Rc = Ra ^ ~Rb_or_imm; }}); + + // conditional moves + 0x14: cmovlbs({{ Rc = ((Ra & 1) == 1) ? Rb_or_imm : Rc; }}); + 0x16: cmovlbc({{ Rc = ((Ra & 1) == 0) ? Rb_or_imm : Rc; }}); + 0x24: cmoveq({{ Rc = (Ra == 0) ? Rb_or_imm : Rc; }}); + 0x26: cmovne({{ Rc = (Ra != 0) ? Rb_or_imm : Rc; }}); + 0x44: cmovlt({{ Rc = (Ra.sq < 0) ? Rb_or_imm : Rc; }}); + 0x46: cmovge({{ Rc = (Ra.sq >= 0) ? Rb_or_imm : Rc; }}); + 0x64: cmovle({{ Rc = (Ra.sq <= 0) ? Rb_or_imm : Rc; }}); + 0x66: cmovgt({{ Rc = (Ra.sq > 0) ? Rb_or_imm : Rc; }}); + + // For AMASK, RA must be R31. + 0x61: decode RA { + 31: amask({{ Rc = Rb_or_imm & ~ULL(0x17); }}); + } + + // For IMPLVER, RA must be R31 and the B operand + // must be the immediate value 1. + 0x6c: decode RA { + 31: decode IMM { + 1: decode INTIMM { + // return EV5 for FULL_SYSTEM and EV6 otherwise + 1: implver({{ +#if FULL_SYSTEM + Rc = 1; +#else + Rc = 2; +#endif + }}); + } + } + } + +#if FULL_SYSTEM + // The mysterious 11.25... + 0x25: WarnUnimpl::eleven25(); +#endif + } + + 0x12: decode INTFUNC { + 0x39: sll({{ Rc = Ra << Rb_or_imm<5:0>; }}); + 0x34: srl({{ Rc = Ra.uq >> Rb_or_imm<5:0>; }}); + 0x3c: sra({{ Rc = Ra.sq >> Rb_or_imm<5:0>; }}); + + 0x02: mskbl({{ Rc = Ra & ~(mask( 8) << (Rb_or_imm<2:0> * 8)); }}); + 0x12: mskwl({{ Rc = Ra & ~(mask(16) << (Rb_or_imm<2:0> * 8)); }}); + 0x22: mskll({{ Rc = Ra & ~(mask(32) << (Rb_or_imm<2:0> * 8)); }}); + 0x32: mskql({{ Rc = Ra & ~(mask(64) << (Rb_or_imm<2:0> * 8)); }}); + + 0x52: mskwh({{ + int bv = Rb_or_imm<2:0>; + Rc = bv ? (Ra & ~(mask(16) >> (64 - 8 * bv))) : Ra; + }}); + 0x62: msklh({{ + int bv = Rb_or_imm<2:0>; + Rc = bv ? (Ra & ~(mask(32) >> (64 - 8 * bv))) : Ra; + }}); + 0x72: mskqh({{ + int bv = Rb_or_imm<2:0>; + Rc = bv ? (Ra & ~(mask(64) >> (64 - 8 * bv))) : Ra; + }}); + + 0x06: extbl({{ Rc = (Ra.uq >> (Rb_or_imm<2:0> * 8))< 7:0>; }}); + 0x16: extwl({{ Rc = (Ra.uq >> (Rb_or_imm<2:0> * 8))<15:0>; }}); + 0x26: extll({{ Rc = (Ra.uq >> (Rb_or_imm<2:0> * 8))<31:0>; }}); + 0x36: extql({{ Rc = (Ra.uq >> (Rb_or_imm<2:0> * 8)); }}); + + 0x5a: extwh({{ + Rc = (Ra << (64 - (Rb_or_imm<2:0> * 8))<5:0>)<15:0>; }}); + 0x6a: extlh({{ + Rc = (Ra << (64 - (Rb_or_imm<2:0> * 8))<5:0>)<31:0>; }}); + 0x7a: extqh({{ + Rc = (Ra << (64 - (Rb_or_imm<2:0> * 8))<5:0>); }}); + + 0x0b: insbl({{ Rc = Ra< 7:0> << (Rb_or_imm<2:0> * 8); }}); + 0x1b: inswl({{ Rc = Ra<15:0> << (Rb_or_imm<2:0> * 8); }}); + 0x2b: insll({{ Rc = Ra<31:0> << (Rb_or_imm<2:0> * 8); }}); + 0x3b: insql({{ Rc = Ra << (Rb_or_imm<2:0> * 8); }}); + + 0x57: inswh({{ + int bv = Rb_or_imm<2:0>; + Rc = bv ? (Ra.uq<15:0> >> (64 - 8 * bv)) : 0; + }}); + 0x67: inslh({{ + int bv = Rb_or_imm<2:0>; + Rc = bv ? (Ra.uq<31:0> >> (64 - 8 * bv)) : 0; + }}); + 0x77: insqh({{ + int bv = Rb_or_imm<2:0>; + Rc = bv ? (Ra.uq >> (64 - 8 * bv)) : 0; + }}); + + 0x30: zap({{ + uint64_t zapmask = 0; + for (int i = 0; i < 8; ++i) { + if (Rb_or_imm<i:>) + zapmask |= (mask(8) << (i * 8)); + } + Rc = Ra & ~zapmask; + }}); + 0x31: zapnot({{ + uint64_t zapmask = 0; + for (int i = 0; i < 8; ++i) { + if (!Rb_or_imm<i:>) + zapmask |= (mask(8) << (i * 8)); + } + Rc = Ra & ~zapmask; + }}); + } + + 0x13: decode INTFUNC { // integer multiplies + 0x00: mull({{ Rc.sl = Ra.sl * Rb_or_imm.sl; }}, IntMultOp); + 0x20: mulq({{ Rc = Ra * Rb_or_imm; }}, IntMultOp); + 0x30: umulh({{ + uint64_t hi, lo; + mul128(Ra, Rb_or_imm, hi, lo); + Rc = hi; + }}, IntMultOp); + 0x40: mullv({{ + // 32-bit multiply with trap on overflow + int64_t Rax = Ra.sl; // sign extended version of Ra.sl + int64_t Rbx = Rb_or_imm.sl; + int64_t tmp = Rax * Rbx; + // To avoid overflow, all the upper 32 bits must match + // the sign bit of the lower 32. We code this as + // checking the upper 33 bits for all 0s or all 1s. + uint64_t sign_bits = tmp<63:31>; + if (sign_bits != 0 && sign_bits != mask(33)) + fault = new IntegerOverflowFault; + Rc.sl = tmp<31:0>; + }}, IntMultOp); + 0x60: mulqv({{ + // 64-bit multiply with trap on overflow + uint64_t hi, lo; + mul128(Ra, Rb_or_imm, hi, lo); + // all the upper 64 bits must match the sign bit of + // the lower 64 + if (!((hi == 0 && lo<63:> == 0) || + (hi == mask(64) && lo<63:> == 1))) + fault = new IntegerOverflowFault; + Rc = lo; + }}, IntMultOp); + } + + 0x1c: decode INTFUNC { + 0x00: decode RA { 31: sextb({{ Rc.sb = Rb_or_imm< 7:0>; }}); } + 0x01: decode RA { 31: sextw({{ Rc.sw = Rb_or_imm<15:0>; }}); } + 0x32: ctlz({{ + uint64_t count = 0; + uint64_t temp = Rb; + if (temp<63:32>) temp >>= 32; else count += 32; + if (temp<31:16>) temp >>= 16; else count += 16; + if (temp<15:8>) temp >>= 8; else count += 8; + if (temp<7:4>) temp >>= 4; else count += 4; + if (temp<3:2>) temp >>= 2; else count += 2; + if (temp<1:1>) temp >>= 1; else count += 1; + if ((temp<0:0>) != 0x1) count += 1; + Rc = count; + }}, IntAluOp); + + 0x33: cttz({{ + uint64_t count = 0; + uint64_t temp = Rb; + if (!(temp<31:0>)) { temp >>= 32; count += 32; } + if (!(temp<15:0>)) { temp >>= 16; count += 16; } + if (!(temp<7:0>)) { temp >>= 8; count += 8; } + if (!(temp<3:0>)) { temp >>= 4; count += 4; } + if (!(temp<1:0>)) { temp >>= 2; count += 2; } + if (!(temp<0:0> & ULL(0x1))) count += 1; + Rc = count; + }}, IntAluOp); + + format FailUnimpl { + 0x30: ctpop(); + 0x31: perr(); + 0x34: unpkbw(); + 0x35: unpkbl(); + 0x36: pkwb(); + 0x37: pklb(); + 0x38: minsb8(); + 0x39: minsw4(); + 0x3a: minub8(); + 0x3b: minuw4(); + 0x3c: maxub8(); + 0x3d: maxuw4(); + 0x3e: maxsb8(); + 0x3f: maxsw4(); + } + + format BasicOperateWithNopCheck { + 0x70: decode RB { + 31: ftoit({{ Rc = Fa.uq; }}, FloatCvtOp); + } + 0x78: decode RB { + 31: ftois({{ Rc.sl = t_to_s(Fa.uq); }}, + FloatCvtOp); + } + } + } + } + + // Conditional branches. + format CondBranch { + 0x39: beq({{ cond = (Ra == 0); }}); + 0x3d: bne({{ cond = (Ra != 0); }}); + 0x3e: bge({{ cond = (Ra.sq >= 0); }}); + 0x3f: bgt({{ cond = (Ra.sq > 0); }}); + 0x3b: ble({{ cond = (Ra.sq <= 0); }}); + 0x3a: blt({{ cond = (Ra.sq < 0); }}); + 0x38: blbc({{ cond = ((Ra & 1) == 0); }}); + 0x3c: blbs({{ cond = ((Ra & 1) == 1); }}); + + 0x31: fbeq({{ cond = (Fa == 0); }}); + 0x35: fbne({{ cond = (Fa != 0); }}); + 0x36: fbge({{ cond = (Fa >= 0); }}); + 0x37: fbgt({{ cond = (Fa > 0); }}); + 0x33: fble({{ cond = (Fa <= 0); }}); + 0x32: fblt({{ cond = (Fa < 0); }}); + } + + // unconditional branches + format UncondBranch { + 0x30: br(); + 0x34: bsr(IsCall); + } + + // indirect branches + 0x1a: decode JMPFUNC { + format Jump { + 0: jmp(); + 1: jsr(IsCall); + 2: ret(IsReturn); + 3: jsr_coroutine(IsCall, IsReturn); + } + } + + // Square root and integer-to-FP moves + 0x14: decode FP_SHORTFUNC { + // Integer to FP register moves must have RB == 31 + 0x4: decode RB { + 31: decode FP_FULLFUNC { + format BasicOperateWithNopCheck { + 0x004: itofs({{ Fc.uq = s_to_t(Ra.ul); }}, FloatCvtOp); + 0x024: itoft({{ Fc.uq = Ra.uq; }}, FloatCvtOp); + 0x014: FailUnimpl::itoff(); // VAX-format conversion + } + } + } + + // Square root instructions must have FA == 31 + 0xb: decode FA { + 31: decode FP_TYPEFUNC { + format FloatingPointOperate { +#if SS_COMPATIBLE_FP + 0x0b: sqrts({{ + if (Fb < 0.0) + fault = new ArithmeticFault; + Fc = sqrt(Fb); + }}, FloatSqrtOp); +#else + 0x0b: sqrts({{ + if (Fb.sf < 0.0) + fault = new ArithmeticFault; + Fc.sf = sqrt(Fb.sf); + }}, FloatSqrtOp); +#endif + 0x2b: sqrtt({{ + if (Fb < 0.0) + fault = new ArithmeticFault; + Fc = sqrt(Fb); + }}, FloatSqrtOp); + } + } + } + + // VAX-format sqrtf and sqrtg are not implemented + 0xa: FailUnimpl::sqrtfg(); + } + + // IEEE floating point + 0x16: decode FP_SHORTFUNC_TOP2 { + // The top two bits of the short function code break this + // space into four groups: binary ops, compares, reserved, and + // conversions. See Table 4-12 of AHB. There are different + // special cases in these different groups, so we decode on + // these top two bits first just to select a decode strategy. + // Most of these instructions may have various trapping and + // rounding mode flags set; these are decoded in the + // FloatingPointDecode template used by the + // FloatingPointOperate format. + + // add/sub/mul/div: just decode on the short function code + // and source type. All valid trapping and rounding modes apply. + 0: decode FP_TRAPMODE { + // check for valid trapping modes here + 0,1,5,7: decode FP_TYPEFUNC { + format FloatingPointOperate { +#if SS_COMPATIBLE_FP + 0x00: adds({{ Fc = Fa + Fb; }}); + 0x01: subs({{ Fc = Fa - Fb; }}); + 0x02: muls({{ Fc = Fa * Fb; }}, FloatMultOp); + 0x03: divs({{ Fc = Fa / Fb; }}, FloatDivOp); +#else + 0x00: adds({{ Fc.sf = Fa.sf + Fb.sf; }}); + 0x01: subs({{ Fc.sf = Fa.sf - Fb.sf; }}); + 0x02: muls({{ Fc.sf = Fa.sf * Fb.sf; }}, FloatMultOp); + 0x03: divs({{ Fc.sf = Fa.sf / Fb.sf; }}, FloatDivOp); +#endif + + 0x20: addt({{ Fc = Fa + Fb; }}); + 0x21: subt({{ Fc = Fa - Fb; }}); + 0x22: mult({{ Fc = Fa * Fb; }}, FloatMultOp); + 0x23: divt({{ Fc = Fa / Fb; }}, FloatDivOp); + } + } + } + + // Floating-point compare instructions must have the default + // rounding mode, and may use the default trapping mode or + // /SU. Both trapping modes are treated the same by M5; the + // only difference on the real hardware (as far a I can tell) + // is that without /SU you'd get an imprecise trap if you + // tried to compare a NaN with something else (instead of an + // "unordered" result). + 1: decode FP_FULLFUNC { + format BasicOperateWithNopCheck { + 0x0a5, 0x5a5: cmpteq({{ Fc = (Fa == Fb) ? 2.0 : 0.0; }}, + FloatCmpOp); + 0x0a7, 0x5a7: cmptle({{ Fc = (Fa <= Fb) ? 2.0 : 0.0; }}, + FloatCmpOp); + 0x0a6, 0x5a6: cmptlt({{ Fc = (Fa < Fb) ? 2.0 : 0.0; }}, + FloatCmpOp); + 0x0a4, 0x5a4: cmptun({{ // unordered + Fc = (!(Fa < Fb) && !(Fa == Fb) && !(Fa > Fb)) ? 2.0 : 0.0; + }}, FloatCmpOp); + } + } + + // The FP-to-integer and integer-to-FP conversion insts + // require that FA be 31. + 3: decode FA { + 31: decode FP_TYPEFUNC { + format FloatingPointOperate { + 0x2f: decode FP_ROUNDMODE { + format FPFixedRounding { + // "chopped" i.e. round toward zero + 0: cvttq({{ Fc.sq = (int64_t)trunc(Fb); }}, + Chopped); + // round to minus infinity + 1: cvttq({{ Fc.sq = (int64_t)floor(Fb); }}, + MinusInfinity); + } + default: cvttq({{ Fc.sq = (int64_t)nearbyint(Fb); }}); + } + + // The cvtts opcode is overloaded to be cvtst if the trap + // mode is 2 or 6 (which are not valid otherwise) + 0x2c: decode FP_FULLFUNC { + format BasicOperateWithNopCheck { + // trap on denorm version "cvtst/s" is + // simulated same as cvtst + 0x2ac, 0x6ac: cvtst({{ Fc = Fb.sf; }}); + } + default: cvtts({{ Fc.sf = Fb; }}); + } + + // The trapping mode for integer-to-FP conversions + // must be /SUI or nothing; /U and /SU are not + // allowed. The full set of rounding modes are + // supported though. + 0x3c: decode FP_TRAPMODE { + 0,7: cvtqs({{ Fc.sf = Fb.sq; }}); + } + 0x3e: decode FP_TRAPMODE { + 0,7: cvtqt({{ Fc = Fb.sq; }}); + } + } + } + } + } + + // misc FP operate + 0x17: decode FP_FULLFUNC { + format BasicOperateWithNopCheck { + 0x010: cvtlq({{ + Fc.sl = (Fb.uq<63:62> << 30) | Fb.uq<58:29>; + }}); + 0x030: cvtql({{ + Fc.uq = (Fb.uq<31:30> << 62) | (Fb.uq<29:0> << 29); + }}); + + // We treat the precise & imprecise trapping versions of + // cvtql identically. + 0x130, 0x530: cvtqlv({{ + // To avoid overflow, all the upper 32 bits must match + // the sign bit of the lower 32. We code this as + // checking the upper 33 bits for all 0s or all 1s. + uint64_t sign_bits = Fb.uq<63:31>; + if (sign_bits != 0 && sign_bits != mask(33)) + fault = new IntegerOverflowFault; + Fc.uq = (Fb.uq<31:30> << 62) | (Fb.uq<29:0> << 29); + }}); + + 0x020: cpys({{ // copy sign + Fc.uq = (Fa.uq<63:> << 63) | Fb.uq<62:0>; + }}); + 0x021: cpysn({{ // copy sign negated + Fc.uq = (~Fa.uq<63:> << 63) | Fb.uq<62:0>; + }}); + 0x022: cpyse({{ // copy sign and exponent + Fc.uq = (Fa.uq<63:52> << 52) | Fb.uq<51:0>; + }}); + + 0x02a: fcmoveq({{ Fc = (Fa == 0) ? Fb : Fc; }}); + 0x02b: fcmovne({{ Fc = (Fa != 0) ? Fb : Fc; }}); + 0x02c: fcmovlt({{ Fc = (Fa < 0) ? Fb : Fc; }}); + 0x02d: fcmovge({{ Fc = (Fa >= 0) ? Fb : Fc; }}); + 0x02e: fcmovle({{ Fc = (Fa <= 0) ? Fb : Fc; }}); + 0x02f: fcmovgt({{ Fc = (Fa > 0) ? Fb : Fc; }}); + + 0x024: mt_fpcr({{ FPCR = Fa.uq; }}, IsIprAccess); + 0x025: mf_fpcr({{ Fa.uq = FPCR; }}, IsIprAccess); + } + } + + // miscellaneous mem-format ops + 0x18: decode MEMFUNC { + format WarnUnimpl { + 0x8000: fetch(); + 0xa000: fetch_m(); + 0xe800: ecb(); + } + + format MiscPrefetch { + 0xf800: wh64({{ EA = Rb & ~ULL(63); }}, + {{ xc->writeHint(EA, 64, memAccessFlags); }}, + mem_flags = NO_FAULT, + inst_flags = [IsMemRef, IsDataPrefetch, + IsStore, MemWriteOp]); + } + + format BasicOperate { + 0xc000: rpcc({{ +#if FULL_SYSTEM + /* Rb is a fake dependency so here is a fun way to get + * the parser to understand that. + */ + Ra = xc->readMiscRegWithEffect(AlphaISA::IPR_CC, fault) + (Rb & 0); + +#else + Ra = curTick; +#endif + }}, IsUnverifiable); + + // All of the barrier instructions below do nothing in + // their execute() methods (hence the empty code blocks). + // All of their functionality is hard-coded in the + // pipeline based on the flags IsSerializing, + // IsMemBarrier, and IsWriteBarrier. In the current + // detailed CPU model, the execute() function only gets + // called at fetch, so there's no way to generate pipeline + // behavior at any other stage. Once we go to an + // exec-in-exec CPU model we should be able to get rid of + // these flags and implement this behavior via the + // execute() methods. + + // trapb is just a barrier on integer traps, where excb is + // a barrier on integer and FP traps. "EXCB is thus a + // superset of TRAPB." (Alpha ARM, Sec 4.11.4) We treat + // them the same though. + 0x0000: trapb({{ }}, IsSerializing, IsSerializeBefore, No_OpClass); + 0x0400: excb({{ }}, IsSerializing, IsSerializeBefore, No_OpClass); + 0x4000: mb({{ }}, IsMemBarrier, MemReadOp); + 0x4400: wmb({{ }}, IsWriteBarrier, MemWriteOp); + } + +#if FULL_SYSTEM + format BasicOperate { + 0xe000: rc({{ + Ra = xc->readIntrFlag(); + xc->setIntrFlag(0); + }}, IsNonSpeculative); + 0xf000: rs({{ + Ra = xc->readIntrFlag(); + xc->setIntrFlag(1); + }}, IsNonSpeculative); + } +#else + format FailUnimpl { + 0xe000: rc(); + 0xf000: rs(); + } +#endif + } + +#if FULL_SYSTEM + 0x00: CallPal::call_pal({{ + if (!palValid || + (palPriv + && xc->readMiscRegWithEffect(AlphaISA::IPR_ICM, fault) != AlphaISA::mode_kernel)) { + // invalid pal function code, or attempt to do privileged + // PAL call in non-kernel mode + fault = new UnimplementedOpcodeFault; + } + else { + // check to see if simulator wants to do something special + // on this PAL call (including maybe suppress it) + bool dopal = xc->simPalCheck(palFunc); + + if (dopal) { + xc->setMiscRegWithEffect(AlphaISA::IPR_EXC_ADDR, NPC); + NPC = xc->readMiscRegWithEffect(AlphaISA::IPR_PAL_BASE, fault) + palOffset; + } + } + }}, IsNonSpeculative); +#else + 0x00: decode PALFUNC { + format EmulatedCallPal { + 0x00: halt ({{ + exitSimLoop(curTick, "halt instruction encountered"); + }}, IsNonSpeculative); + 0x83: callsys({{ + xc->syscall(R0); + }}, IsNonSpeculative); + // Read uniq reg into ABI return value register (r0) + 0x9e: rduniq({{ R0 = Runiq; }}, IsIprAccess); + // Write uniq reg with value from ABI arg register (r16) + 0x9f: wruniq({{ Runiq = R16; }}, IsIprAccess); + } + } +#endif + +#if FULL_SYSTEM + 0x1b: decode PALMODE { + 0: OpcdecFault::hw_st_quad(); + 1: decode HW_LDST_QUAD { + format HwLoad { + 0: hw_ld({{ EA = (Rb + disp) & ~3; }}, {{ Ra = Mem.ul; }}, L); + 1: hw_ld({{ EA = (Rb + disp) & ~7; }}, {{ Ra = Mem.uq; }}, Q); + } + } + } + + 0x1f: decode PALMODE { + 0: OpcdecFault::hw_st_cond(); + format HwStore { + 1: decode HW_LDST_COND { + 0: decode HW_LDST_QUAD { + 0: hw_st({{ EA = (Rb + disp) & ~3; }}, + {{ Mem.ul = Ra<31:0>; }}, L); + 1: hw_st({{ EA = (Rb + disp) & ~7; }}, + {{ Mem.uq = Ra.uq; }}, Q); + } + + 1: FailUnimpl::hw_st_cond(); + } + } + } + + 0x19: decode PALMODE { + 0: OpcdecFault::hw_mfpr(); + format HwMoveIPR { + 1: hw_mfpr({{ + Ra = xc->readMiscRegWithEffect(ipr_index, fault); + }}, IsIprAccess); + } + } + + 0x1d: decode PALMODE { + 0: OpcdecFault::hw_mtpr(); + format HwMoveIPR { + 1: hw_mtpr({{ + xc->setMiscRegWithEffect(ipr_index, Ra); + if (traceData) { traceData->setData(Ra); } + }}, IsIprAccess); + } + } + + format BasicOperate { + 0x1e: decode PALMODE { + 0: OpcdecFault::hw_rei(); + 1:hw_rei({{ xc->hwrei(); }}, IsSerializing, IsSerializeBefore); + } + + // M5 special opcodes use the reserved 0x01 opcode space + 0x01: decode M5FUNC { + 0x00: arm({{ + AlphaPseudo::arm(xc->tcBase()); + }}, IsNonSpeculative); + 0x01: quiesce({{ + AlphaPseudo::quiesce(xc->tcBase()); + }}, IsNonSpeculative, IsQuiesce); + 0x02: quiesceNs({{ + AlphaPseudo::quiesceNs(xc->tcBase(), R16); + }}, IsNonSpeculative, IsQuiesce); + 0x03: quiesceCycles({{ + AlphaPseudo::quiesceCycles(xc->tcBase(), R16); + }}, IsNonSpeculative, IsQuiesce); + 0x04: quiesceTime({{ + R0 = AlphaPseudo::quiesceTime(xc->tcBase()); + }}, IsNonSpeculative); + 0x10: ivlb({{ + AlphaPseudo::ivlb(xc->tcBase()); + }}, No_OpClass, IsNonSpeculative); + 0x11: ivle({{ + AlphaPseudo::ivle(xc->tcBase()); + }}, No_OpClass, IsNonSpeculative); + 0x20: m5exit_old({{ + AlphaPseudo::m5exit_old(xc->tcBase()); + }}, No_OpClass, IsNonSpeculative); + 0x21: m5exit({{ + AlphaPseudo::m5exit(xc->tcBase(), R16); + }}, No_OpClass, IsNonSpeculative); + 0x30: initparam({{ Ra = xc->tcBase()->getCpuPtr()->system->init_param; }}); + 0x40: resetstats({{ + AlphaPseudo::resetstats(xc->tcBase(), R16, R17); + }}, IsNonSpeculative); + 0x41: dumpstats({{ + AlphaPseudo::dumpstats(xc->tcBase(), R16, R17); + }}, IsNonSpeculative); + 0x42: dumpresetstats({{ + AlphaPseudo::dumpresetstats(xc->tcBase(), R16, R17); + }}, IsNonSpeculative); + 0x43: m5checkpoint({{ + AlphaPseudo::m5checkpoint(xc->tcBase(), R16, R17); + }}, IsNonSpeculative); + 0x50: m5readfile({{ + R0 = AlphaPseudo::readfile(xc->tcBase(), R16, R17, R18); + }}, IsNonSpeculative); + 0x51: m5break({{ + AlphaPseudo::debugbreak(xc->tcBase()); + }}, IsNonSpeculative); + 0x52: m5switchcpu({{ + AlphaPseudo::switchcpu(xc->tcBase()); + }}, IsNonSpeculative); + 0x53: m5addsymbol({{ + AlphaPseudo::addsymbol(xc->tcBase(), R16, R17); + }}, IsNonSpeculative); + 0x54: m5panic({{ + panic("M5 panic instruction called at pc=%#x.", xc->readPC()); + }}, IsNonSpeculative); + + } + } +#endif +} diff --git a/src/arch/alpha/isa/fp.isa b/src/arch/alpha/isa/fp.isa new file mode 100644 index 000000000..b4339a1b7 --- /dev/null +++ b/src/arch/alpha/isa/fp.isa @@ -0,0 +1,312 @@ +// -*- mode:c++ -*- + +// Copyright (c) 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 Reinhardt + +//////////////////////////////////////////////////////////////////// +// +// Floating-point instructions +// +// Note that many FP-type instructions which do not support all the +// various rounding & trapping modes use the simpler format +// BasicOperateWithNopCheck. +// + +output exec {{ + /// Check "FP enabled" machine status bit. Called when executing any FP + /// instruction in full-system mode. + /// @retval Full-system mode: NoFault if FP is enabled, FenFault + /// if not. Non-full-system mode: always returns NoFault. +#if FULL_SYSTEM + inline Fault checkFpEnableFault(%(CPU_exec_context)s *xc) + { + Fault fault = NoFault; // dummy... this ipr access should not fault + if (!EV5::ICSR_FPE(xc->readMiscRegWithEffect(AlphaISA::IPR_ICSR, fault))) { + fault = new FloatEnableFault; + } + return fault; + } +#else + inline Fault checkFpEnableFault(%(CPU_exec_context)s *xc) + { + return NoFault; + } +#endif +}}; + +output header {{ + /** + * Base class for general floating-point instructions. Includes + * support for various Alpha rounding and trapping modes. Only FP + * instructions that require this support are derived from this + * class; the rest derive directly from AlphaStaticInst. + */ + class AlphaFP : public AlphaStaticInst + { + public: + /// Alpha FP rounding modes. + enum RoundingMode { + Chopped = 0, ///< round toward zero + Minus_Infinity = 1, ///< round toward minus infinity + Normal = 2, ///< round to nearest (default) + Dynamic = 3, ///< use FPCR setting (in instruction) + Plus_Infinity = 3 ///< round to plus inifinity (in FPCR) + }; + + /// Alpha FP trapping modes. + /// For instructions that produce integer results, the + /// "Underflow Enable" modes really mean "Overflow Enable", and + /// the assembly modifier is V rather than U. + enum TrappingMode { + /// default: nothing enabled + Imprecise = 0, ///< no modifier + /// underflow/overflow traps enabled, inexact disabled + Underflow_Imprecise = 1, ///< /U or /V + Underflow_Precise = 5, ///< /SU or /SV + /// underflow/overflow and inexact traps enabled + Underflow_Inexact_Precise = 7 ///< /SUI or /SVI + }; + + protected: + /// Map Alpha rounding mode to C99 constants from <fenv.h>. + static const int alphaToC99RoundingMode[]; + + /// Map enum RoundingMode values to disassembly suffixes. + static const char *roundingModeSuffix[]; + /// Map enum TrappingMode values to FP disassembly suffixes. + static const char *fpTrappingModeSuffix[]; + /// Map enum TrappingMode values to integer disassembly suffixes. + static const char *intTrappingModeSuffix[]; + + /// This instruction's rounding mode. + RoundingMode roundingMode; + /// This instruction's trapping mode. + TrappingMode trappingMode; + + /// Have we warned about this instruction's unsupported + /// rounding mode (if applicable)? + mutable bool warnedOnRounding; + + /// Have we warned about this instruction's unsupported + /// trapping mode (if applicable)? + mutable bool warnedOnTrapping; + + /// Constructor + AlphaFP(const char *mnem, ExtMachInst _machInst, OpClass __opClass) + : AlphaStaticInst(mnem, _machInst, __opClass), + roundingMode((enum RoundingMode)FP_ROUNDMODE), + trappingMode((enum TrappingMode)FP_TRAPMODE), + warnedOnRounding(false), + warnedOnTrapping(false) + { + } + + int getC99RoundingMode(uint64_t fpcr_val) const; + + // This differs from the AlphaStaticInst version only in + // printing suffixes for non-default rounding & trapping modes. + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; + +}}; + + +output decoder {{ + int + AlphaFP::getC99RoundingMode(uint64_t fpcr_val) const + { + if (roundingMode == Dynamic) { + return alphaToC99RoundingMode[bits(fpcr_val, 59, 58)]; + } + else { + return alphaToC99RoundingMode[roundingMode]; + } + } + + std::string + AlphaFP::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + std::string mnem_str(mnemonic); + +#ifndef SS_COMPATIBLE_DISASSEMBLY + std::string suffix(""); + suffix += ((_destRegIdx[0] >= FP_Base_DepTag) + ? fpTrappingModeSuffix[trappingMode] + : intTrappingModeSuffix[trappingMode]); + suffix += roundingModeSuffix[roundingMode]; + + if (suffix != "") { + mnem_str = csprintf("%s/%s", mnemonic, suffix); + } +#endif + + std::stringstream ss; + ccprintf(ss, "%-10s ", mnem_str.c_str()); + + // just print the first two source regs... if there's + // a third one, it's a read-modify-write dest (Rc), + // e.g. for CMOVxx + if (_numSrcRegs > 0) { + printReg(ss, _srcRegIdx[0]); + } + if (_numSrcRegs > 1) { + ss << ","; + printReg(ss, _srcRegIdx[1]); + } + + // just print the first dest... if there's a second one, + // it's generally implicit + if (_numDestRegs > 0) { + if (_numSrcRegs > 0) + ss << ","; + printReg(ss, _destRegIdx[0]); + } + + return ss.str(); + } + + const int AlphaFP::alphaToC99RoundingMode[] = { + FE_TOWARDZERO, // Chopped + FE_DOWNWARD, // Minus_Infinity + FE_TONEAREST, // Normal + FE_UPWARD // Dynamic in inst, Plus_Infinity in FPCR + }; + + const char *AlphaFP::roundingModeSuffix[] = { "c", "m", "", "d" }; + // mark invalid trapping modes, but don't fail on them, because + // you could decode anything on a misspeculated path + const char *AlphaFP::fpTrappingModeSuffix[] = + { "", "u", "INVTM2", "INVTM3", "INVTM4", "su", "INVTM6", "sui" }; + const char *AlphaFP::intTrappingModeSuffix[] = + { "", "v", "INVTM2", "INVTM3", "INVTM4", "sv", "INVTM6", "svi" }; +}}; + +// FP instruction class execute method template. Handles non-standard +// rounding modes. +def template FloatingPointExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + if (trappingMode != Imprecise && !warnedOnTrapping) { + warn("%s: non-standard trapping mode not supported", + generateDisassembly(0, NULL)); + warnedOnTrapping = true; + } + + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; +#if USE_FENV + if (roundingMode == Normal) { + %(code)s; + } else { + fesetround(getC99RoundingMode( + xc->readMiscReg(AlphaISA::Fpcr_DepTag))); + %(code)s; + fesetround(FE_TONEAREST); + } +#else + if (roundingMode != Normal && !warnedOnRounding) { + warn("%s: non-standard rounding mode not supported", + generateDisassembly(0, NULL)); + warnedOnRounding = true; + } + %(code)s; +#endif + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + +// FP instruction class execute method template where no dynamic +// rounding mode control is needed. Like BasicExecute, but includes +// check & warning for non-standard trapping mode. +def template FPFixedRoundingExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + if (trappingMode != Imprecise && !warnedOnTrapping) { + warn("%s: non-standard trapping mode not supported", + generateDisassembly(0, NULL)); + warnedOnTrapping = true; + } + + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + %(code)s; + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + +def template FloatingPointDecode {{ + { + AlphaStaticInst *i = new %(class_name)s(machInst); + if (FC == 31) { + i = makeNop(i); + } + return i; + } +}}; + +// General format for floating-point operate instructions: +// - Checks trapping and rounding mode flags. Trapping modes +// currently unimplemented (will fail). +// - Generates NOP if FC == 31. +def format FloatingPointOperate(code, *opt_args) {{ + iop = InstObjParams(name, Name, 'AlphaFP', CodeBlock(code), opt_args) + decode_block = FloatingPointDecode.subst(iop) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + exec_output = FloatingPointExecute.subst(iop) +}}; + +// Special format for cvttq where rounding mode is pre-decoded +def format FPFixedRounding(code, class_suffix, *opt_args) {{ + Name += class_suffix + iop = InstObjParams(name, Name, 'AlphaFP', CodeBlock(code), opt_args) + decode_block = FloatingPointDecode.subst(iop) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + exec_output = FPFixedRoundingExecute.subst(iop) +}}; + diff --git a/src/arch/alpha/isa/int.isa b/src/arch/alpha/isa/int.isa new file mode 100644 index 000000000..45e096ebd --- /dev/null +++ b/src/arch/alpha/isa/int.isa @@ -0,0 +1,135 @@ +// -*- mode:c++ -*- + +// Copyright (c) 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 Reinhardt + +//////////////////////////////////////////////////////////////////// +// +// Integer operate instructions +// + +output header {{ + /** + * Base class for integer immediate instructions. + */ + class IntegerImm : public AlphaStaticInst + { + protected: + /// Immediate operand value (unsigned 8-bit int). + uint8_t imm; + + /// Constructor + IntegerImm(const char *mnem, ExtMachInst _machInst, OpClass __opClass) + : AlphaStaticInst(mnem, _machInst, __opClass), imm(INTIMM) + { + } + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; +}}; + +output decoder {{ + std::string + IntegerImm::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + std::stringstream ss; + + ccprintf(ss, "%-10s ", mnemonic); + + // just print the first source reg... if there's + // a second one, it's a read-modify-write dest (Rc), + // e.g. for CMOVxx + if (_numSrcRegs > 0) { + printReg(ss, _srcRegIdx[0]); + ss << ","; + } + + ss << (int)imm; + + if (_numDestRegs > 0) { + ss << ","; + printReg(ss, _destRegIdx[0]); + } + + return ss.str(); + } +}}; + + +def template RegOrImmDecode {{ + { + AlphaStaticInst *i = + (IMM) ? (AlphaStaticInst *)new %(class_name)sImm(machInst) + : (AlphaStaticInst *)new %(class_name)s(machInst); + if (RC == 31) { + i = makeNop(i); + } + return i; + } +}}; + +// Primary format for integer operate instructions: +// - Generates both reg-reg and reg-imm versions if Rb_or_imm is used. +// - Generates NOP if RC == 31. +def format IntegerOperate(code, *opt_flags) {{ + # If the code block contains 'Rb_or_imm', we define two instructions, + # one using 'Rb' and one using 'imm', and have the decoder select + # the right one. + uses_imm = (code.find('Rb_or_imm') != -1) + if uses_imm: + orig_code = code + # base code is reg version: + # rewrite by substituting 'Rb' for 'Rb_or_imm' + code = re.sub(r'Rb_or_imm', 'Rb', orig_code) + # generate immediate version by substituting 'imm' + # note that imm takes no extenstion, so we extend + # the regexp to replace any extension as well + imm_code = re.sub(r'Rb_or_imm(\.\w+)?', 'imm', orig_code) + + # generate declaration for register version + cblk = CodeBlock(code) + iop = InstObjParams(name, Name, 'AlphaStaticInst', cblk, opt_flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + exec_output = BasicExecute.subst(iop) + + if uses_imm: + # append declaration for imm version + imm_cblk = CodeBlock(imm_code) + imm_iop = InstObjParams(name, Name + 'Imm', 'IntegerImm', imm_cblk, + opt_flags) + header_output += BasicDeclare.subst(imm_iop) + decoder_output += BasicConstructor.subst(imm_iop) + exec_output += BasicExecute.subst(imm_iop) + # decode checks IMM bit to pick correct version + decode_block = RegOrImmDecode.subst(iop) + else: + # no imm version: just check for nop + decode_block = OperateNopCheckDecode.subst(iop) +}}; diff --git a/src/arch/alpha/isa/main.isa b/src/arch/alpha/isa/main.isa new file mode 100644 index 000000000..1270bf8d8 --- /dev/null +++ b/src/arch/alpha/isa/main.isa @@ -0,0 +1,463 @@ +// -*- mode:c++ -*- + +// Copyright (c) 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 Reinhardt + +//////////////////////////////////////////////////////////////////// +// +// Alpha ISA description file. +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// +// Output include file directives. +// + +output header {{ +#include <sstream> +#include <iostream> +#include <iomanip> + +#include "config/ss_compatible_fp.hh" +#include "cpu/static_inst.hh" +#include "arch/alpha/faults.hh" +#include "mem/request.hh" // some constructors use MemReq flags +}}; + +output decoder {{ +#include "base/cprintf.hh" +#include "base/fenv.hh" +#include "base/loader/symtab.hh" +#include "config/ss_compatible_fp.hh" +#include "cpu/thread_context.hh" // for Jump::branchTarget() + +#include <math.h> + +using namespace AlphaISA; +}}; + +output exec {{ +#include <math.h> + +#if FULL_SYSTEM +#include "sim/pseudo_inst.hh" +#endif +#include "base/fenv.hh" +#include "config/ss_compatible_fp.hh" +#include "cpu/base.hh" +#include "cpu/exetrace.hh" +#include "sim/sim_exit.hh" +#include "mem/packet_impl.hh" + +using namespace AlphaISA; +}}; + +//////////////////////////////////////////////////////////////////// +// +// Namespace statement. Everything below this line will be in the +// AlphaISAInst namespace. +// + + +namespace AlphaISA; + +//////////////////////////////////////////////////////////////////// +// +// Bitfield definitions. +// + +// Universal (format-independent) fields +def bitfield PALMODE <32:32>; +def bitfield OPCODE <31:26>; +def bitfield RA <25:21>; +def bitfield RB <20:16>; + +// Memory format +def signed bitfield MEMDISP <15: 0>; // displacement +def bitfield MEMFUNC <15: 0>; // function code (same field, unsigned) + +// Memory-format jumps +def bitfield JMPFUNC <15:14>; // function code (disp<15:14>) +def bitfield JMPHINT <13: 0>; // tgt Icache idx hint (disp<13:0>) + +// Branch format +def signed bitfield BRDISP <20: 0>; // displacement + +// Integer operate format(s>; +def bitfield INTIMM <20:13>; // integer immediate (literal) +def bitfield IMM <12:12>; // immediate flag +def bitfield INTFUNC <11: 5>; // function code +def bitfield RC < 4: 0>; // dest reg + +// Floating-point operate format +def bitfield FA <25:21>; +def bitfield FB <20:16>; +def bitfield FP_FULLFUNC <15: 5>; // complete function code + def bitfield FP_TRAPMODE <15:13>; // trapping mode + def bitfield FP_ROUNDMODE <12:11>; // rounding mode + def bitfield FP_TYPEFUNC <10: 5>; // type+func: handiest for decoding + def bitfield FP_SRCTYPE <10: 9>; // source reg type + def bitfield FP_SHORTFUNC < 8: 5>; // short function code + def bitfield FP_SHORTFUNC_TOP2 <8:7>; // top 2 bits of short func code +def bitfield FC < 4: 0>; // dest reg + +// PALcode format +def bitfield PALFUNC <25: 0>; // function code + +// EV5 PAL instructions: +// HW_LD/HW_ST +def bitfield HW_LDST_PHYS <15>; // address is physical +def bitfield HW_LDST_ALT <14>; // use ALT_MODE IPR +def bitfield HW_LDST_WRTCK <13>; // HW_LD only: fault if no write acc +def bitfield HW_LDST_QUAD <12>; // size: 0=32b, 1=64b +def bitfield HW_LDST_VPTE <11>; // HW_LD only: is PTE fetch +def bitfield HW_LDST_LOCK <10>; // HW_LD only: is load locked +def bitfield HW_LDST_COND <10>; // HW_ST only: is store conditional +def signed bitfield HW_LDST_DISP <9:0>; // signed displacement + +// HW_REI +def bitfield HW_REI_TYP <15:14>; // type: stalling vs. non-stallingk +def bitfield HW_REI_MBZ <13: 0>; // must be zero + +// HW_MTPR/MW_MFPR +def bitfield HW_IPR_IDX <15:0>; // IPR index + +// M5 instructions +def bitfield M5FUNC <7:0>; + +def operand_types {{ + 'sb' : ('signed int', 8), + 'ub' : ('unsigned int', 8), + 'sw' : ('signed int', 16), + 'uw' : ('unsigned int', 16), + 'sl' : ('signed int', 32), + 'ul' : ('unsigned int', 32), + 'sq' : ('signed int', 64), + 'uq' : ('unsigned int', 64), + 'sf' : ('float', 32), + 'df' : ('float', 64) +}}; + +def operands {{ + # Int regs default to unsigned, but code should not count on this. + # For clarity, descriptions that depend on unsigned behavior should + # explicitly specify '.uq'. + 'Ra': ('IntReg', 'uq', 'PALMODE ? AlphaISA::reg_redir[RA] : RA', + 'IsInteger', 1), + 'Rb': ('IntReg', 'uq', 'PALMODE ? AlphaISA::reg_redir[RB] : RB', + 'IsInteger', 2), + 'Rc': ('IntReg', 'uq', 'PALMODE ? AlphaISA::reg_redir[RC] : RC', + 'IsInteger', 3), + 'Fa': ('FloatReg', 'df', 'FA', 'IsFloating', 1), + 'Fb': ('FloatReg', 'df', 'FB', 'IsFloating', 2), + 'Fc': ('FloatReg', 'df', 'FC', 'IsFloating', 3), + 'Mem': ('Mem', 'uq', None, ('IsMemRef', 'IsLoad', 'IsStore'), 4), + 'NPC': ('NPC', 'uq', None, ( None, None, 'IsControl' ), 4), + 'Runiq': ('ControlReg', 'uq', 'TheISA::Uniq_DepTag', None, 1), + 'FPCR': (' ControlReg', 'uq', 'TheISA::Fpcr_DepTag', None, 1), + # The next two are hacks for non-full-system call-pal emulation + 'R0': ('IntReg', 'uq', '0', None, 1), + 'R16': ('IntReg', 'uq', '16', None, 1), + 'R17': ('IntReg', 'uq', '17', None, 1), + 'R18': ('IntReg', 'uq', '18', None, 1) +}}; + +//////////////////////////////////////////////////////////////////// +// +// Basic instruction classes/templates/formats etc. +// + +output header {{ +// uncomment the following to get SimpleScalar-compatible disassembly +// (useful for diffing output traces). +// #define SS_COMPATIBLE_DISASSEMBLY + + /** + * Base class for all Alpha static instructions. + */ + class AlphaStaticInst : public StaticInst + { + protected: + + /// Make AlphaISA register dependence tags directly visible in + /// this class and derived classes. Maybe these should really + /// live here and not in the AlphaISA namespace. + enum DependenceTags { + FP_Base_DepTag = AlphaISA::FP_Base_DepTag, + Fpcr_DepTag = AlphaISA::Fpcr_DepTag, + Uniq_DepTag = AlphaISA::Uniq_DepTag, + Lock_Flag_DepTag = AlphaISA::Lock_Flag_DepTag, + Lock_Addr_DepTag = AlphaISA::Lock_Addr_DepTag, + IPR_Base_DepTag = AlphaISA::IPR_Base_DepTag + }; + + /// Constructor. + AlphaStaticInst(const char *mnem, ExtMachInst _machInst, + OpClass __opClass) + : StaticInst(mnem, _machInst, __opClass) + { + } + + /// Print a register name for disassembly given the unique + /// dependence tag number (FP or int). + void printReg(std::ostream &os, int reg) const; + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; +}}; + +output decoder {{ + void + AlphaStaticInst::printReg(std::ostream &os, int reg) const + { + if (reg < FP_Base_DepTag) { + ccprintf(os, "r%d", reg); + } + else { + ccprintf(os, "f%d", reg - FP_Base_DepTag); + } + } + + std::string + AlphaStaticInst::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream ss; + + ccprintf(ss, "%-10s ", mnemonic); + + // just print the first two source regs... if there's + // a third one, it's a read-modify-write dest (Rc), + // e.g. for CMOVxx + if (_numSrcRegs > 0) { + printReg(ss, _srcRegIdx[0]); + } + if (_numSrcRegs > 1) { + ss << ","; + printReg(ss, _srcRegIdx[1]); + } + + // just print the first dest... if there's a second one, + // it's generally implicit + if (_numDestRegs > 0) { + if (_numSrcRegs > 0) + ss << ","; + printReg(ss, _destRegIdx[0]); + } + + return ss.str(); + } +}}; + +// Declarations for execute() methods. +def template BasicExecDeclare {{ + Fault execute(%(CPU_exec_context)s *, Trace::InstRecord *) const; +}}; + +// Basic instruction class declaration template. +def template BasicDeclare {{ + /** + * Static instruction class for "%(mnemonic)s". + */ + class %(class_name)s : public %(base_class)s + { + public: + /// Constructor. + %(class_name)s(ExtMachInst machInst); + + %(BasicExecDeclare)s + }; +}}; + +// Basic instruction class constructor template. +def template BasicConstructor {{ + inline %(class_name)s::%(class_name)s(ExtMachInst machInst) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s) + { + %(constructor)s; + } +}}; + +// Basic instruction class execute method template. +def template BasicExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + %(code)s; + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + +// Basic decode template. +def template BasicDecode {{ + return new %(class_name)s(machInst); +}}; + +// Basic decode template, passing mnemonic in as string arg to constructor. +def template BasicDecodeWithMnemonic {{ + return new %(class_name)s("%(mnemonic)s", machInst); +}}; + +// The most basic instruction format... used only for a few misc. insts +def format BasicOperate(code, *flags) {{ + iop = InstObjParams(name, Name, 'AlphaStaticInst', CodeBlock(code), flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + + + +//////////////////////////////////////////////////////////////////// +// +// Nop +// + +output header {{ + /** + * Static instruction class for no-ops. This is a leaf class. + */ + class Nop : public AlphaStaticInst + { + /// Disassembly of original instruction. + const std::string originalDisassembly; + + public: + /// Constructor + Nop(const std::string _originalDisassembly, ExtMachInst _machInst) + : AlphaStaticInst("nop", _machInst, No_OpClass), + originalDisassembly(_originalDisassembly) + { + flags[IsNop] = true; + } + + ~Nop() { } + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + + %(BasicExecDeclare)s + }; + + /// Helper function for decoding nops. Substitute Nop object + /// for original inst passed in as arg (and delete latter). + static inline + AlphaStaticInst * + makeNop(AlphaStaticInst *inst) + { + AlphaStaticInst *nop = new Nop(inst->disassemble(0), inst->machInst); + delete inst; + return nop; + } +}}; + +output decoder {{ + std::string Nop::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { +#ifdef SS_COMPATIBLE_DISASSEMBLY + return originalDisassembly; +#else + return csprintf("%-10s (%s)", "nop", originalDisassembly); +#endif + } +}}; + +output exec {{ + Fault + Nop::execute(%(CPU_exec_context)s *, Trace::InstRecord *) const + { + return NoFault; + } +}}; + +// integer & FP operate instructions use Rc as dest, so check for +// Rc == 31 to detect nops +def template OperateNopCheckDecode {{ + { + AlphaStaticInst *i = new %(class_name)s(machInst); + if (RC == 31) { + i = makeNop(i); + } + return i; + } +}}; + +// Like BasicOperate format, but generates NOP if RC/FC == 31 +def format BasicOperateWithNopCheck(code, *opt_args) {{ + iop = InstObjParams(name, Name, 'AlphaStaticInst', CodeBlock(code), + opt_args) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = OperateNopCheckDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + +// Integer instruction templates, formats, etc. +##include "int.isa" + +// Floating-point instruction templates, formats, etc. +##include "fp.isa" + +// Memory instruction templates, formats, etc. +##include "mem.isa" + +// Branch/jump instruction templates, formats, etc. +##include "branch.isa" + +// PAL instruction templates, formats, etc. +##include "pal.isa" + +// Opcdec fault instruction templates, formats, etc. +##include "opcdec.isa" + +// Unimplemented instruction templates, formats, etc. +##include "unimp.isa" + +// Unknown instruction templates, formats, etc. +##include "unknown.isa" + +// Execution utility functions +##include "util.isa" + +// The actual decoder +##include "decoder.isa" diff --git a/src/arch/alpha/isa/mem.isa b/src/arch/alpha/isa/mem.isa new file mode 100644 index 000000000..08a0a2343 --- /dev/null +++ b/src/arch/alpha/isa/mem.isa @@ -0,0 +1,737 @@ +// -*- mode:c++ -*- + +// Copyright (c) 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 Reinhardt +// Kevin Lim + +//////////////////////////////////////////////////////////////////// +// +// Memory-format instructions: LoadAddress, Load, Store +// + +output header {{ + /** + * Base class for general Alpha memory-format instructions. + */ + class Memory : public AlphaStaticInst + { + protected: + + /// Memory request flags. See mem_req_base.hh. + unsigned memAccessFlags; + /// Pointer to EAComp object. + const StaticInstPtr eaCompPtr; + /// Pointer to MemAcc object. + const StaticInstPtr memAccPtr; + + /// Constructor + Memory(const char *mnem, ExtMachInst _machInst, OpClass __opClass, + StaticInstPtr _eaCompPtr = nullStaticInstPtr, + StaticInstPtr _memAccPtr = nullStaticInstPtr) + : AlphaStaticInst(mnem, _machInst, __opClass), + memAccessFlags(0), eaCompPtr(_eaCompPtr), memAccPtr(_memAccPtr) + { + } + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + + public: + + const StaticInstPtr &eaCompInst() const { return eaCompPtr; } + const StaticInstPtr &memAccInst() const { return memAccPtr; } + }; + + /** + * Base class for memory-format instructions using a 32-bit + * displacement (i.e. most of them). + */ + class MemoryDisp32 : public Memory + { + protected: + /// Displacement for EA calculation (signed). + int32_t disp; + + /// Constructor. + MemoryDisp32(const char *mnem, ExtMachInst _machInst, OpClass __opClass, + StaticInstPtr _eaCompPtr = nullStaticInstPtr, + StaticInstPtr _memAccPtr = nullStaticInstPtr) + : Memory(mnem, _machInst, __opClass, _eaCompPtr, _memAccPtr), + disp(MEMDISP) + { + } + }; + + + /** + * Base class for a few miscellaneous memory-format insts + * that don't interpret the disp field: wh64, fetch, fetch_m, ecb. + * None of these instructions has a destination register either. + */ + class MemoryNoDisp : public Memory + { + protected: + /// Constructor + MemoryNoDisp(const char *mnem, ExtMachInst _machInst, OpClass __opClass, + StaticInstPtr _eaCompPtr = nullStaticInstPtr, + StaticInstPtr _memAccPtr = nullStaticInstPtr) + : Memory(mnem, _machInst, __opClass, _eaCompPtr, _memAccPtr) + { + } + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; +}}; + + +output decoder {{ + std::string + Memory::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + return csprintf("%-10s %c%d,%d(r%d)", mnemonic, + flags[IsFloating] ? 'f' : 'r', RA, MEMDISP, RB); + } + + std::string + MemoryNoDisp::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + return csprintf("%-10s (r%d)", mnemonic, RB); + } +}}; + +def format LoadAddress(code) {{ + iop = InstObjParams(name, Name, 'MemoryDisp32', CodeBlock(code)) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + + +def template LoadStoreDeclare {{ + /** + * Static instruction class for "%(mnemonic)s". + */ + class %(class_name)s : public %(base_class)s + { + protected: + + /** + * "Fake" effective address computation class for "%(mnemonic)s". + */ + class EAComp : public %(base_class)s + { + public: + /// Constructor + EAComp(ExtMachInst machInst); + + %(BasicExecDeclare)s + }; + + /** + * "Fake" memory access instruction class for "%(mnemonic)s". + */ + class MemAcc : public %(base_class)s + { + public: + /// Constructor + MemAcc(ExtMachInst machInst); + + %(BasicExecDeclare)s + }; + + public: + + /// Constructor. + %(class_name)s(ExtMachInst machInst); + + %(BasicExecDeclare)s + + %(InitiateAccDeclare)s + + %(CompleteAccDeclare)s + }; +}}; + + +def template InitiateAccDeclare {{ + Fault initiateAcc(%(CPU_exec_context)s *, Trace::InstRecord *) const; +}}; + + +def template CompleteAccDeclare {{ + Fault completeAcc(Packet *, %(CPU_exec_context)s *, + Trace::InstRecord *) const; +}}; + + +def template LoadStoreConstructor {{ + /** TODO: change op_class to AddrGenOp or something (requires + * creating new member of OpClass enum in op_class.hh, updating + * config files, etc.). */ + inline %(class_name)s::EAComp::EAComp(ExtMachInst machInst) + : %(base_class)s("%(mnemonic)s (EAComp)", machInst, IntAluOp) + { + %(ea_constructor)s; + } + + inline %(class_name)s::MemAcc::MemAcc(ExtMachInst machInst) + : %(base_class)s("%(mnemonic)s (MemAcc)", machInst, %(op_class)s) + { + %(memacc_constructor)s; + } + + inline %(class_name)s::%(class_name)s(ExtMachInst machInst) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + new EAComp(machInst), new MemAcc(machInst)) + { + %(constructor)s; + } +}}; + + +def template EACompExecute {{ + Fault + %(class_name)s::EAComp::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + %(code)s; + + if (fault == NoFault) { + %(op_wb)s; + xc->setEA(EA); + } + + return fault; + } +}}; + +def template LoadMemAccExecute {{ + Fault + %(class_name)s::MemAcc::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + EA = xc->getEA(); + + if (fault == NoFault) { + fault = xc->read(EA, (uint%(mem_acc_size)d_t&)Mem, memAccessFlags); + %(code)s; + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + + +def template LoadExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + %(ea_code)s; + + if (fault == NoFault) { + fault = xc->read(EA, (uint%(mem_acc_size)d_t&)Mem, memAccessFlags); + %(memacc_code)s; + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + + +def template LoadInitiateAcc {{ + Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_src_decl)s; + %(op_rd)s; + %(ea_code)s; + + if (fault == NoFault) { + fault = xc->read(EA, (uint%(mem_acc_size)d_t &)Mem, memAccessFlags); + } + + return fault; + } +}}; + + +def template LoadCompleteAcc {{ + Fault %(class_name)s::completeAcc(Packet *pkt, + %(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_decl)s; + + Mem = pkt->get<typeof(Mem)>(); + + if (fault == NoFault) { + %(memacc_code)s; + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + + +def template StoreMemAccExecute {{ + Fault + %(class_name)s::MemAcc::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + uint64_t write_result = 0; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + EA = xc->getEA(); + + if (fault == NoFault) { + %(code)s; + } + + if (fault == NoFault) { + fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA, + memAccessFlags, &write_result); + if (traceData) { traceData->setData(Mem); } + } + + if (fault == NoFault) { + %(postacc_code)s; + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + + +def template StoreExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + uint64_t write_result = 0; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + %(ea_code)s; + + if (fault == NoFault) { + %(memacc_code)s; + } + + if (fault == NoFault) { + fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA, + memAccessFlags, &write_result); + if (traceData) { traceData->setData(Mem); } + } + + if (fault == NoFault) { + %(postacc_code)s; + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + +def template StoreInitiateAcc {{ + Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + %(ea_code)s; + + if (fault == NoFault) { + %(memacc_code)s; + } + + if (fault == NoFault) { + fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA, + memAccessFlags, NULL); + if (traceData) { traceData->setData(Mem); } + } + + return fault; + } +}}; + + +def template StoreCompleteAcc {{ + Fault %(class_name)s::completeAcc(Packet *pkt, + %(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_dest_decl)s; + + if (fault == NoFault) { + %(postacc_code)s; + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + + +def template StoreCondCompleteAcc {{ + Fault %(class_name)s::completeAcc(Packet *pkt, + %(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_dest_decl)s; + + uint64_t write_result = pkt->req->getScResult(); + + if (fault == NoFault) { + %(postacc_code)s; + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + + +def template MiscMemAccExecute {{ + Fault %(class_name)s::MemAcc::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + EA = xc->getEA(); + + if (fault == NoFault) { + %(code)s; + } + + return NoFault; + } +}}; + +def template MiscExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + %(ea_code)s; + + if (fault == NoFault) { + %(memacc_code)s; + } + + return NoFault; + } +}}; + +def template MiscInitiateAcc {{ + Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + panic("Misc instruction does not support split access method!"); + return NoFault; + } +}}; + + +def template MiscCompleteAcc {{ + Fault %(class_name)s::completeAcc(Packet *pkt, + %(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + panic("Misc instruction does not support split access method!"); + + return NoFault; + } +}}; + +// load instructions use Ra as dest, so check for +// Ra == 31 to detect nops +def template LoadNopCheckDecode {{ + { + AlphaStaticInst *i = new %(class_name)s(machInst); + if (RA == 31) { + i = makeNop(i); + } + return i; + } +}}; + + +// for some load instructions, Ra == 31 indicates a prefetch (not a nop) +def template LoadPrefetchCheckDecode {{ + { + if (RA != 31) { + return new %(class_name)s(machInst); + } + else { + return new %(class_name)sPrefetch(machInst); + } + } +}}; + + +let {{ +def LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, + postacc_code = '', base_class = 'MemoryDisp32', + decode_template = BasicDecode, exec_template_base = ''): + # Make sure flags are in lists (convert to lists if not). + mem_flags = makeList(mem_flags) + inst_flags = makeList(inst_flags) + + # add hook to get effective addresses into execution trace output. + ea_code += '\nif (traceData) { traceData->setAddr(EA); }\n' + + # generate code block objects + ea_cblk = CodeBlock(ea_code) + memacc_cblk = CodeBlock(memacc_code) + postacc_cblk = CodeBlock(postacc_code) + + # Some CPU models execute the memory operation as an atomic unit, + # while others want to separate them into an effective address + # computation and a memory access operation. As a result, we need + # to generate three StaticInst objects. Note that the latter two + # are nested inside the larger "atomic" one. + + # generate InstObjParams for EAComp object + ea_iop = InstObjParams(name, Name, base_class, ea_cblk, inst_flags) + + # generate InstObjParams for MemAcc object + memacc_iop = InstObjParams(name, Name, base_class, memacc_cblk, inst_flags) + # in the split execution model, the MemAcc portion is responsible + # for the post-access code. + memacc_iop.postacc_code = postacc_cblk.code + + # generate InstObjParams for InitiateAcc, CompleteAcc object + # The code used depends on the template being used + if (exec_template_base == 'Load'): + initiateacc_cblk = CodeBlock(ea_code + memacc_code) + completeacc_cblk = CodeBlock(memacc_code + postacc_code) + elif (exec_template_base.startswith('Store')): + initiateacc_cblk = CodeBlock(ea_code + memacc_code) + completeacc_cblk = CodeBlock(postacc_code) + else: + initiateacc_cblk = '' + completeacc_cblk = '' + + initiateacc_iop = InstObjParams(name, Name, base_class, initiateacc_cblk, + inst_flags) + + completeacc_iop = InstObjParams(name, Name, base_class, completeacc_cblk, + inst_flags) + + if (exec_template_base == 'Load'): + initiateacc_iop.ea_code = ea_cblk.code + initiateacc_iop.memacc_code = memacc_cblk.code + completeacc_iop.memacc_code = memacc_cblk.code + completeacc_iop.postacc_code = postacc_cblk.code + elif (exec_template_base.startswith('Store')): + initiateacc_iop.ea_code = ea_cblk.code + initiateacc_iop.memacc_code = memacc_cblk.code + completeacc_iop.postacc_code = postacc_cblk.code + + # generate InstObjParams for unified execution + cblk = CodeBlock(ea_code + memacc_code + postacc_code) + iop = InstObjParams(name, Name, base_class, cblk, inst_flags) + + iop.ea_constructor = ea_cblk.constructor + iop.ea_code = ea_cblk.code + iop.memacc_constructor = memacc_cblk.constructor + iop.memacc_code = memacc_cblk.code + iop.postacc_code = postacc_cblk.code + + if mem_flags: + s = '\n\tmemAccessFlags = ' + string.join(mem_flags, '|') + ';' + iop.constructor += s + memacc_iop.constructor += s + + # select templates + + # define aliases... most StoreCond templates are the same as the + # corresponding Store templates (only CompleteAcc is different). + StoreCondMemAccExecute = StoreMemAccExecute + StoreCondExecute = StoreExecute + StoreCondInitiateAcc = StoreInitiateAcc + + memAccExecTemplate = eval(exec_template_base + 'MemAccExecute') + fullExecTemplate = eval(exec_template_base + 'Execute') + initiateAccTemplate = eval(exec_template_base + 'InitiateAcc') + completeAccTemplate = eval(exec_template_base + 'CompleteAcc') + + # (header_output, decoder_output, decode_block, exec_output) + return (LoadStoreDeclare.subst(iop), LoadStoreConstructor.subst(iop), + decode_template.subst(iop), + EACompExecute.subst(ea_iop) + + memAccExecTemplate.subst(memacc_iop) + + fullExecTemplate.subst(iop) + + initiateAccTemplate.subst(initiateacc_iop) + + completeAccTemplate.subst(completeacc_iop)) +}}; + + +def format LoadOrNop(memacc_code, ea_code = {{ EA = Rb + disp; }}, + mem_flags = [], inst_flags = []) {{ + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, + decode_template = LoadNopCheckDecode, + exec_template_base = 'Load') +}}; + + +// Note that the flags passed in apply only to the prefetch version +def format LoadOrPrefetch(memacc_code, ea_code = {{ EA = Rb + disp; }}, + mem_flags = [], pf_flags = [], inst_flags = []) {{ + # declare the load instruction object and generate the decode block + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, + decode_template = LoadPrefetchCheckDecode, + exec_template_base = 'Load') + + # Declare the prefetch instruction object. + + # Make sure flag args are lists so we can mess with them. + mem_flags = makeList(mem_flags) + pf_flags = makeList(pf_flags) + inst_flags = makeList(inst_flags) + + pf_mem_flags = mem_flags + pf_flags + ['NO_FAULT'] + pf_inst_flags = inst_flags + ['IsMemRef', 'IsLoad', + 'IsDataPrefetch', 'MemReadOp'] + + (pf_header_output, pf_decoder_output, _, pf_exec_output) = \ + LoadStoreBase(name, Name + 'Prefetch', ea_code, + 'xc->prefetch(EA, memAccessFlags);', + pf_mem_flags, pf_inst_flags, exec_template_base = 'Misc') + + header_output += pf_header_output + decoder_output += pf_decoder_output + exec_output += pf_exec_output +}}; + + +def format Store(memacc_code, ea_code = {{ EA = Rb + disp; }}, + mem_flags = [], inst_flags = []) {{ + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, + exec_template_base = 'Store') +}}; + + +def format StoreCond(memacc_code, postacc_code, + ea_code = {{ EA = Rb + disp; }}, + mem_flags = [], inst_flags = []) {{ + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, + postacc_code, exec_template_base = 'StoreCond') +}}; + + +// Use 'MemoryNoDisp' as base: for wh64, fetch, ecb +def format MiscPrefetch(ea_code, memacc_code, + mem_flags = [], inst_flags = []) {{ + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, + base_class = 'MemoryNoDisp', exec_template_base = 'Misc') +}}; + + diff --git a/src/arch/alpha/isa/opcdec.isa b/src/arch/alpha/isa/opcdec.isa new file mode 100644 index 000000000..d279ae050 --- /dev/null +++ b/src/arch/alpha/isa/opcdec.isa @@ -0,0 +1,79 @@ +// -*- mode:c++ -*- + +// Copyright (c) 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: Kevin Lim + +//////////////////////////////////////////////////////////////////// +// +// OPCDEC fault instructions +// + +output header {{ + /** + * Static instruction class for instructions that cause an OPCDEC fault + * when executed. This is currently only for PAL mode instructions + * executed in non-PAL mode. + */ + class OpcdecFault : public AlphaStaticInst + { + public: + /// Constructor + OpcdecFault(ExtMachInst _machInst) + : AlphaStaticInst("opcdec fault", _machInst, No_OpClass) + { + } + + %(BasicExecDeclare)s + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; +}}; + +output decoder {{ + std::string + OpcdecFault::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + return csprintf("%-10s (inst 0x%x, opcode 0x%x)", + " OPCDEC fault", machInst, OPCODE); + } +}}; + +output exec {{ + Fault + OpcdecFault::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + return new UnimplementedOpcodeFault; + } +}}; + +def format OpcdecFault() {{ + decode_block = 'return new OpcdecFault(machInst);\n' +}}; + diff --git a/src/arch/alpha/isa/pal.isa b/src/arch/alpha/isa/pal.isa new file mode 100644 index 000000000..f4c10da1d --- /dev/null +++ b/src/arch/alpha/isa/pal.isa @@ -0,0 +1,280 @@ +// -*- mode:c++ -*- + +// Copyright (c) 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 Reinhardt + +//////////////////////////////////////////////////////////////////// +// +// PAL calls & PAL-specific instructions +// + +output header {{ + /** + * Base class for emulated call_pal calls (used only in + * non-full-system mode). + */ + class EmulatedCallPal : public AlphaStaticInst + { + protected: + + /// Constructor. + EmulatedCallPal(const char *mnem, ExtMachInst _machInst, + OpClass __opClass) + : AlphaStaticInst(mnem, _machInst, __opClass) + { + } + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; +}}; + +output decoder {{ + std::string + EmulatedCallPal::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { +#ifdef SS_COMPATIBLE_DISASSEMBLY + return csprintf("%s %s", "call_pal", mnemonic); +#else + return csprintf("%-10s %s", "call_pal", mnemonic); +#endif + } +}}; + +def format EmulatedCallPal(code, *flags) {{ + iop = InstObjParams(name, Name, 'EmulatedCallPal', CodeBlock(code), flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + +output header {{ + /** + * Base class for full-system-mode call_pal instructions. + * Probably could turn this into a leaf class and get rid of the + * parser template. + */ + class CallPalBase : public AlphaStaticInst + { + protected: + int palFunc; ///< Function code part of instruction + int palOffset; ///< Target PC, offset from IPR_PAL_BASE + bool palValid; ///< is the function code valid? + bool palPriv; ///< is this call privileged? + + /// Constructor. + CallPalBase(const char *mnem, ExtMachInst _machInst, + OpClass __opClass); + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; +}}; + +output decoder {{ + inline + CallPalBase::CallPalBase(const char *mnem, ExtMachInst _machInst, + OpClass __opClass) + : AlphaStaticInst(mnem, _machInst, __opClass), + palFunc(PALFUNC) + { + // From the 21164 HRM (paraphrased): + // Bit 7 of the function code (mask 0x80) indicates + // whether the call is privileged (bit 7 == 0) or + // unprivileged (bit 7 == 1). The privileged call table + // starts at 0x2000, the unprivielged call table starts at + // 0x3000. Bits 5-0 (mask 0x3f) are used to calculate the + // offset. + const int palPrivMask = 0x80; + const int palOffsetMask = 0x3f; + + // Pal call is invalid unless all other bits are 0 + palValid = ((machInst & ~(palPrivMask | palOffsetMask)) == 0); + palPriv = ((machInst & palPrivMask) == 0); + int shortPalFunc = (machInst & palOffsetMask); + // Add 1 to base to set pal-mode bit + palOffset = (palPriv ? 0x2001 : 0x3001) + (shortPalFunc << 6); + } + + std::string + CallPalBase::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + return csprintf("%-10s %#x", "call_pal", palFunc); + } +}}; + +def format CallPal(code, *flags) {{ + iop = InstObjParams(name, Name, 'CallPalBase', CodeBlock(code), flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + +//////////////////////////////////////////////////////////////////// +// +// hw_ld, hw_st +// + +output header {{ + /** + * Base class for hw_ld and hw_st. + */ + class HwLoadStore : public Memory + { + protected: + + /// Displacement for EA calculation (signed). + int16_t disp; + + /// Constructor + HwLoadStore(const char *mnem, ExtMachInst _machInst, OpClass __opClass, + StaticInstPtr _eaCompPtr = nullStaticInstPtr, + StaticInstPtr _memAccPtr = nullStaticInstPtr); + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; +}}; + + +output decoder {{ + inline + HwLoadStore::HwLoadStore(const char *mnem, ExtMachInst _machInst, + OpClass __opClass, + StaticInstPtr _eaCompPtr, + StaticInstPtr _memAccPtr) + : Memory(mnem, _machInst, __opClass, _eaCompPtr, _memAccPtr), + disp(HW_LDST_DISP) + { + memAccessFlags = 0; + if (HW_LDST_PHYS) memAccessFlags |= PHYSICAL; + if (HW_LDST_ALT) memAccessFlags |= ALTMODE; + if (HW_LDST_VPTE) memAccessFlags |= VPTE; + if (HW_LDST_LOCK) memAccessFlags |= LOCKED; + } + + std::string + HwLoadStore::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { +#ifdef SS_COMPATIBLE_DISASSEMBLY + return csprintf("%-10s r%d,%d(r%d)", mnemonic, RA, disp, RB); +#else + // HW_LDST_LOCK and HW_LDST_COND are the same bit. + const char *lock_str = + (HW_LDST_LOCK) ? (flags[IsLoad] ? ",LOCK" : ",COND") : ""; + + return csprintf("%-10s r%d,%d(r%d)%s%s%s%s%s", + mnemonic, RA, disp, RB, + HW_LDST_PHYS ? ",PHYS" : "", + HW_LDST_ALT ? ",ALT" : "", + HW_LDST_QUAD ? ",QUAD" : "", + HW_LDST_VPTE ? ",VPTE" : "", + lock_str); +#endif + } +}}; + +def format HwLoad(ea_code, memacc_code, class_ext, *flags) {{ + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name + class_ext, ea_code, memacc_code, + mem_flags = [], inst_flags = flags, + base_class = 'HwLoadStore', exec_template_base = 'Load') +}}; + + +def format HwStore(ea_code, memacc_code, class_ext, *flags) {{ + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name + class_ext, ea_code, memacc_code, + mem_flags = [], inst_flags = flags, + base_class = 'HwLoadStore', exec_template_base = 'Store') +}}; + + +def format HwStoreCond(ea_code, memacc_code, postacc_code, class_ext, + *flags) {{ + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name + class_ext, ea_code, memacc_code, + postacc_code, mem_flags = [], inst_flags = flags, + base_class = 'HwLoadStore') +}}; + + +output header {{ + /** + * Base class for hw_mfpr and hw_mtpr. + */ + class HwMoveIPR : public AlphaStaticInst + { + protected: + /// Index of internal processor register. + int ipr_index; + + /// Constructor + HwMoveIPR(const char *mnem, ExtMachInst _machInst, OpClass __opClass) + : AlphaStaticInst(mnem, _machInst, __opClass), + ipr_index(HW_IPR_IDX) + { + } + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; +}}; + +output decoder {{ + std::string + HwMoveIPR::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + if (_numSrcRegs > 0) { + // must be mtpr + return csprintf("%-10s r%d,IPR(%#x)", + mnemonic, RA, ipr_index); + } + else { + // must be mfpr + return csprintf("%-10s IPR(%#x),r%d", + mnemonic, ipr_index, RA); + } + } +}}; + +def format HwMoveIPR(code, *flags) {{ + all_flags = ['IprAccessOp'] + all_flags += flags + iop = InstObjParams(name, Name, 'HwMoveIPR', CodeBlock(code), + all_flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + + diff --git a/src/arch/alpha/isa/unimp.isa b/src/arch/alpha/isa/unimp.isa new file mode 100644 index 000000000..6cfaa6991 --- /dev/null +++ b/src/arch/alpha/isa/unimp.isa @@ -0,0 +1,172 @@ +// -*- mode:c++ -*- + +// Copyright (c) 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 Reinhardt + +//////////////////////////////////////////////////////////////////// +// +// Unimplemented instructions +// + +output header {{ + /** + * Static instruction class for unimplemented instructions that + * cause simulator termination. Note that these are recognized + * (legal) instructions that the simulator does not support; the + * 'Unknown' class is used for unrecognized/illegal instructions. + * This is a leaf class. + */ + class FailUnimplemented : public AlphaStaticInst + { + public: + /// Constructor + FailUnimplemented(const char *_mnemonic, ExtMachInst _machInst) + : AlphaStaticInst(_mnemonic, _machInst, No_OpClass) + { + // don't call execute() (which panics) if we're on a + // speculative path + flags[IsNonSpeculative] = true; + } + + %(BasicExecDeclare)s + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; + + /** + * Base class for unimplemented instructions that cause a warning + * to be printed (but do not terminate simulation). This + * implementation is a little screwy in that it will print a + * warning for each instance of a particular unimplemented machine + * instruction, not just for each unimplemented opcode. Should + * probably make the 'warned' flag a static member of the derived + * class. + */ + class WarnUnimplemented : public AlphaStaticInst + { + private: + /// Have we warned on this instruction yet? + mutable bool warned; + + public: + /// Constructor + WarnUnimplemented(const char *_mnemonic, ExtMachInst _machInst) + : AlphaStaticInst(_mnemonic, _machInst, No_OpClass), warned(false) + { + // don't call execute() (which panics) if we're on a + // speculative path + flags[IsNonSpeculative] = true; + } + + %(BasicExecDeclare)s + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; +}}; + +output decoder {{ + std::string + FailUnimplemented::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + return csprintf("%-10s (unimplemented)", mnemonic); + } + + std::string + WarnUnimplemented::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { +#ifdef SS_COMPATIBLE_DISASSEMBLY + return csprintf("%-10s", mnemonic); +#else + return csprintf("%-10s (unimplemented)", mnemonic); +#endif + } +}}; + +output exec {{ + Fault + FailUnimplemented::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + panic("attempt to execute unimplemented instruction '%s' " + "(inst 0x%08x, opcode 0x%x)", mnemonic, machInst, OPCODE); + return new UnimplementedOpcodeFault; + } + + Fault + WarnUnimplemented::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + if (!warned) { + warn("instruction '%s' unimplemented\n", mnemonic); + warned = true; + } + + return NoFault; + } +}}; + + +def format FailUnimpl() {{ + iop = InstObjParams(name, 'FailUnimplemented') + decode_block = BasicDecodeWithMnemonic.subst(iop) +}}; + +def format WarnUnimpl() {{ + iop = InstObjParams(name, 'WarnUnimplemented') + decode_block = BasicDecodeWithMnemonic.subst(iop) +}}; + +output header {{ + /** + * Static instruction class for unknown (illegal) instructions. + * These cause simulator termination if they are executed in a + * non-speculative mode. This is a leaf class. + */ + class Unknown : public AlphaStaticInst + { + public: + /// Constructor + Unknown(ExtMachInst _machInst) + : AlphaStaticInst("unknown", _machInst, No_OpClass) + { + // don't call execute() (which panics) if we're on a + // speculative path + flags[IsNonSpeculative] = true; + } + + %(BasicExecDeclare)s + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; +}}; + diff --git a/src/arch/alpha/isa/unknown.isa b/src/arch/alpha/isa/unknown.isa new file mode 100644 index 000000000..1e95ccf68 --- /dev/null +++ b/src/arch/alpha/isa/unknown.isa @@ -0,0 +1,59 @@ +// -*- mode:c++ -*- + +// Copyright (c) 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 Reinhardt + +//////////////////////////////////////////////////////////////////// +// +// Unknown instructions +// + +output decoder {{ + std::string + Unknown::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + return csprintf("%-10s (inst 0x%x, opcode 0x%x)", + "unknown", machInst, OPCODE); + } +}}; + +output exec {{ + Fault + Unknown::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + panic("attempt to execute unknown instruction " + "(inst 0x%08x, opcode 0x%x)", machInst, OPCODE); + return new UnimplementedOpcodeFault; + } +}}; + +def format Unknown() {{ + decode_block = 'return new Unknown(machInst);\n' +}}; + diff --git a/src/arch/alpha/isa/util.isa b/src/arch/alpha/isa/util.isa new file mode 100644 index 000000000..8700d1e0b --- /dev/null +++ b/src/arch/alpha/isa/util.isa @@ -0,0 +1,119 @@ +// -*- mode:c++ -*- + +// Copyright (c) 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 Reinhardt + +//////////////////////////////////////////////////////////////////// +// +// Utility functions for execute methods +// + +output exec {{ + + /// Return opa + opb, summing carry into third arg. + inline uint64_t + addc(uint64_t opa, uint64_t opb, int &carry) + { + uint64_t res = opa + opb; + if (res < opa || res < opb) + ++carry; + return res; + } + + /// Multiply two 64-bit values (opa * opb), returning the 128-bit + /// product in res_hi and res_lo. + inline void + mul128(uint64_t opa, uint64_t opb, uint64_t &res_hi, uint64_t &res_lo) + { + // do a 64x64 --> 128 multiply using four 32x32 --> 64 multiplies + uint64_t opa_hi = opa<63:32>; + uint64_t opa_lo = opa<31:0>; + uint64_t opb_hi = opb<63:32>; + uint64_t opb_lo = opb<31:0>; + + res_lo = opa_lo * opb_lo; + + // The middle partial products logically belong in bit + // positions 95 to 32. Thus the lower 32 bits of each product + // sum into the upper 32 bits of the low result, while the + // upper 32 sum into the low 32 bits of the upper result. + uint64_t partial1 = opa_hi * opb_lo; + uint64_t partial2 = opa_lo * opb_hi; + + uint64_t partial1_lo = partial1<31:0> << 32; + uint64_t partial1_hi = partial1<63:32>; + uint64_t partial2_lo = partial2<31:0> << 32; + uint64_t partial2_hi = partial2<63:32>; + + // Add partial1_lo and partial2_lo to res_lo, keeping track + // of any carries out + int carry_out = 0; + res_lo = addc(partial1_lo, res_lo, carry_out); + res_lo = addc(partial2_lo, res_lo, carry_out); + + // Now calculate the high 64 bits... + res_hi = (opa_hi * opb_hi) + partial1_hi + partial2_hi + carry_out; + } + + /// Map 8-bit S-floating exponent to 11-bit T-floating exponent. + /// See Table 2-2 of Alpha AHB. + inline int + map_s(int old_exp) + { + int hibit = old_exp<7:>; + int lobits = old_exp<6:0>; + + if (hibit == 1) { + return (lobits == 0x7f) ? 0x7ff : (0x400 | lobits); + } + else { + return (lobits == 0) ? 0 : (0x380 | lobits); + } + } + + /// Convert a 32-bit S-floating value to the equivalent 64-bit + /// representation to be stored in an FP reg. + inline uint64_t + s_to_t(uint32_t s_val) + { + uint64_t tmp = s_val; + return (tmp<31:> << 63 // sign bit + | (uint64_t)map_s(tmp<30:23>) << 52 // exponent + | tmp<22:0> << 29); // fraction + } + + /// Convert a 64-bit T-floating value to the equivalent 32-bit + /// S-floating representation to be stored in memory. + inline int32_t + t_to_s(uint64_t t_val) + { + return (t_val<63:62> << 30 // sign bit & hi exp bit + | t_val<58:29>); // rest of exp & fraction + } +}}; + diff --git a/src/arch/alpha/isa_traits.hh b/src/arch/alpha/isa_traits.hh new file mode 100644 index 000000000..663b144ab --- /dev/null +++ b/src/arch/alpha/isa_traits.hh @@ -0,0 +1,115 @@ +/* + * Copyright (c) 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 Reinhardt + * Gabe Black + */ + +#ifndef __ARCH_ALPHA_ISA_TRAITS_HH__ +#define __ARCH_ALPHA_ISA_TRAITS_HH__ + +namespace LittleEndianGuest {} + +#include "arch/alpha/types.hh" +#include "arch/alpha/constants.hh" +#include "arch/alpha/regfile.hh" +#include "config/full_system.hh" +#include "sim/host.hh" + +class StaticInstPtr; + +#if !FULL_SYSTEM +class SyscallReturn { + public: + template <class T> + SyscallReturn(T v, bool s) + { + retval = (uint64_t)v; + success = s; + } + + template <class T> + SyscallReturn(T v) + { + success = (v >= 0); + retval = (uint64_t)v; + } + + ~SyscallReturn() {} + + SyscallReturn& operator=(const SyscallReturn& s) { + retval = s.retval; + success = s.success; + return *this; + } + + bool successful() { return success; } + uint64_t value() { return retval; } + + + private: + uint64_t retval; + bool success; +}; + +#endif + +#if FULL_SYSTEM +#include "arch/alpha/isa_fullsys_traits.hh" +#endif + + +namespace AlphaISA +{ + +using namespace LittleEndianGuest; + +// redirected register map, really only used for the full system case. +extern const int reg_redir[NumIntRegs]; + + StaticInstPtr decodeInst(ExtMachInst); + +#if !FULL_SYSTEM + static inline void setSyscallReturn(SyscallReturn return_value, RegFile *regs) + { + // check for error condition. Alpha syscall convention is to + // indicate success/failure in reg a3 (r19) and put the + // return value itself in the standard return value reg (v0). + if (return_value.successful()) { + // no error + regs->setIntReg(SyscallSuccessReg, 0); + regs->setIntReg(ReturnValueReg, return_value.value()); + } else { + // got an error, return details + regs->setIntReg(SyscallSuccessReg, (IntReg)-1); + regs->setIntReg(ReturnValueReg, -return_value.value()); + } + } +#endif +}; + +#endif // __ARCH_ALPHA_ISA_TRAITS_HH__ diff --git a/src/arch/alpha/linux/aligned.hh b/src/arch/alpha/linux/aligned.hh new file mode 100644 index 000000000..c4687e348 --- /dev/null +++ b/src/arch/alpha/linux/aligned.hh @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2004 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 + * Nathan Binkert + */ + +#ifndef __ARCH_ALPHA_LINUX_ALIGNED_HH__ +#define __ARCH_ALPHA_LINUX_ALIGNED_HH__ + + +/* GCC 3.3.X has a bug in which attributes+typedefs don't work. 3.2.X is fine + * as in 3.4.X, but the bug is marked will not fix in 3.3.X so here is + * the work around. + */ +#if (__GNUC__ == 3 && __GNUC_MINOR__ != 3) || __GNUC__ > 3 +typedef uint64_t uint64_ta __attribute__ ((aligned (8))) ; +typedef int64_t int64_ta __attribute__ ((aligned (8))) ; +typedef Addr Addr_a __attribute__ ((aligned (8))) ; +#else +#define uint64_ta uint64_t __attribute__ ((aligned (8))) +#define int64_ta int64_t __attribute__ ((aligned (8))) +#define Addr_a Addr __attribute__ ((aligned (8))) +#endif /* __GNUC__ __GNUC_MINOR__ */ + +#endif /* __ARCH_ALPHA_LINUX_ALIGNED_HH__ */ diff --git a/arch/alpha/linux/hwrpb.hh b/src/arch/alpha/linux/hwrpb.hh index 869ce026b..869ce026b 100644 --- a/arch/alpha/linux/hwrpb.hh +++ b/src/arch/alpha/linux/hwrpb.hh diff --git a/src/arch/alpha/linux/linux.cc b/src/arch/alpha/linux/linux.cc new file mode 100644 index 000000000..bc0d48e0d --- /dev/null +++ b/src/arch/alpha/linux/linux.cc @@ -0,0 +1,72 @@ +/* + * Copyright (c) 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: Korey Sewell + */ + +#include "arch/alpha/linux/linux.hh" + +// open(2) flags translation table +OpenFlagTransTable AlphaLinux::openFlagTable[] = { +#ifdef _MSC_VER + { AlphaLinux::TGT_O_RDONLY, _O_RDONLY }, + { AlphaLinux::TGT_O_WRONLY, _O_WRONLY }, + { AlphaLinux::TGT_O_RDWR, _O_RDWR }, + { AlphaLinux::TGT_O_APPEND, _O_APPEND }, + { AlphaLinux::TGT_O_CREAT, _O_CREAT }, + { AlphaLinux::TGT_O_TRUNC, _O_TRUNC }, + { AlphaLinux::TGT_O_EXCL, _O_EXCL }, +#ifdef _O_NONBLOCK + { AlphaLinux::TGT_O_NONBLOCK, _O_NONBLOCK }, +#endif +#ifdef _O_NOCTTY + { AlphaLinux::TGT_O_NOCTTY, _O_NOCTTY }, +#endif +#ifdef _O_SYNC + { AlphaLinux::TGT_O_SYNC, _O_SYNC }, +#endif +#else /* !_MSC_VER */ + { AlphaLinux::TGT_O_RDONLY, O_RDONLY }, + { AlphaLinux::TGT_O_WRONLY, O_WRONLY }, + { AlphaLinux::TGT_O_RDWR, O_RDWR }, + { AlphaLinux::TGT_O_APPEND, O_APPEND }, + { AlphaLinux::TGT_O_CREAT, O_CREAT }, + { AlphaLinux::TGT_O_TRUNC, O_TRUNC }, + { AlphaLinux::TGT_O_EXCL, O_EXCL }, + { AlphaLinux::TGT_O_NONBLOCK, O_NONBLOCK }, + { AlphaLinux::TGT_O_NOCTTY, O_NOCTTY }, +#ifdef O_SYNC + { AlphaLinux::TGT_O_SYNC, O_SYNC }, +#endif +#endif /* _MSC_VER */ +}; + +const int AlphaLinux::NUM_OPEN_FLAGS = + (sizeof(AlphaLinux::openFlagTable)/sizeof(AlphaLinux::openFlagTable[0])); + + + diff --git a/src/arch/alpha/linux/linux.hh b/src/arch/alpha/linux/linux.hh new file mode 100644 index 000000000..09988bab2 --- /dev/null +++ b/src/arch/alpha/linux/linux.hh @@ -0,0 +1,130 @@ +/* + * Copyright (c) 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: Korey Sewell + */ + +#ifndef __ALPHA_ALPHA_LINUX_HH +#define __ALPHA_ALPHA_LINUX_HH + +#include "kern/linux/linux.hh" + +/* AlphaLinux class contains static constants/definitions/misc. + * structures which are specific to the Linux OS AND the Alpha + * architecture + */ +class AlphaLinux : public Linux +{ + public: + + /// This table maps the target open() flags to the corresponding + /// host open() flags. + static OpenFlagTransTable openFlagTable[]; + + /// Number of entries in openFlagTable[]. + static const int NUM_OPEN_FLAGS; + + //@{ + /// open(2) flag values. + static const int TGT_O_RDONLY = 00000000; //!< O_RDONLY + static const int TGT_O_WRONLY = 00000001; //!< O_WRONLY + static const int TGT_O_RDWR = 00000002; //!< O_RDWR + static const int TGT_O_NONBLOCK = 00000004; //!< O_NONBLOCK + static const int TGT_O_APPEND = 00000010; //!< O_APPEND + static const int TGT_O_CREAT = 00001000; //!< O_CREAT + static const int TGT_O_TRUNC = 00002000; //!< O_TRUNC + static const int TGT_O_EXCL = 00004000; //!< O_EXCL + static const int TGT_O_NOCTTY = 00010000; //!< O_NOCTTY + static const int TGT_O_SYNC = 00040000; //!< O_SYNC + static const int TGT_O_DRD = 00100000; //!< O_DRD + static const int TGT_O_DIRECTIO = 00200000; //!< O_DIRECTIO + static const int TGT_O_CACHE = 00400000; //!< O_CACHE + static const int TGT_O_DSYNC = 02000000; //!< O_DSYNC + static const int TGT_O_RSYNC = 04000000; //!< O_RSYNC + //@} + + /// For mmap(). + static const unsigned TGT_MAP_ANONYMOUS = 0x10; + + //@{ + /// For getsysinfo(). + static const unsigned GSI_PLATFORM_NAME = 103; //!< platform name as string + static const unsigned GSI_CPU_INFO = 59; //!< CPU information + static const unsigned GSI_PROC_TYPE = 60; //!< get proc_type + static const unsigned GSI_MAX_CPU = 30; //!< max # cpu's on this machine + static const unsigned GSI_CPUS_IN_BOX = 55; //!< number of CPUs in system + static const unsigned GSI_PHYSMEM = 19; //!< Physical memory in KB + static const unsigned GSI_CLK_TCK = 42; //!< clock freq in Hz + static const unsigned GSI_IEEE_FP_CONTROL = 45; + //@} + + //@{ + /// For getrusage(). + static const int TGT_RUSAGE_SELF = 0; + static const int TGT_RUSAGE_CHILDREN = -1; + static const int TGT_RUSAGE_BOTH = -2; + //@} + + //@{ + /// For setsysinfo(). + static const unsigned SSI_IEEE_FP_CONTROL = 14; //!< ieee_set_fp_control() + //@} + + //@{ + /// ioctl() command codes. + static const unsigned TIOCGETP = 0x40067408; + static const unsigned TIOCSETP = 0x80067409; + static const unsigned TIOCSETN = 0x8006740a; + static const unsigned TIOCSETC = 0x80067411; + static const unsigned TIOCGETC = 0x40067412; + static const unsigned FIONREAD = 0x4004667f; + static const unsigned TIOCISATTY = 0x2000745e; + static const unsigned TIOCGETS = 0x402c7413; + static const unsigned TIOCGETA = 0x40127417; + //@} + + /// For table(). + static const int TBL_SYSINFO = 12; + + /// Resource enumeration for getrlimit(). + enum rlimit_resources { + TGT_RLIMIT_CPU = 0, + TGT_RLIMIT_FSIZE = 1, + TGT_RLIMIT_DATA = 2, + TGT_RLIMIT_STACK = 3, + TGT_RLIMIT_CORE = 4, + TGT_RLIMIT_RSS = 5, + TGT_RLIMIT_NOFILE = 6, + TGT_RLIMIT_AS = 7, + TGT_RLIMIT_VMEM = 7, + TGT_RLIMIT_NPROC = 8, + TGT_RLIMIT_MEMLOCK = 9, + TGT_RLIMIT_LOCKS = 10 + }; +}; + +#endif diff --git a/src/arch/alpha/linux/process.cc b/src/arch/alpha/linux/process.cc new file mode 100644 index 000000000..997c78ac9 --- /dev/null +++ b/src/arch/alpha/linux/process.cc @@ -0,0 +1,594 @@ +/* + * Copyright (c) 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 Reinhardt + * Ali Saidi + */ + +#include "arch/alpha/linux/linux.hh" +#include "arch/alpha/linux/process.hh" +#include "arch/alpha/isa_traits.hh" + +#include "base/trace.hh" +#include "cpu/thread_context.hh" +#include "kern/linux/linux.hh" + +#include "sim/process.hh" +#include "sim/syscall_emul.hh" + +using namespace std; +using namespace AlphaISA; + + + +/// Target uname() handler. +static SyscallReturn +unameFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + TypedBufferArg<Linux::utsname> name(tc->getSyscallArg(0)); + + strcpy(name->sysname, "Linux"); + strcpy(name->nodename, "m5.eecs.umich.edu"); + strcpy(name->release, "2.4.20"); + strcpy(name->version, "#1 Mon Aug 18 11:32:15 EDT 2003"); + strcpy(name->machine, "alpha"); + + name.copyOut(tc->getMemPort()); + return 0; +} + +/// Target osf_getsysyinfo() handler. Even though this call is +/// borrowed from Tru64, the subcases that get used appear to be +/// different in practice from those used by Tru64 processes. +static SyscallReturn +osf_getsysinfoFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + unsigned op = tc->getSyscallArg(0); + // unsigned nbytes = tc->getSyscallArg(2); + + switch (op) { + + case 45: { // GSI_IEEE_FP_CONTROL + TypedBufferArg<uint64_t> fpcr(tc->getSyscallArg(1)); + // I don't think this exactly matches the HW FPCR + *fpcr = 0; + fpcr.copyOut(tc->getMemPort()); + return 0; + } + + default: + cerr << "osf_getsysinfo: unknown op " << op << endl; + abort(); + break; + } + + return 1; +} + +/// Target osf_setsysinfo() handler. +static SyscallReturn +osf_setsysinfoFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + unsigned op = tc->getSyscallArg(0); + // unsigned nbytes = tc->getSyscallArg(2); + + switch (op) { + + case 14: { // SSI_IEEE_FP_CONTROL + TypedBufferArg<uint64_t> fpcr(tc->getSyscallArg(1)); + // I don't think this exactly matches the HW FPCR + fpcr.copyIn(tc->getMemPort()); + DPRINTFR(SyscallVerbose, "osf_setsysinfo(SSI_IEEE_FP_CONTROL): " + " setting FPCR to 0x%x\n", gtoh(*(uint64_t*)fpcr)); + return 0; + } + + default: + cerr << "osf_setsysinfo: unknown op " << op << endl; + abort(); + break; + } + + return 1; +} + + +SyscallDesc AlphaLinuxProcess::syscallDescs[] = { + /* 0 */ SyscallDesc("osf_syscall", unimplementedFunc), + /* 1 */ SyscallDesc("exit", exitFunc), + /* 2 */ SyscallDesc("fork", unimplementedFunc), + /* 3 */ SyscallDesc("read", readFunc), + /* 4 */ SyscallDesc("write", writeFunc), + /* 5 */ SyscallDesc("osf_old_open", unimplementedFunc), + /* 6 */ SyscallDesc("close", closeFunc), + /* 7 */ SyscallDesc("osf_wait4", unimplementedFunc), + /* 8 */ SyscallDesc("osf_old_creat", unimplementedFunc), + /* 9 */ SyscallDesc("link", unimplementedFunc), + /* 10 */ SyscallDesc("unlink", unlinkFunc), + /* 11 */ SyscallDesc("osf_execve", unimplementedFunc), + /* 12 */ SyscallDesc("chdir", unimplementedFunc), + /* 13 */ SyscallDesc("fchdir", unimplementedFunc), + /* 14 */ SyscallDesc("mknod", unimplementedFunc), + /* 15 */ SyscallDesc("chmod", chmodFunc<AlphaLinux>), + /* 16 */ SyscallDesc("chown", chownFunc), + /* 17 */ SyscallDesc("brk", obreakFunc), + /* 18 */ SyscallDesc("osf_getfsstat", unimplementedFunc), + /* 19 */ SyscallDesc("lseek", lseekFunc), + /* 20 */ SyscallDesc("getxpid", getpidPseudoFunc), + /* 21 */ SyscallDesc("osf_mount", unimplementedFunc), + /* 22 */ SyscallDesc("umount", unimplementedFunc), + /* 23 */ SyscallDesc("setuid", setuidFunc), + /* 24 */ SyscallDesc("getxuid", getuidPseudoFunc), + /* 25 */ SyscallDesc("exec_with_loader", unimplementedFunc), + /* 26 */ SyscallDesc("osf_ptrace", unimplementedFunc), + /* 27 */ SyscallDesc("osf_nrecvmsg", unimplementedFunc), + /* 28 */ SyscallDesc("osf_nsendmsg", unimplementedFunc), + /* 29 */ SyscallDesc("osf_nrecvfrom", unimplementedFunc), + /* 30 */ SyscallDesc("osf_naccept", unimplementedFunc), + /* 31 */ SyscallDesc("osf_ngetpeername", unimplementedFunc), + /* 32 */ SyscallDesc("osf_ngetsockname", unimplementedFunc), + /* 33 */ SyscallDesc("access", unimplementedFunc), + /* 34 */ SyscallDesc("osf_chflags", unimplementedFunc), + /* 35 */ SyscallDesc("osf_fchflags", unimplementedFunc), + /* 36 */ SyscallDesc("sync", unimplementedFunc), + /* 37 */ SyscallDesc("kill", unimplementedFunc), + /* 38 */ SyscallDesc("osf_old_stat", unimplementedFunc), + /* 39 */ SyscallDesc("setpgid", unimplementedFunc), + /* 40 */ SyscallDesc("osf_old_lstat", unimplementedFunc), + /* 41 */ SyscallDesc("dup", unimplementedFunc), + /* 42 */ SyscallDesc("pipe", pipePseudoFunc), + /* 43 */ SyscallDesc("osf_set_program_attributes", unimplementedFunc), + /* 44 */ SyscallDesc("osf_profil", unimplementedFunc), + /* 45 */ SyscallDesc("open", openFunc<AlphaLinux>), + /* 46 */ SyscallDesc("osf_old_sigaction", unimplementedFunc), + /* 47 */ SyscallDesc("getxgid", getgidPseudoFunc), + /* 48 */ SyscallDesc("osf_sigprocmask", ignoreFunc), + /* 49 */ SyscallDesc("osf_getlogin", unimplementedFunc), + /* 50 */ SyscallDesc("osf_setlogin", unimplementedFunc), + /* 51 */ SyscallDesc("acct", unimplementedFunc), + /* 52 */ SyscallDesc("sigpending", unimplementedFunc), + /* 53 */ SyscallDesc("osf_classcntl", unimplementedFunc), + /* 54 */ SyscallDesc("ioctl", ioctlFunc<AlphaLinux>), + /* 55 */ SyscallDesc("osf_reboot", unimplementedFunc), + /* 56 */ SyscallDesc("osf_revoke", unimplementedFunc), + /* 57 */ SyscallDesc("symlink", unimplementedFunc), + /* 58 */ SyscallDesc("readlink", unimplementedFunc), + /* 59 */ SyscallDesc("execve", unimplementedFunc), + /* 60 */ SyscallDesc("umask", unimplementedFunc), + /* 61 */ SyscallDesc("chroot", unimplementedFunc), + /* 62 */ SyscallDesc("osf_old_fstat", unimplementedFunc), + /* 63 */ SyscallDesc("getpgrp", unimplementedFunc), + /* 64 */ SyscallDesc("getpagesize", getpagesizeFunc), + /* 65 */ SyscallDesc("osf_mremap", unimplementedFunc), + /* 66 */ SyscallDesc("vfork", unimplementedFunc), + /* 67 */ SyscallDesc("stat", statFunc<AlphaLinux>), + /* 68 */ SyscallDesc("lstat", lstatFunc<AlphaLinux>), + /* 69 */ SyscallDesc("osf_sbrk", unimplementedFunc), + /* 70 */ SyscallDesc("osf_sstk", unimplementedFunc), + /* 71 */ SyscallDesc("mmap", mmapFunc<AlphaLinux>), + /* 72 */ SyscallDesc("osf_old_vadvise", unimplementedFunc), + /* 73 */ SyscallDesc("munmap", munmapFunc), + /* 74 */ SyscallDesc("mprotect", ignoreFunc), + /* 75 */ SyscallDesc("madvise", unimplementedFunc), + /* 76 */ SyscallDesc("vhangup", unimplementedFunc), + /* 77 */ SyscallDesc("osf_kmodcall", unimplementedFunc), + /* 78 */ SyscallDesc("osf_mincore", unimplementedFunc), + /* 79 */ SyscallDesc("getgroups", unimplementedFunc), + /* 80 */ SyscallDesc("setgroups", unimplementedFunc), + /* 81 */ SyscallDesc("osf_old_getpgrp", unimplementedFunc), + /* 82 */ SyscallDesc("setpgrp", unimplementedFunc), + /* 83 */ SyscallDesc("osf_setitimer", unimplementedFunc), + /* 84 */ SyscallDesc("osf_old_wait", unimplementedFunc), + /* 85 */ SyscallDesc("osf_table", unimplementedFunc), + /* 86 */ SyscallDesc("osf_getitimer", unimplementedFunc), + /* 87 */ SyscallDesc("gethostname", gethostnameFunc), + /* 88 */ SyscallDesc("sethostname", unimplementedFunc), + /* 89 */ SyscallDesc("getdtablesize", unimplementedFunc), + /* 90 */ SyscallDesc("dup2", unimplementedFunc), + /* 91 */ SyscallDesc("fstat", fstatFunc<AlphaLinux>), + /* 92 */ SyscallDesc("fcntl", fcntlFunc), + /* 93 */ SyscallDesc("osf_select", unimplementedFunc), + /* 94 */ SyscallDesc("poll", unimplementedFunc), + /* 95 */ SyscallDesc("fsync", unimplementedFunc), + /* 96 */ SyscallDesc("setpriority", unimplementedFunc), + /* 97 */ SyscallDesc("socket", unimplementedFunc), + /* 98 */ SyscallDesc("connect", unimplementedFunc), + /* 99 */ SyscallDesc("accept", unimplementedFunc), + /* 100 */ SyscallDesc("getpriority", unimplementedFunc), + /* 101 */ SyscallDesc("send", unimplementedFunc), + /* 102 */ SyscallDesc("recv", unimplementedFunc), + /* 103 */ SyscallDesc("sigreturn", unimplementedFunc), + /* 104 */ SyscallDesc("bind", unimplementedFunc), + /* 105 */ SyscallDesc("setsockopt", unimplementedFunc), + /* 106 */ SyscallDesc("listen", unimplementedFunc), + /* 107 */ SyscallDesc("osf_plock", unimplementedFunc), + /* 108 */ SyscallDesc("osf_old_sigvec", unimplementedFunc), + /* 109 */ SyscallDesc("osf_old_sigblock", unimplementedFunc), + /* 110 */ SyscallDesc("osf_old_sigsetmask", unimplementedFunc), + /* 111 */ SyscallDesc("sigsuspend", unimplementedFunc), + /* 112 */ SyscallDesc("osf_sigstack", ignoreFunc), + /* 113 */ SyscallDesc("recvmsg", unimplementedFunc), + /* 114 */ SyscallDesc("sendmsg", unimplementedFunc), + /* 115 */ SyscallDesc("osf_old_vtrace", unimplementedFunc), + /* 116 */ SyscallDesc("osf_gettimeofday", unimplementedFunc), + /* 117 */ SyscallDesc("osf_getrusage", unimplementedFunc), + /* 118 */ SyscallDesc("getsockopt", unimplementedFunc), + /* 119 */ SyscallDesc("numa_syscalls", unimplementedFunc), + /* 120 */ SyscallDesc("readv", unimplementedFunc), + /* 121 */ SyscallDesc("writev", writevFunc<AlphaLinux>), + /* 122 */ SyscallDesc("osf_settimeofday", unimplementedFunc), + /* 123 */ SyscallDesc("fchown", fchownFunc), + /* 124 */ SyscallDesc("fchmod", fchmodFunc<AlphaLinux>), + /* 125 */ SyscallDesc("recvfrom", unimplementedFunc), + /* 126 */ SyscallDesc("setreuid", unimplementedFunc), + /* 127 */ SyscallDesc("setregid", unimplementedFunc), + /* 128 */ SyscallDesc("rename", renameFunc), + /* 129 */ SyscallDesc("truncate", unimplementedFunc), + /* 130 */ SyscallDesc("ftruncate", unimplementedFunc), + /* 131 */ SyscallDesc("flock", unimplementedFunc), + /* 132 */ SyscallDesc("setgid", unimplementedFunc), + /* 133 */ SyscallDesc("sendto", unimplementedFunc), + /* 134 */ SyscallDesc("shutdown", unimplementedFunc), + /* 135 */ SyscallDesc("socketpair", unimplementedFunc), + /* 136 */ SyscallDesc("mkdir", unimplementedFunc), + /* 137 */ SyscallDesc("rmdir", unimplementedFunc), + /* 138 */ SyscallDesc("osf_utimes", unimplementedFunc), + /* 139 */ SyscallDesc("osf_old_sigreturn", unimplementedFunc), + /* 140 */ SyscallDesc("osf_adjtime", unimplementedFunc), + /* 141 */ SyscallDesc("getpeername", unimplementedFunc), + /* 142 */ SyscallDesc("osf_gethostid", unimplementedFunc), + /* 143 */ SyscallDesc("osf_sethostid", unimplementedFunc), + /* 144 */ SyscallDesc("getrlimit", getrlimitFunc<AlphaLinux>), + /* 145 */ SyscallDesc("setrlimit", ignoreFunc), + /* 146 */ SyscallDesc("osf_old_killpg", unimplementedFunc), + /* 147 */ SyscallDesc("setsid", unimplementedFunc), + /* 148 */ SyscallDesc("quotactl", unimplementedFunc), + /* 149 */ SyscallDesc("osf_oldquota", unimplementedFunc), + /* 150 */ SyscallDesc("getsockname", unimplementedFunc), + /* 151 */ SyscallDesc("osf_pread", unimplementedFunc), + /* 152 */ SyscallDesc("osf_pwrite", unimplementedFunc), + /* 153 */ SyscallDesc("osf_pid_block", unimplementedFunc), + /* 154 */ SyscallDesc("osf_pid_unblock", unimplementedFunc), + /* 155 */ SyscallDesc("osf_signal_urti", unimplementedFunc), + /* 156 */ SyscallDesc("sigaction", ignoreFunc), + /* 157 */ SyscallDesc("osf_sigwaitprim", unimplementedFunc), + /* 158 */ SyscallDesc("osf_nfssvc", unimplementedFunc), + /* 159 */ SyscallDesc("osf_getdirentries", unimplementedFunc), + /* 160 */ SyscallDesc("osf_statfs", unimplementedFunc), + /* 161 */ SyscallDesc("osf_fstatfs", unimplementedFunc), + /* 162 */ SyscallDesc("unknown #162", unimplementedFunc), + /* 163 */ SyscallDesc("osf_async_daemon", unimplementedFunc), + /* 164 */ SyscallDesc("osf_getfh", unimplementedFunc), + /* 165 */ SyscallDesc("osf_getdomainname", unimplementedFunc), + /* 166 */ SyscallDesc("setdomainname", unimplementedFunc), + /* 167 */ SyscallDesc("unknown #167", unimplementedFunc), + /* 168 */ SyscallDesc("unknown #168", unimplementedFunc), + /* 169 */ SyscallDesc("osf_exportfs", unimplementedFunc), + /* 170 */ SyscallDesc("unknown #170", unimplementedFunc), + /* 171 */ SyscallDesc("unknown #171", unimplementedFunc), + /* 172 */ SyscallDesc("unknown #172", unimplementedFunc), + /* 173 */ SyscallDesc("unknown #173", unimplementedFunc), + /* 174 */ SyscallDesc("unknown #174", unimplementedFunc), + /* 175 */ SyscallDesc("unknown #175", unimplementedFunc), + /* 176 */ SyscallDesc("unknown #176", unimplementedFunc), + /* 177 */ SyscallDesc("unknown #177", unimplementedFunc), + /* 178 */ SyscallDesc("unknown #178", unimplementedFunc), + /* 179 */ SyscallDesc("unknown #179", unimplementedFunc), + /* 180 */ SyscallDesc("unknown #180", unimplementedFunc), + /* 181 */ SyscallDesc("osf_alt_plock", unimplementedFunc), + /* 182 */ SyscallDesc("unknown #182", unimplementedFunc), + /* 183 */ SyscallDesc("unknown #183", unimplementedFunc), + /* 184 */ SyscallDesc("osf_getmnt", unimplementedFunc), + /* 185 */ SyscallDesc("unknown #185", unimplementedFunc), + /* 186 */ SyscallDesc("unknown #186", unimplementedFunc), + /* 187 */ SyscallDesc("osf_alt_sigpending", unimplementedFunc), + /* 188 */ SyscallDesc("osf_alt_setsid", unimplementedFunc), + /* 189 */ SyscallDesc("unknown #189", unimplementedFunc), + /* 190 */ SyscallDesc("unknown #190", unimplementedFunc), + /* 191 */ SyscallDesc("unknown #191", unimplementedFunc), + /* 192 */ SyscallDesc("unknown #192", unimplementedFunc), + /* 193 */ SyscallDesc("unknown #193", unimplementedFunc), + /* 194 */ SyscallDesc("unknown #194", unimplementedFunc), + /* 195 */ SyscallDesc("unknown #195", unimplementedFunc), + /* 196 */ SyscallDesc("unknown #196", unimplementedFunc), + /* 197 */ SyscallDesc("unknown #197", unimplementedFunc), + /* 198 */ SyscallDesc("unknown #198", unimplementedFunc), + /* 199 */ SyscallDesc("osf_swapon", unimplementedFunc), + /* 200 */ SyscallDesc("msgctl", unimplementedFunc), + /* 201 */ SyscallDesc("msgget", unimplementedFunc), + /* 202 */ SyscallDesc("msgrcv", unimplementedFunc), + /* 203 */ SyscallDesc("msgsnd", unimplementedFunc), + /* 204 */ SyscallDesc("semctl", unimplementedFunc), + /* 205 */ SyscallDesc("semget", unimplementedFunc), + /* 206 */ SyscallDesc("semop", unimplementedFunc), + /* 207 */ SyscallDesc("osf_utsname", unimplementedFunc), + /* 208 */ SyscallDesc("lchown", unimplementedFunc), + /* 209 */ SyscallDesc("osf_shmat", unimplementedFunc), + /* 210 */ SyscallDesc("shmctl", unimplementedFunc), + /* 211 */ SyscallDesc("shmdt", unimplementedFunc), + /* 212 */ SyscallDesc("shmget", unimplementedFunc), + /* 213 */ SyscallDesc("osf_mvalid", unimplementedFunc), + /* 214 */ SyscallDesc("osf_getaddressconf", unimplementedFunc), + /* 215 */ SyscallDesc("osf_msleep", unimplementedFunc), + /* 216 */ SyscallDesc("osf_mwakeup", unimplementedFunc), + /* 217 */ SyscallDesc("msync", unimplementedFunc), + /* 218 */ SyscallDesc("osf_signal", unimplementedFunc), + /* 219 */ SyscallDesc("osf_utc_gettime", unimplementedFunc), + /* 220 */ SyscallDesc("osf_utc_adjtime", unimplementedFunc), + /* 221 */ SyscallDesc("unknown #221", unimplementedFunc), + /* 222 */ SyscallDesc("osf_security", unimplementedFunc), + /* 223 */ SyscallDesc("osf_kloadcall", unimplementedFunc), + /* 224 */ SyscallDesc("unknown #224", unimplementedFunc), + /* 225 */ SyscallDesc("unknown #225", unimplementedFunc), + /* 226 */ SyscallDesc("unknown #226", unimplementedFunc), + /* 227 */ SyscallDesc("unknown #227", unimplementedFunc), + /* 228 */ SyscallDesc("unknown #228", unimplementedFunc), + /* 229 */ SyscallDesc("unknown #229", unimplementedFunc), + /* 230 */ SyscallDesc("unknown #230", unimplementedFunc), + /* 231 */ SyscallDesc("unknown #231", unimplementedFunc), + /* 232 */ SyscallDesc("unknown #232", unimplementedFunc), + /* 233 */ SyscallDesc("getpgid", unimplementedFunc), + /* 234 */ SyscallDesc("getsid", unimplementedFunc), + /* 235 */ SyscallDesc("sigaltstack", ignoreFunc), + /* 236 */ SyscallDesc("osf_waitid", unimplementedFunc), + /* 237 */ SyscallDesc("osf_priocntlset", unimplementedFunc), + /* 238 */ SyscallDesc("osf_sigsendset", unimplementedFunc), + /* 239 */ SyscallDesc("osf_set_speculative", unimplementedFunc), + /* 240 */ SyscallDesc("osf_msfs_syscall", unimplementedFunc), + /* 241 */ SyscallDesc("osf_sysinfo", unimplementedFunc), + /* 242 */ SyscallDesc("osf_uadmin", unimplementedFunc), + /* 243 */ SyscallDesc("osf_fuser", unimplementedFunc), + /* 244 */ SyscallDesc("osf_proplist_syscall", unimplementedFunc), + /* 245 */ SyscallDesc("osf_ntp_adjtime", unimplementedFunc), + /* 246 */ SyscallDesc("osf_ntp_gettime", unimplementedFunc), + /* 247 */ SyscallDesc("osf_pathconf", unimplementedFunc), + /* 248 */ SyscallDesc("osf_fpathconf", unimplementedFunc), + /* 249 */ SyscallDesc("unknown #249", unimplementedFunc), + /* 250 */ SyscallDesc("osf_uswitch", unimplementedFunc), + /* 251 */ SyscallDesc("osf_usleep_thread", unimplementedFunc), + /* 252 */ SyscallDesc("osf_audcntl", unimplementedFunc), + /* 253 */ SyscallDesc("osf_audgen", unimplementedFunc), + /* 254 */ SyscallDesc("sysfs", unimplementedFunc), + /* 255 */ SyscallDesc("osf_subsys_info", unimplementedFunc), + /* 256 */ SyscallDesc("osf_getsysinfo", osf_getsysinfoFunc), + /* 257 */ SyscallDesc("osf_setsysinfo", osf_setsysinfoFunc), + /* 258 */ SyscallDesc("osf_afs_syscall", unimplementedFunc), + /* 259 */ SyscallDesc("osf_swapctl", unimplementedFunc), + /* 260 */ SyscallDesc("osf_memcntl", unimplementedFunc), + /* 261 */ SyscallDesc("osf_fdatasync", unimplementedFunc), + /* 262 */ SyscallDesc("unknown #262", unimplementedFunc), + /* 263 */ SyscallDesc("unknown #263", unimplementedFunc), + /* 264 */ SyscallDesc("unknown #264", unimplementedFunc), + /* 265 */ SyscallDesc("unknown #265", unimplementedFunc), + /* 266 */ SyscallDesc("unknown #266", unimplementedFunc), + /* 267 */ SyscallDesc("unknown #267", unimplementedFunc), + /* 268 */ SyscallDesc("unknown #268", unimplementedFunc), + /* 269 */ SyscallDesc("unknown #269", unimplementedFunc), + /* 270 */ SyscallDesc("unknown #270", unimplementedFunc), + /* 271 */ SyscallDesc("unknown #271", unimplementedFunc), + /* 272 */ SyscallDesc("unknown #272", unimplementedFunc), + /* 273 */ SyscallDesc("unknown #273", unimplementedFunc), + /* 274 */ SyscallDesc("unknown #274", unimplementedFunc), + /* 275 */ SyscallDesc("unknown #275", unimplementedFunc), + /* 276 */ SyscallDesc("unknown #276", unimplementedFunc), + /* 277 */ SyscallDesc("unknown #277", unimplementedFunc), + /* 278 */ SyscallDesc("unknown #278", unimplementedFunc), + /* 279 */ SyscallDesc("unknown #279", unimplementedFunc), + /* 280 */ SyscallDesc("unknown #280", unimplementedFunc), + /* 281 */ SyscallDesc("unknown #281", unimplementedFunc), + /* 282 */ SyscallDesc("unknown #282", unimplementedFunc), + /* 283 */ SyscallDesc("unknown #283", unimplementedFunc), + /* 284 */ SyscallDesc("unknown #284", unimplementedFunc), + /* 285 */ SyscallDesc("unknown #285", unimplementedFunc), + /* 286 */ SyscallDesc("unknown #286", unimplementedFunc), + /* 287 */ SyscallDesc("unknown #287", unimplementedFunc), + /* 288 */ SyscallDesc("unknown #288", unimplementedFunc), + /* 289 */ SyscallDesc("unknown #289", unimplementedFunc), + /* 290 */ SyscallDesc("unknown #290", unimplementedFunc), + /* 291 */ SyscallDesc("unknown #291", unimplementedFunc), + /* 292 */ SyscallDesc("unknown #292", unimplementedFunc), + /* 293 */ SyscallDesc("unknown #293", unimplementedFunc), + /* 294 */ SyscallDesc("unknown #294", unimplementedFunc), + /* 295 */ SyscallDesc("unknown #295", unimplementedFunc), + /* 296 */ SyscallDesc("unknown #296", unimplementedFunc), + /* 297 */ SyscallDesc("unknown #297", unimplementedFunc), + /* 298 */ SyscallDesc("unknown #298", unimplementedFunc), + /* 299 */ SyscallDesc("unknown #299", unimplementedFunc), +/* + * Linux-specific system calls begin at 300 + */ + /* 300 */ SyscallDesc("bdflush", unimplementedFunc), + /* 301 */ SyscallDesc("sethae", unimplementedFunc), + /* 302 */ SyscallDesc("mount", unimplementedFunc), + /* 303 */ SyscallDesc("old_adjtimex", unimplementedFunc), + /* 304 */ SyscallDesc("swapoff", unimplementedFunc), + /* 305 */ SyscallDesc("getdents", unimplementedFunc), + /* 306 */ SyscallDesc("create_module", unimplementedFunc), + /* 307 */ SyscallDesc("init_module", unimplementedFunc), + /* 308 */ SyscallDesc("delete_module", unimplementedFunc), + /* 309 */ SyscallDesc("get_kernel_syms", unimplementedFunc), + /* 310 */ SyscallDesc("syslog", unimplementedFunc), + /* 311 */ SyscallDesc("reboot", unimplementedFunc), + /* 312 */ SyscallDesc("clone", unimplementedFunc), + /* 313 */ SyscallDesc("uselib", unimplementedFunc), + /* 314 */ SyscallDesc("mlock", unimplementedFunc), + /* 315 */ SyscallDesc("munlock", unimplementedFunc), + /* 316 */ SyscallDesc("mlockall", unimplementedFunc), + /* 317 */ SyscallDesc("munlockall", unimplementedFunc), + /* 318 */ SyscallDesc("sysinfo", unimplementedFunc), + /* 319 */ SyscallDesc("_sysctl", unimplementedFunc), + /* 320 */ SyscallDesc("was sys_idle", unimplementedFunc), + /* 321 */ SyscallDesc("oldumount", unimplementedFunc), + /* 322 */ SyscallDesc("swapon", unimplementedFunc), + /* 323 */ SyscallDesc("times", ignoreFunc), + /* 324 */ SyscallDesc("personality", unimplementedFunc), + /* 325 */ SyscallDesc("setfsuid", unimplementedFunc), + /* 326 */ SyscallDesc("setfsgid", unimplementedFunc), + /* 327 */ SyscallDesc("ustat", unimplementedFunc), + /* 328 */ SyscallDesc("statfs", unimplementedFunc), + /* 329 */ SyscallDesc("fstatfs", unimplementedFunc), + /* 330 */ SyscallDesc("sched_setparam", unimplementedFunc), + /* 331 */ SyscallDesc("sched_getparam", unimplementedFunc), + /* 332 */ SyscallDesc("sched_setscheduler", unimplementedFunc), + /* 333 */ SyscallDesc("sched_getscheduler", unimplementedFunc), + /* 334 */ SyscallDesc("sched_yield", unimplementedFunc), + /* 335 */ SyscallDesc("sched_get_priority_max", unimplementedFunc), + /* 336 */ SyscallDesc("sched_get_priority_min", unimplementedFunc), + /* 337 */ SyscallDesc("sched_rr_get_interval", unimplementedFunc), + /* 338 */ SyscallDesc("afs_syscall", unimplementedFunc), + /* 339 */ SyscallDesc("uname", unameFunc), + /* 340 */ SyscallDesc("nanosleep", unimplementedFunc), + /* 341 */ SyscallDesc("mremap", unimplementedFunc), + /* 342 */ SyscallDesc("nfsservctl", unimplementedFunc), + /* 343 */ SyscallDesc("setresuid", unimplementedFunc), + /* 344 */ SyscallDesc("getresuid", unimplementedFunc), + /* 345 */ SyscallDesc("pciconfig_read", unimplementedFunc), + /* 346 */ SyscallDesc("pciconfig_write", unimplementedFunc), + /* 347 */ SyscallDesc("query_module", unimplementedFunc), + /* 348 */ SyscallDesc("prctl", unimplementedFunc), + /* 349 */ SyscallDesc("pread", unimplementedFunc), + /* 350 */ SyscallDesc("pwrite", unimplementedFunc), + /* 351 */ SyscallDesc("rt_sigreturn", unimplementedFunc), + /* 352 */ SyscallDesc("rt_sigaction", ignoreFunc), + /* 353 */ SyscallDesc("rt_sigprocmask", unimplementedFunc), + /* 354 */ SyscallDesc("rt_sigpending", unimplementedFunc), + /* 355 */ SyscallDesc("rt_sigtimedwait", unimplementedFunc), + /* 356 */ SyscallDesc("rt_sigqueueinfo", unimplementedFunc), + /* 357 */ SyscallDesc("rt_sigsuspend", unimplementedFunc), + /* 358 */ SyscallDesc("select", unimplementedFunc), + /* 359 */ SyscallDesc("gettimeofday", gettimeofdayFunc<AlphaLinux>), + /* 360 */ SyscallDesc("settimeofday", unimplementedFunc), + /* 361 */ SyscallDesc("getitimer", unimplementedFunc), + /* 362 */ SyscallDesc("setitimer", unimplementedFunc), + /* 363 */ SyscallDesc("utimes", utimesFunc<AlphaLinux>), + /* 364 */ SyscallDesc("getrusage", getrusageFunc<AlphaLinux>), + /* 365 */ SyscallDesc("wait4", unimplementedFunc), + /* 366 */ SyscallDesc("adjtimex", unimplementedFunc), + /* 367 */ SyscallDesc("getcwd", unimplementedFunc), + /* 368 */ SyscallDesc("capget", unimplementedFunc), + /* 369 */ SyscallDesc("capset", unimplementedFunc), + /* 370 */ SyscallDesc("sendfile", unimplementedFunc), + /* 371 */ SyscallDesc("setresgid", unimplementedFunc), + /* 372 */ SyscallDesc("getresgid", unimplementedFunc), + /* 373 */ SyscallDesc("dipc", unimplementedFunc), + /* 374 */ SyscallDesc("pivot_root", unimplementedFunc), + /* 375 */ SyscallDesc("mincore", unimplementedFunc), + /* 376 */ SyscallDesc("pciconfig_iobase", unimplementedFunc), + /* 377 */ SyscallDesc("getdents64", unimplementedFunc), + /* 378 */ SyscallDesc("gettid", unimplementedFunc), + /* 379 */ SyscallDesc("readahead", unimplementedFunc), + /* 380 */ SyscallDesc("security", unimplementedFunc), + /* 381 */ SyscallDesc("tkill", unimplementedFunc), + /* 382 */ SyscallDesc("setxattr", unimplementedFunc), + /* 383 */ SyscallDesc("lsetxattr", unimplementedFunc), + /* 384 */ SyscallDesc("fsetxattr", unimplementedFunc), + /* 385 */ SyscallDesc("getxattr", unimplementedFunc), + /* 386 */ SyscallDesc("lgetxattr", unimplementedFunc), + /* 387 */ SyscallDesc("fgetxattr", unimplementedFunc), + /* 388 */ SyscallDesc("listxattr", unimplementedFunc), + /* 389 */ SyscallDesc("llistxattr", unimplementedFunc), + /* 390 */ SyscallDesc("flistxattr", unimplementedFunc), + /* 391 */ SyscallDesc("removexattr", unimplementedFunc), + /* 392 */ SyscallDesc("lremovexattr", unimplementedFunc), + /* 393 */ SyscallDesc("fremovexattr", unimplementedFunc), + /* 394 */ SyscallDesc("futex", unimplementedFunc), + /* 395 */ SyscallDesc("sched_setaffinity", unimplementedFunc), + /* 396 */ SyscallDesc("sched_getaffinity", unimplementedFunc), + /* 397 */ SyscallDesc("tuxcall", unimplementedFunc), + /* 398 */ SyscallDesc("io_setup", unimplementedFunc), + /* 399 */ SyscallDesc("io_destroy", unimplementedFunc), + /* 400 */ SyscallDesc("io_getevents", unimplementedFunc), + /* 401 */ SyscallDesc("io_submit", unimplementedFunc), + /* 402 */ SyscallDesc("io_cancel", unimplementedFunc), + /* 403 */ SyscallDesc("unknown #403", unimplementedFunc), + /* 404 */ SyscallDesc("unknown #404", unimplementedFunc), + /* 405 */ SyscallDesc("exit_group", exitFunc), // exit all threads... + /* 406 */ SyscallDesc("lookup_dcookie", unimplementedFunc), + /* 407 */ SyscallDesc("sys_epoll_create", unimplementedFunc), + /* 408 */ SyscallDesc("sys_epoll_ctl", unimplementedFunc), + /* 409 */ SyscallDesc("sys_epoll_wait", unimplementedFunc), + /* 410 */ SyscallDesc("remap_file_pages", unimplementedFunc), + /* 411 */ SyscallDesc("set_tid_address", unimplementedFunc), + /* 412 */ SyscallDesc("restart_syscall", unimplementedFunc), + /* 413 */ SyscallDesc("fadvise64", unimplementedFunc), + /* 414 */ SyscallDesc("timer_create", unimplementedFunc), + /* 415 */ SyscallDesc("timer_settime", unimplementedFunc), + /* 416 */ SyscallDesc("timer_gettime", unimplementedFunc), + /* 417 */ SyscallDesc("timer_getoverrun", unimplementedFunc), + /* 418 */ SyscallDesc("timer_delete", unimplementedFunc), + /* 419 */ SyscallDesc("clock_settime", unimplementedFunc), + /* 420 */ SyscallDesc("clock_gettime", unimplementedFunc), + /* 421 */ SyscallDesc("clock_getres", unimplementedFunc), + /* 422 */ SyscallDesc("clock_nanosleep", unimplementedFunc), + /* 423 */ SyscallDesc("semtimedop", unimplementedFunc), + /* 424 */ SyscallDesc("tgkill", unimplementedFunc), + /* 425 */ SyscallDesc("stat64", unimplementedFunc), + /* 426 */ SyscallDesc("lstat64", lstat64Func<AlphaLinux>), + /* 427 */ SyscallDesc("fstat64", fstat64Func<AlphaLinux>), + /* 428 */ SyscallDesc("vserver", unimplementedFunc), + /* 429 */ SyscallDesc("mbind", unimplementedFunc), + /* 430 */ SyscallDesc("get_mempolicy", unimplementedFunc), + /* 431 */ SyscallDesc("set_mempolicy", unimplementedFunc), + /* 432 */ SyscallDesc("mq_open", unimplementedFunc), + /* 433 */ SyscallDesc("mq_unlink", unimplementedFunc), + /* 434 */ SyscallDesc("mq_timedsend", unimplementedFunc), + /* 435 */ SyscallDesc("mq_timedreceive", unimplementedFunc), + /* 436 */ SyscallDesc("mq_notify", unimplementedFunc), + /* 437 */ SyscallDesc("mq_getsetattr", unimplementedFunc), + /* 438 */ SyscallDesc("waitid", unimplementedFunc), + /* 439 */ SyscallDesc("add_key", unimplementedFunc), + /* 440 */ SyscallDesc("request_key", unimplementedFunc), + /* 441 */ SyscallDesc("keyctl", unimplementedFunc) +}; + +AlphaLinuxProcess::AlphaLinuxProcess(const std::string &name, + ObjectFile *objFile, + System *system, + int stdin_fd, + int stdout_fd, + int stderr_fd, + std::vector<std::string> &argv, + std::vector<std::string> &envp) + : AlphaLiveProcess(name, objFile, system, stdin_fd, stdout_fd, + stderr_fd, argv, envp), + Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc)) +{ + //init_regs->intRegFile[0] = 0; +} + + + +SyscallDesc* +AlphaLinuxProcess::getDesc(int callnum) +{ + if (callnum < 0 || callnum > Num_Syscall_Descs) + return NULL; + return &syscallDescs[callnum]; +} diff --git a/src/arch/alpha/linux/process.hh b/src/arch/alpha/linux/process.hh new file mode 100644 index 000000000..9cc7dc7b6 --- /dev/null +++ b/src/arch/alpha/linux/process.hh @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2003-2004 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 + */ + +#ifndef __ALPHA_LINUX_PROCESS_HH__ +#define __ALPHA_LINUX_PROCESS_HH__ + +#include "arch/alpha/process.hh" + +namespace AlphaISA { + +/// A process with emulated Alpha/Linux syscalls. +class AlphaLinuxProcess : public AlphaLiveProcess +{ + public: + /// Constructor. + AlphaLinuxProcess(const std::string &name, + ObjectFile *objFile, + System *system, + int stdin_fd, int stdout_fd, int stderr_fd, + std::vector<std::string> &argv, + std::vector<std::string> &envp); + + virtual SyscallDesc* getDesc(int callnum); + + /// The target system's hostname. + static const char *hostname; + + /// Array of syscall descriptors, indexed by call number. + static SyscallDesc syscallDescs[]; + + const int Num_Syscall_Descs; +}; + +} // namespace AlphaISA +#endif // __ALPHA_LINUX_PROCESS_HH__ diff --git a/src/arch/alpha/linux/system.cc b/src/arch/alpha/linux/system.cc new file mode 100644 index 000000000..bb35f046d --- /dev/null +++ b/src/arch/alpha/linux/system.cc @@ -0,0 +1,245 @@ +/* + * 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: Ali Saidi + * Lisa Hsu + * Nathan Binkert + * Steve Reinhardt + */ + +/** + * @file + * This code loads the linux kernel, console, pal and patches certain + * functions. The symbol tables are loaded so that traces can show + * the executing function and we can skip functions. Various delay + * loops are skipped and their final values manually computed to speed + * up boot time. + */ + +#include "arch/arguments.hh" +#include "arch/vtophys.hh" +#include "arch/alpha/linux/system.hh" +#include "arch/alpha/linux/threadinfo.hh" +#include "arch/alpha/system.hh" +#include "base/loader/symtab.hh" +#include "cpu/thread_context.hh" +#include "cpu/base.hh" +#include "dev/platform.hh" +#include "kern/linux/printk.hh" +#include "kern/linux/events.hh" +#include "mem/physical.hh" +#include "mem/port.hh" +#include "sim/builder.hh" +#include "sim/byteswap.hh" + +using namespace std; +using namespace AlphaISA; +using namespace Linux; + +LinuxAlphaSystem::LinuxAlphaSystem(Params *p) + : AlphaSystem(p) +{ + Addr addr = 0; + + /** + * The symbol swapper_pg_dir marks the beginning of the kernel and + * the location of bootloader passed arguments + */ + if (!kernelSymtab->findAddress("swapper_pg_dir", KernelStart)) { + panic("Could not determine start location of kernel"); + } + + /** + * Since we aren't using a bootloader, we have to copy the + * kernel arguments directly into the kernel's memory. + */ + virtPort.writeBlob(CommandLine(), (uint8_t*)params()->boot_osflags.c_str(), + params()->boot_osflags.length()+1); + + /** + * find the address of the est_cycle_freq variable and insert it + * so we don't through the lengthly process of trying to + * calculated it by using the PIT, RTC, etc. + */ + if (kernelSymtab->findAddress("est_cycle_freq", addr)) + virtPort.write(addr, (uint64_t)(Clock::Frequency / + p->boot_cpu_frequency)); + + + /** + * EV5 only supports 127 ASNs so we are going to tell the kernel that the + * paritiuclar EV6 we have only supports 127 asns. + * @todo At some point we should change ev5.hh and the palcode to support + * 255 ASNs. + */ + if (kernelSymtab->findAddress("dp264_mv", addr)) + virtPort.write(addr + 0x18, LittleEndianGuest::htog((uint32_t)127)); + else + panic("could not find dp264_mv\n"); + +#ifndef NDEBUG + kernelPanicEvent = addKernelFuncEvent<BreakPCEvent>("panic"); + if (!kernelPanicEvent) + panic("could not find kernel symbol \'panic\'"); + +#if 0 + kernelDieEvent = addKernelFuncEvent<BreakPCEvent>("die_if_kernel"); + if (!kernelDieEvent) + panic("could not find kernel symbol \'die_if_kernel\'"); +#endif + +#endif + + /** + * Any time ide_delay_50ms, calibarte_delay or + * determine_cpu_caches is called just skip the + * function. Currently determine_cpu_caches only is used put + * information in proc, however if that changes in the future we + * will have to fill in the cache size variables appropriately. + */ + + skipIdeDelay50msEvent = + addKernelFuncEvent<SkipFuncEvent>("ide_delay_50ms"); + skipDelayLoopEvent = + addKernelFuncEvent<SkipDelayLoopEvent>("calibrate_delay"); + skipCacheProbeEvent = + addKernelFuncEvent<SkipFuncEvent>("determine_cpu_caches"); + debugPrintkEvent = addKernelFuncEvent<DebugPrintkEvent>("dprintk"); + idleStartEvent = addKernelFuncEvent<IdleStartEvent>("cpu_idle"); + + if (kernelSymtab->findAddress("alpha_switch_to", addr) && DTRACE(Thread)) { + printThreadEvent = new PrintThreadInfo(&pcEventQueue, "threadinfo", + addr + sizeof(MachInst) * 6); + } else { + printThreadEvent = NULL; + } +} + +LinuxAlphaSystem::~LinuxAlphaSystem() +{ +#ifndef NDEBUG + delete kernelPanicEvent; +#endif + delete skipIdeDelay50msEvent; + delete skipDelayLoopEvent; + delete skipCacheProbeEvent; + delete debugPrintkEvent; + delete idleStartEvent; + delete printThreadEvent; + delete intStartEvent; + delete intEndEvent; + delete intEndEvent2; +} + + +void +LinuxAlphaSystem::setDelayLoop(ThreadContext *tc) +{ + Addr addr = 0; + if (kernelSymtab->findAddress("loops_per_jiffy", addr)) { + Tick cpuFreq = tc->getCpuPtr()->frequency(); + Tick intrFreq = platform->intrFrequency(); + VirtualPort *vp; + + vp = tc->getVirtPort(); + vp->writeHtoG(addr, (uint32_t)((cpuFreq / intrFreq) * 0.9988)); + tc->delVirtPort(vp); + } +} + + +void +LinuxAlphaSystem::SkipDelayLoopEvent::process(ThreadContext *tc) +{ + SkipFuncEvent::process(tc); + // calculate and set loops_per_jiffy + ((LinuxAlphaSystem *)tc->getSystemPtr())->setDelayLoop(tc); +} + +void +LinuxAlphaSystem::PrintThreadInfo::process(ThreadContext *tc) +{ + Linux::ThreadInfo ti(tc); + + DPRINTF(Thread, "Currently Executing Thread %s, pid %d, started at: %d\n", + ti.curTaskName(), ti.curTaskPID(), ti.curTaskStart()); +} + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(LinuxAlphaSystem) + + Param<Tick> boot_cpu_frequency; + SimObjectParam<PhysicalMemory *> physmem; + + Param<string> kernel; + Param<string> console; + Param<string> pal; + + Param<string> boot_osflags; + Param<string> readfile; + Param<unsigned int> init_param; + + Param<uint64_t> system_type; + Param<uint64_t> system_rev; + +END_DECLARE_SIM_OBJECT_PARAMS(LinuxAlphaSystem) + +BEGIN_INIT_SIM_OBJECT_PARAMS(LinuxAlphaSystem) + + INIT_PARAM(boot_cpu_frequency, "Frequency of the boot CPU"), + INIT_PARAM(physmem, "phsyical memory"), + INIT_PARAM(kernel, "file that contains the kernel code"), + INIT_PARAM(console, "file that contains the console code"), + INIT_PARAM(pal, "file that contains palcode"), + INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot", + "a"), + INIT_PARAM_DFLT(readfile, "file to read startup script from", ""), + INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0), + INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 34), + INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10) + +END_INIT_SIM_OBJECT_PARAMS(LinuxAlphaSystem) + +CREATE_SIM_OBJECT(LinuxAlphaSystem) +{ + AlphaSystem::Params *p = new AlphaSystem::Params; + p->name = getInstanceName(); + p->boot_cpu_frequency = boot_cpu_frequency; + p->physmem = physmem; + p->kernel_path = kernel; + p->console_path = console; + p->palcode = pal; + p->boot_osflags = boot_osflags; + p->init_param = init_param; + p->readfile = readfile; + p->system_type = system_type; + p->system_rev = system_rev; + return new LinuxAlphaSystem(p); +} + +REGISTER_SIM_OBJECT("LinuxAlphaSystem", LinuxAlphaSystem) + diff --git a/src/arch/alpha/linux/system.hh b/src/arch/alpha/linux/system.hh new file mode 100644 index 000000000..6921ba820 --- /dev/null +++ b/src/arch/alpha/linux/system.hh @@ -0,0 +1,137 @@ +/* + * 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: Ali Saidi + * Lisa Hsu + * Nathan Binkert + */ + +#ifndef __ARCH_ALPHA_LINUX_SYSTEM_HH__ +#define __ARCH_ALPHA_LINUX_SYSTEM_HH__ + +class ThreadContext; + +class BreakPCEvent; +class IdleStartEvent; + +#include "arch/alpha/system.hh" +#include "kern/linux/events.hh" + +using namespace AlphaISA; +using namespace Linux; + +/** + * This class contains linux specific system code (Loading, Events). + * It points to objects that are the system binaries to load and patches them + * appropriately to work in simulator. + */ +class LinuxAlphaSystem : public AlphaSystem +{ + private: + class SkipDelayLoopEvent : public SkipFuncEvent + { + public: + SkipDelayLoopEvent(PCEventQueue *q, const std::string &desc, Addr addr) + : SkipFuncEvent(q, desc, addr) {} + virtual void process(ThreadContext *tc); + }; + + class PrintThreadInfo : public PCEvent + { + public: + PrintThreadInfo(PCEventQueue *q, const std::string &desc, Addr addr) + : PCEvent(q, desc, addr) {} + virtual void process(ThreadContext *tc); + }; + + + /** + * Addresses defining where the kernel bootloader places various + * elements. Details found in include/asm-alpha/system.h + */ + Addr KernelStart; // Lookup the symbol swapper_pg_dir + + public: + Addr InitStack() const { return KernelStart + 0x02000; } + Addr EmptyPGT() const { return KernelStart + 0x04000; } + Addr EmptyPGE() const { return KernelStart + 0x08000; } + Addr ZeroPGE() const { return KernelStart + 0x0A000; } + Addr StartAddr() const { return KernelStart + 0x10000; } + + Addr Param() const { return ZeroPGE() + 0x0; } + Addr CommandLine() const { return Param() + 0x0; } + Addr InitrdStart() const { return Param() + 0x100; } + Addr InitrdSize() const { return Param() + 0x108; } + static const int CommandLineSize = 256; + + private: +#ifndef NDEBUG + /** Event to halt the simulator if the kernel calls panic() */ + BreakPCEvent *kernelPanicEvent; + + /** Event to halt the simulator if the kernel calls die_if_kernel */ + BreakPCEvent *kernelDieEvent; +#endif + + /** + * Event to skip determine_cpu_caches() because we don't support + * the IPRs that the code can access to figure out cache sizes + */ + SkipFuncEvent *skipCacheProbeEvent; + + /** PC based event to skip the ide_delay_50ms() call */ + SkipFuncEvent *skipIdeDelay50msEvent; + + /** + * PC based event to skip the dprink() call and emulate its + * functionality + */ + DebugPrintkEvent *debugPrintkEvent; + + /** + * Skip calculate_delay_loop() rather than waiting for this to be + * calculated + */ + SkipDelayLoopEvent *skipDelayLoopEvent; + + /** + * Event to print information about thread switches if the trace flag + * Thread is set + */ + PrintThreadInfo *printThreadEvent; + + /** Grab the PCBB of the idle process when it starts */ + IdleStartEvent *idleStartEvent; + + public: + LinuxAlphaSystem(Params *p); + ~LinuxAlphaSystem(); + + void setDelayLoop(ThreadContext *tc); +}; + +#endif // __ARCH_ALPHA_LINUX_SYSTEM_HH__ diff --git a/src/arch/alpha/linux/thread_info.hh b/src/arch/alpha/linux/thread_info.hh new file mode 100644 index 000000000..78257da56 --- /dev/null +++ b/src/arch/alpha/linux/thread_info.hh @@ -0,0 +1,44 @@ +/* + * Copyright (c) 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: Ali Saidi + * Nathan Binkert + */ + +#ifndef __ARCH_ALPHA_LINUX_THREAD_INFO_H__ +#define __ARCH_ALPHA_LINUX_THREAD_INFO_H__ + +#include "arch/alpha/linux/hwrpb.hh" + +namespace Linux { + struct thread_info { + struct pcb_struct pcb; + Addr_a task; + }; +} + +#endif // __ARCH_ALPHA_LINUX_THREAD_INFO_H__ diff --git a/src/arch/alpha/linux/threadinfo.hh b/src/arch/alpha/linux/threadinfo.hh new file mode 100644 index 000000000..caeb69f15 --- /dev/null +++ b/src/arch/alpha/linux/threadinfo.hh @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2004 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 + * Nathan Binkert + */ + +#ifndef __ARCH_ALPHA_LINUX_LINUX_TREADNIFO_HH__ +#define __ARCH_ALPHA_LINUX_LINUX_TREADNIFO_HH__ + +#include "arch/alpha/linux/thread_info.hh" +#include "cpu/thread_context.hh" +#include "kern/linux/sched.hh" +#include "sim/vptr.hh" + +namespace Linux { + +class ThreadInfo +{ + private: + ThreadContext *tc; + + public: + ThreadInfo(ThreadContext *_tc) : tc(_tc) {} + ~ThreadInfo() {} + + inline VPtr<thread_info> + curThreadInfo() + { + Addr current; + + /* Each kernel stack is only 2 pages, the start of which is the + * thread_info struct. So we can get the address by masking off + * the lower 14 bits. + */ + current = tc->readIntReg(TheISA::StackPointerReg) & ~0x3fff; + return VPtr<thread_info>(tc, current); + } + + inline VPtr<task_struct> + curTaskInfo() + { + Addr task = curThreadInfo()->task; + return VPtr<task_struct>(tc, task); + } + + std::string + curTaskName() + { + return curTaskInfo()->name; + } + + int32_t + curTaskPID() + { + return curTaskInfo()->pid; + } + + uint64_t + curTaskStart() + { + return curTaskInfo()->start; + } +}; + +/* namespace Linux */ } + +#endif // __ARCH_ALPHA_LINUX_LINUX_THREADINFO_HH__ diff --git a/src/arch/alpha/osfpal.cc b/src/arch/alpha/osfpal.cc new file mode 100644 index 000000000..ed1d255a6 --- /dev/null +++ b/src/arch/alpha/osfpal.cc @@ -0,0 +1,306 @@ +/* + * Copyright (c) 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: Nathan Binkert + */ + +#include "arch/alpha/osfpal.hh" + +namespace { + const char *strings[PAL::NumCodes] = { + // Priviledged PAL instructions + "halt", // 0x00 + "cflush", // 0x01 + "draina", // 0x02 + 0, // 0x03 + 0, // 0x04 + 0, // 0x05 + 0, // 0x06 + 0, // 0x07 + 0, // 0x08 + "cserve", // 0x09 + "swppal", // 0x0a + 0, // 0x0b + 0, // 0x0c + "wripir", // 0x0d + 0, // 0x0e + 0, // 0x0f + "rdmces", // 0x10 + "wrmces", // 0x11 + 0, // 0x12 + 0, // 0x13 + 0, // 0x14 + 0, // 0x15 + 0, // 0x16 + 0, // 0x17 + 0, // 0x18 + 0, // 0x19 + 0, // 0x1a + 0, // 0x1b + 0, // 0x1c + 0, // 0x1d + 0, // 0x1e + 0, // 0x1f + 0, // 0x20 + 0, // 0x21 + 0, // 0x22 + 0, // 0x23 + 0, // 0x24 + 0, // 0x25 + 0, // 0x26 + 0, // 0x27 + 0, // 0x28 + 0, // 0x29 + 0, // 0x2a + "wrfen", // 0x2b + 0, // 0x2c + "wrvptptr", // 0x2d + 0, // 0x2e + 0, // 0x2f + "swpctx", // 0x30 + "wrval", // 0x31 + "rdval", // 0x32 + "tbi", // 0x33 + "wrent", // 0x34 + "swpipl", // 0x35 + "rdps", // 0x36 + "wrkgp", // 0x37 + "wrusp", // 0x38 + "wrperfmon", // 0x39 + "rdusp", // 0x3a + 0, // 0x3b + "whami", // 0x3c + "retsys", // 0x3d + "wtint", // 0x3e + "rti", // 0x3f + 0, // 0x40 + 0, // 0x41 + 0, // 0x42 + 0, // 0x43 + 0, // 0x44 + 0, // 0x45 + 0, // 0x46 + 0, // 0x47 + 0, // 0x48 + 0, // 0x49 + 0, // 0x4a + 0, // 0x4b + 0, // 0x4c + 0, // 0x4d + 0, // 0x4e + 0, // 0x4f + 0, // 0x50 + 0, // 0x51 + 0, // 0x52 + 0, // 0x53 + 0, // 0x54 + 0, // 0x55 + 0, // 0x56 + 0, // 0x57 + 0, // 0x58 + 0, // 0x59 + 0, // 0x5a + 0, // 0x5b + 0, // 0x5c + 0, // 0x5d + 0, // 0x5e + 0, // 0x5f + 0, // 0x60 + 0, // 0x61 + 0, // 0x62 + 0, // 0x63 + 0, // 0x64 + 0, // 0x65 + 0, // 0x66 + 0, // 0x67 + 0, // 0x68 + 0, // 0x69 + 0, // 0x6a + 0, // 0x6b + 0, // 0x6c + 0, // 0x6d + 0, // 0x6e + 0, // 0x6f + 0, // 0x70 + 0, // 0x71 + 0, // 0x72 + 0, // 0x73 + 0, // 0x74 + 0, // 0x75 + 0, // 0x76 + 0, // 0x77 + 0, // 0x78 + 0, // 0x79 + 0, // 0x7a + 0, // 0x7b + 0, // 0x7c + 0, // 0x7d + 0, // 0x7e + 0, // 0x7f + + // Unpriviledged PAL instructions + "bpt", // 0x80 + "bugchk", // 0x81 + 0, // 0x82 + "callsys", // 0x83 + 0, // 0x84 + 0, // 0x85 + "imb", // 0x86 + 0, // 0x87 + 0, // 0x88 + 0, // 0x89 + 0, // 0x8a + 0, // 0x8b + 0, // 0x8c + 0, // 0x8d + 0, // 0x8e + 0, // 0x8f + 0, // 0x90 + 0, // 0x91 + "urti", // 0x92 + 0, // 0x93 + 0, // 0x94 + 0, // 0x95 + 0, // 0x96 + 0, // 0x97 + 0, // 0x98 + 0, // 0x99 + 0, // 0x9a + 0, // 0x9b + 0, // 0x9c + 0, // 0x9d + "rdunique", // 0x9e + "wrunique", // 0x9f + 0, // 0xa0 + 0, // 0xa1 + 0, // 0xa2 + 0, // 0xa3 + 0, // 0xa4 + 0, // 0xa5 + 0, // 0xa6 + 0, // 0xa7 + 0, // 0xa8 + 0, // 0xa9 + "gentrap", // 0xaa + 0, // 0xab + 0, // 0xac + 0, // 0xad + "clrfen", // 0xae + 0, // 0xaf + 0, // 0xb0 + 0, // 0xb1 + 0, // 0xb2 + 0, // 0xb3 + 0, // 0xb4 + 0, // 0xb5 + 0, // 0xb6 + 0, // 0xb7 + 0, // 0xb8 + 0, // 0xb9 + 0, // 0xba + 0, // 0xbb + 0, // 0xbc + 0, // 0xbd + "nphalt", // 0xbe + "copypal", // 0xbf +#if 0 + 0, // 0xc0 + 0, // 0xc1 + 0, // 0xc2 + 0, // 0xc3 + 0, // 0xc4 + 0, // 0xc5 + 0, // 0xc6 + 0, // 0xc7 + 0, // 0xc8 + 0, // 0xc9 + 0, // 0xca + 0, // 0xcb + 0, // 0xcc + 0, // 0xcd + 0, // 0xce + 0, // 0xcf + 0, // 0xd0 + 0, // 0xd1 + 0, // 0xd2 + 0, // 0xd3 + 0, // 0xd4 + 0, // 0xd5 + 0, // 0xd6 + 0, // 0xd7 + 0, // 0xd8 + 0, // 0xd9 + 0, // 0xda + 0, // 0xdb + 0, // 0xdc + 0, // 0xdd + 0, // 0xde + 0, // 0xdf + 0, // 0xe0 + 0, // 0xe1 + 0, // 0xe2 + 0, // 0xe3 + 0, // 0xe4 + 0, // 0xe5 + 0, // 0xe6 + 0, // 0xe7 + 0, // 0xe8 + 0, // 0xe9 + 0, // 0xea + 0, // 0xeb + 0, // 0xec + 0, // 0xed + 0, // 0xee + 0, // 0xef + 0, // 0xf0 + 0, // 0xf1 + 0, // 0xf2 + 0, // 0xf3 + 0, // 0xf4 + 0, // 0xf5 + 0, // 0xf6 + 0, // 0xf7 + 0, // 0xf8 + 0, // 0xf9 + 0, // 0xfa + 0, // 0xfb + 0, // 0xfc + 0, // 0xfd + 0, // 0xfe + 0 // 0xff +#endif + }; +} + +const char * +PAL::name(int index) +{ + if (index > NumCodes || index < 0) + return 0; + + return strings[index]; +} diff --git a/src/arch/alpha/osfpal.hh b/src/arch/alpha/osfpal.hh new file mode 100644 index 000000000..cf3940b85 --- /dev/null +++ b/src/arch/alpha/osfpal.hh @@ -0,0 +1,82 @@ +/* + * Copyright (c) 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: Nathan Binkert + */ + +#ifndef __OSFPAL_HH__ +#define __OSFPAL_HH__ + +struct PAL +{ + enum { + // Privileged PAL functions + halt = 0x00, + cflush = 0x01, + draina = 0x02, + cserve = 0x09, + swppal = 0x0a, + wripir = 0x0d, + rdmces = 0x10, + wrmces = 0x11, + wrfen = 0x2b, + wrvptptr = 0x2d, + swpctx = 0x30, + wrval = 0x31, + rdval = 0x32, + tbi = 0x33, + wrent = 0x34, + swpipl = 0x35, + rdps = 0x36, + wrkgp = 0x37, + wrusp = 0x38, + wrperfmon = 0x39, + rdusp = 0x3a, + whami = 0x3c, + retsys = 0x3d, + wtint = 0x3e, + rti = 0x3f, + + // unprivileged pal functions + bpt = 0x80, + bugchk = 0x81, + callsys = 0x83, + imb = 0x86, + urti = 0x92, + rdunique = 0x9e, + wrunique = 0x9f, + gentrap = 0xaa, + clrfen = 0xae, + nphalt = 0xbe, + copypal = 0xbf, + NumCodes + }; + + static const char *name(int index); +}; + +#endif // __OSFPAL_HH__ diff --git a/src/arch/alpha/process.cc b/src/arch/alpha/process.cc new file mode 100644 index 000000000..4c0c68761 --- /dev/null +++ b/src/arch/alpha/process.cc @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2003-2004 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 + * Ali Saidi + */ + +#include "arch/alpha/constants.hh" +#include "arch/alpha/process.hh" +#include "arch/alpha/linux/process.hh" +#include "arch/alpha/tru64/process.hh" +#include "base/loader/object_file.hh" +#include "base/misc.hh" +#include "cpu/thread_context.hh" +#include "sim/builder.hh" +#include "sim/system.hh" + + +using namespace AlphaISA; +using namespace std; + +AlphaLiveProcess * +AlphaLiveProcess::create(const std::string &nm, System *system, int stdin_fd, + int stdout_fd, int stderr_fd, std::string executable, + std::vector<std::string> &argv, std::vector<std::string> &envp) +{ + AlphaLiveProcess *process = NULL; + + ObjectFile *objFile = createObjectFile(executable); + if (objFile == NULL) { + fatal("Can't load object file %s", executable); + } + + + if (objFile->getArch() != ObjectFile::Alpha) + fatal("Object file does not match architecture."); + switch (objFile->getOpSys()) { + case ObjectFile::Tru64: + process = new AlphaTru64Process(nm, objFile, system, + stdin_fd, stdout_fd, stderr_fd, + argv, envp); + break; + + case ObjectFile::Linux: + process = new AlphaLinuxProcess(nm, objFile, system, + stdin_fd, stdout_fd, stderr_fd, + argv, envp); + break; + + default: + fatal("Unknown/unsupported operating system."); + } + + if (process == NULL) + fatal("Unknown error creating process object."); + return process; +} + +AlphaLiveProcess::AlphaLiveProcess(const std::string &nm, ObjectFile *objFile, + System *_system, int stdin_fd, int stdout_fd, int stderr_fd, + std::vector<std::string> &argv, std::vector<std::string> &envp) + : LiveProcess(nm, objFile, _system, stdin_fd, stdout_fd, stderr_fd, + argv, envp) +{ + brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize(); + brk_point = roundUp(brk_point, VMPageSize); + + // Set up stack. On Alpha, stack goes below text section. This + // code should get moved to some architecture-specific spot. + stack_base = objFile->textBase() - (409600+4096); + + // Set up region for mmaps. Tru64 seems to start just above 0 and + // grow up from there. + mmap_start = mmap_end = 0x10000; + + // Set pointer for next thread stack. Reserve 8M for main stack. + next_thread_stack_base = stack_base - (8 * 1024 * 1024); + +} + +void +AlphaLiveProcess::startup() +{ + argsInit(MachineBytes, VMPageSize); + + threadContexts[0]->setIntReg(GlobalPointerReg, objFile->globalPointer()); +} + + + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaLiveProcess) + + VectorParam<string> cmd; + Param<string> executable; + Param<string> input; + Param<string> output; + VectorParam<string> env; + SimObjectParam<System *> system; + +END_DECLARE_SIM_OBJECT_PARAMS(AlphaLiveProcess) + + +BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaLiveProcess) + + INIT_PARAM(cmd, "command line (executable plus arguments)"), + INIT_PARAM(executable, "executable (overrides cmd[0] if set)"), + INIT_PARAM(input, "filename for stdin (dflt: use sim stdin)"), + INIT_PARAM(output, "filename for stdout/stderr (dflt: use sim stdout)"), + INIT_PARAM(env, "environment settings"), + INIT_PARAM(system, "system") + +END_INIT_SIM_OBJECT_PARAMS(AlphaLiveProcess) + + +CREATE_SIM_OBJECT(AlphaLiveProcess) +{ + string in = input; + string out = output; + + // initialize file descriptors to default: same as simulator + int stdin_fd, stdout_fd, stderr_fd; + + if (in == "stdin" || in == "cin") + stdin_fd = STDIN_FILENO; + else + stdin_fd = Process::openInputFile(input); + + if (out == "stdout" || out == "cout") + stdout_fd = STDOUT_FILENO; + else if (out == "stderr" || out == "cerr") + stdout_fd = STDERR_FILENO; + else + stdout_fd = Process::openOutputFile(out); + + stderr_fd = (stdout_fd != STDOUT_FILENO) ? stdout_fd : STDERR_FILENO; + + return AlphaLiveProcess::create(getInstanceName(), system, + stdin_fd, stdout_fd, stderr_fd, + (string)executable == "" ? cmd[0] : executable, + cmd, env); +} + + +REGISTER_SIM_OBJECT("AlphaLiveProcess", AlphaLiveProcess) + diff --git a/src/arch/alpha/process.hh b/src/arch/alpha/process.hh new file mode 100644 index 000000000..7fa913cad --- /dev/null +++ b/src/arch/alpha/process.hh @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2003-2004 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 + * Ali Saidi + */ + +#ifndef __ALPHA_PROCESS_HH__ +#define __ALPHA_PROCESS_HH__ + +#include <string> +#include <vector> +#include "sim/process.hh" + +class ObjectFile; +class System; + + +class AlphaLiveProcess : public LiveProcess +{ + protected: + AlphaLiveProcess(const std::string &nm, ObjectFile *objFile, + System *_system, int stdin_fd, int stdout_fd, int stderr_fd, + std::vector<std::string> &argv, + std::vector<std::string> &envp); + + void startup(); + + public: + // this function is used to create the LiveProcess object, since + // we can't tell which subclass of LiveProcess to use until we + // open and look at the object file. + static AlphaLiveProcess *create(const std::string &nm, + System *_system, + int stdin_fd, int stdout_fd, int stderr_fd, + std::string executable, + std::vector<std::string> &argv, + std::vector<std::string> &envp); + +}; + + +#endif // __ALPHA_PROCESS_HH__ diff --git a/src/arch/alpha/regfile.hh b/src/arch/alpha/regfile.hh new file mode 100644 index 000000000..1025412cd --- /dev/null +++ b/src/arch/alpha/regfile.hh @@ -0,0 +1,290 @@ +/* + * Copyright (c) 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: Gabe Black + */ + +#ifndef __ARCH_ALPHA_REGFILE_HH__ +#define __ARCH_ALPHA_REGFILE_HH__ + +#include "arch/alpha/types.hh" +#include "arch/alpha/constants.hh" +#include "sim/faults.hh" + +class Checkpoint; +class ThreadContext; + +namespace AlphaISA +{ + class IntRegFile + { + protected: + IntReg regs[NumIntRegs]; + + public: + + IntReg readReg(int intReg) + { + return regs[intReg]; + } + + Fault setReg(int intReg, const IntReg &val) + { + regs[intReg] = val; + return NoFault; + } + + void serialize(std::ostream &os); + + void unserialize(Checkpoint *cp, const std::string §ion); + + void clear() + { bzero(regs, sizeof(regs)); } + }; + + class FloatRegFile + { + public: + + union { + uint64_t q[NumFloatRegs]; // integer qword view + double d[NumFloatRegs]; // double-precision floating point view + }; + + void serialize(std::ostream &os); + + void unserialize(Checkpoint *cp, const std::string §ion); + + void clear() + { bzero(d, sizeof(d)); } + }; + + class MiscRegFile { + protected: + uint64_t fpcr; // floating point condition codes + uint64_t uniq; // process-unique register + bool lock_flag; // lock flag for LL/SC + Addr lock_addr; // lock address for LL/SC + + public: + MiscReg readReg(int misc_reg); + + MiscReg readRegWithEffect(int misc_reg, Fault &fault, + ThreadContext *tc); + + //These functions should be removed once the simplescalar cpu model + //has been replaced. + int getInstAsid(); + int getDataAsid(); + + Fault setReg(int misc_reg, const MiscReg &val); + + Fault setRegWithEffect(int misc_reg, const MiscReg &val, + ThreadContext *tc); + + void clear() + { + fpcr = uniq = 0; + lock_flag = 0; + lock_addr = 0; + } +#if FULL_SYSTEM + protected: + typedef uint64_t InternalProcReg; + + InternalProcReg ipr[NumInternalProcRegs]; // Internal processor regs + + private: + InternalProcReg readIpr(int idx, Fault &fault, ThreadContext *tc); + + Fault setIpr(int idx, InternalProcReg val, ThreadContext *tc); +#endif + friend class RegFile; + }; + + class RegFile { + + protected: + Addr pc; // program counter + Addr npc; // next-cycle program counter + Addr nnpc; + + public: + Addr readPC() + { + return pc; + } + + void setPC(Addr val) + { + pc = val; + } + + Addr readNextPC() + { + return npc; + } + + void setNextPC(Addr val) + { + npc = val; + } + + Addr readNextNPC() + { + return nnpc; + } + + void setNextNPC(Addr val) + { + nnpc = val; + } + + protected: + IntRegFile intRegFile; // (signed) integer register file + FloatRegFile floatRegFile; // floating point register file + MiscRegFile miscRegFile; // control register file + + public: + +#if FULL_SYSTEM + int intrflag; // interrupt flag + inline int instAsid() + { return miscRegFile.getInstAsid(); } + inline int dataAsid() + { return miscRegFile.getDataAsid(); } +#endif // FULL_SYSTEM + + void clear() + { + intRegFile.clear(); + floatRegFile.clear(); + miscRegFile.clear(); + } + + MiscReg readMiscReg(int miscReg) + { + return miscRegFile.readReg(miscReg); + } + + MiscReg readMiscRegWithEffect(int miscReg, + Fault &fault, ThreadContext *tc) + { + fault = NoFault; + return miscRegFile.readRegWithEffect(miscReg, fault, tc); + } + + Fault setMiscReg(int miscReg, const MiscReg &val) + { + return miscRegFile.setReg(miscReg, val); + } + + Fault setMiscRegWithEffect(int miscReg, const MiscReg &val, + ThreadContext * tc) + { + return miscRegFile.setRegWithEffect(miscReg, val, tc); + } + + FloatReg readFloatReg(int floatReg) + { + return floatRegFile.d[floatReg]; + } + + FloatReg readFloatReg(int floatReg, int width) + { + return readFloatReg(floatReg); + } + + FloatRegBits readFloatRegBits(int floatReg) + { + return floatRegFile.q[floatReg]; + } + + FloatRegBits readFloatRegBits(int floatReg, int width) + { + return readFloatRegBits(floatReg); + } + + Fault setFloatReg(int floatReg, const FloatReg &val) + { + floatRegFile.d[floatReg] = val; + return NoFault; + } + + Fault setFloatReg(int floatReg, const FloatReg &val, int width) + { + return setFloatReg(floatReg, val); + } + + Fault setFloatRegBits(int floatReg, const FloatRegBits &val) + { + floatRegFile.q[floatReg] = val; + return NoFault; + } + + Fault setFloatRegBits(int floatReg, const FloatRegBits &val, int width) + { + return setFloatRegBits(floatReg, val); + } + + IntReg readIntReg(int intReg) + { + return intRegFile.readReg(intReg); + } + + Fault setIntReg(int intReg, const IntReg &val) + { + return intRegFile.setReg(intReg, val); + } + + void serialize(std::ostream &os); + void unserialize(Checkpoint *cp, const std::string §ion); + + enum ContextParam + { + CONTEXT_PALMODE + }; + + typedef bool ContextVal; + + void changeContext(ContextParam param, ContextVal val) + { + //This would be an alternative place to call/implement + //the swapPALShadow function + } + }; + + void copyRegs(ThreadContext *src, ThreadContext *dest); + + void copyMiscRegs(ThreadContext *src, ThreadContext *dest); + +#if FULL_SYSTEM + void copyIprs(ThreadContext *src, ThreadContext *dest); +#endif +} // namespace AlphaISA + +#endif diff --git a/src/arch/alpha/stacktrace.cc b/src/arch/alpha/stacktrace.cc new file mode 100644 index 000000000..d70a4d6dd --- /dev/null +++ b/src/arch/alpha/stacktrace.cc @@ -0,0 +1,368 @@ +/* + * Copyright (c) 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 + */ + +#include <string> + +#include "arch/alpha/isa_traits.hh" +#include "arch/alpha/stacktrace.hh" +#include "arch/alpha/vtophys.hh" +#include "base/bitfield.hh" +#include "base/trace.hh" +#include "cpu/base.hh" +#include "cpu/thread_context.hh" +#include "sim/system.hh" + +using namespace std; +using namespace AlphaISA; + +ProcessInfo::ProcessInfo(ThreadContext *_tc) + : tc(_tc) +{ + Addr addr = 0; + + VirtualPort *vp; + + vp = tc->getVirtPort(); + + if (!tc->getSystemPtr()->kernelSymtab->findAddress("thread_info_size", addr)) + panic("thread info not compiled into kernel\n"); + thread_info_size = vp->readGtoH<int32_t>(addr); + + if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_size", addr)) + panic("thread info not compiled into kernel\n"); + task_struct_size = vp->readGtoH<int32_t>(addr); + + if (!tc->getSystemPtr()->kernelSymtab->findAddress("thread_info_task", addr)) + panic("thread info not compiled into kernel\n"); + task_off = vp->readGtoH<int32_t>(addr); + + if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_pid", addr)) + panic("thread info not compiled into kernel\n"); + pid_off = vp->readGtoH<int32_t>(addr); + + if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_comm", addr)) + panic("thread info not compiled into kernel\n"); + name_off = vp->readGtoH<int32_t>(addr); + + tc->delVirtPort(vp); +} + +Addr +ProcessInfo::task(Addr ksp) const +{ + Addr base = ksp & ~0x3fff; + if (base == ULL(0xfffffc0000000000)) + return 0; + + Addr tsk; + + VirtualPort *vp; + + vp = tc->getVirtPort(); + tsk = vp->readGtoH<Addr>(base + task_off); + tc->delVirtPort(vp); + + return tsk; +} + +int +ProcessInfo::pid(Addr ksp) const +{ + Addr task = this->task(ksp); + if (!task) + return -1; + + uint16_t pd; + + VirtualPort *vp; + + vp = tc->getVirtPort(); + pd = vp->readGtoH<uint16_t>(task + pid_off); + tc->delVirtPort(vp); + + return pd; +} + +string +ProcessInfo::name(Addr ksp) const +{ + Addr task = this->task(ksp); + if (!task) + return "console"; + + char comm[256]; + CopyStringOut(tc, comm, task + name_off, sizeof(comm)); + if (!comm[0]) + return "startup"; + + return comm; +} + +StackTrace::StackTrace() + : tc(0), stack(64) +{ +} + +StackTrace::StackTrace(ThreadContext *_tc, StaticInstPtr inst) + : tc(0), stack(64) +{ + trace(_tc, inst); +} + +StackTrace::~StackTrace() +{ +} + +void +StackTrace::trace(ThreadContext *_tc, bool is_call) +{ + tc = _tc; + + bool usermode = (tc->readMiscReg(AlphaISA::IPR_DTB_CM) & 0x18) != 0; + + Addr pc = tc->readNextPC(); + bool kernel = tc->getSystemPtr()->kernelStart <= pc && + pc <= tc->getSystemPtr()->kernelEnd; + + if (usermode) { + stack.push_back(user); + return; + } + + if (!kernel) { + stack.push_back(console); + return; + } + + SymbolTable *symtab = tc->getSystemPtr()->kernelSymtab; + Addr ksp = tc->readIntReg(TheISA::StackPointerReg); + Addr bottom = ksp & ~0x3fff; + Addr addr; + + if (is_call) { + if (!symtab->findNearestAddr(pc, addr)) + panic("could not find address %#x", pc); + + stack.push_back(addr); + pc = tc->readPC(); + } + + Addr ra; + int size; + + while (ksp > bottom) { + if (!symtab->findNearestAddr(pc, addr)) + panic("could not find symbol for pc=%#x", pc); + assert(pc >= addr && "symbol botch: callpc < func"); + + stack.push_back(addr); + + if (isEntry(addr)) + return; + + if (decodePrologue(ksp, pc, addr, size, ra)) { + if (!ra) + return; + + if (size <= 0) { + stack.push_back(unknown); + return; + } + + pc = ra; + ksp += size; + } else { + stack.push_back(unknown); + return; + } + + bool kernel = tc->getSystemPtr()->kernelStart <= pc && + pc <= tc->getSystemPtr()->kernelEnd; + if (!kernel) + return; + + if (stack.size() >= 1000) + panic("unwinding too far"); + } + + panic("unwinding too far"); +} + +bool +StackTrace::isEntry(Addr addr) +{ + if (addr == tc->readMiscReg(AlphaISA::IPR_PALtemp12)) + return true; + + if (addr == tc->readMiscReg(AlphaISA::IPR_PALtemp7)) + return true; + + if (addr == tc->readMiscReg(AlphaISA::IPR_PALtemp11)) + return true; + + if (addr == tc->readMiscReg(AlphaISA::IPR_PALtemp21)) + return true; + + if (addr == tc->readMiscReg(AlphaISA::IPR_PALtemp9)) + return true; + + if (addr == tc->readMiscReg(AlphaISA::IPR_PALtemp2)) + return true; + + return false; +} + +bool +StackTrace::decodeStack(MachInst inst, int &disp) +{ + // lda $sp, -disp($sp) + // + // Opcode<31:26> == 0x08 + // RA<25:21> == 30 + // RB<20:16> == 30 + // Disp<15:0> + const MachInst mem_mask = 0xffff0000; + const MachInst lda_pattern = 0x23de0000; + const MachInst lda_disp_mask = 0x0000ffff; + + // subq $sp, disp, $sp + // addq $sp, disp, $sp + // + // Opcode<31:26> == 0x10 + // RA<25:21> == 30 + // Lit<20:13> + // One<12> = 1 + // Func<11:5> == 0x20 (addq) + // Func<11:5> == 0x29 (subq) + // RC<4:0> == 30 + const MachInst intop_mask = 0xffe01fff; + const MachInst addq_pattern = 0x43c0141e; + const MachInst subq_pattern = 0x43c0153e; + const MachInst intop_disp_mask = 0x001fe000; + const int intop_disp_shift = 13; + + if ((inst & mem_mask) == lda_pattern) + disp = -sext<16>(inst & lda_disp_mask); + else if ((inst & intop_mask) == addq_pattern) + disp = -int((inst & intop_disp_mask) >> intop_disp_shift); + else if ((inst & intop_mask) == subq_pattern) + disp = int((inst & intop_disp_mask) >> intop_disp_shift); + else + return false; + + return true; +} + +bool +StackTrace::decodeSave(MachInst inst, int ®, int &disp) +{ + // lda $stq, disp($sp) + // + // Opcode<31:26> == 0x08 + // RA<25:21> == ? + // RB<20:16> == 30 + // Disp<15:0> + const MachInst stq_mask = 0xfc1f0000; + const MachInst stq_pattern = 0xb41e0000; + const MachInst stq_disp_mask = 0x0000ffff; + const MachInst reg_mask = 0x03e00000; + const int reg_shift = 21; + + if ((inst & stq_mask) == stq_pattern) { + reg = (inst & reg_mask) >> reg_shift; + disp = sext<16>(inst & stq_disp_mask); + } else { + return false; + } + + return true; +} + +/* + * Decode the function prologue for the function we're in, and note + * which registers are stored where, and how large the stack frame is. + */ +bool +StackTrace::decodePrologue(Addr sp, Addr callpc, Addr func, + int &size, Addr &ra) +{ + size = 0; + ra = 0; + + for (Addr pc = func; pc < callpc; pc += sizeof(MachInst)) { + MachInst inst; + CopyOut(tc, (uint8_t *)&inst, pc, sizeof(MachInst)); + + int reg, disp; + if (decodeStack(inst, disp)) { + if (size) { + // panic("decoding frame size again"); + return true; + } + size += disp; + } else if (decodeSave(inst, reg, disp)) { + if (!ra && reg == ReturnAddressReg) { + CopyOut(tc, (uint8_t *)&ra, sp + disp, sizeof(Addr)); + if (!ra) { + // panic("no return address value pc=%#x\n", pc); + return false; + } + } + } + } + + return true; +} + +#if TRACING_ON +void +StackTrace::dump() +{ + StringWrap name(tc->getCpuPtr()->name()); + SymbolTable *symtab = tc->getSystemPtr()->kernelSymtab; + + DPRINTFN("------ Stack ------\n"); + + string symbol; + for (int i = 0, size = stack.size(); i < size; ++i) { + Addr addr = stack[size - i - 1]; + if (addr == user) + symbol = "user"; + else if (addr == console) + symbol = "console"; + else if (addr == unknown) + symbol = "unknown"; + else + symtab->findSymbol(addr, symbol); + + DPRINTFN("%#x: %s\n", addr, symbol); + } +} +#endif diff --git a/src/arch/alpha/stacktrace.hh b/src/arch/alpha/stacktrace.hh new file mode 100644 index 000000000..d12aee211 --- /dev/null +++ b/src/arch/alpha/stacktrace.hh @@ -0,0 +1,121 @@ +/* + * Copyright (c) 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 + */ + +#ifndef __ARCH_ALPHA_STACKTRACE_HH__ +#define __ARCH_ALPHA_STACKTRACE_HH__ + +#include "base/trace.hh" +#include "cpu/static_inst.hh" + +class ThreadContext; +class StackTrace; + +class ProcessInfo +{ + private: + ThreadContext *tc; + + int thread_info_size; + int task_struct_size; + int task_off; + int pid_off; + int name_off; + + public: + ProcessInfo(ThreadContext *_tc); + + Addr task(Addr ksp) const; + int pid(Addr ksp) const; + std::string name(Addr ksp) const; +}; + +class StackTrace +{ + protected: + typedef TheISA::MachInst MachInst; + private: + ThreadContext *tc; + std::vector<Addr> stack; + + private: + bool isEntry(Addr addr); + bool decodePrologue(Addr sp, Addr callpc, Addr func, int &size, Addr &ra); + bool decodeSave(MachInst inst, int ®, int &disp); + bool decodeStack(MachInst inst, int &disp); + + void trace(ThreadContext *tc, bool is_call); + + public: + StackTrace(); + StackTrace(ThreadContext *tc, StaticInstPtr inst); + ~StackTrace(); + + void clear() + { + tc = 0; + stack.clear(); + } + + bool valid() const { return tc != NULL; } + bool trace(ThreadContext *tc, StaticInstPtr inst); + + public: + const std::vector<Addr> &getstack() const { return stack; } + + static const int user = 1; + static const int console = 2; + static const int unknown = 3; + +#if TRACING_ON + private: + void dump(); + + public: + void dprintf() { if (DTRACE(Stack)) dump(); } +#else + public: + void dprintf() {} +#endif +}; + +inline bool +StackTrace::trace(ThreadContext *tc, StaticInstPtr inst) +{ + if (!inst->isCall() && !inst->isReturn()) + return false; + + if (valid()) + clear(); + + trace(tc, !inst->isReturn()); + return true; +} + +#endif // __ARCH_ALPHA_STACKTRACE_HH__ diff --git a/src/arch/alpha/system.cc b/src/arch/alpha/system.cc new file mode 100644 index 000000000..3aaba7d58 --- /dev/null +++ b/src/arch/alpha/system.cc @@ -0,0 +1,272 @@ +/* + * 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: Ali Saidi + */ + +#include "arch/alpha/ev5.hh" +#include "arch/alpha/system.hh" +#include "arch/vtophys.hh" +#include "base/remote_gdb.hh" +#include "base/loader/object_file.hh" +#include "base/loader/symtab.hh" +#include "base/trace.hh" +#include "mem/physical.hh" +#include "sim/byteswap.hh" +#include "sim/builder.hh" + + +using namespace LittleEndianGuest; + +AlphaSystem::AlphaSystem(Params *p) + : System(p) +{ + consoleSymtab = new SymbolTable; + palSymtab = new SymbolTable; + + + /** + * Load the pal, and console code into memory + */ + // Load Console Code + console = createObjectFile(params()->console_path); + if (console == NULL) + fatal("Could not load console file %s", params()->console_path); + + // Load pal file + pal = createObjectFile(params()->palcode); + if (pal == NULL) + fatal("Could not load PALcode file %s", params()->palcode); + + + // Load program sections into memory + pal->loadSections(&functionalPort, AlphaISA::LoadAddrMask); + console->loadSections(&functionalPort, AlphaISA::LoadAddrMask); + + // load symbols + if (!console->loadGlobalSymbols(consoleSymtab)) + panic("could not load console symbols\n"); + + if (!pal->loadGlobalSymbols(palSymtab)) + panic("could not load pal symbols\n"); + + if (!pal->loadLocalSymbols(palSymtab)) + panic("could not load pal symbols\n"); + + if (!console->loadGlobalSymbols(debugSymbolTable)) + panic("could not load console symbols\n"); + + if (!pal->loadGlobalSymbols(debugSymbolTable)) + panic("could not load pal symbols\n"); + + if (!pal->loadLocalSymbols(debugSymbolTable)) + panic("could not load pal symbols\n"); + + Addr addr = 0; +#ifndef NDEBUG + consolePanicEvent = addConsoleFuncEvent<BreakPCEvent>("panic"); +#endif + + /** + * Copy the osflags (kernel arguments) into the consoles + * memory. (Presently Linux does not use the console service + * routine to get these command line arguments, but Tru64 and + * others do.) + */ + if (consoleSymtab->findAddress("env_booted_osflags", addr)) { + virtPort.writeBlob(addr, (uint8_t*)params()->boot_osflags.c_str(), + strlen(params()->boot_osflags.c_str())); + } + + /** + * Set the hardware reset parameter block system type and revision + * information to Tsunami. + */ + if (consoleSymtab->findAddress("m5_rpb", addr)) { + uint64_t data; + data = htog(params()->system_type); + virtPort.write(addr+0x50, data); + data = htog(params()->system_rev); + virtPort.write(addr+0x58, data); + } else + panic("could not find hwrpb\n"); + +} + +AlphaSystem::~AlphaSystem() +{ + delete consoleSymtab; + delete console; + delete pal; +#ifdef DEBUG + delete consolePanicEvent; +#endif +} + +/** + * This function fixes up addresses that are used to match PCs for + * hooking simulator events on to target function executions. + * + * Alpha binaries may have multiple global offset table (GOT) + * sections. A function that uses the GOT starts with a + * two-instruction prolog which sets the global pointer (gp == r29) to + * the appropriate GOT section. The proper gp value is calculated + * based on the function address, which must be passed by the caller + * in the procedure value register (pv aka t12 == r27). This sequence + * looks like the following: + * + * opcode Ra Rb offset + * ldah gp,X(pv) 09 29 27 X + * lda gp,Y(gp) 08 29 29 Y + * + * for some constant offsets X and Y. The catch is that the linker + * (or maybe even the compiler, I'm not sure) may recognize that the + * caller and callee are using the same GOT section, making this + * prolog redundant, and modify the call target to skip these + * instructions. If we check for execution of the first instruction + * of a function (the one the symbol points to) to detect when to skip + * it, we'll miss all these modified calls. It might work to + * unconditionally check for the third instruction, but not all + * functions have this prolog, and there's some chance that those + * first two instructions could have undesired consequences. So we do + * the Right Thing and pattern-match the first two instructions of the + * function to decide where to patch. + * + * Eventually this code should be moved into an ISA-specific file. + */ +Addr +AlphaSystem::fixFuncEventAddr(Addr addr) +{ + // mask for just the opcode, Ra, and Rb fields (not the offset) + const uint32_t inst_mask = 0xffff0000; + // ldah gp,X(pv): opcode 9, Ra = 29, Rb = 27 + const uint32_t gp_ldah_pattern = (9 << 26) | (29 << 21) | (27 << 16); + // lda gp,Y(gp): opcode 8, Ra = 29, rb = 29 + const uint32_t gp_lda_pattern = (8 << 26) | (29 << 21) | (29 << 16); + + uint32_t i1 = virtPort.read<uint32_t>(addr); + uint32_t i2 = virtPort.read<uint32_t>(addr + sizeof(AlphaISA::MachInst)); + + if ((i1 & inst_mask) == gp_ldah_pattern && + (i2 & inst_mask) == gp_lda_pattern) { + Addr new_addr = addr + 2* sizeof(AlphaISA::MachInst); + DPRINTF(Loader, "fixFuncEventAddr: %p -> %p", addr, new_addr); + return new_addr; + } else { + return addr; + } +} + + +void +AlphaSystem::setAlphaAccess(Addr access) +{ + Addr addr = 0; + if (consoleSymtab->findAddress("m5AlphaAccess", addr)) { + virtPort.write(addr, htog(EV5::Phys2K0Seg(access))); + } else + panic("could not find m5AlphaAccess\n"); +} + +bool +AlphaSystem::breakpoint() +{ + return remoteGDB[0]->trap(ALPHA_KENTRY_INT); +} + +void +AlphaSystem::serialize(std::ostream &os) +{ + System::serialize(os); + consoleSymtab->serialize("console_symtab", os); + palSymtab->serialize("pal_symtab", os); +} + + +void +AlphaSystem::unserialize(Checkpoint *cp, const std::string §ion) +{ + System::unserialize(cp,section); + consoleSymtab->unserialize("console_symtab", cp, section); + palSymtab->unserialize("pal_symtab", cp, section); +} + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaSystem) + + Param<Tick> boot_cpu_frequency; + SimObjectParam<PhysicalMemory *> physmem; + + Param<std::string> kernel; + Param<std::string> console; + Param<std::string> pal; + + Param<std::string> boot_osflags; + Param<std::string> readfile; + Param<unsigned int> init_param; + + Param<uint64_t> system_type; + Param<uint64_t> system_rev; + +END_DECLARE_SIM_OBJECT_PARAMS(AlphaSystem) + +BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaSystem) + + INIT_PARAM(boot_cpu_frequency, "Frequency of the boot CPU"), + INIT_PARAM(physmem, "phsyical memory"), + INIT_PARAM(kernel, "file that contains the kernel code"), + INIT_PARAM(console, "file that contains the console code"), + INIT_PARAM(pal, "file that contains palcode"), + INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot", + "a"), + INIT_PARAM_DFLT(readfile, "file to read startup script from", ""), + INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0), + INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 34), + INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10) + +END_INIT_SIM_OBJECT_PARAMS(AlphaSystem) + +CREATE_SIM_OBJECT(AlphaSystem) +{ + AlphaSystem::Params *p = new AlphaSystem::Params; + p->name = getInstanceName(); + p->boot_cpu_frequency = boot_cpu_frequency; + p->physmem = physmem; + p->kernel_path = kernel; + p->console_path = console; + p->palcode = pal; + p->boot_osflags = boot_osflags; + p->init_param = init_param; + p->readfile = readfile; + p->system_type = system_type; + p->system_rev = system_rev; + return new AlphaSystem(p); +} + +REGISTER_SIM_OBJECT("AlphaSystem", AlphaSystem) + + diff --git a/src/arch/alpha/system.hh b/src/arch/alpha/system.hh new file mode 100644 index 000000000..b26a5e301 --- /dev/null +++ b/src/arch/alpha/system.hh @@ -0,0 +1,110 @@ +/* + * 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: Ali Saidi + */ + +#ifndef __ARCH_ALPHA_SYSTEM_HH__ +#define __ARCH_ALPHA_SYSTEM_HH__ + +#include <string> +#include <vector> + +#include "sim/system.hh" +#include "base/loader/symtab.hh" +#include "cpu/pc_event.hh" +#include "kern/system_events.hh" +#include "sim/sim_object.hh" + +class AlphaSystem : public System +{ + public: + struct Params : public System::Params + { + std::string console_path; + std::string palcode; + uint64_t system_type; + uint64_t system_rev; + }; + + AlphaSystem(Params *p); + + ~AlphaSystem(); + + virtual bool breakpoint(); + +/** + * Serialization stuff + */ + public: + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + + /** + * Set the m5AlphaAccess pointer in the console + */ + void setAlphaAccess(Addr access); + + /** console symbol table */ + SymbolTable *consoleSymtab; + + /** pal symbol table */ + SymbolTable *palSymtab; + + /** Object pointer for the console code */ + ObjectFile *console; + + /** Object pointer for the PAL code */ + ObjectFile *pal; + +#ifndef NDEBUG + /** Event to halt the simulator if the console calls panic() */ + BreakPCEvent *consolePanicEvent; +#endif + protected: + const Params *params() const { return (const Params *)_params; } + + /** Add a function-based event to PALcode. */ + template <class T> + T *AlphaSystem::addPalFuncEvent(const char *lbl) + { + return addFuncEvent<T>(palSymtab, lbl); + } + + /** Add a function-based event to the console code. */ + template <class T> + T *AlphaSystem::addConsoleFuncEvent(const char *lbl) + { + return addFuncEvent<T>(consoleSymtab, lbl); + } + + virtual Addr fixFuncEventAddr(Addr addr); + +}; + +#endif + diff --git a/src/arch/alpha/tlb.cc b/src/arch/alpha/tlb.cc new file mode 100644 index 000000000..c6684274b --- /dev/null +++ b/src/arch/alpha/tlb.cc @@ -0,0 +1,632 @@ +/* + * 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 + * Steve Reinhardt + * Andrew Schultz + */ + +#include <string> +#include <vector> + +#include "arch/alpha/tlb.hh" +#include "base/inifile.hh" +#include "base/str.hh" +#include "base/trace.hh" +#include "config/alpha_tlaser.hh" +#include "cpu/thread_context.hh" +#include "sim/builder.hh" + +using namespace std; +using namespace EV5; + +/////////////////////////////////////////////////////////////////////// +// +// Alpha TLB +// +#ifdef DEBUG +bool uncacheBit39 = false; +bool uncacheBit40 = false; +#endif + +#define MODE2MASK(X) (1 << (X)) + +AlphaTLB::AlphaTLB(const string &name, int s) + : SimObject(name), size(s), nlu(0) +{ + table = new AlphaISA::PTE[size]; + memset(table, 0, sizeof(AlphaISA::PTE[size])); +} + +AlphaTLB::~AlphaTLB() +{ + if (table) + delete [] table; +} + +// look up an entry in the TLB +AlphaISA::PTE * +AlphaTLB::lookup(Addr vpn, uint8_t asn) const +{ + // assume not found... + AlphaISA::PTE *retval = NULL; + + PageTable::const_iterator i = lookupTable.find(vpn); + if (i != lookupTable.end()) { + while (i->first == vpn) { + int index = i->second; + AlphaISA::PTE *pte = &table[index]; + assert(pte->valid); + if (vpn == pte->tag && (pte->asma || pte->asn == asn)) { + retval = pte; + break; + } + + ++i; + } + } + + DPRINTF(TLB, "lookup %#x, asn %#x -> %s ppn %#x\n", vpn, (int)asn, + retval ? "hit" : "miss", retval ? retval->ppn : 0); + return retval; +} + + +Fault +AlphaTLB::checkCacheability(RequestPtr &req) +{ + // in Alpha, cacheability is controlled by upper-level bits of the + // physical address + + /* + * We support having the uncacheable bit in either bit 39 or bit 40. + * The Turbolaser platform (and EV5) support having the bit in 39, but + * Tsunami (which Linux assumes uses an EV6) generates accesses with + * the bit in 40. So we must check for both, but we have debug flags + * to catch a weird case where both are used, which shouldn't happen. + */ + + +#if ALPHA_TLASER + if (req->getPaddr() & PAddrUncachedBit39) { +#else + if (req->getPaddr() & PAddrUncachedBit43) { +#endif + // IPR memory space not implemented + if (PAddrIprSpace(req->getPaddr())) { + return new UnimpFault("IPR memory space not implemented!"); + } else { + // mark request as uncacheable + req->setFlags(req->getFlags() | UNCACHEABLE); + +#if !ALPHA_TLASER + // Clear bits 42:35 of the physical address (10-2 in Tsunami manual) + req->setPaddr(req->getPaddr() & PAddrUncachedMask); +#endif + } + } + return NoFault; +} + + +// insert a new TLB entry +void +AlphaTLB::insert(Addr addr, AlphaISA::PTE &pte) +{ + AlphaISA::VAddr vaddr = addr; + if (table[nlu].valid) { + Addr oldvpn = table[nlu].tag; + PageTable::iterator i = lookupTable.find(oldvpn); + + if (i == lookupTable.end()) + panic("TLB entry not found in lookupTable"); + + int index; + while ((index = i->second) != nlu) { + if (table[index].tag != oldvpn) + panic("TLB entry not found in lookupTable"); + + ++i; + } + + DPRINTF(TLB, "remove @%d: %#x -> %#x\n", nlu, oldvpn, table[nlu].ppn); + + lookupTable.erase(i); + } + + DPRINTF(TLB, "insert @%d: %#x -> %#x\n", nlu, vaddr.vpn(), pte.ppn); + + table[nlu] = pte; + table[nlu].tag = vaddr.vpn(); + table[nlu].valid = true; + + lookupTable.insert(make_pair(vaddr.vpn(), nlu)); + nextnlu(); +} + +void +AlphaTLB::flushAll() +{ + DPRINTF(TLB, "flushAll\n"); + memset(table, 0, sizeof(AlphaISA::PTE[size])); + lookupTable.clear(); + nlu = 0; +} + +void +AlphaTLB::flushProcesses() +{ + PageTable::iterator i = lookupTable.begin(); + PageTable::iterator end = lookupTable.end(); + while (i != end) { + int index = i->second; + AlphaISA::PTE *pte = &table[index]; + assert(pte->valid); + + // we can't increment i after we erase it, so save a copy and + // increment it to get the next entry now + PageTable::iterator cur = i; + ++i; + + if (!pte->asma) { + DPRINTF(TLB, "flush @%d: %#x -> %#x\n", index, pte->tag, pte->ppn); + pte->valid = false; + lookupTable.erase(cur); + } + } +} + +void +AlphaTLB::flushAddr(Addr addr, uint8_t asn) +{ + AlphaISA::VAddr vaddr = addr; + + PageTable::iterator i = lookupTable.find(vaddr.vpn()); + if (i == lookupTable.end()) + return; + + while (i->first == vaddr.vpn()) { + int index = i->second; + AlphaISA::PTE *pte = &table[index]; + assert(pte->valid); + + if (vaddr.vpn() == pte->tag && (pte->asma || pte->asn == asn)) { + DPRINTF(TLB, "flushaddr @%d: %#x -> %#x\n", index, vaddr.vpn(), + pte->ppn); + + // invalidate this entry + pte->valid = false; + + lookupTable.erase(i); + } + + ++i; + } +} + + +void +AlphaTLB::serialize(ostream &os) +{ + SERIALIZE_SCALAR(size); + SERIALIZE_SCALAR(nlu); + + for (int i = 0; i < size; i++) { + nameOut(os, csprintf("%s.PTE%d", name(), i)); + table[i].serialize(os); + } +} + +void +AlphaTLB::unserialize(Checkpoint *cp, const string §ion) +{ + UNSERIALIZE_SCALAR(size); + UNSERIALIZE_SCALAR(nlu); + + for (int i = 0; i < size; i++) { + table[i].unserialize(cp, csprintf("%s.PTE%d", section, i)); + if (table[i].valid) { + lookupTable.insert(make_pair(table[i].tag, i)); + } + } +} + + +/////////////////////////////////////////////////////////////////////// +// +// Alpha ITB +// +AlphaITB::AlphaITB(const std::string &name, int size) + : AlphaTLB(name, size) +{} + + +void +AlphaITB::regStats() +{ + hits + .name(name() + ".hits") + .desc("ITB hits"); + misses + .name(name() + ".misses") + .desc("ITB misses"); + acv + .name(name() + ".acv") + .desc("ITB acv"); + accesses + .name(name() + ".accesses") + .desc("ITB accesses"); + + accesses = hits + misses; +} + + +Fault +AlphaITB::translate(RequestPtr &req, ThreadContext *tc) const +{ + if (AlphaISA::PcPAL(req->getVaddr())) { + // strip off PAL PC marker (lsb is 1) + req->setPaddr((req->getVaddr() & ~3) & PAddrImplMask); + hits++; + return NoFault; + } + + if (req->getFlags() & PHYSICAL) { + req->setPaddr(req->getVaddr()); + } else { + // verify that this is a good virtual address + if (!validVirtualAddress(req->getVaddr())) { + acv++; + return new ItbAcvFault(req->getVaddr()); + } + + + // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13> for EV5 + // VA<47:41> == 0x7e, VA<40:13> maps directly to PA<40:13> for EV6 +#if ALPHA_TLASER + if ((MCSR_SP(tc->readMiscReg(AlphaISA::IPR_MCSR)) & 2) && + VAddrSpaceEV5(req->getVaddr()) == 2) { +#else + if (VAddrSpaceEV6(req->getVaddr()) == 0x7e) { +#endif + // only valid in kernel mode + if (ICM_CM(tc->readMiscReg(AlphaISA::IPR_ICM)) != + AlphaISA::mode_kernel) { + acv++; + return new ItbAcvFault(req->getVaddr()); + } + + req->setPaddr(req->getVaddr() & PAddrImplMask); + +#if !ALPHA_TLASER + // sign extend the physical address properly + if (req->getPaddr() & PAddrUncachedBit40) + req->setPaddr(req->getPaddr() | ULL(0xf0000000000)); + else + req->setPaddr(req->getPaddr() & ULL(0xffffffffff)); +#endif + + } else { + // not a physical address: need to look up pte + int asn = DTB_ASN_ASN(tc->readMiscReg(AlphaISA::IPR_DTB_ASN)); + AlphaISA::PTE *pte = lookup(AlphaISA::VAddr(req->getVaddr()).vpn(), + asn); + + if (!pte) { + misses++; + return new ItbPageFault(req->getVaddr()); + } + + req->setPaddr((pte->ppn << AlphaISA::PageShift) + + (AlphaISA::VAddr(req->getVaddr()).offset() + & ~3)); + + // check permissions for this access + if (!(pte->xre & + (1 << ICM_CM(tc->readMiscReg(AlphaISA::IPR_ICM))))) { + // instruction access fault + acv++; + return new ItbAcvFault(req->getVaddr()); + } + + hits++; + } + } + + // check that the physical address is ok (catch bad physical addresses) + if (req->getPaddr() & ~PAddrImplMask) + return genMachineCheckFault(); + + return checkCacheability(req); + +} + +/////////////////////////////////////////////////////////////////////// +// +// Alpha DTB +// +AlphaDTB::AlphaDTB(const std::string &name, int size) + : AlphaTLB(name, size) +{} + +void +AlphaDTB::regStats() +{ + read_hits + .name(name() + ".read_hits") + .desc("DTB read hits") + ; + + read_misses + .name(name() + ".read_misses") + .desc("DTB read misses") + ; + + read_acv + .name(name() + ".read_acv") + .desc("DTB read access violations") + ; + + read_accesses + .name(name() + ".read_accesses") + .desc("DTB read accesses") + ; + + write_hits + .name(name() + ".write_hits") + .desc("DTB write hits") + ; + + write_misses + .name(name() + ".write_misses") + .desc("DTB write misses") + ; + + write_acv + .name(name() + ".write_acv") + .desc("DTB write access violations") + ; + + write_accesses + .name(name() + ".write_accesses") + .desc("DTB write accesses") + ; + + hits + .name(name() + ".hits") + .desc("DTB hits") + ; + + misses + .name(name() + ".misses") + .desc("DTB misses") + ; + + acv + .name(name() + ".acv") + .desc("DTB access violations") + ; + + accesses + .name(name() + ".accesses") + .desc("DTB accesses") + ; + + hits = read_hits + write_hits; + misses = read_misses + write_misses; + acv = read_acv + write_acv; + accesses = read_accesses + write_accesses; +} + +Fault +AlphaDTB::translate(RequestPtr &req, ThreadContext *tc, bool write) const +{ + Addr pc = tc->readPC(); + + AlphaISA::mode_type mode = + (AlphaISA::mode_type)DTB_CM_CM(tc->readMiscReg(AlphaISA::IPR_DTB_CM)); + + + /** + * Check for alignment faults + */ + if (req->getVaddr() & (req->getSize() - 1)) { + DPRINTF(TLB, "Alignment Fault on %#x, size = %d", req->getVaddr(), + req->getSize()); + uint64_t flags = write ? MM_STAT_WR_MASK : 0; + return new DtbAlignmentFault(req->getVaddr(), req->getFlags(), flags); + } + + if (pc & 0x1) { + mode = (req->getFlags() & ALTMODE) ? + (AlphaISA::mode_type)ALT_MODE_AM( + tc->readMiscReg(AlphaISA::IPR_ALT_MODE)) + : AlphaISA::mode_kernel; + } + + if (req->getFlags() & PHYSICAL) { + req->setPaddr(req->getVaddr()); + } else { + // verify that this is a good virtual address + if (!validVirtualAddress(req->getVaddr())) { + if (write) { write_acv++; } else { read_acv++; } + uint64_t flags = (write ? MM_STAT_WR_MASK : 0) | + MM_STAT_BAD_VA_MASK | + MM_STAT_ACV_MASK; + return new DtbPageFault(req->getVaddr(), req->getFlags(), flags); + } + + // Check for "superpage" mapping +#if ALPHA_TLASER + if ((MCSR_SP(tc->readMiscReg(AlphaISA::IPR_MCSR)) & 2) && + VAddrSpaceEV5(req->getVaddr()) == 2) { +#else + if (VAddrSpaceEV6(req->getVaddr()) == 0x7e) { +#endif + + // only valid in kernel mode + if (DTB_CM_CM(tc->readMiscReg(AlphaISA::IPR_DTB_CM)) != + AlphaISA::mode_kernel) { + if (write) { write_acv++; } else { read_acv++; } + uint64_t flags = ((write ? MM_STAT_WR_MASK : 0) | + MM_STAT_ACV_MASK); + return new DtbAcvFault(req->getVaddr(), req->getFlags(), flags); + } + + req->setPaddr(req->getVaddr() & PAddrImplMask); + +#if !ALPHA_TLASER + // sign extend the physical address properly + if (req->getPaddr() & PAddrUncachedBit40) + req->setPaddr(req->getPaddr() | ULL(0xf0000000000)); + else + req->setPaddr(req->getPaddr() & ULL(0xffffffffff)); +#endif + + } else { + if (write) + write_accesses++; + else + read_accesses++; + + int asn = DTB_ASN_ASN(tc->readMiscReg(AlphaISA::IPR_DTB_ASN)); + + // not a physical address: need to look up pte + AlphaISA::PTE *pte = lookup(AlphaISA::VAddr(req->getVaddr()).vpn(), + asn); + + if (!pte) { + // page fault + if (write) { write_misses++; } else { read_misses++; } + uint64_t flags = (write ? MM_STAT_WR_MASK : 0) | + MM_STAT_DTB_MISS_MASK; + return (req->getFlags() & VPTE) ? + (Fault)(new PDtbMissFault(req->getVaddr(), req->getFlags(), + flags)) : + (Fault)(new NDtbMissFault(req->getVaddr(), req->getFlags(), + flags)); + } + + req->setPaddr((pte->ppn << AlphaISA::PageShift) + + AlphaISA::VAddr(req->getVaddr()).offset()); + + if (write) { + if (!(pte->xwe & MODE2MASK(mode))) { + // declare the instruction access fault + write_acv++; + uint64_t flags = MM_STAT_WR_MASK | + MM_STAT_ACV_MASK | + (pte->fonw ? MM_STAT_FONW_MASK : 0); + return new DtbPageFault(req->getVaddr(), req->getFlags(), flags); + } + if (pte->fonw) { + write_acv++; + uint64_t flags = MM_STAT_WR_MASK | + MM_STAT_FONW_MASK; + return new DtbPageFault(req->getVaddr(), req->getFlags(), flags); + } + } else { + if (!(pte->xre & MODE2MASK(mode))) { + read_acv++; + uint64_t flags = MM_STAT_ACV_MASK | + (pte->fonr ? MM_STAT_FONR_MASK : 0); + return new DtbAcvFault(req->getVaddr(), req->getFlags(), flags); + } + if (pte->fonr) { + read_acv++; + uint64_t flags = MM_STAT_FONR_MASK; + return new DtbPageFault(req->getVaddr(), req->getFlags(), flags); + } + } + } + + if (write) + write_hits++; + else + read_hits++; + } + + // check that the physical address is ok (catch bad physical addresses) + if (req->getPaddr() & ~PAddrImplMask) + return genMachineCheckFault(); + + return checkCacheability(req); +} + +AlphaISA::PTE & +AlphaTLB::index(bool advance) +{ + AlphaISA::PTE *pte = &table[nlu]; + + if (advance) + nextnlu(); + + return *pte; +} + +DEFINE_SIM_OBJECT_CLASS_NAME("AlphaTLB", AlphaTLB) + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaITB) + + Param<int> size; + +END_DECLARE_SIM_OBJECT_PARAMS(AlphaITB) + +BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaITB) + + INIT_PARAM_DFLT(size, "TLB size", 48) + +END_INIT_SIM_OBJECT_PARAMS(AlphaITB) + + +CREATE_SIM_OBJECT(AlphaITB) +{ + return new AlphaITB(getInstanceName(), size); +} + +REGISTER_SIM_OBJECT("AlphaITB", AlphaITB) + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaDTB) + + Param<int> size; + +END_DECLARE_SIM_OBJECT_PARAMS(AlphaDTB) + +BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaDTB) + + INIT_PARAM_DFLT(size, "TLB size", 64) + +END_INIT_SIM_OBJECT_PARAMS(AlphaDTB) + + +CREATE_SIM_OBJECT(AlphaDTB) +{ + return new AlphaDTB(getInstanceName(), size); +} + +REGISTER_SIM_OBJECT("AlphaDTB", AlphaDTB) + diff --git a/src/arch/alpha/tlb.hh b/src/arch/alpha/tlb.hh new file mode 100644 index 000000000..07d01fa5c --- /dev/null +++ b/src/arch/alpha/tlb.hh @@ -0,0 +1,124 @@ +/* + * 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 + * Steve Reinhardt + */ + +#ifndef __ALPHA_MEMORY_HH__ +#define __ALPHA_MEMORY_HH__ + +#include <map> + +#include "arch/alpha/ev5.hh" +#include "arch/alpha/isa_traits.hh" +#include "arch/alpha/faults.hh" +#include "base/statistics.hh" +#include "mem/request.hh" +#include "sim/sim_object.hh" + +class ThreadContext; + +class AlphaTLB : public SimObject +{ + protected: + typedef std::multimap<Addr, int> PageTable; + PageTable lookupTable; // Quick lookup into page table + + AlphaISA::PTE *table; // the Page Table + int size; // TLB Size + int nlu; // not last used entry (for replacement) + + void nextnlu() { if (++nlu >= size) nlu = 0; } + AlphaISA::PTE *lookup(Addr vpn, uint8_t asn) const; + + public: + AlphaTLB(const std::string &name, int size); + virtual ~AlphaTLB(); + + int getsize() const { return size; } + + AlphaISA::PTE &index(bool advance = true); + void insert(Addr vaddr, AlphaISA::PTE &pte); + + void flushAll(); + void flushProcesses(); + void flushAddr(Addr addr, uint8_t asn); + + // static helper functions... really EV5 VM traits + static bool validVirtualAddress(Addr vaddr) { + // unimplemented bits must be all 0 or all 1 + Addr unimplBits = vaddr & EV5::VAddrUnImplMask; + return (unimplBits == 0) || (unimplBits == EV5::VAddrUnImplMask); + } + + static Fault checkCacheability(RequestPtr &req); + + // Checkpointing + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); +}; + +class AlphaITB : public AlphaTLB +{ + protected: + mutable Stats::Scalar<> hits; + mutable Stats::Scalar<> misses; + mutable Stats::Scalar<> acv; + mutable Stats::Formula accesses; + + public: + AlphaITB(const std::string &name, int size); + virtual void regStats(); + + Fault translate(RequestPtr &req, ThreadContext *tc) const; +}; + +class AlphaDTB : public AlphaTLB +{ + protected: + mutable Stats::Scalar<> read_hits; + mutable Stats::Scalar<> read_misses; + mutable Stats::Scalar<> read_acv; + mutable Stats::Scalar<> read_accesses; + mutable Stats::Scalar<> write_hits; + mutable Stats::Scalar<> write_misses; + mutable Stats::Scalar<> write_acv; + mutable Stats::Scalar<> write_accesses; + Stats::Formula hits; + Stats::Formula misses; + Stats::Formula acv; + Stats::Formula accesses; + + public: + AlphaDTB(const std::string &name, int size); + virtual void regStats(); + + Fault translate(RequestPtr &req, ThreadContext *tc, bool write) const; +}; + +#endif // __ALPHA_MEMORY_HH__ diff --git a/src/arch/alpha/tru64/process.cc b/src/arch/alpha/tru64/process.cc new file mode 100644 index 000000000..82e44b9e7 --- /dev/null +++ b/src/arch/alpha/tru64/process.cc @@ -0,0 +1,589 @@ +/* + * 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 + * Ali Saidi + */ + +#include "arch/alpha/tru64/tru64.hh" +#include "arch/alpha/isa_traits.hh" +#include "arch/alpha/tru64/process.hh" + +#include "cpu/thread_context.hh" +#include "kern/tru64/tru64.hh" + +#include "sim/process.hh" +#include "sim/syscall_emul.hh" + +using namespace std; +using namespace AlphaISA; + +/// Target uname() handler. +static SyscallReturn +unameFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + TypedBufferArg<AlphaTru64::utsname> name(tc->getSyscallArg(0)); + + strcpy(name->sysname, "OSF1"); + strcpy(name->nodename, "m5.eecs.umich.edu"); + strcpy(name->release, "V5.1"); + strcpy(name->version, "732"); + strcpy(name->machine, "alpha"); + + name.copyOut(tc->getMemPort()); + return 0; +} + +/// Target getsysyinfo() handler. +static SyscallReturn +getsysinfoFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + unsigned op = tc->getSyscallArg(0); + unsigned nbytes = tc->getSyscallArg(2); + + switch (op) { + + case AlphaTru64::GSI_MAX_CPU: { + TypedBufferArg<uint32_t> max_cpu(tc->getSyscallArg(1)); + *max_cpu = htog((uint32_t)process->numCpus()); + max_cpu.copyOut(tc->getMemPort()); + return 1; + } + + case AlphaTru64::GSI_CPUS_IN_BOX: { + TypedBufferArg<uint32_t> cpus_in_box(tc->getSyscallArg(1)); + *cpus_in_box = htog((uint32_t)process->numCpus()); + cpus_in_box.copyOut(tc->getMemPort()); + return 1; + } + + case AlphaTru64::GSI_PHYSMEM: { + TypedBufferArg<uint64_t> physmem(tc->getSyscallArg(1)); + *physmem = htog((uint64_t)1024 * 1024); // physical memory in KB + physmem.copyOut(tc->getMemPort()); + return 1; + } + + case AlphaTru64::GSI_CPU_INFO: { + TypedBufferArg<AlphaTru64::cpu_info> infop(tc->getSyscallArg(1)); + + infop->current_cpu = htog(0); + infop->cpus_in_box = htog(process->numCpus()); + infop->cpu_type = htog(57); + infop->ncpus = htog(process->numCpus()); + uint64_t cpumask = (1 << process->numCpus()) - 1; + infop->cpus_present = infop->cpus_running = htog(cpumask); + infop->cpu_binding = htog(0); + infop->cpu_ex_binding = htog(0); + infop->mhz = htog(667); + + infop.copyOut(tc->getMemPort()); + return 1; + } + + case AlphaTru64::GSI_PROC_TYPE: { + TypedBufferArg<uint64_t> proc_type(tc->getSyscallArg(1)); + *proc_type = htog((uint64_t)11); + proc_type.copyOut(tc->getMemPort()); + return 1; + } + + case AlphaTru64::GSI_PLATFORM_NAME: { + BufferArg bufArg(tc->getSyscallArg(1), nbytes); + strncpy((char *)bufArg.bufferPtr(), + "COMPAQ Professional Workstation XP1000", + nbytes); + bufArg.copyOut(tc->getMemPort()); + return 1; + } + + case AlphaTru64::GSI_CLK_TCK: { + TypedBufferArg<uint64_t> clk_hz(tc->getSyscallArg(1)); + *clk_hz = htog((uint64_t)1024); + clk_hz.copyOut(tc->getMemPort()); + return 1; + } + + default: + warn("getsysinfo: unknown op %d\n", op); + break; + } + + return 0; +} + +/// Target setsysyinfo() handler. +static SyscallReturn +setsysinfoFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + unsigned op = tc->getSyscallArg(0); + + switch (op) { + case AlphaTru64::SSI_IEEE_FP_CONTROL: + warn("setsysinfo: ignoring ieee_set_fp_control() arg 0x%x\n", + tc->getSyscallArg(1)); + break; + + default: + warn("setsysinfo: unknown op %d\n", op); + break; + } + + return 0; +} + + +/// Target table() handler. +static +SyscallReturn tableFunc(SyscallDesc *desc, int callnum,Process *process, + ThreadContext *tc) +{ + using namespace std; + using namespace TheISA; + + int id = tc->getSyscallArg(0); // table ID + int index = tc->getSyscallArg(1); // index into table + // arg 2 is buffer pointer; type depends on table ID + int nel = tc->getSyscallArg(3); // number of elements + int lel = tc->getSyscallArg(4); // expected element size + + switch (id) { + case AlphaTru64::TBL_SYSINFO: { + if (index != 0 || nel != 1 || lel != sizeof(Tru64::tbl_sysinfo)) + return -EINVAL; + TypedBufferArg<Tru64::tbl_sysinfo> elp(tc->getSyscallArg(2)); + + const int clk_hz = one_million; + elp->si_user = htog(curTick / (Clock::Frequency / clk_hz)); + elp->si_nice = htog(0); + elp->si_sys = htog(0); + elp->si_idle = htog(0); + elp->wait = htog(0); + elp->si_hz = htog(clk_hz); + elp->si_phz = htog(clk_hz); + elp->si_boottime = htog(seconds_since_epoch); // seconds since epoch? + elp->si_max_procs = htog(process->numCpus()); + elp.copyOut(tc->getMemPort()); + return 0; + } + + default: + cerr << "table(): id " << id << " unknown." << endl; + return -EINVAL; + } +} + +SyscallDesc AlphaTru64Process::syscallDescs[] = { + /* 0 */ SyscallDesc("syscall (#0)", AlphaTru64::indirectSyscallFunc, + SyscallDesc::SuppressReturnValue), + /* 1 */ SyscallDesc("exit", exitFunc), + /* 2 */ SyscallDesc("fork", unimplementedFunc), + /* 3 */ SyscallDesc("read", readFunc), + /* 4 */ SyscallDesc("write", writeFunc), + /* 5 */ SyscallDesc("old_open", unimplementedFunc), + /* 6 */ SyscallDesc("close", closeFunc), + /* 7 */ SyscallDesc("wait4", unimplementedFunc), + /* 8 */ SyscallDesc("old_creat", unimplementedFunc), + /* 9 */ SyscallDesc("link", unimplementedFunc), + /* 10 */ SyscallDesc("unlink", unlinkFunc), + /* 11 */ SyscallDesc("execv", unimplementedFunc), + /* 12 */ SyscallDesc("chdir", unimplementedFunc), + /* 13 */ SyscallDesc("fchdir", unimplementedFunc), + /* 14 */ SyscallDesc("mknod", unimplementedFunc), + /* 15 */ SyscallDesc("chmod", unimplementedFunc), + /* 16 */ SyscallDesc("chown", unimplementedFunc), + /* 17 */ SyscallDesc("obreak", obreakFunc), + /* 18 */ SyscallDesc("pre_F64_getfsstat", unimplementedFunc), + /* 19 */ SyscallDesc("lseek", lseekFunc), + /* 20 */ SyscallDesc("getpid", getpidPseudoFunc), + /* 21 */ SyscallDesc("mount", unimplementedFunc), + /* 22 */ SyscallDesc("unmount", unimplementedFunc), + /* 23 */ SyscallDesc("setuid", setuidFunc), + /* 24 */ SyscallDesc("getuid", getuidPseudoFunc), + /* 25 */ SyscallDesc("exec_with_loader", unimplementedFunc), + /* 26 */ SyscallDesc("ptrace", unimplementedFunc), + /* 27 */ SyscallDesc("recvmsg", unimplementedFunc), + /* 28 */ SyscallDesc("sendmsg", unimplementedFunc), + /* 29 */ SyscallDesc("recvfrom", unimplementedFunc), + /* 30 */ SyscallDesc("accept", unimplementedFunc), + /* 31 */ SyscallDesc("getpeername", unimplementedFunc), + /* 32 */ SyscallDesc("getsockname", unimplementedFunc), + /* 33 */ SyscallDesc("access", unimplementedFunc), + /* 34 */ SyscallDesc("chflags", unimplementedFunc), + /* 35 */ SyscallDesc("fchflags", unimplementedFunc), + /* 36 */ SyscallDesc("sync", unimplementedFunc), + /* 37 */ SyscallDesc("kill", unimplementedFunc), + /* 38 */ SyscallDesc("old_stat", unimplementedFunc), + /* 39 */ SyscallDesc("setpgid", unimplementedFunc), + /* 40 */ SyscallDesc("old_lstat", unimplementedFunc), + /* 41 */ SyscallDesc("dup", unimplementedFunc), + /* 42 */ SyscallDesc("pipe", unimplementedFunc), + /* 43 */ SyscallDesc("set_program_attributes", unimplementedFunc), + /* 44 */ SyscallDesc("profil", unimplementedFunc), + /* 45 */ SyscallDesc("open", openFunc<AlphaTru64>), + /* 46 */ SyscallDesc("obsolete osigaction", unimplementedFunc), + /* 47 */ SyscallDesc("getgid", getgidPseudoFunc), + /* 48 */ SyscallDesc("sigprocmask", ignoreFunc), + /* 49 */ SyscallDesc("getlogin", unimplementedFunc), + /* 50 */ SyscallDesc("setlogin", unimplementedFunc), + /* 51 */ SyscallDesc("acct", unimplementedFunc), + /* 52 */ SyscallDesc("sigpending", unimplementedFunc), + /* 53 */ SyscallDesc("classcntl", unimplementedFunc), + /* 54 */ SyscallDesc("ioctl", ioctlFunc<AlphaTru64>), + /* 55 */ SyscallDesc("reboot", unimplementedFunc), + /* 56 */ SyscallDesc("revoke", unimplementedFunc), + /* 57 */ SyscallDesc("symlink", unimplementedFunc), + /* 58 */ SyscallDesc("readlink", unimplementedFunc), + /* 59 */ SyscallDesc("execve", unimplementedFunc), + /* 60 */ SyscallDesc("umask", unimplementedFunc), + /* 61 */ SyscallDesc("chroot", unimplementedFunc), + /* 62 */ SyscallDesc("old_fstat", unimplementedFunc), + /* 63 */ SyscallDesc("getpgrp", unimplementedFunc), + /* 64 */ SyscallDesc("getpagesize", getpagesizeFunc), + /* 65 */ SyscallDesc("mremap", unimplementedFunc), + /* 66 */ SyscallDesc("vfork", unimplementedFunc), + /* 67 */ SyscallDesc("pre_F64_stat", statFunc<AlphaTru64::PreF64>), + /* 68 */ SyscallDesc("pre_F64_lstat", lstatFunc<AlphaTru64::PreF64>), + /* 69 */ SyscallDesc("sbrk", unimplementedFunc), + /* 70 */ SyscallDesc("sstk", unimplementedFunc), + /* 71 */ SyscallDesc("mmap", mmapFunc<AlphaTru64>), + /* 72 */ SyscallDesc("ovadvise", unimplementedFunc), + /* 73 */ SyscallDesc("munmap", munmapFunc), + /* 74 */ SyscallDesc("mprotect", ignoreFunc), + /* 75 */ SyscallDesc("madvise", unimplementedFunc), + /* 76 */ SyscallDesc("old_vhangup", unimplementedFunc), + /* 77 */ SyscallDesc("kmodcall", unimplementedFunc), + /* 78 */ SyscallDesc("mincore", unimplementedFunc), + /* 79 */ SyscallDesc("getgroups", unimplementedFunc), + /* 80 */ SyscallDesc("setgroups", unimplementedFunc), + /* 81 */ SyscallDesc("old_getpgrp", unimplementedFunc), + /* 82 */ SyscallDesc("setpgrp", unimplementedFunc), + /* 83 */ SyscallDesc("setitimer", unimplementedFunc), + /* 84 */ SyscallDesc("old_wait", unimplementedFunc), + /* 85 */ SyscallDesc("table", tableFunc), + /* 86 */ SyscallDesc("getitimer", unimplementedFunc), + /* 87 */ SyscallDesc("gethostname", gethostnameFunc), + /* 88 */ SyscallDesc("sethostname", unimplementedFunc), + /* 89 */ SyscallDesc("getdtablesize", unimplementedFunc), + /* 90 */ SyscallDesc("dup2", unimplementedFunc), + /* 91 */ SyscallDesc("pre_F64_fstat", fstatFunc<AlphaTru64::PreF64>), + /* 92 */ SyscallDesc("fcntl", fcntlFunc), + /* 93 */ SyscallDesc("select", unimplementedFunc), + /* 94 */ SyscallDesc("poll", unimplementedFunc), + /* 95 */ SyscallDesc("fsync", unimplementedFunc), + /* 96 */ SyscallDesc("setpriority", unimplementedFunc), + /* 97 */ SyscallDesc("socket", unimplementedFunc), + /* 98 */ SyscallDesc("connect", unimplementedFunc), + /* 99 */ SyscallDesc("old_accept", unimplementedFunc), + /* 100 */ SyscallDesc("getpriority", unimplementedFunc), + /* 101 */ SyscallDesc("old_send", unimplementedFunc), + /* 102 */ SyscallDesc("old_recv", unimplementedFunc), + /* 103 */ SyscallDesc("sigreturn", AlphaTru64::sigreturnFunc, + SyscallDesc::SuppressReturnValue), + /* 104 */ SyscallDesc("bind", unimplementedFunc), + /* 105 */ SyscallDesc("setsockopt", unimplementedFunc), + /* 106 */ SyscallDesc("listen", unimplementedFunc), + /* 107 */ SyscallDesc("plock", unimplementedFunc), + /* 108 */ SyscallDesc("old_sigvec", unimplementedFunc), + /* 109 */ SyscallDesc("old_sigblock", unimplementedFunc), + /* 110 */ SyscallDesc("old_sigsetmask", unimplementedFunc), + /* 111 */ SyscallDesc("sigsuspend", unimplementedFunc), + /* 112 */ SyscallDesc("sigstack", ignoreFunc), + /* 113 */ SyscallDesc("old_recvmsg", unimplementedFunc), + /* 114 */ SyscallDesc("old_sendmsg", unimplementedFunc), + /* 115 */ SyscallDesc("obsolete vtrace", unimplementedFunc), + /* 116 */ SyscallDesc("gettimeofday", gettimeofdayFunc<AlphaTru64>), + /* 117 */ SyscallDesc("getrusage", getrusageFunc<AlphaTru64>), + /* 118 */ SyscallDesc("getsockopt", unimplementedFunc), + /* 119 */ SyscallDesc("numa_syscalls", unimplementedFunc), + /* 120 */ SyscallDesc("readv", unimplementedFunc), + /* 121 */ SyscallDesc("writev", unimplementedFunc), + /* 122 */ SyscallDesc("settimeofday", unimplementedFunc), + /* 123 */ SyscallDesc("fchown", unimplementedFunc), + /* 124 */ SyscallDesc("fchmod", unimplementedFunc), + /* 125 */ SyscallDesc("old_recvfrom", unimplementedFunc), + /* 126 */ SyscallDesc("setreuid", unimplementedFunc), + /* 127 */ SyscallDesc("setregid", unimplementedFunc), + /* 128 */ SyscallDesc("rename", renameFunc), + /* 129 */ SyscallDesc("truncate", truncateFunc), + /* 130 */ SyscallDesc("ftruncate", ftruncateFunc), + /* 131 */ SyscallDesc("flock", unimplementedFunc), + /* 132 */ SyscallDesc("setgid", unimplementedFunc), + /* 133 */ SyscallDesc("sendto", unimplementedFunc), + /* 134 */ SyscallDesc("shutdown", unimplementedFunc), + /* 135 */ SyscallDesc("socketpair", unimplementedFunc), + /* 136 */ SyscallDesc("mkdir", unimplementedFunc), + /* 137 */ SyscallDesc("rmdir", unimplementedFunc), + /* 138 */ SyscallDesc("utimes", unimplementedFunc), + /* 139 */ SyscallDesc("obsolete 4.2 sigreturn", unimplementedFunc), + /* 140 */ SyscallDesc("adjtime", unimplementedFunc), + /* 141 */ SyscallDesc("old_getpeername", unimplementedFunc), + /* 142 */ SyscallDesc("gethostid", unimplementedFunc), + /* 143 */ SyscallDesc("sethostid", unimplementedFunc), + /* 144 */ SyscallDesc("getrlimit", getrlimitFunc<AlphaTru64>), + /* 145 */ SyscallDesc("setrlimit", ignoreFunc), + /* 146 */ SyscallDesc("old_killpg", unimplementedFunc), + /* 147 */ SyscallDesc("setsid", unimplementedFunc), + /* 148 */ SyscallDesc("quotactl", unimplementedFunc), + /* 149 */ SyscallDesc("oldquota", unimplementedFunc), + /* 150 */ SyscallDesc("old_getsockname", unimplementedFunc), + /* 151 */ SyscallDesc("pread", unimplementedFunc), + /* 152 */ SyscallDesc("pwrite", unimplementedFunc), + /* 153 */ SyscallDesc("pid_block", unimplementedFunc), + /* 154 */ SyscallDesc("pid_unblock", unimplementedFunc), + /* 155 */ SyscallDesc("signal_urti", unimplementedFunc), + /* 156 */ SyscallDesc("sigaction", ignoreFunc), + /* 157 */ SyscallDesc("sigwaitprim", unimplementedFunc), + /* 158 */ SyscallDesc("nfssvc", unimplementedFunc), + /* 159 */ SyscallDesc("getdirentries", AlphaTru64::getdirentriesFunc), + /* 160 */ SyscallDesc("pre_F64_statfs", statfsFunc<AlphaTru64::PreF64>), + /* 161 */ SyscallDesc("pre_F64_fstatfs", fstatfsFunc<AlphaTru64::PreF64>), + /* 162 */ SyscallDesc("unknown #162", unimplementedFunc), + /* 163 */ SyscallDesc("async_daemon", unimplementedFunc), + /* 164 */ SyscallDesc("getfh", unimplementedFunc), + /* 165 */ SyscallDesc("getdomainname", unimplementedFunc), + /* 166 */ SyscallDesc("setdomainname", unimplementedFunc), + /* 167 */ SyscallDesc("unknown #167", unimplementedFunc), + /* 168 */ SyscallDesc("unknown #168", unimplementedFunc), + /* 169 */ SyscallDesc("exportfs", unimplementedFunc), + /* 170 */ SyscallDesc("unknown #170", unimplementedFunc), + /* 171 */ SyscallDesc("unknown #171", unimplementedFunc), + /* 172 */ SyscallDesc("unknown #172", unimplementedFunc), + /* 173 */ SyscallDesc("unknown #173", unimplementedFunc), + /* 174 */ SyscallDesc("unknown #174", unimplementedFunc), + /* 175 */ SyscallDesc("unknown #175", unimplementedFunc), + /* 176 */ SyscallDesc("unknown #176", unimplementedFunc), + /* 177 */ SyscallDesc("unknown #177", unimplementedFunc), + /* 178 */ SyscallDesc("unknown #178", unimplementedFunc), + /* 179 */ SyscallDesc("unknown #179", unimplementedFunc), + /* 180 */ SyscallDesc("unknown #180", unimplementedFunc), + /* 181 */ SyscallDesc("alt_plock", unimplementedFunc), + /* 182 */ SyscallDesc("unknown #182", unimplementedFunc), + /* 183 */ SyscallDesc("unknown #183", unimplementedFunc), + /* 184 */ SyscallDesc("getmnt", unimplementedFunc), + /* 185 */ SyscallDesc("unknown #185", unimplementedFunc), + /* 186 */ SyscallDesc("unknown #186", unimplementedFunc), + /* 187 */ SyscallDesc("alt_sigpending", unimplementedFunc), + /* 188 */ SyscallDesc("alt_setsid", unimplementedFunc), + /* 189 */ SyscallDesc("unknown #189", unimplementedFunc), + /* 190 */ SyscallDesc("unknown #190", unimplementedFunc), + /* 191 */ SyscallDesc("unknown #191", unimplementedFunc), + /* 192 */ SyscallDesc("unknown #192", unimplementedFunc), + /* 193 */ SyscallDesc("unknown #193", unimplementedFunc), + /* 194 */ SyscallDesc("unknown #194", unimplementedFunc), + /* 195 */ SyscallDesc("unknown #195", unimplementedFunc), + /* 196 */ SyscallDesc("unknown #196", unimplementedFunc), + /* 197 */ SyscallDesc("unknown #197", unimplementedFunc), + /* 198 */ SyscallDesc("unknown #198", unimplementedFunc), + /* 199 */ SyscallDesc("swapon", unimplementedFunc), + /* 200 */ SyscallDesc("msgctl", unimplementedFunc), + /* 201 */ SyscallDesc("msgget", unimplementedFunc), + /* 202 */ SyscallDesc("msgrcv", unimplementedFunc), + /* 203 */ SyscallDesc("msgsnd", unimplementedFunc), + /* 204 */ SyscallDesc("semctl", unimplementedFunc), + /* 205 */ SyscallDesc("semget", unimplementedFunc), + /* 206 */ SyscallDesc("semop", unimplementedFunc), + /* 207 */ SyscallDesc("uname", unameFunc), + /* 208 */ SyscallDesc("lchown", unimplementedFunc), + /* 209 */ SyscallDesc("shmat", unimplementedFunc), + /* 210 */ SyscallDesc("shmctl", unimplementedFunc), + /* 211 */ SyscallDesc("shmdt", unimplementedFunc), + /* 212 */ SyscallDesc("shmget", unimplementedFunc), + /* 213 */ SyscallDesc("mvalid", unimplementedFunc), + /* 214 */ SyscallDesc("getaddressconf", unimplementedFunc), + /* 215 */ SyscallDesc("msleep", unimplementedFunc), + /* 216 */ SyscallDesc("mwakeup", unimplementedFunc), + /* 217 */ SyscallDesc("msync", unimplementedFunc), + /* 218 */ SyscallDesc("signal", unimplementedFunc), + /* 219 */ SyscallDesc("utc_gettime", unimplementedFunc), + /* 220 */ SyscallDesc("utc_adjtime", unimplementedFunc), + /* 221 */ SyscallDesc("unknown #221", unimplementedFunc), + /* 222 */ SyscallDesc("security", unimplementedFunc), + /* 223 */ SyscallDesc("kloadcall", unimplementedFunc), + /* 224 */ SyscallDesc("stat", statFunc<AlphaTru64::F64>), + /* 225 */ SyscallDesc("lstat", lstatFunc<AlphaTru64::F64>), + /* 226 */ SyscallDesc("fstat", fstatFunc<AlphaTru64::F64>), + /* 227 */ SyscallDesc("statfs", statfsFunc<AlphaTru64::F64>), + /* 228 */ SyscallDesc("fstatfs", fstatfsFunc<AlphaTru64::F64>), + /* 229 */ SyscallDesc("getfsstat", unimplementedFunc), + /* 230 */ SyscallDesc("gettimeofday64", unimplementedFunc), + /* 231 */ SyscallDesc("settimeofday64", unimplementedFunc), + /* 232 */ SyscallDesc("unknown #232", unimplementedFunc), + /* 233 */ SyscallDesc("getpgid", unimplementedFunc), + /* 234 */ SyscallDesc("getsid", unimplementedFunc), + /* 235 */ SyscallDesc("sigaltstack", ignoreFunc), + /* 236 */ SyscallDesc("waitid", unimplementedFunc), + /* 237 */ SyscallDesc("priocntlset", unimplementedFunc), + /* 238 */ SyscallDesc("sigsendset", unimplementedFunc), + /* 239 */ SyscallDesc("set_speculative", unimplementedFunc), + /* 240 */ SyscallDesc("msfs_syscall", unimplementedFunc), + /* 241 */ SyscallDesc("sysinfo", unimplementedFunc), + /* 242 */ SyscallDesc("uadmin", unimplementedFunc), + /* 243 */ SyscallDesc("fuser", unimplementedFunc), + /* 244 */ SyscallDesc("proplist_syscall", unimplementedFunc), + /* 245 */ SyscallDesc("ntp_adjtime", unimplementedFunc), + /* 246 */ SyscallDesc("ntp_gettime", unimplementedFunc), + /* 247 */ SyscallDesc("pathconf", unimplementedFunc), + /* 248 */ SyscallDesc("fpathconf", unimplementedFunc), + /* 249 */ SyscallDesc("sync2", unimplementedFunc), + /* 250 */ SyscallDesc("uswitch", unimplementedFunc), + /* 251 */ SyscallDesc("usleep_thread", unimplementedFunc), + /* 252 */ SyscallDesc("audcntl", unimplementedFunc), + /* 253 */ SyscallDesc("audgen", unimplementedFunc), + /* 254 */ SyscallDesc("sysfs", unimplementedFunc), + /* 255 */ SyscallDesc("subsys_info", unimplementedFunc), + /* 256 */ SyscallDesc("getsysinfo", getsysinfoFunc), + /* 257 */ SyscallDesc("setsysinfo", setsysinfoFunc), + /* 258 */ SyscallDesc("afs_syscall", unimplementedFunc), + /* 259 */ SyscallDesc("swapctl", unimplementedFunc), + /* 260 */ SyscallDesc("memcntl", unimplementedFunc), + /* 261 */ SyscallDesc("fdatasync", unimplementedFunc), + /* 262 */ SyscallDesc("oflock", unimplementedFunc), + /* 263 */ SyscallDesc("F64_readv", unimplementedFunc), + /* 264 */ SyscallDesc("F64_writev", unimplementedFunc), + /* 265 */ SyscallDesc("cdslxlate", unimplementedFunc), + /* 266 */ SyscallDesc("sendfile", unimplementedFunc), +}; + + + +SyscallDesc AlphaTru64Process::machSyscallDescs[] = { + /* 0 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 1 */ SyscallDesc("m5_mutex_lock", AlphaTru64::m5_mutex_lockFunc), + /* 2 */ SyscallDesc("m5_mutex_trylock", AlphaTru64::m5_mutex_trylockFunc), + /* 3 */ SyscallDesc("m5_mutex_unlock", AlphaTru64::m5_mutex_unlockFunc), + /* 4 */ SyscallDesc("m5_cond_signal", AlphaTru64::m5_cond_signalFunc), + /* 5 */ SyscallDesc("m5_cond_broadcast", AlphaTru64::m5_cond_broadcastFunc), + /* 6 */ SyscallDesc("m5_cond_wait", AlphaTru64::m5_cond_waitFunc), + /* 7 */ SyscallDesc("m5_thread_exit", AlphaTru64::m5_thread_exitFunc), + /* 8 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 9 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 10 */ SyscallDesc("task_self", unimplementedFunc), + /* 11 */ SyscallDesc("thread_reply", unimplementedFunc), + /* 12 */ SyscallDesc("task_notify", unimplementedFunc), + /* 13 */ SyscallDesc("thread_self", unimplementedFunc), + /* 14 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 15 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 16 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 17 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 18 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 19 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 20 */ SyscallDesc("msg_send_trap", unimplementedFunc), + /* 21 */ SyscallDesc("msg_receive_trap", unimplementedFunc), + /* 22 */ SyscallDesc("msg_rpc_trap", unimplementedFunc), + /* 23 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 24 */ SyscallDesc("nxm_block", AlphaTru64::nxm_blockFunc), + /* 25 */ SyscallDesc("nxm_unblock", AlphaTru64::nxm_unblockFunc), + /* 26 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 27 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 28 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 29 */ SyscallDesc("nxm_thread_destroy", unimplementedFunc), + /* 30 */ SyscallDesc("lw_wire", unimplementedFunc), + /* 31 */ SyscallDesc("lw_unwire", unimplementedFunc), + /* 32 */ SyscallDesc("nxm_thread_create", AlphaTru64::nxm_thread_createFunc), + /* 33 */ SyscallDesc("nxm_task_init", AlphaTru64::nxm_task_initFunc), + /* 34 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 35 */ SyscallDesc("nxm_idle", AlphaTru64::nxm_idleFunc), + /* 36 */ SyscallDesc("nxm_wakeup_idle", unimplementedFunc), + /* 37 */ SyscallDesc("nxm_set_pthid", unimplementedFunc), + /* 38 */ SyscallDesc("nxm_thread_kill", unimplementedFunc), + /* 39 */ SyscallDesc("nxm_thread_block", AlphaTru64::nxm_thread_blockFunc), + /* 40 */ SyscallDesc("nxm_thread_wakeup", unimplementedFunc), + /* 41 */ SyscallDesc("init_process", unimplementedFunc), + /* 42 */ SyscallDesc("nxm_get_binding", unimplementedFunc), + /* 43 */ SyscallDesc("map_fd", unimplementedFunc), + /* 44 */ SyscallDesc("nxm_resched", unimplementedFunc), + /* 45 */ SyscallDesc("nxm_set_cancel", unimplementedFunc), + /* 46 */ SyscallDesc("nxm_set_binding", unimplementedFunc), + /* 47 */ SyscallDesc("stack_create", AlphaTru64::stack_createFunc), + /* 48 */ SyscallDesc("nxm_get_state", unimplementedFunc), + /* 49 */ SyscallDesc("nxm_thread_suspend", unimplementedFunc), + /* 50 */ SyscallDesc("nxm_thread_resume", unimplementedFunc), + /* 51 */ SyscallDesc("nxm_signal_check", unimplementedFunc), + /* 52 */ SyscallDesc("htg_unix_syscall", unimplementedFunc), + /* 53 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 54 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 55 */ SyscallDesc("host_self", unimplementedFunc), + /* 56 */ SyscallDesc("host_priv_self", unimplementedFunc), + /* 57 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 58 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 59 */ SyscallDesc("swtch_pri", AlphaTru64::swtch_priFunc), + /* 60 */ SyscallDesc("swtch", unimplementedFunc), + /* 61 */ SyscallDesc("thread_switch", unimplementedFunc), + /* 62 */ SyscallDesc("semop_fast", unimplementedFunc), + /* 63 */ SyscallDesc("nxm_pshared_init", unimplementedFunc), + /* 64 */ SyscallDesc("nxm_pshared_block", unimplementedFunc), + /* 65 */ SyscallDesc("nxm_pshared_unblock", unimplementedFunc), + /* 66 */ SyscallDesc("nxm_pshared_destroy", unimplementedFunc), + /* 67 */ SyscallDesc("nxm_swtch_pri", AlphaTru64::swtch_priFunc), + /* 68 */ SyscallDesc("lw_syscall", unimplementedFunc), + /* 69 */ SyscallDesc("kern_invalid", unimplementedFunc), + /* 70 */ SyscallDesc("mach_sctimes_0", unimplementedFunc), + /* 71 */ SyscallDesc("mach_sctimes_1", unimplementedFunc), + /* 72 */ SyscallDesc("mach_sctimes_2", unimplementedFunc), + /* 73 */ SyscallDesc("mach_sctimes_3", unimplementedFunc), + /* 74 */ SyscallDesc("mach_sctimes_4", unimplementedFunc), + /* 75 */ SyscallDesc("mach_sctimes_5", unimplementedFunc), + /* 76 */ SyscallDesc("mach_sctimes_6", unimplementedFunc), + /* 77 */ SyscallDesc("mach_sctimes_7", unimplementedFunc), + /* 78 */ SyscallDesc("mach_sctimes_8", unimplementedFunc), + /* 79 */ SyscallDesc("mach_sctimes_9", unimplementedFunc), + /* 80 */ SyscallDesc("mach_sctimes_10", unimplementedFunc), + /* 81 */ SyscallDesc("mach_sctimes_11", unimplementedFunc), + /* 82 */ SyscallDesc("mach_sctimes_port_alloc_dealloc", unimplementedFunc) +}; + +SyscallDesc* +AlphaTru64Process::getDesc(int callnum) +{ + if (callnum < -Num_Mach_Syscall_Descs || callnum > Num_Syscall_Descs) + return NULL; + + if (callnum < 0) + return &machSyscallDescs[-callnum]; + else + return &syscallDescs[callnum]; +} + + +AlphaTru64Process::AlphaTru64Process(const std::string &name, + ObjectFile *objFile, + System *system, + int stdin_fd, + int stdout_fd, + int stderr_fd, + std::vector<std::string> &argv, + std::vector<std::string> &envp) + : AlphaLiveProcess(name, objFile, system, stdin_fd, stdout_fd, + stderr_fd, argv, envp), + Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc)), + Num_Mach_Syscall_Descs(sizeof(machSyscallDescs) / sizeof(SyscallDesc)) +{ +} diff --git a/src/arch/alpha/tru64/process.hh b/src/arch/alpha/tru64/process.hh new file mode 100644 index 000000000..5d91f6ac1 --- /dev/null +++ b/src/arch/alpha/tru64/process.hh @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2003-2004 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 + */ + +#ifndef __ALPHA_TRU64_PROCESS_HH__ +#define __ALPHA_TRU64_PROCESS_HH__ + +#include "arch/alpha/process.hh" + +namespace AlphaISA { +/// A process with emulated Alpha Tru64 syscalls. +class AlphaTru64Process : public AlphaLiveProcess +{ + public: + /// Constructor. + AlphaTru64Process(const std::string &name, + ObjectFile *objFile, + System *system, + int stdin_fd, int stdout_fd, int stderr_fd, + std::vector<std::string> &argv, + std::vector<std::string> &envp); + + /// Array of syscall descriptors, indexed by call number. + static SyscallDesc syscallDescs[]; + + /// Array of mach syscall descriptors, indexed by call number. + static SyscallDesc machSyscallDescs[]; + + const int Num_Syscall_Descs; + const int Num_Mach_Syscall_Descs; + + virtual SyscallDesc* getDesc(int callnum); +}; + +} // namespace AlphaISA + +#endif // __ALPHA_TRU64_PROCESS_HH__ diff --git a/src/arch/alpha/tru64/system.cc b/src/arch/alpha/tru64/system.cc new file mode 100644 index 000000000..6c0edc1ee --- /dev/null +++ b/src/arch/alpha/tru64/system.cc @@ -0,0 +1,146 @@ +/* + * Copyright (c) 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: Nathan Binkert + * Lisa Hsu + */ + +#include "arch/alpha/tru64/system.hh" +#include "arch/isa_traits.hh" +#include "arch/vtophys.hh" +#include "base/loader/symtab.hh" +#include "base/trace.hh" +#include "cpu/base.hh" +#include "cpu/thread_context.hh" +#include "kern/tru64/tru64_events.hh" +#include "kern/system_events.hh" +#include "mem/physical.hh" +#include "mem/port.hh" +#include "sim/builder.hh" + +using namespace std; + +Tru64AlphaSystem::Tru64AlphaSystem(Tru64AlphaSystem::Params *p) + : AlphaSystem(p) +{ + Addr addr = 0; + if (kernelSymtab->findAddress("enable_async_printf", addr)) { + virtPort.write(addr, (uint32_t)0); + } + +#ifdef DEBUG + kernelPanicEvent = addKernelFuncEvent<BreakPCEvent>("panic"); + if (!kernelPanicEvent) + panic("could not find kernel symbol \'panic\'"); +#endif + + badaddrEvent = addKernelFuncEvent<BadAddrEvent>("badaddr"); + if (!badaddrEvent) + panic("could not find kernel symbol \'badaddr\'"); + + skipPowerStateEvent = + addKernelFuncEvent<SkipFuncEvent>("tl_v48_capture_power_state"); + skipScavengeBootEvent = + addKernelFuncEvent<SkipFuncEvent>("pmap_scavenge_boot"); + +#if TRACING_ON + printfEvent = addKernelFuncEvent<PrintfEvent>("printf"); + debugPrintfEvent = addKernelFuncEvent<DebugPrintfEvent>("m5printf"); + debugPrintfrEvent = addKernelFuncEvent<DebugPrintfrEvent>("m5printfr"); + dumpMbufEvent = addKernelFuncEvent<DumpMbufEvent>("m5_dump_mbuf"); +#endif +} + +Tru64AlphaSystem::~Tru64AlphaSystem() +{ +#ifdef DEBUG + delete kernelPanicEvent; +#endif + delete badaddrEvent; + delete skipPowerStateEvent; + delete skipScavengeBootEvent; +#if TRACING_ON + delete printfEvent; + delete debugPrintfEvent; + delete debugPrintfrEvent; + delete dumpMbufEvent; +#endif +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(Tru64AlphaSystem) + + Param<Tick> boot_cpu_frequency; + SimObjectParam<PhysicalMemory *> physmem; + + Param<string> kernel; + Param<string> console; + Param<string> pal; + + Param<string> boot_osflags; + Param<string> readfile; + Param<unsigned int> init_param; + + Param<uint64_t> system_type; + Param<uint64_t> system_rev; + +END_DECLARE_SIM_OBJECT_PARAMS(Tru64AlphaSystem) + +BEGIN_INIT_SIM_OBJECT_PARAMS(Tru64AlphaSystem) + + INIT_PARAM(boot_cpu_frequency, "frequency of the boot cpu"), + INIT_PARAM(physmem, "phsyical memory"), + INIT_PARAM(kernel, "file that contains the kernel code"), + INIT_PARAM(console, "file that contains the console code"), + INIT_PARAM(pal, "file that contains palcode"), + INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot", + "a"), + INIT_PARAM_DFLT(readfile, "file to read startup script from", ""), + INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0), + INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 12), + INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 2<<1) + +END_INIT_SIM_OBJECT_PARAMS(Tru64AlphaSystem) + +CREATE_SIM_OBJECT(Tru64AlphaSystem) +{ + AlphaSystem::Params *p = new AlphaSystem::Params; + p->name = getInstanceName(); + p->boot_cpu_frequency = boot_cpu_frequency; + p->physmem = physmem; + p->kernel_path = kernel; + p->console_path = console; + p->palcode = pal; + p->boot_osflags = boot_osflags; + p->init_param = init_param; + p->readfile = readfile; + p->system_type = system_type; + p->system_rev = system_rev; + + return new Tru64AlphaSystem(p); +} + +REGISTER_SIM_OBJECT("Tru64AlphaSystem", Tru64AlphaSystem) diff --git a/src/arch/alpha/tru64/system.hh b/src/arch/alpha/tru64/system.hh new file mode 100644 index 000000000..947e92f50 --- /dev/null +++ b/src/arch/alpha/tru64/system.hh @@ -0,0 +1,74 @@ +/* + * Copyright (c) 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: Nathan Binkert + * Lisa Hsu + */ + +#ifndef __ARCH_ALPHA_TRU64_SYSTEM_HH__ +#define __ARCH_ALPHA_TRU64_SYSTEM_HH__ + +#include "arch/alpha/system.hh" +#include "arch/isa_traits.hh" +#include "sim/system.hh" + +class ThreadContext; + +class BreakPCEvent; +class BadAddrEvent; +class SkipFuncEvent; +class PrintfEvent; +class DebugPrintfEvent; +class DebugPrintfrEvent; +class DumpMbufEvent; +class AlphaArguments; + +class Tru64AlphaSystem : public AlphaSystem +{ + private: +#ifdef DEBUG + /** Event to halt the simulator if the kernel calls panic() */ + BreakPCEvent *kernelPanicEvent; +#endif + + BadAddrEvent *badaddrEvent; + SkipFuncEvent *skipPowerStateEvent; + SkipFuncEvent *skipScavengeBootEvent; + PrintfEvent *printfEvent; + DebugPrintfEvent *debugPrintfEvent; + DebugPrintfrEvent *debugPrintfrEvent; + DumpMbufEvent *dumpMbufEvent; + + public: + Tru64AlphaSystem(Params *p); + ~Tru64AlphaSystem(); + + static void Printf(AlphaArguments args); + static void DumpMbuf(AlphaArguments args); +}; + +#endif // __ARCH_ALPHA_TRU64_SYSTEM_HH__ diff --git a/src/arch/alpha/tru64/tru64.cc b/src/arch/alpha/tru64/tru64.cc new file mode 100644 index 000000000..56b04846f --- /dev/null +++ b/src/arch/alpha/tru64/tru64.cc @@ -0,0 +1,72 @@ +/* + * Copyright (c) 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: Korey Sewell + */ + +#include "arch/alpha/tru64/tru64.hh" + +// open(2) flags translation table +OpenFlagTransTable AlphaTru64::openFlagTable[] = { +#ifdef _MSC_VER + { AlphaTru64::TGT_O_RDONLY, _O_RDONLY }, + { AlphaTru64::TGT_O_WRONLY, _O_WRONLY }, + { AlphaTru64::TGT_O_RDWR, _O_RDWR }, + { AlphaTru64::TGT_O_APPEND, _O_APPEND }, + { AlphaTru64::TGT_O_CREAT, _O_CREAT }, + { AlphaTru64::TGT_O_TRUNC, _O_TRUNC }, + { AlphaTru64::TGT_O_EXCL, _O_EXCL }, +#ifdef _O_NONBLOCK + { AlphaTru64::TGT_O_NONBLOCK, _O_NONBLOCK }, +#endif +#ifdef _O_NOCTTY + { AlphaTru64::TGT_O_NOCTTY, _O_NOCTTY }, +#endif +#ifdef _O_SYNC + { AlphaTru64::TGT_O_SYNC, _O_SYNC }, +#endif +#else /* !_MSC_VER */ + { AlphaTru64::TGT_O_RDONLY, O_RDONLY }, + { AlphaTru64::TGT_O_WRONLY, O_WRONLY }, + { AlphaTru64::TGT_O_RDWR, O_RDWR }, + { AlphaTru64::TGT_O_APPEND, O_APPEND }, + { AlphaTru64::TGT_O_CREAT, O_CREAT }, + { AlphaTru64::TGT_O_TRUNC, O_TRUNC }, + { AlphaTru64::TGT_O_EXCL, O_EXCL }, + { AlphaTru64::TGT_O_NONBLOCK, O_NONBLOCK }, + { AlphaTru64::TGT_O_NOCTTY, O_NOCTTY }, +#ifdef O_SYNC + { AlphaTru64::TGT_O_SYNC, O_SYNC }, +#endif +#endif /* _MSC_VER */ +}; + +const int AlphaTru64::NUM_OPEN_FLAGS = + (sizeof(AlphaTru64::openFlagTable)/sizeof(AlphaTru64::openFlagTable[0])); + + + diff --git a/src/arch/alpha/tru64/tru64.hh b/src/arch/alpha/tru64/tru64.hh new file mode 100644 index 000000000..f0711b995 --- /dev/null +++ b/src/arch/alpha/tru64/tru64.hh @@ -0,0 +1,129 @@ +/* + * Copyright (c) 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: Korey Sewell + */ + +#ifndef __ALPHA_ALPHA_TRU64_HH +#define __ALPHA_ALPHA_TRU64_HH + +#include "kern/tru64/tru64.hh" + +class AlphaTru64 : public Tru64 +{ + + public: + /// This table maps the target open() flags to the corresponding + /// host open() flags. + static OpenFlagTransTable openFlagTable[]; + + /// Number of entries in openFlagTable[]. + static const int NUM_OPEN_FLAGS; + + //@{ + /// open(2) flag values. + static const int TGT_O_RDONLY = 00000000; //!< O_RDONLY + static const int TGT_O_WRONLY = 00000001; //!< O_WRONLY + static const int TGT_O_RDWR = 00000002; //!< O_RDWR + static const int TGT_O_NONBLOCK = 00000004; //!< O_NONBLOCK + static const int TGT_O_APPEND = 00000010; //!< O_APPEND + static const int TGT_O_CREAT = 00001000; //!< O_CREAT + static const int TGT_O_TRUNC = 00002000; //!< O_TRUNC + static const int TGT_O_EXCL = 00004000; //!< O_EXCL + static const int TGT_O_NOCTTY = 00010000; //!< O_NOCTTY + static const int TGT_O_SYNC = 00040000; //!< O_SYNC + static const int TGT_O_DRD = 00100000; //!< O_DRD + static const int TGT_O_DIRECTIO = 00200000; //!< O_DIRECTIO + static const int TGT_O_CACHE = 00400000; //!< O_CACHE + static const int TGT_O_DSYNC = 02000000; //!< O_DSYNC + static const int TGT_O_RSYNC = 04000000; //!< O_RSYNC + //@} + + /// For mmap(). + static const unsigned TGT_MAP_ANONYMOUS = 0x10; + + //@{ + /// For getsysinfo(). + static const unsigned GSI_PLATFORM_NAME = 103; //!< platform name as string + static const unsigned GSI_CPU_INFO = 59; //!< CPU information + static const unsigned GSI_PROC_TYPE = 60; //!< get proc_type + static const unsigned GSI_MAX_CPU = 30; //!< max # cpu's on this machine + static const unsigned GSI_CPUS_IN_BOX = 55; //!< number of CPUs in system + static const unsigned GSI_PHYSMEM = 19; //!< Physical memory in KB + static const unsigned GSI_CLK_TCK = 42; //!< clock freq in Hz + //@} + + //@{ + /// For getrusage(). + static const int TGT_RUSAGE_THREAD = 1; + static const int TGT_RUSAGE_SELF = 0; + static const int TGT_RUSAGE_CHILDREN = -1; + //@} + + //@{ + /// For setsysinfo(). + static const unsigned SSI_IEEE_FP_CONTROL = 14; //!< ieee_set_fp_control() + //@} + + //@{ + /// ioctl() command codes. + static const unsigned TIOCGETP = 0x40067408; + static const unsigned TIOCSETP = 0x80067409; + static const unsigned TIOCSETN = 0x8006740a; + static const unsigned TIOCSETC = 0x80067411; + static const unsigned TIOCGETC = 0x40067412; + static const unsigned FIONREAD = 0x4004667f; + static const unsigned TIOCISATTY = 0x2000745e; + static const unsigned TIOCGETS = 0x402c7413; + static const unsigned TIOCGETA = 0x40127417; + //@} + + //@{ + /// For table(). + static const int TBL_SYSINFO = 12; + //@} + + /// Resource enumeration for getrlimit(). + enum rlimit_resources { + TGT_RLIMIT_CPU = 0, + TGT_RLIMIT_FSIZE = 1, + TGT_RLIMIT_DATA = 2, + TGT_RLIMIT_STACK = 3, + TGT_RLIMIT_CORE = 4, + TGT_RLIMIT_RSS = 5, + TGT_RLIMIT_NOFILE = 6, + TGT_RLIMIT_AS = 7, + TGT_RLIMIT_VMEM = 7, + TGT_RLIMIT_NPROC = 8, + TGT_RLIMIT_MEMLOCK = 9, + TGT_RLIMIT_LOCKS = 10 + }; +}; + + + +#endif diff --git a/src/arch/alpha/types.hh b/src/arch/alpha/types.hh new file mode 100644 index 000000000..5859052e9 --- /dev/null +++ b/src/arch/alpha/types.hh @@ -0,0 +1,67 @@ +/* + * Copyright (c) 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: Nathan Binkert + * Steve Reinhardt + */ + +#ifndef __ARCH_ALPHA_TYPES_HH__ +#define __ARCH_ALPHA_TYPES_HH__ + +#include "sim/host.hh" + +namespace AlphaISA +{ + + typedef uint32_t MachInst; + typedef uint64_t ExtMachInst; + typedef uint8_t RegIndex; + + typedef uint64_t IntReg; + + // floating point register file entry type + typedef double FloatReg; + typedef uint64_t FloatRegBits; + + // control register file contents + typedef uint64_t MiscReg; + + typedef union { + IntReg intreg; + FloatReg fpreg; + MiscReg ctrlreg; + } AnyReg; + + enum annotes { + ANNOTE_NONE = 0, + // An impossible number for instruction annotations + ITOUCH_ANNOTE = 0xffffffff, + }; + +} // namespace AlphaISA + +#endif diff --git a/src/arch/alpha/utility.hh b/src/arch/alpha/utility.hh new file mode 100644 index 000000000..ec136091c --- /dev/null +++ b/src/arch/alpha/utility.hh @@ -0,0 +1,159 @@ +/* + * Copyright (c) 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: Nathan Binkert + * Steve Reinhardt + */ + +#ifndef __ARCH_ALPHA_UTILITY_HH__ +#define __ARCH_ALPHA_UTILITY_HH__ + +#include "config/full_system.hh" +#include "arch/alpha/types.hh" +#include "arch/alpha/constants.hh" +#include "arch/alpha/regfile.hh" +#include "base/misc.hh" + +namespace AlphaISA +{ + + static inline ExtMachInst + makeExtMI(MachInst inst, const uint64_t &pc) { +#if FULL_SYSTEM + ExtMachInst ext_inst = inst; + if (pc && 0x1) + return ext_inst|=(static_cast<ExtMachInst>(pc & 0x1) << 32); + else + return ext_inst; +#else + return ExtMachInst(inst); +#endif + } + + inline bool isCallerSaveIntegerRegister(unsigned int reg) { + panic("register classification not implemented"); + return (reg >= 1 && reg <= 8 || reg >= 22 && reg <= 25 || reg == 27); + } + + inline bool isCalleeSaveIntegerRegister(unsigned int reg) { + panic("register classification not implemented"); + return (reg >= 9 && reg <= 15); + } + + inline bool isCallerSaveFloatRegister(unsigned int reg) { + panic("register classification not implemented"); + return false; + } + + inline bool isCalleeSaveFloatRegister(unsigned int reg) { + panic("register classification not implemented"); + return false; + } + + inline Addr alignAddress(const Addr &addr, + unsigned int nbytes) { + return (addr & ~(nbytes - 1)); + } + + // Instruction address compression hooks + inline Addr realPCToFetchPC(const Addr &addr) { + return addr; + } + + inline Addr fetchPCToRealPC(const Addr &addr) { + return addr; + } + + // the size of "fetched" instructions (not necessarily the size + // of real instructions for PISA) + inline size_t fetchInstSize() { + return sizeof(MachInst); + } + + inline MachInst makeRegisterCopy(int dest, int src) { + panic("makeRegisterCopy not implemented"); + return 0; + } + + // Machine operations + + void saveMachineReg(AnyReg &savereg, const RegFile ®_file, + int regnum); + + void restoreMachineReg(RegFile ®s, const AnyReg ®, + int regnum); + + /** + * Function to insure ISA semantics about 0 registers. + * @param tc The thread context. + */ + template <class TC> + void zeroRegisters(TC *tc); + +#if FULL_SYSTEM + // Alpha IPR register accessors + inline bool PcPAL(Addr addr) { return addr & 0x1; } + + //////////////////////////////////////////////////////////////////////// + // + // Translation stuff + // + + inline Addr PteAddr(Addr a) { return (a & PteMask) << PteShift; } + + // User Virtual + inline bool IsUSeg(Addr a) { return USegBase <= a && a <= USegEnd; } + + // Kernel Direct Mapped + inline bool IsK0Seg(Addr a) { return K0SegBase <= a && a <= K0SegEnd; } + inline Addr K0Seg2Phys(Addr addr) { return addr & ~K0SegBase; } + + // Kernel Virtual + inline bool IsK1Seg(Addr a) { return K1SegBase <= a && a <= K1SegEnd; } + + inline Addr + TruncPage(Addr addr) + { return addr & ~(PageBytes - 1); } + + inline Addr + RoundPage(Addr addr) + { return (addr + PageBytes - 1) & ~(PageBytes - 1); } + + void initCPU(ThreadContext *tc, int cpuId); + void initIPRs(ThreadContext *tc, int cpuId); + + /** + * Function to check for and process any interrupts. + * @param tc The thread context. + */ + template <class TC> + void processInterrupts(TC *tc); +#endif + +} // namespace AlphaISA + +#endif diff --git a/src/arch/alpha/vtophys.cc b/src/arch/alpha/vtophys.cc new file mode 100644 index 000000000..f7fd92c15 --- /dev/null +++ b/src/arch/alpha/vtophys.cc @@ -0,0 +1,166 @@ +/* + * 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 + * Steve Reinhardt + * Ali Saidi + */ + +#include <string> + +#include "arch/alpha/ev5.hh" +#include "arch/alpha/vtophys.hh" +#include "base/chunk_generator.hh" +#include "base/trace.hh" +#include "cpu/thread_context.hh" +#include "mem/vport.hh" + +using namespace std; +using namespace AlphaISA; + +AlphaISA::PageTableEntry +AlphaISA::kernel_pte_lookup(FunctionalPort *mem, Addr ptbr, AlphaISA::VAddr vaddr) +{ + Addr level1_pte = ptbr + vaddr.level1(); + AlphaISA::PageTableEntry level1 = mem->read<uint64_t>(level1_pte); + if (!level1.valid()) { + DPRINTF(VtoPhys, "level 1 PTE not valid, va = %#\n", vaddr); + return 0; + } + + Addr level2_pte = level1.paddr() + vaddr.level2(); + AlphaISA::PageTableEntry level2 = mem->read<uint64_t>(level2_pte); + if (!level2.valid()) { + DPRINTF(VtoPhys, "level 2 PTE not valid, va = %#x\n", vaddr); + return 0; + } + + Addr level3_pte = level2.paddr() + vaddr.level3(); + AlphaISA::PageTableEntry level3 = mem->read<uint64_t>(level3_pte); + if (!level3.valid()) { + DPRINTF(VtoPhys, "level 3 PTE not valid, va = %#x\n", vaddr); + return 0; + } + return level3; +} + +Addr +AlphaISA::vtophys(Addr vaddr) +{ + Addr paddr = 0; + if (AlphaISA::IsUSeg(vaddr)) + DPRINTF(VtoPhys, "vtophys: invalid vaddr %#x", vaddr); + else if (AlphaISA::IsK0Seg(vaddr)) + paddr = AlphaISA::K0Seg2Phys(vaddr); + else + panic("vtophys: ptbr is not set on virtual lookup"); + + DPRINTF(VtoPhys, "vtophys(%#x) -> %#x\n", vaddr, paddr); + + return paddr; +} + +Addr +AlphaISA::vtophys(ThreadContext *tc, Addr addr) +{ + AlphaISA::VAddr vaddr = addr; + Addr ptbr = tc->readMiscReg(AlphaISA::IPR_PALtemp20); + Addr paddr = 0; + //@todo Andrew couldn't remember why he commented some of this code + //so I put it back in. Perhaps something to do with gdb debugging? + if (AlphaISA::PcPAL(vaddr) && (vaddr < EV5::PalMax)) { + paddr = vaddr & ~ULL(1); + } else { + if (AlphaISA::IsK0Seg(vaddr)) { + paddr = AlphaISA::K0Seg2Phys(vaddr); + } else if (!ptbr) { + paddr = vaddr; + } else { + AlphaISA::PageTableEntry pte = + kernel_pte_lookup(tc->getPhysPort(), ptbr, vaddr); + if (pte.valid()) + paddr = pte.paddr() | vaddr.offset(); + } + } + + + DPRINTF(VtoPhys, "vtophys(%#x) -> %#x\n", vaddr, paddr); + + return paddr; +} + + +void +AlphaISA::CopyOut(ThreadContext *tc, void *dest, Addr src, size_t cplen) +{ + uint8_t *dst = (uint8_t *)dest; + VirtualPort *vp = tc->getVirtPort(tc); + + vp->readBlob(src, dst, cplen); + + tc->delVirtPort(vp); + +} + +void +AlphaISA::CopyIn(ThreadContext *tc, Addr dest, void *source, size_t cplen) +{ + uint8_t *src = (uint8_t *)source; + VirtualPort *vp = tc->getVirtPort(tc); + + vp->writeBlob(dest, src, cplen); + + tc->delVirtPort(vp); +} + +void +AlphaISA::CopyStringOut(ThreadContext *tc, char *dst, Addr vaddr, size_t maxlen) +{ + int len = 0; + VirtualPort *vp = tc->getVirtPort(tc); + + do { + vp->readBlob(vaddr++, (uint8_t*)dst++, 1); + len++; + } while (len < maxlen && dst[len] != 0 ); + + tc->delVirtPort(vp); + dst[len] = 0; +} + +void +AlphaISA::CopyStringIn(ThreadContext *tc, char *src, Addr vaddr) +{ + VirtualPort *vp = tc->getVirtPort(tc); + for (ChunkGenerator gen(vaddr, strlen(src), AlphaISA::PageBytes); !gen.done(); + gen.next()) + { + vp->writeBlob(gen.addr(), (uint8_t*)src, gen.size()); + src += gen.size(); + } + tc->delVirtPort(vp); +} diff --git a/src/arch/alpha/vtophys.hh b/src/arch/alpha/vtophys.hh new file mode 100644 index 000000000..472c694ff --- /dev/null +++ b/src/arch/alpha/vtophys.hh @@ -0,0 +1,55 @@ +/* + * 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 + * Steve Reinhardt + */ + +#ifndef __ARCH_ALPHA_VTOPHYS_H__ +#define __ARCH_ALPHA_VTOPHYS_H__ + +#include "arch/alpha/isa_traits.hh" + +class ThreadContext; +class FunctionalPort; + +namespace AlphaISA { + +PageTableEntry +kernel_pte_lookup(FunctionalPort *mem, Addr ptbr, AlphaISA::VAddr vaddr); + +Addr vtophys(Addr vaddr); +Addr vtophys(ThreadContext *tc, Addr vaddr); + +void CopyOut(ThreadContext *tc, void *dst, Addr src, size_t len); +void CopyIn(ThreadContext *tc, Addr dst, void *src, size_t len); +void CopyStringOut(ThreadContext *tc, char *dst, Addr vaddr, size_t maxlen); +void CopyStringIn(ThreadContext *tc, char *src, Addr vaddr); + +}; +#endif // __ARCH_ALPHA_VTOPHYS_H__ + diff --git a/src/arch/isa_parser.py b/src/arch/isa_parser.py new file mode 100755 index 000000000..4d522e18a --- /dev/null +++ b/src/arch/isa_parser.py @@ -0,0 +1,1818 @@ +# Copyright (c) 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 Reinhardt +# Korey Sewell + +import os +import sys +import re +import string +import traceback +# get type names +from types import * + +# Prepend the directory where the PLY lex & yacc modules are found +# to the search path. Assumes we're compiling in a subdirectory +# of 'build' in the current tree. +sys.path[0:0] = [os.environ['M5_PLY']] + +import lex +import yacc + +##################################################################### +# +# Lexer +# +# The PLY lexer module takes two things as input: +# - A list of token names (the string list 'tokens') +# - A regular expression describing a match for each token. The +# regexp for token FOO can be provided in two ways: +# - as a string variable named t_FOO +# - as the doc string for a function named t_FOO. In this case, +# the function is also executed, allowing an action to be +# associated with each token match. +# +##################################################################### + +# Reserved words. These are listed separately as they are matched +# using the same regexp as generic IDs, but distinguished in the +# t_ID() function. The PLY documentation suggests this approach. +reserved = ( + 'BITFIELD', 'DECODE', 'DECODER', 'DEFAULT', 'DEF', 'EXEC', 'FORMAT', + 'HEADER', 'LET', 'NAMESPACE', 'OPERAND_TYPES', 'OPERANDS', + 'OUTPUT', 'SIGNED', 'TEMPLATE' + ) + +# List of tokens. The lex module requires this. +tokens = reserved + ( + # identifier + 'ID', + + # integer literal + 'INTLIT', + + # string literal + 'STRLIT', + + # code literal + 'CODELIT', + + # ( ) [ ] { } < > , ; : :: * + 'LPAREN', 'RPAREN', + 'LBRACKET', 'RBRACKET', + 'LBRACE', 'RBRACE', + 'LESS', 'GREATER', 'EQUALS', + 'COMMA', 'SEMI', 'COLON', 'DBLCOLON', + 'ASTERISK', + + # C preprocessor directives + 'CPPDIRECTIVE' + +# The following are matched but never returned. commented out to +# suppress PLY warning + # newfile directive +# 'NEWFILE', + + # endfile directive +# 'ENDFILE' +) + +# Regular expressions for token matching +t_LPAREN = r'\(' +t_RPAREN = r'\)' +t_LBRACKET = r'\[' +t_RBRACKET = r'\]' +t_LBRACE = r'\{' +t_RBRACE = r'\}' +t_LESS = r'\<' +t_GREATER = r'\>' +t_EQUALS = r'=' +t_COMMA = r',' +t_SEMI = r';' +t_COLON = r':' +t_DBLCOLON = r'::' +t_ASTERISK = r'\*' + +# Identifiers and reserved words +reserved_map = { } +for r in reserved: + reserved_map[r.lower()] = r + +def t_ID(t): + r'[A-Za-z_]\w*' + t.type = reserved_map.get(t.value,'ID') + return t + +# Integer literal +def t_INTLIT(t): + r'(0x[\da-fA-F]+)|\d+' + try: + t.value = int(t.value,0) + except ValueError: + error(t.lineno, 'Integer value "%s" too large' % t.value) + t.value = 0 + return t + +# String literal. Note that these use only single quotes, and +# can span multiple lines. +def t_STRLIT(t): + r"(?m)'([^'])+'" + # strip off quotes + t.value = t.value[1:-1] + t.lineno += t.value.count('\n') + return t + + +# "Code literal"... like a string literal, but delimiters are +# '{{' and '}}' so they get formatted nicely under emacs c-mode +def t_CODELIT(t): + r"(?m)\{\{([^\}]|}(?!\}))+\}\}" + # strip off {{ & }} + t.value = t.value[2:-2] + t.lineno += t.value.count('\n') + return t + +def t_CPPDIRECTIVE(t): + r'^\#[^\#].*\n' + t.lineno += t.value.count('\n') + return t + +def t_NEWFILE(t): + r'^\#\#newfile\s+"[\w/.-]*"' + fileNameStack.push((t.value[11:-1], t.lineno)) + t.lineno = 0 + +def t_ENDFILE(t): + r'^\#\#endfile' + (old_filename, t.lineno) = fileNameStack.pop() + +# +# The functions t_NEWLINE, t_ignore, and t_error are +# special for the lex module. +# + +# Newlines +def t_NEWLINE(t): + r'\n+' + t.lineno += t.value.count('\n') + +# Comments +def t_comment(t): + r'//.*' + +# Completely ignored characters +t_ignore = ' \t\x0c' + +# Error handler +def t_error(t): + error(t.lineno, "illegal character '%s'" % t.value[0]) + t.skip(1) + +# Build the lexer +lex.lex() + +##################################################################### +# +# Parser +# +# Every function whose name starts with 'p_' defines a grammar rule. +# The rule is encoded in the function's doc string, while the +# function body provides the action taken when the rule is matched. +# The argument to each function is a list of the values of the +# rule's symbols: t[0] for the LHS, and t[1..n] for the symbols +# on the RHS. For tokens, the value is copied from the t.value +# attribute provided by the lexer. For non-terminals, the value +# is assigned by the producing rule; i.e., the job of the grammar +# rule function is to set the value for the non-terminal on the LHS +# (by assigning to t[0]). +##################################################################### + +# The LHS of the first grammar rule is used as the start symbol +# (in this case, 'specification'). Note that this rule enforces +# that there will be exactly one namespace declaration, with 0 or more +# global defs/decls before and after it. The defs & decls before +# the namespace decl will be outside the namespace; those after +# will be inside. The decoder function is always inside the namespace. +def p_specification(t): + 'specification : opt_defs_and_outputs name_decl opt_defs_and_outputs decode_block' + global_code = t[1] + isa_name = t[2] + namespace = isa_name + "Inst" + # wrap the decode block as a function definition + t[4].wrap_decode_block(''' +StaticInstPtr +%(isa_name)s::decodeInst(%(isa_name)s::ExtMachInst machInst) +{ + using namespace %(namespace)s; +''' % vars(), '}') + # both the latter output blocks and the decode block are in the namespace + namespace_code = t[3] + t[4] + # pass it all back to the caller of yacc.parse() + t[0] = (isa_name, namespace, global_code, namespace_code) + +# ISA name declaration looks like "namespace <foo>;" +def p_name_decl(t): + 'name_decl : NAMESPACE ID SEMI' + t[0] = t[2] + +# 'opt_defs_and_outputs' is a possibly empty sequence of +# def and/or output statements. +def p_opt_defs_and_outputs_0(t): + 'opt_defs_and_outputs : empty' + t[0] = GenCode() + +def p_opt_defs_and_outputs_1(t): + 'opt_defs_and_outputs : defs_and_outputs' + t[0] = t[1] + +def p_defs_and_outputs_0(t): + 'defs_and_outputs : def_or_output' + t[0] = t[1] + +def p_defs_and_outputs_1(t): + 'defs_and_outputs : defs_and_outputs def_or_output' + t[0] = t[1] + t[2] + +# The list of possible definition/output statements. +def p_def_or_output(t): + '''def_or_output : def_format + | def_bitfield + | def_template + | def_operand_types + | def_operands + | output_header + | output_decoder + | output_exec + | global_let''' + t[0] = t[1] + +# Output blocks 'output <foo> {{...}}' (C++ code blocks) are copied +# directly to the appropriate output section. + + +# Protect any non-dict-substitution '%'s in a format string +# (i.e. those not followed by '(') +def protect_non_subst_percents(s): + return re.sub(r'%(?!\()', '%%', s) + +# Massage output block by substituting in template definitions and bit +# operators. We handle '%'s embedded in the string that don't +# indicate template substitutions (or CPU-specific symbols, which get +# handled in GenCode) by doubling them first so that the format +# operation will reduce them back to single '%'s. +def process_output(s): + s = protect_non_subst_percents(s) + # protects cpu-specific symbols too + s = protect_cpu_symbols(s) + return substBitOps(s % templateMap) + +def p_output_header(t): + 'output_header : OUTPUT HEADER CODELIT SEMI' + t[0] = GenCode(header_output = process_output(t[3])) + +def p_output_decoder(t): + 'output_decoder : OUTPUT DECODER CODELIT SEMI' + t[0] = GenCode(decoder_output = process_output(t[3])) + +def p_output_exec(t): + 'output_exec : OUTPUT EXEC CODELIT SEMI' + t[0] = GenCode(exec_output = process_output(t[3])) + +# global let blocks 'let {{...}}' (Python code blocks) are executed +# directly when seen. Note that these execute in a special variable +# context 'exportContext' to prevent the code from polluting this +# script's namespace. +def p_global_let(t): + 'global_let : LET CODELIT SEMI' + updateExportContext() + try: + exec fixPythonIndentation(t[2]) in exportContext + except Exception, exc: + error(t.lineno(1), + 'error: %s in global let block "%s".' % (exc, t[2])) + t[0] = GenCode() # contributes nothing to the output C++ file + +# Define the mapping from operand type extensions to C++ types and bit +# widths (stored in operandTypeMap). +def p_def_operand_types(t): + 'def_operand_types : DEF OPERAND_TYPES CODELIT SEMI' + try: + userDict = eval('{' + t[3] + '}') + except Exception, exc: + error(t.lineno(1), + 'error: %s in def operand_types block "%s".' % (exc, t[3])) + buildOperandTypeMap(userDict, t.lineno(1)) + t[0] = GenCode() # contributes nothing to the output C++ file + +# Define the mapping from operand names to operand classes and other +# traits. Stored in operandNameMap. +def p_def_operands(t): + 'def_operands : DEF OPERANDS CODELIT SEMI' + if not globals().has_key('operandTypeMap'): + error(t.lineno(1), + 'error: operand types must be defined before operands') + try: + userDict = eval('{' + t[3] + '}') + except Exception, exc: + error(t.lineno(1), + 'error: %s in def operands block "%s".' % (exc, t[3])) + buildOperandNameMap(userDict, t.lineno(1)) + t[0] = GenCode() # contributes nothing to the output C++ file + +# A bitfield definition looks like: +# 'def [signed] bitfield <ID> [<first>:<last>]' +# This generates a preprocessor macro in the output file. +def p_def_bitfield_0(t): + 'def_bitfield : DEF opt_signed BITFIELD ID LESS INTLIT COLON INTLIT GREATER SEMI' + expr = 'bits(machInst, %2d, %2d)' % (t[6], t[8]) + if (t[2] == 'signed'): + expr = 'sext<%d>(%s)' % (t[6] - t[8] + 1, expr) + hash_define = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr) + t[0] = GenCode(header_output = hash_define) + +# alternate form for single bit: 'def [signed] bitfield <ID> [<bit>]' +def p_def_bitfield_1(t): + 'def_bitfield : DEF opt_signed BITFIELD ID LESS INTLIT GREATER SEMI' + expr = 'bits(machInst, %2d, %2d)' % (t[6], t[6]) + if (t[2] == 'signed'): + expr = 'sext<%d>(%s)' % (1, expr) + hash_define = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr) + t[0] = GenCode(header_output = hash_define) + +def p_opt_signed_0(t): + 'opt_signed : SIGNED' + t[0] = t[1] + +def p_opt_signed_1(t): + 'opt_signed : empty' + t[0] = '' + +# Global map variable to hold templates +templateMap = {} + +def p_def_template(t): + 'def_template : DEF TEMPLATE ID CODELIT SEMI' + templateMap[t[3]] = Template(t[4]) + t[0] = GenCode() + +# An instruction format definition looks like +# "def format <fmt>(<params>) {{...}};" +def p_def_format(t): + 'def_format : DEF FORMAT ID LPAREN param_list RPAREN CODELIT SEMI' + (id, params, code) = (t[3], t[5], t[7]) + defFormat(id, params, code, t.lineno(1)) + t[0] = GenCode() + +# The formal parameter list for an instruction format is a possibly +# empty list of comma-separated parameters. Positional (standard, +# non-keyword) parameters must come first, followed by keyword +# parameters, followed by a '*foo' parameter that gets excess +# positional arguments (as in Python). Each of these three parameter +# categories is optional. +# +# Note that we do not support the '**foo' parameter for collecting +# otherwise undefined keyword args. Otherwise the parameter list is +# (I believe) identical to what is supported in Python. +# +# The param list generates a tuple, where the first element is a list of +# the positional params and the second element is a dict containing the +# keyword params. +def p_param_list_0(t): + 'param_list : positional_param_list COMMA nonpositional_param_list' + t[0] = t[1] + t[3] + +def p_param_list_1(t): + '''param_list : positional_param_list + | nonpositional_param_list''' + t[0] = t[1] + +def p_positional_param_list_0(t): + 'positional_param_list : empty' + t[0] = [] + +def p_positional_param_list_1(t): + 'positional_param_list : ID' + t[0] = [t[1]] + +def p_positional_param_list_2(t): + 'positional_param_list : positional_param_list COMMA ID' + t[0] = t[1] + [t[3]] + +def p_nonpositional_param_list_0(t): + 'nonpositional_param_list : keyword_param_list COMMA excess_args_param' + t[0] = t[1] + t[3] + +def p_nonpositional_param_list_1(t): + '''nonpositional_param_list : keyword_param_list + | excess_args_param''' + t[0] = t[1] + +def p_keyword_param_list_0(t): + 'keyword_param_list : keyword_param' + t[0] = [t[1]] + +def p_keyword_param_list_1(t): + 'keyword_param_list : keyword_param_list COMMA keyword_param' + t[0] = t[1] + [t[3]] + +def p_keyword_param(t): + 'keyword_param : ID EQUALS expr' + t[0] = t[1] + ' = ' + t[3].__repr__() + +def p_excess_args_param(t): + 'excess_args_param : ASTERISK ID' + # Just concatenate them: '*ID'. Wrap in list to be consistent + # with positional_param_list and keyword_param_list. + t[0] = [t[1] + t[2]] + +# End of format definition-related rules. +############## + +# +# A decode block looks like: +# decode <field1> [, <field2>]* [default <inst>] { ... } +# +def p_decode_block(t): + 'decode_block : DECODE ID opt_default LBRACE decode_stmt_list RBRACE' + default_defaults = defaultStack.pop() + codeObj = t[5] + # use the "default defaults" only if there was no explicit + # default statement in decode_stmt_list + if not codeObj.has_decode_default: + codeObj += default_defaults + codeObj.wrap_decode_block('switch (%s) {\n' % t[2], '}\n') + t[0] = codeObj + +# The opt_default statement serves only to push the "default defaults" +# onto defaultStack. This value will be used by nested decode blocks, +# and used and popped off when the current decode_block is processed +# (in p_decode_block() above). +def p_opt_default_0(t): + 'opt_default : empty' + # no default specified: reuse the one currently at the top of the stack + defaultStack.push(defaultStack.top()) + # no meaningful value returned + t[0] = None + +def p_opt_default_1(t): + 'opt_default : DEFAULT inst' + # push the new default + codeObj = t[2] + codeObj.wrap_decode_block('\ndefault:\n', 'break;\n') + defaultStack.push(codeObj) + # no meaningful value returned + t[0] = None + +def p_decode_stmt_list_0(t): + 'decode_stmt_list : decode_stmt' + t[0] = t[1] + +def p_decode_stmt_list_1(t): + 'decode_stmt_list : decode_stmt decode_stmt_list' + if (t[1].has_decode_default and t[2].has_decode_default): + error(t.lineno(1), 'Two default cases in decode block') + t[0] = t[1] + t[2] + +# +# Decode statement rules +# +# There are four types of statements allowed in a decode block: +# 1. Format blocks 'format <foo> { ... }' +# 2. Nested decode blocks +# 3. Instruction definitions. +# 4. C preprocessor directives. + + +# Preprocessor directives found in a decode statement list are passed +# through to the output, replicated to all of the output code +# streams. This works well for ifdefs, so we can ifdef out both the +# declarations and the decode cases generated by an instruction +# definition. Handling them as part of the grammar makes it easy to +# keep them in the right place with respect to the code generated by +# the other statements. +def p_decode_stmt_cpp(t): + 'decode_stmt : CPPDIRECTIVE' + t[0] = GenCode(t[1], t[1], t[1], t[1]) + +# A format block 'format <foo> { ... }' sets the default instruction +# format used to handle instruction definitions inside the block. +# This format can be overridden by using an explicit format on the +# instruction definition or with a nested format block. +def p_decode_stmt_format(t): + 'decode_stmt : FORMAT push_format_id LBRACE decode_stmt_list RBRACE' + # The format will be pushed on the stack when 'push_format_id' is + # processed (see below). Once the parser has recognized the full + # production (though the right brace), we're done with the format, + # so now we can pop it. + formatStack.pop() + t[0] = t[4] + +# This rule exists so we can set the current format (& push the stack) +# when we recognize the format name part of the format block. +def p_push_format_id(t): + 'push_format_id : ID' + try: + formatStack.push(formatMap[t[1]]) + t[0] = ('', '// format %s' % t[1]) + except KeyError: + error(t.lineno(1), 'instruction format "%s" not defined.' % t[1]) + +# Nested decode block: if the value of the current field matches the +# specified constant, do a nested decode on some other field. +def p_decode_stmt_decode(t): + 'decode_stmt : case_label COLON decode_block' + label = t[1] + codeObj = t[3] + # just wrap the decoding code from the block as a case in the + # outer switch statement. + codeObj.wrap_decode_block('\n%s:\n' % label) + codeObj.has_decode_default = (label == 'default') + t[0] = codeObj + +# Instruction definition (finally!). +def p_decode_stmt_inst(t): + 'decode_stmt : case_label COLON inst SEMI' + label = t[1] + codeObj = t[3] + codeObj.wrap_decode_block('\n%s:' % label, 'break;\n') + codeObj.has_decode_default = (label == 'default') + t[0] = codeObj + +# The case label is either a list of one or more constants or 'default' +def p_case_label_0(t): + 'case_label : intlit_list' + t[0] = ': '.join(map(lambda a: 'case %#x' % a, t[1])) + +def p_case_label_1(t): + 'case_label : DEFAULT' + t[0] = 'default' + +# +# The constant list for a decode case label must be non-empty, but may have +# one or more comma-separated integer literals in it. +# +def p_intlit_list_0(t): + 'intlit_list : INTLIT' + t[0] = [t[1]] + +def p_intlit_list_1(t): + 'intlit_list : intlit_list COMMA INTLIT' + t[0] = t[1] + t[0].append(t[3]) + +# Define an instruction using the current instruction format (specified +# by an enclosing format block). +# "<mnemonic>(<args>)" +def p_inst_0(t): + 'inst : ID LPAREN arg_list RPAREN' + # Pass the ID and arg list to the current format class to deal with. + currentFormat = formatStack.top() + codeObj = currentFormat.defineInst(t[1], t[3], t.lineno(1)) + args = ','.join(map(str, t[3])) + args = re.sub('(?m)^', '//', args) + args = re.sub('^//', '', args) + comment = '\n// %s::%s(%s)\n' % (currentFormat.id, t[1], args) + codeObj.prepend_all(comment) + t[0] = codeObj + +# Define an instruction using an explicitly specified format: +# "<fmt>::<mnemonic>(<args>)" +def p_inst_1(t): + 'inst : ID DBLCOLON ID LPAREN arg_list RPAREN' + try: + format = formatMap[t[1]] + except KeyError: + error(t.lineno(1), 'instruction format "%s" not defined.' % t[1]) + codeObj = format.defineInst(t[3], t[5], t.lineno(1)) + comment = '\n// %s::%s(%s)\n' % (t[1], t[3], t[5]) + codeObj.prepend_all(comment) + t[0] = codeObj + +# The arg list generates a tuple, where the first element is a list of +# the positional args and the second element is a dict containing the +# keyword args. +def p_arg_list_0(t): + 'arg_list : positional_arg_list COMMA keyword_arg_list' + t[0] = ( t[1], t[3] ) + +def p_arg_list_1(t): + 'arg_list : positional_arg_list' + t[0] = ( t[1], {} ) + +def p_arg_list_2(t): + 'arg_list : keyword_arg_list' + t[0] = ( [], t[1] ) + +def p_positional_arg_list_0(t): + 'positional_arg_list : empty' + t[0] = [] + +def p_positional_arg_list_1(t): + 'positional_arg_list : expr' + t[0] = [t[1]] + +def p_positional_arg_list_2(t): + 'positional_arg_list : positional_arg_list COMMA expr' + t[0] = t[1] + [t[3]] + +def p_keyword_arg_list_0(t): + 'keyword_arg_list : keyword_arg' + t[0] = t[1] + +def p_keyword_arg_list_1(t): + 'keyword_arg_list : keyword_arg_list COMMA keyword_arg' + t[0] = t[1] + t[0].update(t[3]) + +def p_keyword_arg(t): + 'keyword_arg : ID EQUALS expr' + t[0] = { t[1] : t[3] } + +# +# Basic expressions. These constitute the argument values of +# "function calls" (i.e. instruction definitions in the decode block) +# and default values for formal parameters of format functions. +# +# Right now, these are either strings, integers, or (recursively) +# lists of exprs (using Python square-bracket list syntax). Note that +# bare identifiers are trated as string constants here (since there +# isn't really a variable namespace to refer to). +# +def p_expr_0(t): + '''expr : ID + | INTLIT + | STRLIT + | CODELIT''' + t[0] = t[1] + +def p_expr_1(t): + '''expr : LBRACKET list_expr RBRACKET''' + t[0] = t[2] + +def p_list_expr_0(t): + 'list_expr : expr' + t[0] = [t[1]] + +def p_list_expr_1(t): + 'list_expr : list_expr COMMA expr' + t[0] = t[1] + [t[3]] + +def p_list_expr_2(t): + 'list_expr : empty' + t[0] = [] + +# +# Empty production... use in other rules for readability. +# +def p_empty(t): + 'empty :' + pass + +# Parse error handler. Note that the argument here is the offending +# *token*, not a grammar symbol (hence the need to use t.value) +def p_error(t): + if t: + error(t.lineno, "syntax error at '%s'" % t.value) + else: + error(0, "unknown syntax error", True) + +# END OF GRAMMAR RULES +# +# Now build the parser. +yacc.yacc() + + +##################################################################### +# +# Support Classes +# +##################################################################### + +# Expand template with CPU-specific references into a dictionary with +# an entry for each CPU model name. The entry key is the model name +# and the corresponding value is the template with the CPU-specific +# refs substituted for that model. +def expand_cpu_symbols_to_dict(template): + # Protect '%'s that don't go with CPU-specific terms + t = re.sub(r'%(?!\(CPU_)', '%%', template) + result = {} + for cpu in cpu_models: + result[cpu.name] = t % cpu.strings + return result + +# *If* the template has CPU-specific references, return a single +# string containing a copy of the template for each CPU model with the +# corresponding values substituted in. If the template has no +# CPU-specific references, it is returned unmodified. +def expand_cpu_symbols_to_string(template): + if template.find('%(CPU_') != -1: + return reduce(lambda x,y: x+y, + expand_cpu_symbols_to_dict(template).values()) + else: + return template + +# Protect CPU-specific references by doubling the corresponding '%'s +# (in preparation for substituting a different set of references into +# the template). +def protect_cpu_symbols(template): + return re.sub(r'%(?=\(CPU_)', '%%', template) + +############### +# GenCode class +# +# The GenCode class encapsulates generated code destined for various +# output files. The header_output and decoder_output attributes are +# strings containing code destined for decoder.hh and decoder.cc +# respectively. The decode_block attribute contains code to be +# incorporated in the decode function itself (that will also end up in +# decoder.cc). The exec_output attribute is a dictionary with a key +# for each CPU model name; the value associated with a particular key +# is the string of code for that CPU model's exec.cc file. The +# has_decode_default attribute is used in the decode block to allow +# explicit default clauses to override default default clauses. + +class GenCode: + # Constructor. At this point we substitute out all CPU-specific + # symbols. For the exec output, these go into the per-model + # dictionary. For all other output types they get collapsed into + # a single string. + def __init__(self, + header_output = '', decoder_output = '', exec_output = '', + decode_block = '', has_decode_default = False): + self.header_output = expand_cpu_symbols_to_string(header_output) + self.decoder_output = expand_cpu_symbols_to_string(decoder_output) + if isinstance(exec_output, dict): + self.exec_output = exec_output + elif isinstance(exec_output, str): + # If the exec_output arg is a single string, we replicate + # it for each of the CPU models, substituting and + # %(CPU_foo)s params appropriately. + self.exec_output = expand_cpu_symbols_to_dict(exec_output) + self.decode_block = expand_cpu_symbols_to_string(decode_block) + self.has_decode_default = has_decode_default + + # Override '+' operator: generate a new GenCode object that + # concatenates all the individual strings in the operands. + def __add__(self, other): + exec_output = {} + for cpu in cpu_models: + n = cpu.name + exec_output[n] = self.exec_output[n] + other.exec_output[n] + return GenCode(self.header_output + other.header_output, + self.decoder_output + other.decoder_output, + exec_output, + self.decode_block + other.decode_block, + self.has_decode_default or other.has_decode_default) + + # Prepend a string (typically a comment) to all the strings. + def prepend_all(self, pre): + self.header_output = pre + self.header_output + self.decoder_output = pre + self.decoder_output + self.decode_block = pre + self.decode_block + for cpu in cpu_models: + self.exec_output[cpu.name] = pre + self.exec_output[cpu.name] + + # Wrap the decode block in a pair of strings (e.g., 'case foo:' + # and 'break;'). Used to build the big nested switch statement. + def wrap_decode_block(self, pre, post = ''): + self.decode_block = pre + indent(self.decode_block) + post + +################ +# Format object. +# +# A format object encapsulates an instruction format. It must provide +# a defineInst() method that generates the code for an instruction +# definition. + +exportContextSymbols = ('InstObjParams', 'CodeBlock', + 'makeList', 're', 'string') + +exportContext = {} + +def updateExportContext(): + exportContext.update(exportDict(*exportContextSymbols)) + exportContext.update(templateMap) + +def exportDict(*symNames): + return dict([(s, eval(s)) for s in symNames]) + + +class Format: + def __init__(self, id, params, code): + # constructor: just save away arguments + self.id = id + self.params = params + label = 'def format ' + id + self.user_code = compile(fixPythonIndentation(code), label, 'exec') + param_list = string.join(params, ", ") + f = '''def defInst(_code, _context, %s): + my_locals = vars().copy() + exec _code in _context, my_locals + return my_locals\n''' % param_list + c = compile(f, label + ' wrapper', 'exec') + exec c + self.func = defInst + + def defineInst(self, name, args, lineno): + context = {} + updateExportContext() + context.update(exportContext) + context.update({ 'name': name, 'Name': string.capitalize(name) }) + try: + vars = self.func(self.user_code, context, *args[0], **args[1]) + except Exception, exc: + error(lineno, 'error defining "%s": %s.' % (name, exc)) + for k in vars.keys(): + if k not in ('header_output', 'decoder_output', + 'exec_output', 'decode_block'): + del vars[k] + return GenCode(**vars) + +# Special null format to catch an implicit-format instruction +# definition outside of any format block. +class NoFormat: + def __init__(self): + self.defaultInst = '' + + def defineInst(self, name, args, lineno): + error(lineno, + 'instruction definition "%s" with no active format!' % name) + +# This dictionary maps format name strings to Format objects. +formatMap = {} + +# Define a new format +def defFormat(id, params, code, lineno): + # make sure we haven't already defined this one + if formatMap.get(id, None) != None: + error(lineno, 'format %s redefined.' % id) + # create new object and store in global map + formatMap[id] = Format(id, params, code) + + +############## +# Stack: a simple stack object. Used for both formats (formatStack) +# and default cases (defaultStack). Simply wraps a list to give more +# stack-like syntax and enable initialization with an argument list +# (as opposed to an argument that's a list). + +class Stack(list): + def __init__(self, *items): + list.__init__(self, items) + + def push(self, item): + self.append(item); + + def top(self): + return self[-1] + +# The global format stack. +formatStack = Stack(NoFormat()) + +# The global default case stack. +defaultStack = Stack( None ) + +# Global stack that tracks current file and line number. +# Each element is a tuple (filename, lineno) that records the +# *current* filename and the line number in the *previous* file where +# it was included. +fileNameStack = Stack() + +################### +# Utility functions + +# +# Indent every line in string 's' by two spaces +# (except preprocessor directives). +# Used to make nested code blocks look pretty. +# +def indent(s): + return re.sub(r'(?m)^(?!#)', ' ', s) + +# +# Munge a somewhat arbitrarily formatted piece of Python code +# (e.g. from a format 'let' block) into something whose indentation +# will get by the Python parser. +# +# The two keys here are that Python will give a syntax error if +# there's any whitespace at the beginning of the first line, and that +# all lines at the same lexical nesting level must have identical +# indentation. Unfortunately the way code literals work, an entire +# let block tends to have some initial indentation. Rather than +# trying to figure out what that is and strip it off, we prepend 'if +# 1:' to make the let code the nested block inside the if (and have +# the parser automatically deal with the indentation for us). +# +# We don't want to do this if (1) the code block is empty or (2) the +# first line of the block doesn't have any whitespace at the front. + +def fixPythonIndentation(s): + # get rid of blank lines first + s = re.sub(r'(?m)^\s*\n', '', s); + if (s != '' and re.match(r'[ \t]', s[0])): + s = 'if 1:\n' + s + return s + +# Error handler. Just call exit. Output formatted to work under +# Emacs compile-mode. Optional 'print_traceback' arg, if set to True, +# prints a Python stack backtrace too (can be handy when trying to +# debug the parser itself). +def error(lineno, string, print_traceback = False): + spaces = "" + for (filename, line) in fileNameStack[0:-1]: + print spaces + "In file included from " + filename + ":" + spaces += " " + # Print a Python stack backtrace if requested. + if (print_traceback): + traceback.print_exc() + if lineno != 0: + line_str = "%d:" % lineno + else: + line_str = "" + sys.exit(spaces + "%s:%s %s" % (fileNameStack[-1][0], line_str, string)) + + +##################################################################### +# +# Bitfield Operator Support +# +##################################################################### + +bitOp1ArgRE = re.compile(r'<\s*(\w+)\s*:\s*>') + +bitOpWordRE = re.compile(r'(?<![\w\.])([\w\.]+)<\s*(\w+)\s*:\s*(\w+)\s*>') +bitOpExprRE = re.compile(r'\)<\s*(\w+)\s*:\s*(\w+)\s*>') + +def substBitOps(code): + # first convert single-bit selectors to two-index form + # i.e., <n> --> <n:n> + code = bitOp1ArgRE.sub(r'<\1:\1>', code) + # simple case: selector applied to ID (name) + # i.e., foo<a:b> --> bits(foo, a, b) + code = bitOpWordRE.sub(r'bits(\1, \2, \3)', code) + # if selector is applied to expression (ending in ')'), + # we need to search backward for matching '(' + match = bitOpExprRE.search(code) + while match: + exprEnd = match.start() + here = exprEnd - 1 + nestLevel = 1 + while nestLevel > 0: + if code[here] == '(': + nestLevel -= 1 + elif code[here] == ')': + nestLevel += 1 + here -= 1 + if here < 0: + sys.exit("Didn't find '('!") + exprStart = here+1 + newExpr = r'bits(%s, %s, %s)' % (code[exprStart:exprEnd+1], + match.group(1), match.group(2)) + code = code[:exprStart] + newExpr + code[match.end():] + match = bitOpExprRE.search(code) + return code + + +#################### +# Template objects. +# +# Template objects are format strings that allow substitution from +# the attribute spaces of other objects (e.g. InstObjParams instances). + +class Template: + def __init__(self, t): + self.template = t + + def subst(self, d): + # Start with the template namespace. Make a copy since we're + # going to modify it. + myDict = templateMap.copy() + # if the argument is a dictionary, we just use it. + if isinstance(d, dict): + myDict.update(d) + # if the argument is an object, we use its attribute map. + elif hasattr(d, '__dict__'): + myDict.update(d.__dict__) + else: + raise TypeError, "Template.subst() arg must be or have dictionary" + # Protect non-Python-dict substitutions (e.g. if there's a printf + # in the templated C++ code) + template = protect_non_subst_percents(self.template) + # CPU-model-specific substitutions are handled later (in GenCode). + template = protect_cpu_symbols(template) + return template % myDict + + # Convert to string. This handles the case when a template with a + # CPU-specific term gets interpolated into another template or into + # an output block. + def __str__(self): + return expand_cpu_symbols_to_string(self.template) + +##################################################################### +# +# Code Parser +# +# The remaining code is the support for automatically extracting +# instruction characteristics from pseudocode. +# +##################################################################### + +# Force the argument to be a list. Useful for flags, where a caller +# can specify a singleton flag or a list of flags. Also usful for +# converting tuples to lists so they can be modified. +def makeList(arg): + if isinstance(arg, list): + return arg + elif isinstance(arg, tuple): + return list(arg) + elif not arg: + return [] + else: + return [ arg ] + +# Generate operandTypeMap from the user's 'def operand_types' +# statement. +def buildOperandTypeMap(userDict, lineno): + global operandTypeMap + operandTypeMap = {} + for (ext, (desc, size)) in userDict.iteritems(): + if desc == 'signed int': + ctype = 'int%d_t' % size + is_signed = 1 + elif desc == 'unsigned int': + ctype = 'uint%d_t' % size + is_signed = 0 + elif desc == 'float': + is_signed = 1 # shouldn't really matter + if size == 32: + ctype = 'float' + elif size == 64: + ctype = 'double' + if ctype == '': + error(lineno, 'Unrecognized type description "%s" in userDict') + operandTypeMap[ext] = (size, ctype, is_signed) + +# +# +# +# Base class for operand descriptors. An instance of this class (or +# actually a class derived from this one) represents a specific +# operand for a code block (e.g, "Rc.sq" as a dest). Intermediate +# derived classes encapsulates the traits of a particular operand type +# (e.g., "32-bit integer register"). +# +class Operand(object): + def __init__(self, full_name, ext, is_src, is_dest): + self.full_name = full_name + self.ext = ext + self.is_src = is_src + self.is_dest = is_dest + # The 'effective extension' (eff_ext) is either the actual + # extension, if one was explicitly provided, or the default. + if ext: + self.eff_ext = ext + else: + self.eff_ext = self.dflt_ext + + (self.size, self.ctype, self.is_signed) = operandTypeMap[self.eff_ext] + + # note that mem_acc_size is undefined for non-mem operands... + # template must be careful not to use it if it doesn't apply. + if self.isMem(): + self.mem_acc_size = self.makeAccSize() + self.mem_acc_type = self.ctype + + # Finalize additional fields (primarily code fields). This step + # is done separately since some of these fields may depend on the + # register index enumeration that hasn't been performed yet at the + # time of __init__(). + def finalize(self): + self.flags = self.getFlags() + self.constructor = self.makeConstructor() + self.op_decl = self.makeDecl() + + if self.is_src: + self.op_rd = self.makeRead() + self.op_src_decl = self.makeDecl() + else: + self.op_rd = '' + self.op_src_decl = '' + + if self.is_dest: + self.op_wb = self.makeWrite() + self.op_dest_decl = self.makeDecl() + else: + self.op_wb = '' + self.op_dest_decl = '' + + def isMem(self): + return 0 + + def isReg(self): + return 0 + + def isFloatReg(self): + return 0 + + def isIntReg(self): + return 0 + + def isControlReg(self): + return 0 + + def getFlags(self): + # note the empty slice '[:]' gives us a copy of self.flags[0] + # instead of a reference to it + my_flags = self.flags[0][:] + if self.is_src: + my_flags += self.flags[1] + if self.is_dest: + my_flags += self.flags[2] + return my_flags + + def makeDecl(self): + # Note that initializations in the declarations are solely + # to avoid 'uninitialized variable' errors from the compiler. + return self.ctype + ' ' + self.base_name + ' = 0;\n'; + +class IntRegOperand(Operand): + def isReg(self): + return 1 + + def isIntReg(self): + return 1 + + def makeConstructor(self): + c = '' + if self.is_src: + c += '\n\t_srcRegIdx[%d] = %s;' % \ + (self.src_reg_idx, self.reg_spec) + if self.is_dest: + c += '\n\t_destRegIdx[%d] = %s;' % \ + (self.dest_reg_idx, self.reg_spec) + return c + + def makeRead(self): + if (self.ctype == 'float' or self.ctype == 'double'): + error(0, 'Attempt to read integer register as FP') + if (self.size == self.dflt_size): + return '%s = xc->readIntReg(this, %d);\n' % \ + (self.base_name, self.src_reg_idx) + elif (self.size > self.dflt_size): + int_reg_val = 'xc->readIntReg(this, %d)' % (self.src_reg_idx) + if (self.is_signed): + int_reg_val = 'sext<%d>(%s)' % (self.dflt_size, int_reg_val) + return '%s = %s;\n' % (self.base_name, int_reg_val) + else: + return '%s = bits(xc->readIntReg(this, %d), %d, 0);\n' % \ + (self.base_name, self.src_reg_idx, self.size-1) + + def makeWrite(self): + if (self.ctype == 'float' or self.ctype == 'double'): + error(0, 'Attempt to write integer register as FP') + if (self.size != self.dflt_size and self.is_signed): + final_val = 'sext<%d>(%s)' % (self.size, self.base_name) + else: + final_val = self.base_name + wb = ''' + { + %s final_val = %s; + xc->setIntReg(this, %d, final_val);\n + if (traceData) { traceData->setData(final_val); } + }''' % (self.dflt_ctype, final_val, self.dest_reg_idx) + return wb + +class FloatRegOperand(Operand): + def isReg(self): + return 1 + + def isFloatReg(self): + return 1 + + def makeConstructor(self): + c = '' + if self.is_src: + c += '\n\t_srcRegIdx[%d] = %s + FP_Base_DepTag;' % \ + (self.src_reg_idx, self.reg_spec) + if self.is_dest: + c += '\n\t_destRegIdx[%d] = %s + FP_Base_DepTag;' % \ + (self.dest_reg_idx, self.reg_spec) + return c + + def makeRead(self): + bit_select = 0 + width = 0; + if (self.ctype == 'float'): + func = 'readFloatReg' + width = 32; + elif (self.ctype == 'double'): + func = 'readFloatReg' + width = 64; + else: + func = 'readFloatRegBits' + if (self.ctype == 'uint32_t'): + width = 32; + elif (self.ctype == 'uint64_t'): + width = 64; + if (self.size != self.dflt_size): + bit_select = 1 + if width: + base = 'xc->%s(this, %d, %d)' % \ + (func, self.src_reg_idx, width) + else: + base = 'xc->%s(this, %d)' % \ + (func, self.src_reg_idx) + if bit_select: + return '%s = bits(%s, %d, 0);\n' % \ + (self.base_name, base, self.size-1) + else: + return '%s = %s;\n' % (self.base_name, base) + + def makeWrite(self): + final_val = self.base_name + final_ctype = self.ctype + widthSpecifier = '' + width = 0 + if (self.ctype == 'float'): + width = 32 + func = 'setFloatReg' + elif (self.ctype == 'double'): + width = 64 + func = 'setFloatReg' + elif (self.ctype == 'uint32_t'): + func = 'setFloatRegBits' + width = 32 + elif (self.ctype == 'uint64_t'): + func = 'setFloatRegBits' + width = 64 + else: + func = 'setFloatRegBits' + final_ctype = 'uint%d_t' % self.dflt_size + if (self.size != self.dflt_size and self.is_signed): + final_val = 'sext<%d>(%s)' % (self.size, self.base_name) + if width: + widthSpecifier = ', %d' % width + wb = ''' + { + %s final_val = %s; + xc->%s(this, %d, final_val%s);\n + if (traceData) { traceData->setData(final_val); } + }''' % (final_ctype, final_val, func, self.dest_reg_idx, + widthSpecifier) + return wb + +class ControlRegOperand(Operand): + def isReg(self): + return 1 + + def isControlReg(self): + return 1 + + def makeConstructor(self): + c = '' + if self.is_src: + c += '\n\t_srcRegIdx[%d] = %s;' % \ + (self.src_reg_idx, self.reg_spec) + if self.is_dest: + c += '\n\t_destRegIdx[%d] = %s;' % \ + (self.dest_reg_idx, self.reg_spec) + return c + + def makeRead(self): + bit_select = 0 + if (self.ctype == 'float' or self.ctype == 'double'): + error(0, 'Attempt to read control register as FP') + base = 'xc->readMiscReg(%s)' % self.reg_spec + if self.size == self.dflt_size: + return '%s = %s;\n' % (self.base_name, base) + else: + return '%s = bits(%s, %d, 0);\n' % \ + (self.base_name, base, self.size-1) + + def makeWrite(self): + if (self.ctype == 'float' or self.ctype == 'double'): + error(0, 'Attempt to write control register as FP') + wb = 'xc->setMiscReg(%s, %s);\n' % (self.reg_spec, self.base_name) + wb += 'if (traceData) { traceData->setData(%s); }' % \ + self.base_name + return wb + +class MemOperand(Operand): + def isMem(self): + return 1 + + def makeConstructor(self): + return '' + + def makeDecl(self): + # Note that initializations in the declarations are solely + # to avoid 'uninitialized variable' errors from the compiler. + # Declare memory data variable. + c = '%s %s = 0;\n' % (self.ctype, self.base_name) + return c + + def makeRead(self): + return '' + + def makeWrite(self): + return '' + + # Return the memory access size *in bits*, suitable for + # forming a type via "uint%d_t". Divide by 8 if you want bytes. + def makeAccSize(self): + return self.size + + +class NPCOperand(Operand): + def makeConstructor(self): + return '' + + def makeRead(self): + return '%s = xc->readNextPC();\n' % self.base_name + + def makeWrite(self): + return 'xc->setNextPC(%s);\n' % self.base_name + +class NNPCOperand(Operand): + def makeConstructor(self): + return '' + + def makeRead(self): + return '%s = xc->readNextNPC();\n' % self.base_name + + def makeWrite(self): + return 'xc->setNextNPC(%s);\n' % self.base_name + +def buildOperandNameMap(userDict, lineno): + global operandNameMap + operandNameMap = {} + for (op_name, val) in userDict.iteritems(): + (base_cls_name, dflt_ext, reg_spec, flags, sort_pri) = val + (dflt_size, dflt_ctype, dflt_is_signed) = operandTypeMap[dflt_ext] + # Canonical flag structure is a triple of lists, where each list + # indicates the set of flags implied by this operand always, when + # used as a source, and when used as a dest, respectively. + # For simplicity this can be initialized using a variety of fairly + # obvious shortcuts; we convert these to canonical form here. + if not flags: + # no flags specified (e.g., 'None') + flags = ( [], [], [] ) + elif isinstance(flags, str): + # a single flag: assumed to be unconditional + flags = ( [ flags ], [], [] ) + elif isinstance(flags, list): + # a list of flags: also assumed to be unconditional + flags = ( flags, [], [] ) + elif isinstance(flags, tuple): + # it's a tuple: it should be a triple, + # but each item could be a single string or a list + (uncond_flags, src_flags, dest_flags) = flags + flags = (makeList(uncond_flags), + makeList(src_flags), makeList(dest_flags)) + # Accumulate attributes of new operand class in tmp_dict + tmp_dict = {} + for attr in ('dflt_ext', 'reg_spec', 'flags', 'sort_pri', + 'dflt_size', 'dflt_ctype', 'dflt_is_signed'): + tmp_dict[attr] = eval(attr) + tmp_dict['base_name'] = op_name + # New class name will be e.g. "IntReg_Ra" + cls_name = base_cls_name + '_' + op_name + # Evaluate string arg to get class object. Note that the + # actual base class for "IntReg" is "IntRegOperand", i.e. we + # have to append "Operand". + try: + base_cls = eval(base_cls_name + 'Operand') + except NameError: + error(lineno, + 'error: unknown operand base class "%s"' % base_cls_name) + # The following statement creates a new class called + # <cls_name> as a subclass of <base_cls> with the attributes + # in tmp_dict, just as if we evaluated a class declaration. + operandNameMap[op_name] = type(cls_name, (base_cls,), tmp_dict) + + # Define operand variables. + operands = userDict.keys() + + operandsREString = (r''' + (?<![\w\.]) # neg. lookbehind assertion: prevent partial matches + ((%s)(?:\.(\w+))?) # match: operand with optional '.' then suffix + (?![\w\.]) # neg. lookahead assertion: prevent partial matches + ''' + % string.join(operands, '|')) + + global operandsRE + operandsRE = re.compile(operandsREString, re.MULTILINE|re.VERBOSE) + + # Same as operandsREString, but extension is mandatory, and only two + # groups are returned (base and ext, not full name as above). + # Used for subtituting '_' for '.' to make C++ identifiers. + operandsWithExtREString = (r'(?<![\w\.])(%s)\.(\w+)(?![\w\.])' + % string.join(operands, '|')) + + global operandsWithExtRE + operandsWithExtRE = re.compile(operandsWithExtREString, re.MULTILINE) + + +class OperandList: + + # Find all the operands in the given code block. Returns an operand + # descriptor list (instance of class OperandList). + def __init__(self, code): + self.items = [] + self.bases = {} + # delete comments so we don't match on reg specifiers inside + code = commentRE.sub('', code) + # search for operands + next_pos = 0 + while 1: + match = operandsRE.search(code, next_pos) + if not match: + # no more matches: we're done + break + op = match.groups() + # regexp groups are operand full name, base, and extension + (op_full, op_base, op_ext) = op + # if the token following the operand is an assignment, this is + # a destination (LHS), else it's a source (RHS) + is_dest = (assignRE.match(code, match.end()) != None) + is_src = not is_dest + # see if we've already seen this one + op_desc = self.find_base(op_base) + if op_desc: + if op_desc.ext != op_ext: + error(0, 'Inconsistent extensions for operand %s' % \ + op_base) + op_desc.is_src = op_desc.is_src or is_src + op_desc.is_dest = op_desc.is_dest or is_dest + else: + # new operand: create new descriptor + op_desc = operandNameMap[op_base](op_full, op_ext, + is_src, is_dest) + self.append(op_desc) + # start next search after end of current match + next_pos = match.end() + self.sort() + # enumerate source & dest register operands... used in building + # constructor later + self.numSrcRegs = 0 + self.numDestRegs = 0 + self.numFPDestRegs = 0 + self.numIntDestRegs = 0 + self.memOperand = None + for op_desc in self.items: + if op_desc.isReg(): + if op_desc.is_src: + op_desc.src_reg_idx = self.numSrcRegs + self.numSrcRegs += 1 + if op_desc.is_dest: + op_desc.dest_reg_idx = self.numDestRegs + self.numDestRegs += 1 + if op_desc.isFloatReg(): + self.numFPDestRegs += 1 + elif op_desc.isIntReg(): + self.numIntDestRegs += 1 + elif op_desc.isMem(): + if self.memOperand: + error(0, "Code block has more than one memory operand.") + self.memOperand = op_desc + # now make a final pass to finalize op_desc fields that may depend + # on the register enumeration + for op_desc in self.items: + op_desc.finalize() + + def __len__(self): + return len(self.items) + + def __getitem__(self, index): + return self.items[index] + + def append(self, op_desc): + self.items.append(op_desc) + self.bases[op_desc.base_name] = op_desc + + def find_base(self, base_name): + # like self.bases[base_name], but returns None if not found + # (rather than raising exception) + return self.bases.get(base_name) + + # internal helper function for concat[Some]Attr{Strings|Lists} + def __internalConcatAttrs(self, attr_name, filter, result): + for op_desc in self.items: + if filter(op_desc): + result += getattr(op_desc, attr_name) + return result + + # return a single string that is the concatenation of the (string) + # values of the specified attribute for all operands + def concatAttrStrings(self, attr_name): + return self.__internalConcatAttrs(attr_name, lambda x: 1, '') + + # like concatAttrStrings, but only include the values for the operands + # for which the provided filter function returns true + def concatSomeAttrStrings(self, filter, attr_name): + return self.__internalConcatAttrs(attr_name, filter, '') + + # return a single list that is the concatenation of the (list) + # values of the specified attribute for all operands + def concatAttrLists(self, attr_name): + return self.__internalConcatAttrs(attr_name, lambda x: 1, []) + + # like concatAttrLists, but only include the values for the operands + # for which the provided filter function returns true + def concatSomeAttrLists(self, filter, attr_name): + return self.__internalConcatAttrs(attr_name, filter, []) + + def sort(self): + self.items.sort(lambda a, b: a.sort_pri - b.sort_pri) + +# Regular expression object to match C++ comments +# (used in findOperands()) +commentRE = re.compile(r'//.*\n') + +# Regular expression object to match assignment statements +# (used in findOperands()) +assignRE = re.compile(r'\s*=(?!=)', re.MULTILINE) + +# Munge operand names in code string to make legal C++ variable names. +# This means getting rid of the type extension if any. +# (Will match base_name attribute of Operand object.) +def substMungedOpNames(code): + return operandsWithExtRE.sub(r'\1', code) + +def joinLists(t): + return map(string.join, t) + +def makeFlagConstructor(flag_list): + if len(flag_list) == 0: + return '' + # filter out repeated flags + flag_list.sort() + i = 1 + while i < len(flag_list): + if flag_list[i] == flag_list[i-1]: + del flag_list[i] + else: + i += 1 + pre = '\n\tflags[' + post = '] = true;' + code = pre + string.join(flag_list, post + pre) + post + return code + +class CodeBlock: + def __init__(self, code): + self.orig_code = code + self.operands = OperandList(code) + self.code = substMungedOpNames(substBitOps(code)) + self.constructor = self.operands.concatAttrStrings('constructor') + self.constructor += \ + '\n\t_numSrcRegs = %d;' % self.operands.numSrcRegs + self.constructor += \ + '\n\t_numDestRegs = %d;' % self.operands.numDestRegs + self.constructor += \ + '\n\t_numFPDestRegs = %d;' % self.operands.numFPDestRegs + self.constructor += \ + '\n\t_numIntDestRegs = %d;' % self.operands.numIntDestRegs + + self.op_decl = self.operands.concatAttrStrings('op_decl') + + is_src = lambda op: op.is_src + is_dest = lambda op: op.is_dest + + self.op_src_decl = \ + self.operands.concatSomeAttrStrings(is_src, 'op_src_decl') + self.op_dest_decl = \ + self.operands.concatSomeAttrStrings(is_dest, 'op_dest_decl') + + self.op_rd = self.operands.concatAttrStrings('op_rd') + self.op_wb = self.operands.concatAttrStrings('op_wb') + + self.flags = self.operands.concatAttrLists('flags') + + if self.operands.memOperand: + self.mem_acc_size = self.operands.memOperand.mem_acc_size + self.mem_acc_type = self.operands.memOperand.mem_acc_type + + # Make a basic guess on the operand class (function unit type). + # These are good enough for most cases, and will be overridden + # later otherwise. + if 'IsStore' in self.flags: + self.op_class = 'MemWriteOp' + elif 'IsLoad' in self.flags or 'IsPrefetch' in self.flags: + self.op_class = 'MemReadOp' + elif 'IsFloating' in self.flags: + self.op_class = 'FloatAddOp' + else: + self.op_class = 'IntAluOp' + +# Assume all instruction flags are of the form 'IsFoo' +instFlagRE = re.compile(r'Is.*') + +# OpClass constants end in 'Op' except No_OpClass +opClassRE = re.compile(r'.*Op|No_OpClass') + +class InstObjParams: + def __init__(self, mnem, class_name, base_class = '', + code = None, opt_args = [], *extras): + self.mnemonic = mnem + self.class_name = class_name + self.base_class = base_class + if code: + #If the user already made a CodeBlock, pick the parts from it + if isinstance(code, CodeBlock): + origCode = code.orig_code + codeBlock = code + else: + origCode = code + codeBlock = CodeBlock(code) + compositeCode = '\n'.join([origCode] + + [pair[1] for pair in extras]) + compositeBlock = CodeBlock(compositeCode) + for code_attr in compositeBlock.__dict__.keys(): + setattr(self, code_attr, getattr(compositeBlock, code_attr)) + for (key, snippet) in extras: + setattr(self, key, CodeBlock(snippet).code) + self.code = codeBlock.code + self.orig_code = origCode + else: + self.constructor = '' + self.flags = [] + # Optional arguments are assumed to be either StaticInst flags + # or an OpClass value. To avoid having to import a complete + # list of these values to match against, we do it ad-hoc + # with regexps. + for oa in opt_args: + if instFlagRE.match(oa): + self.flags.append(oa) + elif opClassRE.match(oa): + self.op_class = oa + else: + error(0, 'InstObjParams: optional arg "%s" not recognized ' + 'as StaticInst::Flag or OpClass.' % oa) + + # add flag initialization to contructor here to include + # any flags added via opt_args + self.constructor += makeFlagConstructor(self.flags) + + # if 'IsFloating' is set, add call to the FP enable check + # function (which should be provided by isa_desc via a declare) + if 'IsFloating' in self.flags: + self.fp_enable_check = 'fault = checkFpEnableFault(xc);' + else: + self.fp_enable_check = '' + +####################### +# +# Output file template +# + +file_template = ''' +/* + * DO NOT EDIT THIS FILE!!! + * + * It was automatically generated from the ISA description in %(filename)s + */ + +%(includes)s + +%(global_output)s + +namespace %(namespace)s { + +%(namespace_output)s + +} // namespace %(namespace)s + +%(decode_function)s +''' + + +# Update the output file only if the new contents are different from +# the current contents. Minimizes the files that need to be rebuilt +# after minor changes. +def update_if_needed(file, contents): + update = False + if os.access(file, os.R_OK): + f = open(file, 'r') + old_contents = f.read() + f.close() + if contents != old_contents: + print 'Updating', file + os.remove(file) # in case it's write-protected + update = True + else: + print 'File', file, 'is unchanged' + else: + print 'Generating', file + update = True + if update: + f = open(file, 'w') + f.write(contents) + f.close() + +# This regular expression matches '##include' directives +includeRE = re.compile(r'^\s*##include\s+"(?P<filename>[\w/.-]*)".*$', + re.MULTILINE) + +# Function to replace a matched '##include' directive with the +# contents of the specified file (with nested ##includes replaced +# recursively). 'matchobj' is an re match object (from a match of +# includeRE) and 'dirname' is the directory relative to which the file +# path should be resolved. +def replace_include(matchobj, dirname): + fname = matchobj.group('filename') + full_fname = os.path.normpath(os.path.join(dirname, fname)) + contents = '##newfile "%s"\n%s\n##endfile\n' % \ + (full_fname, read_and_flatten(full_fname)) + return contents + +# Read a file and recursively flatten nested '##include' files. +def read_and_flatten(filename): + current_dir = os.path.dirname(filename) + try: + contents = open(filename).read() + except IOError: + error(0, 'Error including file "%s"' % filename) + fileNameStack.push((filename, 0)) + # Find any includes and include them + contents = includeRE.sub(lambda m: replace_include(m, current_dir), + contents) + fileNameStack.pop() + return contents + +# +# Read in and parse the ISA description. +# +def parse_isa_desc(isa_desc_file, output_dir): + # Read file and (recursively) all included files into a string. + # PLY requires that the input be in a single string so we have to + # do this up front. + isa_desc = read_and_flatten(isa_desc_file) + + # Initialize filename stack with outer file. + fileNameStack.push((isa_desc_file, 0)) + + # Parse it. + (isa_name, namespace, global_code, namespace_code) = yacc.parse(isa_desc) + + # grab the last three path components of isa_desc_file to put in + # the output + filename = '/'.join(isa_desc_file.split('/')[-3:]) + + # generate decoder.hh + includes = '#include "base/bitfield.hh" // for bitfield support' + global_output = global_code.header_output + namespace_output = namespace_code.header_output + decode_function = '' + update_if_needed(output_dir + '/decoder.hh', file_template % vars()) + + # generate decoder.cc + includes = '#include "decoder.hh"' + global_output = global_code.decoder_output + namespace_output = namespace_code.decoder_output + # namespace_output += namespace_code.decode_block + decode_function = namespace_code.decode_block + update_if_needed(output_dir + '/decoder.cc', file_template % vars()) + + # generate per-cpu exec files + for cpu in cpu_models: + includes = '#include "decoder.hh"\n' + includes += cpu.includes + global_output = global_code.exec_output[cpu.name] + namespace_output = namespace_code.exec_output[cpu.name] + decode_function = '' + update_if_needed(output_dir + '/' + cpu.filename, + file_template % vars()) + +# global list of CpuModel objects (see cpu_models.py) +cpu_models = [] + +# Called as script: get args from command line. +# Args are: <path to cpu_models.py> <isa desc file> <output dir> <cpu models> +if __name__ == '__main__': + execfile(sys.argv[1]) # read in CpuModel definitions + cpu_models = [CpuModel.dict[cpu] for cpu in sys.argv[4:]] + parse_isa_desc(sys.argv[2], sys.argv[3]) diff --git a/src/arch/isa_specific.hh b/src/arch/isa_specific.hh new file mode 100644 index 000000000..181e81302 --- /dev/null +++ b/src/arch/isa_specific.hh @@ -0,0 +1,64 @@ +/* + * Copyright (c) 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: Gabe Black + */ + +#ifndef __ARCH_ISA_SPECIFIC_HH__ +#define __ARCH_ISA_SPECIFIC_HH__ + +//This file provides a mechanism for other source code to bring in +//files from the ISA being compiled with + +//These are constants so you can selective compile code based on the isa +//To use them, do something like +// +//#if THE_ISA == YOUR_FAVORITE_ISA +// conditional_code +//#endif +// +//Note that this is how this file sets up the other isa "hooks" + +//These macros have numerical values because otherwise the preprocessor +//would treat them as 0 in comparisons. +#define ALPHA_ISA 21064 +#define SPARC_ISA 42 +#define MIPS_ISA 34000 + +//These tell the preprocessor where to find the files of a particular +//ISA, and set the "TheISA" macro for use elsewhere. +#if THE_ISA == ALPHA_ISA + #define TheISA AlphaISA +#elif THE_ISA == SPARC_ISA + #define TheISA SparcISA +#elif THE_ISA == MIPS_ISA + #define TheISA MipsISA +#else + #error "THE_ISA not set" +#endif + +#endif diff --git a/src/arch/mips/SConscript b/src/arch/mips/SConscript new file mode 100644 index 000000000..6295a6c11 --- /dev/null +++ b/src/arch/mips/SConscript @@ -0,0 +1,84 @@ +# -*- mode:python -*- + +# Copyright (c) 2004-2005 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black +# Steve Reinhardt +# Korey Sewell + +import os +import sys +from os.path import isdir + +# Import build environment variable from SConstruct. +Import('env') + +################################################### +# +# Define needed sources. +# +################################################### + +# Base sources used by all configurations. +base_sources = Split(''' + faults.cc + isa_traits.cc + utility.cc + ''') + +# Full-system sources +full_system_sources = Split(''' + memory.cc + mips34k.cc + ''') + +# Syscall emulation (non-full-system) sources +syscall_emulation_sources = Split(''' + linux/linux.cc + linux/process.cc + process.cc + ''') + +# Set up complete list of sources based on configuration. +sources = base_sources + +if env['FULL_SYSTEM']: + sources += full_system_sources +else: + sources += syscall_emulation_sources + +# Convert file names to SCons File objects. This takes care of the +# path relative to the top of the directory tree. +sources = [File(s) for s in sources] + +# Add in files generated by the ISA description. +isa_desc_files = env.ISADesc('isa/main.isa') +# Only non-header files need to be compiled. +isa_desc_sources = [f for f in isa_desc_files if not f.path.endswith('.hh')] +sources += isa_desc_sources + +Return('sources') diff --git a/src/arch/mips/faults.cc b/src/arch/mips/faults.cc new file mode 100644 index 000000000..810c3fed4 --- /dev/null +++ b/src/arch/mips/faults.cc @@ -0,0 +1,133 @@ +/* + * Copyright (c) 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: Korey Sewell + */ + +#include "arch/mips/faults.hh" +#include "cpu/thread_context.hh" +#include "cpu/base.hh" +#include "base/trace.hh" + +namespace MipsISA +{ + +FaultName MachineCheckFault::_name = "Machine Check"; +FaultVect MachineCheckFault::_vect = 0x0401; +FaultStat MachineCheckFault::_count; + +FaultName AlignmentFault::_name = "Alignment"; +FaultVect AlignmentFault::_vect = 0x0301; +FaultStat AlignmentFault::_count; + +FaultName ResetFault::_name = "reset"; +FaultVect ResetFault::_vect = 0x0001; +FaultStat ResetFault::_count; + +FaultName ArithmeticFault::_name = "arith"; +FaultVect ArithmeticFault::_vect = 0x0501; +FaultStat ArithmeticFault::_count; + +FaultName InterruptFault::_name = "interrupt"; +FaultVect InterruptFault::_vect = 0x0101; +FaultStat InterruptFault::_count; + +FaultName NDtbMissFault::_name = "dtb_miss_single"; +FaultVect NDtbMissFault::_vect = 0x0201; +FaultStat NDtbMissFault::_count; + +FaultName PDtbMissFault::_name = "dtb_miss_double"; +FaultVect PDtbMissFault::_vect = 0x0281; +FaultStat PDtbMissFault::_count; + +FaultName DtbPageFault::_name = "dfault"; +FaultVect DtbPageFault::_vect = 0x0381; +FaultStat DtbPageFault::_count; + +FaultName DtbAcvFault::_name = "dfault"; +FaultVect DtbAcvFault::_vect = 0x0381; +FaultStat DtbAcvFault::_count; + +FaultName ItbMissFault::_name = "itbmiss"; +FaultVect ItbMissFault::_vect = 0x0181; +FaultStat ItbMissFault::_count; + +FaultName ItbPageFault::_name = "itbmiss"; +FaultVect ItbPageFault::_vect = 0x0181; +FaultStat ItbPageFault::_count; + +FaultName ItbAcvFault::_name = "iaccvio"; +FaultVect ItbAcvFault::_vect = 0x0081; +FaultStat ItbAcvFault::_count; + +FaultName UnimplementedOpcodeFault::_name = "opdec"; +FaultVect UnimplementedOpcodeFault::_vect = 0x0481; +FaultStat UnimplementedOpcodeFault::_count; + +FaultName FloatEnableFault::_name = "fen"; +FaultVect FloatEnableFault::_vect = 0x0581; +FaultStat FloatEnableFault::_count; + +FaultName PalFault::_name = "pal"; +FaultVect PalFault::_vect = 0x2001; +FaultStat PalFault::_count; + +FaultName IntegerOverflowFault::_name = "intover"; +FaultVect IntegerOverflowFault::_vect = 0x0501; +FaultStat IntegerOverflowFault::_count; + +#if FULL_SYSTEM + +void MipsFault::invoke(ThreadContext * tc) +{ + FaultBase::invoke(tc); + countStat()++; + + // exception restart address + if (setRestartAddress() || !tc->inPalMode()) + tc->setMiscReg(MipsISA::IPR_EXC_ADDR, tc->readPC()); + + if (skipFaultingInstruction()) { + // traps... skip faulting instruction. + tc->setMiscReg(MipsISA::IPR_EXC_ADDR, + tc->readMiscReg(MipsISA::IPR_EXC_ADDR) + 4); + } + + tc->setPC(tc->readMiscReg(MipsISA::IPR_PAL_BASE) + vect()); + tc->setNextPC(tc->readPC() + sizeof(MachInst)); +} + +void ArithmeticFault::invoke(ThreadContext * tc) +{ + FaultBase::invoke(tc); + panic("Arithmetic traps are unimplemented!"); +} + +#endif + +} // namespace MipsISA + diff --git a/src/arch/mips/faults.hh b/src/arch/mips/faults.hh new file mode 100644 index 000000000..d8bf59cc1 --- /dev/null +++ b/src/arch/mips/faults.hh @@ -0,0 +1,271 @@ +/* + * Copyright (c) 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: Korey Sewell + */ + +#ifndef __MIPS_FAULTS_HH__ +#define __MIPS_FAULTS_HH__ + +#include "sim/faults.hh" + +// The design of the "name" and "vect" functions is in sim/faults.hh + +namespace MipsISA +{ + +typedef const Addr FaultVect; + +class MipsFault : public FaultBase +{ + protected: + virtual bool skipFaultingInstruction() {return false;} + virtual bool setRestartAddress() {return true;} + public: +#if FULL_SYSTEM + void invoke(ThreadContext * tc); +#endif + virtual FaultVect vect() = 0; + virtual FaultStat & countStat() = 0; +}; + +class MachineCheckFault : public MipsFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} + bool isMachineCheckFault() {return true;} +}; + +class AlignmentFault : public MipsFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} + bool isAlignmentFault() {return true;} +}; + +static inline Fault genMachineCheckFault() +{ + return new MachineCheckFault; +} + +static inline Fault genAlignmentFault() +{ + return new AlignmentFault; +} + +class ResetFault : public MipsFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class ArithmeticFault : public MipsFault +{ + protected: + bool skipFaultingInstruction() {return true;} + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +#if FULL_SYSTEM + void invoke(ThreadContext * tc); +#endif +}; + +class InterruptFault : public MipsFault +{ + protected: + bool setRestartAddress() {return false;} + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class NDtbMissFault : public MipsFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class PDtbMissFault : public MipsFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class DtbPageFault : public MipsFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class DtbAcvFault : public MipsFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class ItbMissFault : public MipsFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class ItbPageFault : public MipsFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class ItbAcvFault : public MipsFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class UnimplementedOpcodeFault : public MipsFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class FloatEnableFault : public MipsFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class PalFault : public MipsFault +{ + protected: + bool skipFaultingInstruction() {return true;} + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +class IntegerOverflowFault : public MipsFault +{ + private: + static FaultName _name; + static FaultVect _vect; + static FaultStat _count; + public: + FaultName name() {return _name;} + FaultVect vect() {return _vect;} + FaultStat & countStat() {return _count;} +}; + +} // MipsISA namespace + +#endif // __FAULTS_HH__ diff --git a/src/arch/mips/isa/base.isa b/src/arch/mips/isa/base.isa new file mode 100644 index 000000000..b733da7da --- /dev/null +++ b/src/arch/mips/isa/base.isa @@ -0,0 +1,106 @@ +// -*- mode:c++ -*- + +// 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: Korey Sewell + +//////////////////////////////////////////////////////////////////// +// +// Base class for MIPS instructions, and some support functions +// + +//Outputs to decoder.hh +output header {{ + + using namespace MipsISA; + + + /** + * Base class for all MIPS static instructions. + */ + class MipsStaticInst : public StaticInst + { + protected: + + // Constructor + MipsStaticInst(const char *mnem, MachInst _machInst, OpClass __opClass) + : StaticInst(mnem, _machInst, __opClass) + { + } + + /// Print a register name for disassembly given the unique + /// dependence tag number (FP or int). + void printReg(std::ostream &os, int reg) const; + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; + +}}; + +//Ouputs to decoder.cc +output decoder {{ + + void MipsStaticInst::printReg(std::ostream &os, int reg) const + { + if (reg < FP_Base_DepTag) { + ccprintf(os, "r%d", reg); + } + else { + ccprintf(os, "f%d", reg - FP_Base_DepTag); + } + } + + std::string MipsStaticInst::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + std::stringstream ss; + + ccprintf(ss, "%-10s ", mnemonic); + + if(_numDestRegs > 0){ + printReg(ss, _destRegIdx[0]); + } + + if(_numSrcRegs > 0) { + ss << ", "; + printReg(ss, _srcRegIdx[0]); + } + + if(_numSrcRegs > 1) { + ss << ", "; + printReg(ss, _srcRegIdx[1]); + } + + + if(mnemonic == "sll" || mnemonic == "sra"){ + ccprintf(ss,", %d",SA); + } + + return ss.str(); + } + +}}; + diff --git a/src/arch/mips/isa/bitfields.isa b/src/arch/mips/isa/bitfields.isa new file mode 100644 index 000000000..e8d4578c7 --- /dev/null +++ b/src/arch/mips/isa/bitfields.isa @@ -0,0 +1,102 @@ +// -*- mode:c++ -*- + +// 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: Korey Sewell + +//////////////////////////////////////////////////////////////////// +// +// Bitfield definitions. +// + +def bitfield OPCODE <31:26>; +def bitfield OPCODE_HI <31:29>; +def bitfield OPCODE_LO <28:26>; + +def bitfield REGIMM <20:16>; +def bitfield REGIMM_HI <20:19>; +def bitfield REGIMM_LO <18:16>; + +def bitfield FUNCTION < 5: 0>; +def bitfield FUNCTION_HI < 5: 3>; +def bitfield FUNCTION_LO < 2: 0>; + +def bitfield RS <25:21>; +def bitfield RS_MSB <25:25>; +def bitfield RS_HI <25:24>; +def bitfield RS_LO <23:21>; +def bitfield RS_SRL <25:22>; +def bitfield RS_RT <25:16>; +def bitfield RT <20:16>; +def bitfield RT_HI <20:19>; +def bitfield RT_LO <18:16>; +def bitfield RT_RD <20:11>; +def bitfield RD <15:11>; + +def bitfield INTIMM <15: 0>; + +// Floating-point operate format +def bitfield FMT <25:21>; +def bitfield FR <25:21>; +def bitfield FT <20:16>; +def bitfield FS <15:11>; +def bitfield FD <10:6>; + +def bitfield ND <17:17>; +def bitfield TF <16:16>; +def bitfield MOVCI <16:16>; +def bitfield MOVCF <16:16>; +def bitfield SRL <21:21>; +def bitfield SRLV < 6: 6>; +def bitfield SA <10: 6>; + +// Floating Point Condition Codes +def bitfield CC <10:8>; +def bitfield BRANCH_CC <20:18>; + +// CP0 Register Select +def bitfield SEL < 2: 0>; + +// Interrupts +def bitfield SC < 5: 5>; + +// Branch format +def bitfield OFFSET <15: 0>; // displacement + +// Jmp format +def bitfield JMPTARG <25: 0>; +def bitfield HINT <10: 6>; + +def bitfield SYSCALLCODE <25: 6>; +def bitfield TRAPCODE <15:13>; + +// EXT/INS instructions +def bitfield MSB <15:11>; +def bitfield LSB <10: 6>; + +// M5 instructions +def bitfield M5FUNC <7:0>; diff --git a/src/arch/mips/isa/decoder.isa b/src/arch/mips/isa/decoder.isa new file mode 100644 index 000000000..a64f74c4f --- /dev/null +++ b/src/arch/mips/isa/decoder.isa @@ -0,0 +1,1095 @@ +// -*- mode:c++ -*- + +// 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: Korey Sewell + +//////////////////////////////////////////////////////////////////// +// +// The actual MIPS32 ISA decoder +// ----------------------------- +// The following instructions are specified in the MIPS32 ISA +// Specification. Decoding closely follows the style specified +// in the MIPS32 ISA specification document starting with Table +// A-2 (document available @ www.mips.com) +// +decode OPCODE_HI default Unknown::unknown() { + //Table A-2 + 0x0: decode OPCODE_LO { + 0x0: decode FUNCTION_HI { + 0x0: decode FUNCTION_LO { + 0x1: decode MOVCI { + format BasicOp { + 0: movf({{ Rd = (getCondCode(FCSR, CC) == 0) ? Rd : Rs; }}); + 1: movt({{ Rd = (getCondCode(FCSR, CC) == 1) ? Rd : Rs; }}); + } + } + + format BasicOp { + //Table A-3 Note: "Specific encodings of the rd, rs, and + //rt fields are used to distinguish SLL, SSNOP, and EHB + //functions + 0x0: decode RS { + 0x0: decode RT_RD { + 0x0: decode SA default Nop::nop(){ + 0x1: WarnUnimpl::ssnop(); + 0x3: WarnUnimpl::ehb(); + } + default: sll({{ Rd = Rt.uw << SA; }}); + } + } + + 0x2: decode RS_SRL { + 0x0:decode SRL { + 0: srl({{ Rd = Rt.uw >> SA; }}); + + //Hardcoded assuming 32-bit ISA, probably need parameter here + 1: rotr({{ Rd = (Rt.uw << (32 - SA)) | (Rt.uw >> SA);}}); + } + } + + 0x3: decode RS { + 0x0: sra({{ + uint32_t temp = Rt >> SA; + if ( (Rt & 0x80000000) > 0 ) { + uint32_t mask = 0x80000000; + for(int i=0; i < SA; i++) { + temp |= mask; + mask = mask >> 1; + } + } + Rd = temp; + }}); + } + + 0x4: sllv({{ Rd = Rt.uw << Rs<4:0>; }}); + + 0x6: decode SRLV { + 0: srlv({{ Rd = Rt.uw >> Rs<4:0>; }}); + + //Hardcoded assuming 32-bit ISA, probably need parameter here + 1: rotrv({{ Rd = (Rt.uw << (32 - Rs<4:0>)) | (Rt.uw >> Rs<4:0>);}}); + } + + 0x7: srav({{ + int shift_amt = Rs<4:0>; + + uint32_t temp = Rt >> shift_amt; + + if ( (Rt & 0x80000000) > 0 ) { + uint32_t mask = 0x80000000; + for(int i=0; i < shift_amt; i++) { + temp |= mask; + mask = mask >> 1; + } + } + + Rd = temp; + }}); + } + } + + 0x1: decode FUNCTION_LO { + //Table A-3 Note: "Specific encodings of the hint field are + //used to distinguish JR from JR.HB and JALR from JALR.HB" + format Jump { + 0x0: decode HINT { + 0x1: jr_hb({{ NNPC = Rs & ~1; }}, IsReturn, ClearHazards); + default: jr({{ NNPC = Rs & ~1; }}, IsReturn); + } + + 0x1: decode HINT { + 0x1: jalr_hb({{ Rd = NNPC; NNPC = Rs; }}, IsCall, Link + , ClearHazards); + default: jalr({{ Rd = NNPC; NNPC = Rs; }}, IsCall, + Link); + } + } + + format BasicOp { + 0x2: movz({{ Rd = (Rt == 0) ? Rs : Rd; }}); + 0x3: movn({{ Rd = (Rt != 0) ? Rs : Rd; }}); + 0x4: syscall({{ xc->syscall(R2); }}, IsNonSpeculative); + 0x7: sync({{ ; }}, IsMemBarrier); + } + + format FailUnimpl { + 0x5: break(); + } + } + + 0x2: decode FUNCTION_LO { + format HiLoMiscOp { + 0x0: mfhi({{ Rd = HI; }}); + 0x1: mthi({{ HI = Rs; }}); + 0x2: mflo({{ Rd = LO; }}); + 0x3: mtlo({{ LO = Rs; }}); + } + } + + 0x3: decode FUNCTION_LO { + format HiLoOp { + 0x0: mult({{ val = Rs.sd * Rt.sd; }}); + 0x1: multu({{ val = Rs.ud * Rt.ud; }}); + } + + format HiLoMiscOp { + 0x2: div({{ + HI = Rs.sd % Rt.sd; + LO = Rs.sd / Rt.sd; + }}); + 0x3: divu({{ + HI = Rs.ud % Rt.ud; + LO = Rs.ud / Rt.ud; + }}); + } + } + + 0x4: decode HINT { + 0x0: decode FUNCTION_LO { + format IntOp { + 0x0: add({{ Rd.sw = Rs.sw + Rt.sw; /*Trap on Overflow*/}}); + 0x1: addu({{ Rd.sw = Rs.sw + Rt.sw;}}); + 0x2: sub({{ Rd.sw = Rs.sw - Rt.sw; /*Trap on Overflow*/}}); + 0x3: subu({{ Rd.sw = Rs.sw - Rt.sw;}}); + 0x4: and({{ Rd = Rs & Rt;}}); + 0x5: or({{ Rd = Rs | Rt;}}); + 0x6: xor({{ Rd = Rs ^ Rt;}}); + 0x7: nor({{ Rd = ~(Rs | Rt);}}); + } + } + } + + 0x5: decode HINT { + 0x0: decode FUNCTION_LO { + format IntOp{ + 0x2: slt({{ Rd.sw = ( Rs.sw < Rt.sw ) ? 1 : 0}}); + 0x3: sltu({{ Rd.uw = ( Rs.uw < Rt.uw ) ? 1 : 0}}); + } + } + } + + 0x6: decode FUNCTION_LO { + format Trap { + 0x0: tge({{ cond = (Rs.sw >= Rt.sw); }}); + 0x1: tgeu({{ cond = (Rs.uw >= Rt.uw); }}); + 0x2: tlt({{ cond = (Rs.sw < Rt.sw); }}); + 0x3: tltu({{ cond = (Rs.uw >= Rt.uw); }}); + 0x4: teq({{ cond = (Rs.sw == Rt.sw); }}); + 0x6: tne({{ cond = (Rs.sw != Rt.sw); }}); + } + } + } + + 0x1: decode REGIMM_HI { + 0x0: decode REGIMM_LO { + format Branch { + 0x0: bltz({{ cond = (Rs.sw < 0); }}); + 0x1: bgez({{ cond = (Rs.sw >= 0); }}); + 0x2: bltzl({{ cond = (Rs.sw < 0); }}, Likely); + 0x3: bgezl({{ cond = (Rs.sw >= 0); }}, Likely); + } + } + + 0x1: decode REGIMM_LO { + format Trap { + 0x0: tgei( {{ cond = (Rs.sw >= INTIMM); }}); + 0x1: tgeiu({{ cond = (Rs.uw >= INTIMM); }}); + 0x2: tlti( {{ cond = (Rs.sw < INTIMM); }}); + 0x3: tltiu({{ cond = (Rs.uw < INTIMM); }}); + 0x4: teqi( {{ cond = (Rs.sw == INTIMM);}}); + 0x6: tnei( {{ cond = (Rs.sw != INTIMM);}}); + } + } + + 0x2: decode REGIMM_LO { + format Branch { + 0x0: bltzal({{ cond = (Rs.sw < 0); }}, Link); + 0x1: decode RS { + 0x0: bal ({{ cond = 1; }}, IsCall, Link); + default: bgezal({{ cond = (Rs.sw >= 0); }}, Link); + } + 0x2: bltzall({{ cond = (Rs.sw < 0); }}, Link, Likely); + 0x3: bgezall({{ cond = (Rs.sw >= 0); }}, Link, Likely); + } + } + + 0x3: decode REGIMM_LO { + format WarnUnimpl { + 0x7: synci(); + } + } + } + + format Jump { + 0x2: j({{ NNPC = (NPC & 0xF0000000) | (JMPTARG << 2);}}); + 0x3: jal({{ NNPC = (NPC & 0xF0000000) | (JMPTARG << 2); }}, IsCall, + Link); + } + + format Branch { + 0x4: decode RS_RT { + 0x0: b({{ cond = 1; }}); + default: beq({{ cond = (Rs.sw == Rt.sw); }}); + } + 0x5: bne({{ cond = (Rs.sw != Rt.sw); }}); + 0x6: blez({{ cond = (Rs.sw <= 0); }}); + 0x7: bgtz({{ cond = (Rs.sw > 0); }}); + } + } + + 0x1: decode OPCODE_LO { + format IntImmOp { + 0x0: addi({{ Rt.sw = Rs.sw + imm; /*Trap If Overflow*/}}); + 0x1: addiu({{ Rt.sw = Rs.sw + imm;}}); + 0x2: slti({{ Rt.sw = ( Rs.sw < imm) ? 1 : 0 }}); + 0x3: sltiu({{ Rt.uw = ( Rs.uw < (uint32_t)sextImm ) ? 1 : 0 }}); + 0x4: andi({{ Rt.sw = Rs.sw & zextImm;}}); + 0x5: ori({{ Rt.sw = Rs.sw | zextImm;}}); + 0x6: xori({{ Rt.sw = Rs.sw ^ zextImm;}}); + + 0x7: decode RS { + 0x0: lui({{ Rt = imm << 16}}); + } + } + } + + 0x2: decode OPCODE_LO { + //Table A-11 MIPS32 COP0 Encoding of rs Field + 0x0: decode RS_MSB { + 0x0: decode RS { + format CP0Control { + 0x0: mfc0({{ Rt = xc->readMiscReg(RD << 5 | SEL); }}); + 0x4: mtc0({{ xc->setMiscReg(RD << 5 | SEL, Rt); }}); + } + + format MipsMT { + 0x8: mftr(); + 0xC: mttr(); + 0xB: decode RD { + 0x0: decode SC { + 0x0: dvpe(); + 0x1: evpe(); + } + 0x1: decode SC { + 0x0: dmt(); + 0x1: emt(); + 0xC: decode SC { + 0x0: di(); + 0x1: ei(); + } + } + } + } + + format FailUnimpl { + 0xA: rdpgpr(); + 0xE: wrpgpr(); + } + } + + //Table A-12 MIPS32 COP0 Encoding of Function Field When rs=CO + 0x1: decode FUNCTION { + format FailUnimpl { + 0x01: tlbr(); + 0x02: tlbwi(); + 0x06: tlbwr(); + 0x08: tlbp(); + + 0x18: eret(); + 0x1F: deret(); + 0x20: wait(); + } + } + } + + //Table A-13 MIPS32 COP1 Encoding of rs Field + 0x1: decode RS_MSB { + + 0x0: decode RS_HI { + 0x0: decode RS_LO { + format CP1Control { + 0x0: mfc1 ({{ Rt.uw = Fs.uw<31:0>; }}); + + 0x2: cfc1({{ + switch (FS) + { + case 0: + Rt = FIR; + break; + case 25: + Rt = 0 | (FCSR & 0xFE000000) >> 24 | (FCSR & 0x00800000) >> 23; + break; + case 26: + Rt = 0 | (FCSR & 0x0003F07C); + break; + case 28: + Rt = 0 | (FCSR & 0x00000F80) | (FCSR & 0x01000000) >> 21 | (FCSR & 0x00000003); + break; + case 31: + Rt = FCSR; + break; + default: + panic("FP Control Value (%d) Not Valid"); + } + }}); + + 0x3: mfhc1({{ Rt.uw = Fs.ud<63:32>;}}); + + 0x4: mtc1 ({{ Fs.uw = Rt.uw; }}); + + 0x6: ctc1({{ + switch (FS) + { + case 25: + FCSR = 0 | (Rt.uw<7:1> << 25) // move 31...25 + | (FCSR & 0x01000000) // bit 24 + | (FCSR & 0x004FFFFF);// bit 22...0 + break; + + case 26: + FCSR = 0 | (FCSR & 0xFFFC0000) // move 31...18 + | Rt.uw<17:12> << 12 // bit 17...12 + | (FCSR & 0x00000F80) << 7// bit 11...7 + | Rt.uw<6:2> << 2 // bit 6...2 + | (FCSR & 0x00000002); // bit 1...0 + break; + + case 28: + FCSR = 0 | (FCSR & 0xFE000000) // move 31...25 + | Rt.uw<2:2> << 24 // bit 24 + | (FCSR & 0x00FFF000) << 23// bit 23...12 + | Rt.uw<11:7> << 7 // bit 24 + | (FCSR & 0x000007E) + | Rt.uw<1:0>;// bit 22...0 + break; + + case 31: + FCSR = Rt.uw; + break; + + default: + panic("FP Control Value (%d) Not Available. Ignoring Access to" + "Floating Control Status Register", FS); + } + }}); + + 0x7: mthc1({{ + uint64_t fs_hi = Rt.uw; + uint64_t fs_lo = Fs.ud & 0x0FFFFFFFF; + Fs.ud = (fs_hi << 32) | fs_lo; + }}); + + } + } + + 0x1: decode ND { + format Branch { + 0x0: decode TF { + 0x0: bc1f({{ cond = getCondCode(FCSR, BRANCH_CC) == 0; + }}); + 0x1: bc1t({{ cond = getCondCode(FCSR, BRANCH_CC) == 1; + }}); + } + 0x1: decode TF { + 0x0: bc1fl({{ cond = getCondCode(FCSR, BRANCH_CC) == 0; + }}, Likely); + 0x1: bc1tl({{ cond = getCondCode(FCSR, BRANCH_CC) == 1; + }}, Likely); + } + } + } + } + + 0x1: decode RS_HI { + 0x2: decode RS_LO { + //Table A-14 MIPS32 COP1 Encoding of Function Field When rs=S + //(( single-precision floating point)) + 0x0: decode FUNCTION_HI { + 0x0: decode FUNCTION_LO { + format FloatOp { + 0x0: add_s({{ Fd.sf = Fs.sf + Ft.sf;}}); + 0x1: sub_s({{ Fd.sf = Fs.sf - Ft.sf;}}); + 0x2: mul_s({{ Fd.sf = Fs.sf * Ft.sf;}}); + 0x3: div_s({{ Fd.sf = Fs.sf / Ft.sf;}}); + 0x4: sqrt_s({{ Fd.sf = sqrt(Fs.sf);}}); + 0x5: abs_s({{ Fd.sf = fabs(Fs.sf);}}); + 0x6: mov_s({{ Fd.sf = Fs.sf;}}); + 0x7: neg_s({{ Fd.sf = -Fs.sf;}}); + } + } + + 0x1: decode FUNCTION_LO { + format FloatConvertOp { + 0x0: round_l_s({{ val = Fs.sf; }}, ToLong, + Round); + 0x1: trunc_l_s({{ val = Fs.sf; }}, ToLong, + Trunc); + 0x2: ceil_l_s({{ val = Fs.sf; }}, ToLong, + Ceil); + 0x3: floor_l_s({{ val = Fs.sf; }}, ToLong, + Floor); + 0x4: round_w_s({{ val = Fs.sf; }}, ToWord, + Round); + 0x5: trunc_w_s({{ val = Fs.sf; }}, ToWord, + Trunc); + 0x6: ceil_w_s({{ val = Fs.sf; }}, ToWord, + Ceil); + 0x7: floor_w_s({{ val = Fs.sf; }}, ToWord, + Floor); + } + } + + 0x2: decode FUNCTION_LO { + 0x1: decode MOVCF { + format BasicOp { + 0x0: movf_s({{ Fd = (getCondCode(FCSR,CC) == 0) ? Fs : Fd; }}); + 0x1: movt_s({{ Fd = (getCondCode(FCSR,CC) == 1) ? Fs : Fd; }}); + } + } + + format BasicOp { + 0x2: movz_s({{ Fd = (Rt == 0) ? Fs : Fd; }}); + 0x3: movn_s({{ Fd = (Rt != 0) ? Fs : Fd; }}); + } + + format FloatOp { + 0x5: recip_s({{ Fd = 1 / Fs; }}); + 0x6: rsqrt_s({{ Fd = 1 / sqrt(Fs);}}); + } + } + + 0x4: decode FUNCTION_LO { + format FloatConvertOp { + 0x1: cvt_d_s({{ val = Fs.sf; }}, ToDouble); + 0x4: cvt_w_s({{ val = Fs.sf; }}, ToWord); + 0x5: cvt_l_s({{ val = Fs.sf; }}, ToLong); + } + + 0x6: FloatOp::cvt_ps_s({{ + Fd.ud = (uint64_t) Fs.uw << 32 | + (uint64_t) Ft.uw; + }}); + } + + 0x6: decode FUNCTION_LO { + format FloatCompareOp { + 0x0: c_f_s({{ cond = 0; }}, SinglePrecision, + UnorderedFalse); + 0x1: c_un_s({{ cond = 0; }}, SinglePrecision, + UnorderedTrue); + 0x2: c_eq_s({{ cond = (Fs.sf == Ft.sf); }}, + UnorderedFalse); + 0x3: c_ueq_s({{ cond = (Fs.sf == Ft.sf); }}, + UnorderedTrue); + 0x4: c_olt_s({{ cond = (Fs.sf < Ft.sf); }}, + UnorderedFalse); + 0x5: c_ult_s({{ cond = (Fs.sf < Ft.sf); }}, + UnorderedTrue); + 0x6: c_ole_s({{ cond = (Fs.sf <= Ft.sf); }}, + UnorderedFalse); + 0x7: c_ule_s({{ cond = (Fs.sf <= Ft.sf); }}, + UnorderedTrue); + } + } + + 0x7: decode FUNCTION_LO { + format FloatCompareOp { + 0x0: c_sf_s({{ cond = 0; }}, SinglePrecision, + UnorderedFalse, QnanException); + 0x1: c_ngle_s({{ cond = 0; }}, SinglePrecision, + UnorderedTrue, QnanException); + 0x2: c_seq_s({{ cond = (Fs.sf == Ft.sf);}}, + UnorderedFalse, QnanException); + 0x3: c_ngl_s({{ cond = (Fs.sf == Ft.sf); }}, + UnorderedTrue, QnanException); + 0x4: c_lt_s({{ cond = (Fs.sf < Ft.sf); }}, + UnorderedFalse, QnanException); + 0x5: c_nge_s({{ cond = (Fs.sf < Ft.sf); }}, + UnorderedTrue, QnanException); + 0x6: c_le_s({{ cond = (Fs.sf <= Ft.sf); }}, + UnorderedFalse, QnanException); + 0x7: c_ngt_s({{ cond = (Fs.sf <= Ft.sf); }}, + UnorderedTrue, QnanException); + } + } + } + + //Table A-15 MIPS32 COP1 Encoding of Function Field When rs=D + 0x1: decode FUNCTION_HI { + 0x0: decode FUNCTION_LO { + format FloatOp { + 0x0: add_d({{ Fd.df = Fs.df + Ft.df; }}); + 0x1: sub_d({{ Fd.df = Fs.df - Ft.df; }}); + 0x2: mul_d({{ Fd.df = Fs.df * Ft.df; }}); + 0x3: div_d({{ Fd.df = Fs.df / Ft.df; }}); + 0x4: sqrt_d({{ Fd.df = sqrt(Fs.df); }}); + 0x5: abs_d({{ Fd.df = fabs(Fs.df); }}); + 0x6: mov_d({{ Fd.df = Fs.df; }}); + 0x7: neg_d({{ Fd.df = -1 * Fs.df; }}); + } + } + + 0x1: decode FUNCTION_LO { + format FloatConvertOp { + 0x0: round_l_d({{ val = Fs.df; }}, ToLong, + Round); + 0x1: trunc_l_d({{ val = Fs.df; }}, ToLong, + Trunc); + 0x2: ceil_l_d({{ val = Fs.df; }}, ToLong, + Ceil); + 0x3: floor_l_d({{ val = Fs.df; }}, ToLong, + Floor); + 0x4: round_w_d({{ val = Fs.df; }}, ToWord, + Round); + 0x5: trunc_w_d({{ val = Fs.df; }}, ToWord, + Trunc); + 0x6: ceil_w_d({{ val = Fs.df; }}, ToWord, + Ceil); + 0x7: floor_w_d({{ val = Fs.df; }}, ToWord, + Floor); + } + } + + 0x2: decode FUNCTION_LO { + 0x1: decode MOVCF { + format BasicOp { + 0x0: movf_d({{ Fd.df = (getCondCode(FCSR,CC) == 0) ? + Fs.df : Fd.df; + }}); + 0x1: movt_d({{ Fd.df = (getCondCode(FCSR,CC) == 1) ? + Fs.df : Fd.df; + }}); + } + } + + format BasicOp { + 0x2: movz_d({{ Fd.df = (Rt == 0) ? Fs.df : Fd.df; }}); + 0x3: movn_d({{ Fd.df = (Rt != 0) ? Fs.df : Fd.df; }}); + } + + format FloatOp { + 0x5: recip_d({{ Fd.df = 1 / Fs.df }}); + 0x6: rsqrt_d({{ Fd.df = 1 / sqrt(Fs.df) }}); + } + } + + 0x4: decode FUNCTION_LO { + format FloatConvertOp { + 0x0: cvt_s_d({{ val = Fs.df; }}, ToSingle); + 0x4: cvt_w_d({{ val = Fs.df; }}, ToWord); + 0x5: cvt_l_d({{ val = Fs.df; }}, ToLong); + } + } + + 0x6: decode FUNCTION_LO { + format FloatCompareOp { + 0x0: c_f_d({{ cond = 0; }}, DoublePrecision, + UnorderedFalse); + 0x1: c_un_d({{ cond = 0; }}, DoublePrecision, + UnorderedTrue); + 0x2: c_eq_d({{ cond = (Fs.df == Ft.df); }}, + UnorderedFalse); + 0x3: c_ueq_d({{ cond = (Fs.df == Ft.df); }}, + UnorderedTrue); + 0x4: c_olt_d({{ cond = (Fs.df < Ft.df); }}, + UnorderedFalse); + 0x5: c_ult_d({{ cond = (Fs.df < Ft.df); }}, + UnorderedTrue); + 0x6: c_ole_d({{ cond = (Fs.df <= Ft.df); }}, + UnorderedFalse); + 0x7: c_ule_d({{ cond = (Fs.df <= Ft.df); }}, + UnorderedTrue); + } + } + + 0x7: decode FUNCTION_LO { + format FloatCompareOp { + 0x0: c_sf_d({{ cond = 0; }}, DoublePrecision, + UnorderedFalse, QnanException); + 0x1: c_ngle_d({{ cond = 0; }}, DoublePrecision, + UnorderedTrue, QnanException); + 0x2: c_seq_d({{ cond = (Fs.df == Ft.df); }}, + UnorderedFalse, QnanException); + 0x3: c_ngl_d({{ cond = (Fs.df == Ft.df); }}, + UnorderedTrue, QnanException); + 0x4: c_lt_d({{ cond = (Fs.df < Ft.df); }}, + UnorderedFalse, QnanException); + 0x5: c_nge_d({{ cond = (Fs.df < Ft.df); }}, + UnorderedTrue, QnanException); + 0x6: c_le_d({{ cond = (Fs.df <= Ft.df); }}, + UnorderedFalse, QnanException); + 0x7: c_ngt_d({{ cond = (Fs.df <= Ft.df); }}, + UnorderedTrue, QnanException); + } + } + } + + //Table A-16 MIPS32 COP1 Encoding of Function Field When rs=W + 0x4: decode FUNCTION { + format FloatConvertOp { + 0x20: cvt_s_w({{ val = Fs.uw; }}, ToSingle); + 0x21: cvt_d_w({{ val = Fs.uw; }}, ToDouble); + 0x26: FailUnimpl::cvt_ps_w(); + } + } + + //Table A-16 MIPS32 COP1 Encoding of Function Field When rs=L1 + //Note: "1. Format type L is legal only if 64-bit floating point operations + //are enabled." + 0x5: decode FUNCTION_HI { + format FloatConvertOp { + 0x20: cvt_s_l({{ val = Fs.ud; }}, ToSingle); + 0x21: cvt_d_l({{ val = Fs.ud; }}, ToDouble); + 0x26: FailUnimpl::cvt_ps_l(); + } + } + + //Table A-17 MIPS64 COP1 Encoding of Function Field When rs=PS1 + //Note: "1. Format type PS is legal only if 64-bit floating point operations + //are enabled. " + 0x6: decode FUNCTION_HI { + 0x0: decode FUNCTION_LO { + format Float64Op { + 0x0: add_ps({{ + Fd1.sf = Fs1.sf + Ft2.sf; + Fd2.sf = Fs2.sf + Ft2.sf; + }}); + 0x1: sub_ps({{ + Fd1.sf = Fs1.sf - Ft2.sf; + Fd2.sf = Fs2.sf - Ft2.sf; + }}); + 0x2: mul_ps({{ + Fd1.sf = Fs1.sf * Ft2.sf; + Fd2.sf = Fs2.sf * Ft2.sf; + }}); + 0x5: abs_ps({{ + Fd1.sf = fabs(Fs1.sf); + Fd2.sf = fabs(Fs2.sf); + }}); + 0x6: mov_ps({{ + Fd1.sf = Fs1.sf; + Fd2.sf = Fs2.sf; + }}); + 0x7: neg_ps({{ + Fd1.sf = -(Fs1.sf); + Fd2.sf = -(Fs2.sf); + }}); + } + } + + 0x2: decode FUNCTION_LO { + 0x1: decode MOVCF { + format Float64Op { + 0x0: movf_ps({{ + Fd1 = (getCondCode(FCSR, CC) == 0) ? + Fs1 : Fd1; + Fd2 = (getCondCode(FCSR, CC+1) == 0) ? + Fs2 : Fd2; + }}); + 0x1: movt_ps({{ + Fd2 = (getCondCode(FCSR, CC) == 1) ? + Fs1 : Fd1; + Fd2 = (getCondCode(FCSR, CC+1) == 1) ? + Fs2 : Fd2; + }}); + } + } + + format Float64Op { + 0x2: movz_ps({{ + Fd1 = (getCondCode(FCSR, CC) == 0) ? + Fs1 : Fd1; + Fd2 = (getCondCode(FCSR, CC) == 0) ? + Fs2 : Fd2; + }}); + 0x3: movn_ps({{ + Fd1 = (getCondCode(FCSR, CC) == 1) ? + Fs1 : Fd1; + Fd2 = (getCondCode(FCSR, CC) == 1) ? + Fs2 : Fd2; + }}); + } + + } + + 0x4: decode FUNCTION_LO { + 0x0: FloatOp::cvt_s_pu({{ Fd.sf = Fs2.sf; }}); + } + + 0x5: decode FUNCTION_LO { + 0x0: FloatOp::cvt_s_pl({{ Fd.sf = Fs1.sf; }}); + + format Float64Op { + 0x4: pll({{ Fd.ud = (uint64_t) Fs1.uw << 32 | + Ft1.uw; + }}); + 0x5: plu({{ Fd.ud = (uint64_t) Fs1.uw << 32 | + Ft2.uw; + }}); + 0x6: pul({{ Fd.ud = (uint64_t) Fs2.uw << 32 | + Ft1.uw; + }}); + 0x7: puu({{ Fd.ud = (uint64_t) Fs2.uw << 32 | + Ft2.uw; + }}); + } + } + + 0x6: decode FUNCTION_LO { + format FloatPSCompareOp { + 0x0: c_f_ps({{ cond1 = 0; }}, {{ cond2 = 0; }}, + UnorderedFalse); + 0x1: c_un_ps({{ cond1 = 0; }}, {{ cond2 = 0; }}, + UnorderedTrue); + 0x2: c_eq_ps({{ cond1 = (Fs1.sf == Ft1.sf); }}, + {{ cond2 = (Fs2.sf == Ft2.sf); }}, + UnorderedFalse); + 0x3: c_ueq_ps({{ cond1 = (Fs1.sf == Ft1.sf); }}, + {{ cond2 = (Fs2.sf == Ft2.sf); }}, + UnorderedTrue); + 0x4: c_olt_ps({{ cond1 = (Fs1.sf < Ft1.sf); }}, + {{ cond2 = (Fs2.sf < Ft2.sf); }}, + UnorderedFalse); + 0x5: c_ult_ps({{ cond1 = (Fs.sf < Ft.sf); }}, + {{ cond2 = (Fs2.sf < Ft2.sf); }}, + UnorderedTrue); + 0x6: c_ole_ps({{ cond1 = (Fs.sf <= Ft.sf); }}, + {{ cond2 = (Fs2.sf <= Ft2.sf); }}, + UnorderedFalse); + 0x7: c_ule_ps({{ cond1 = (Fs1.sf <= Ft1.sf); }}, + {{ cond2 = (Fs2.sf <= Ft2.sf); }}, + UnorderedTrue); + } + } + + 0x7: decode FUNCTION_LO { + format FloatPSCompareOp { + 0x0: c_sf_ps({{ cond1 = 0; }}, {{ cond2 = 0; }}, + UnorderedFalse, QnanException); + 0x1: c_ngle_ps({{ cond1 = 0; }}, + {{ cond2 = 0; }}, + UnorderedTrue, QnanException); + 0x2: c_seq_ps({{ cond1 = (Fs1.sf == Ft1.sf); }}, + {{ cond2 = (Fs2.sf == Ft2.sf); }}, + UnorderedFalse, QnanException); + 0x3: c_ngl_ps({{ cond1 = (Fs1.sf == Ft1.sf); }}, + {{ cond2 = (Fs2.sf == Ft2.sf); }}, + UnorderedTrue, QnanException); + 0x4: c_lt_ps({{ cond1 = (Fs1.sf < Ft1.sf); }}, + {{ cond2 = (Fs2.sf < Ft2.sf); }}, + UnorderedFalse, QnanException); + 0x5: c_nge_ps({{ cond1 = (Fs1.sf < Ft1.sf); }}, + {{ cond2 = (Fs2.sf < Ft2.sf); }}, + UnorderedTrue, QnanException); + 0x6: c_le_ps({{ cond1 = (Fs1.sf <= Ft1.sf); }}, + {{ cond2 = (Fs2.sf <= Ft2.sf); }}, + UnorderedFalse, QnanException); + 0x7: c_ngt_ps({{ cond1 = (Fs1.sf <= Ft1.sf); }}, + {{ cond2 = (Fs2.sf <= Ft2.sf); }}, + UnorderedTrue, QnanException); + } + } + } + } + } + } + + //Table A-19 MIPS32 COP2 Encoding of rs Field + 0x2: decode RS_MSB { + format FailUnimpl { + 0x0: decode RS_HI { + 0x0: decode RS_LO { + 0x0: mfc2(); + 0x2: cfc2(); + 0x3: mfhc2(); + 0x4: mtc2(); + 0x6: ctc2(); + 0x7: mftc2(); + } + + 0x1: decode ND { + 0x0: decode TF { + 0x0: bc2f(); + 0x1: bc2t(); + } + + 0x1: decode TF { + 0x0: bc2fl(); + 0x1: bc2tl(); + } + } + } + } + } + + //Table A-20 MIPS64 COP1X Encoding of Function Field 1 + //Note: "COP1X instructions are legal only if 64-bit floating point + //operations are enabled." + 0x3: decode FUNCTION_HI { + 0x0: decode FUNCTION_LO { + format LoadIndexedMemory { + 0x0: lwxc1({{ Ft.uw = Mem.uw;}}); + 0x1: ldxc1({{ Ft.ud = Mem.ud;}}); + 0x5: luxc1({{ Ft.uw = Mem.ud;}}); + } + } + + 0x1: decode FUNCTION_LO { + format StoreIndexedMemory { + 0x0: swxc1({{ Mem.uw = Ft.uw;}}); + 0x1: sdxc1({{ Mem.ud = Ft.ud;}}); + 0x5: suxc1({{ Mem.ud = Ft.ud;}}); + } + + 0x7: Prefetch::prefx({{ EA = Rs + Rt; }}); + } + + 0x3: decode FUNCTION_LO { + 0x6: Float64Op::alnv_ps({{ if (Rs<2:0> == 0) { + Fd.ud = Fs.ud; + } else if (Rs<2:0> == 4) { + #if BYTE_ORDER == BIG_ENDIAN + Fd.ud = Fs.ud<31:0> << 32 | + Ft.ud<63:32>; + #elif BYTE_ORDER == LITTLE_ENDIAN + Fd.ud = Ft.ud<31:0> << 32 | + Fs.ud<63:32>; + #endif + } else { + Fd.ud = Fd.ud; + } + }}); + } + + format FloatAccOp { + 0x4: decode FUNCTION_LO { + 0x0: madd_s({{ Fd.sf = (Fs.sf * Ft.sf) + Fr.sf; }}); + 0x1: madd_d({{ Fd.df = (Fs.df * Ft.df) + Fr.df; }}); + 0x6: madd_ps({{ + Fd1.sf = (Fs1.df * Ft1.df) + Fr1.df; + Fd2.sf = (Fs2.df * Ft2.df) + Fr2.df; + }}); + } + + 0x5: decode FUNCTION_LO { + 0x0: msub_s({{ Fd.sf = (Fs.sf * Ft.sf) - Fr.sf; }}); + 0x1: msub_d({{ Fd.df = (Fs.df * Ft.df) - Fr.df; }}); + 0x6: msub_ps({{ + Fd1.sf = (Fs1.df * Ft1.df) - Fr1.df; + Fd2.sf = (Fs2.df * Ft2.df) - Fr2.df; + }}); + } + + 0x6: decode FUNCTION_LO { + 0x0: nmadd_s({{ Fd.sf = (-1 * Fs.sf * Ft.sf) - Fr.sf; }}); + 0x1: nmadd_d({{ Fd.df = (-1 * Fs.df * Ft.df) + Fr.df; }}); + 0x6: nmadd_ps({{ + Fd1.sf = -((Fs1.df * Ft1.df) + Fr1.df); + Fd2.sf = -((Fs2.df * Ft2.df) + Fr2.df); + }}); + } + + 0x7: decode FUNCTION_LO { + 0x0: nmsub_s({{ Fd.sf = (-1 * Fs.sf * Ft.sf) - Fr.sf; }}); + 0x1: nmsub_d({{ Fd.df = (-1 * Fs.df * Ft.df) - Fr.df; }}); + 0x6: nmsub_ps({{ + Fd1.sf = -((Fs1.df * Ft1.df) - Fr1.df); + Fd2.sf = -((Fs2.df * Ft2.df) - Fr2.df); + }}); + } + + } + } + + format Branch { + 0x4: beql({{ cond = (Rs.sw == Rt.sw); }}, Likely); + 0x5: bnel({{ cond = (Rs.sw != Rt.sw); }}, Likely); + 0x6: blezl({{ cond = (Rs.sw <= 0); }}, Likely); + 0x7: bgtzl({{ cond = (Rs.sw > 0); }}, Likely); + } + } + + 0x3: decode OPCODE_LO { + //Table A-5 MIPS32 SPECIAL2 Encoding of Function Field + 0x4: decode FUNCTION_HI { + 0x0: decode FUNCTION_LO { + 0x2: IntOp::mul({{ int64_t temp1 = Rs.sd * Rt.sd; + Rd.sw = temp1<31:0> + }}); + + format HiLoOp { + 0x0: madd({{ val = ((int64_t) HI << 32 | LO) + + (Rs.sd * Rt.sd); + }}); + 0x1: maddu({{ val = ((uint64_t) HI << 32 | LO) + + (Rs.ud * Rt.ud); + }}); + 0x4: msub({{ val = ((int64_t) HI << 32 | LO) - + (Rs.sd * Rt.sd); + }}); + 0x5: msubu({{ val = ((uint64_t) HI << 32 | LO) - + (Rs.ud * Rt.ud); + }}); + } + } + + 0x4: decode FUNCTION_LO { + format BasicOp { + 0x0: clz({{ int cnt = 32; + for (int idx = 31; idx >= 0; idx--) { + if( Rs<idx:idx> == 1) { + cnt = 31 - idx; + break; + } + } + Rd.uw = cnt; + }}); + 0x1: clo({{ int cnt = 32; + for (int idx = 31; idx >= 0; idx--) { + if( Rs<idx:idx> == 0) { + cnt = 31 - idx; + break; + } + } + Rd.uw = cnt; + }}); + } + } + + 0x7: decode FUNCTION_LO { + 0x7: FailUnimpl::sdbbp(); + } + } + + //Table A-6 MIPS32 SPECIAL3 Encoding of Function Field for Release 2 + //of the Architecture + 0x7: decode FUNCTION_HI { + 0x0: decode FUNCTION_LO { + format BasicOp { + 0x1: ext({{ Rt.uw = bits(Rs.uw, MSB+LSB, LSB); }}); + 0x4: ins({{ Rt.uw = bits(Rt.uw, 31, MSB+1) << (MSB+1) | + bits(Rs.uw, MSB-LSB, 0) << LSB | + bits(Rt.uw, LSB-1, 0); + }}); + } + } + + 0x1: decode FUNCTION_LO { + format MipsMT { + 0x0: fork(); + 0x1: yield(); + } + } + + //Table A-10 MIPS32 BSHFL Encoding of sa Field + 0x4: decode SA { + format BasicOp { + 0x02: wsbh({{ Rd.uw = Rt.uw<23:16> << 24 | + Rt.uw<31:24> << 16 | + Rt.uw<7:0> << 8 | + Rt.uw<15:8>; + }}); + 0x10: seb({{ Rd.sw = Rt.sw<7:0>}}); + 0x18: seh({{ Rd.sw = Rt.sw<15:0>}}); + } + } + + 0x6: decode FUNCTION_LO { + 0x7: FailUnimpl::rdhwr(); + } + } + } + + 0x4: decode OPCODE_LO { + format LoadMemory { + 0x0: lb({{ Rt.sw = Mem.sb; }}); + 0x1: lh({{ Rt.sw = Mem.sh; }}); + 0x3: lw({{ Rt.sw = Mem.sw; }}); + 0x4: lbu({{ Rt.uw = Mem.ub; }}); + 0x5: lhu({{ Rt.uw = Mem.uh; }}); + } + + format LoadUnalignedMemory { + 0x2: lwl({{ uint32_t mem_shift = 24 - (8 * byte_offset); + Rt.uw = mem_word << mem_shift | + Rt.uw & mask(mem_shift); + }}); + 0x6: lwr({{ uint32_t mem_shift = 8 * byte_offset; + Rt.uw = Rt.uw & (mask(mem_shift) << (32 - mem_shift)) | + mem_word >> mem_shift; + }}); + } + } + + 0x5: decode OPCODE_LO { + format StoreMemory { + 0x0: sb({{ Mem.ub = Rt<7:0>; }}); + 0x1: sh({{ Mem.uh = Rt<15:0>; }}); + 0x3: sw({{ Mem.uw = Rt<31:0>; }}); + } + + format StoreUnalignedMemory { + 0x2: swl({{ uint32_t reg_shift = 24 - (8 * byte_offset); + uint32_t mem_shift = 32 - reg_shift; + mem_word = mem_word & (mask(reg_shift) << mem_shift) | + Rt.uw >> reg_shift; + }}); + 0x6: swr({{ uint32_t reg_shift = 8 * byte_offset; + mem_word = Rt.uw << reg_shift | + mem_word & (mask(reg_shift)); + }}); + } + + 0x7: FailUnimpl::cache(); + } + + 0x6: decode OPCODE_LO { + format LoadMemory { + 0x0: ll({{ Rt.uw = Mem.uw; }}, mem_flags=LOCKED); + 0x1: lwc1({{ Ft.uw = Mem.uw; }}); + 0x5: ldc1({{ Ft.ud = Mem.ud; }}); + } + + 0x3: Prefetch::pref(); + } + + + 0x7: decode OPCODE_LO { + 0x0: StoreCond::sc({{ Mem.uw = Rt.uw;}}, + {{ uint64_t tmp = write_result; + Rt.uw = (tmp == 0 || tmp == 1) ? tmp : Rt.uw; + }}, mem_flags=LOCKED); + + format StoreMemory { + 0x1: swc1({{ Mem.uw = Ft.uw; }}); + 0x5: sdc1({{ Mem.ud = Ft.ud; }}); + } + } +} + + diff --git a/src/arch/mips/isa/formats/basic.isa b/src/arch/mips/isa/formats/basic.isa new file mode 100644 index 000000000..35ce09205 --- /dev/null +++ b/src/arch/mips/isa/formats/basic.isa @@ -0,0 +1,95 @@ +// -*- mode:c++ -*- + +// 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: Korey Sewell + +// Declarations for execute() methods. +def template BasicExecDeclare {{ + Fault execute(%(CPU_exec_context)s *, Trace::InstRecord *) const; +}}; + +// Basic instruction class declaration template. +def template BasicDeclare {{ + /** + * Static instruction class for "%(mnemonic)s". + */ + class %(class_name)s : public %(base_class)s + { + public: + /// Constructor. + %(class_name)s(MachInst machInst); + %(BasicExecDeclare)s + }; +}}; + +// Basic instruction class constructor template. +def template BasicConstructor {{ + inline %(class_name)s::%(class_name)s(MachInst machInst) : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s) + { + %(constructor)s; + } +}}; + + +// Basic instruction class execute method template. +def template BasicExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const + { + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + %(code)s; + + if(fault == NoFault) + { + %(op_wb)s; + } + return fault; + } +}}; + +// Basic decode template. +def template BasicDecode {{ + return new %(class_name)s(machInst); +}}; + +// Basic decode template, passing mnemonic in as string arg to constructor. +def template BasicDecodeWithMnemonic {{ + return new %(class_name)s("%(mnemonic)s", machInst); +}}; + +// The most basic instruction format... used only for a few misc. insts +def format BasicOp(code, *flags) {{ + iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; diff --git a/src/arch/mips/isa/formats/branch.isa b/src/arch/mips/isa/formats/branch.isa new file mode 100644 index 000000000..827e3ccf0 --- /dev/null +++ b/src/arch/mips/isa/formats/branch.isa @@ -0,0 +1,278 @@ +// -*- mode:c++ -*- + +// 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: Korey Sewell + +//////////////////////////////////////////////////////////////////// +// +// Control transfer instructions +// + +output header {{ + +#include <iostream> + using namespace std; + + /** + * Base class for instructions whose disassembly is not purely a + * function of the machine instruction (i.e., it depends on the + * PC). This class overrides the disassemble() method to check + * the PC and symbol table values before re-using a cached + * disassembly string. This is necessary for branches and jumps, + * where the disassembly string includes the target address (which + * may depend on the PC and/or symbol table). + */ + class PCDependentDisassembly : public MipsStaticInst + { + protected: + /// Cached program counter from last disassembly + mutable Addr cachedPC; + + /// Cached symbol table pointer from last disassembly + mutable const SymbolTable *cachedSymtab; + + /// Constructor + PCDependentDisassembly(const char *mnem, MachInst _machInst, + OpClass __opClass) + : MipsStaticInst(mnem, _machInst, __opClass), + cachedPC(0), cachedSymtab(0) + { + } + + const std::string & + disassemble(Addr pc, const SymbolTable *symtab) const; + }; + + /** + * Base class for branches (PC-relative control transfers), + * conditional or unconditional. + */ + class Branch : public PCDependentDisassembly + { + protected: + /// target address (signed) Displacement . + int32_t disp; + + /// Constructor. + Branch(const char *mnem, MachInst _machInst, OpClass __opClass) + : PCDependentDisassembly(mnem, _machInst, __opClass), + disp(OFFSET << 2) + { + //If Bit 17 is 1 then Sign Extend + if ( (disp & 0x00020000) > 0 ) { + disp |= 0xFFFE0000; + } + } + + Addr branchTarget(Addr branchPC) const; + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; + + /** + * Base class for jumps (register-indirect control transfers). In + * the Mips ISA, these are always unconditional. + */ + class Jump : public PCDependentDisassembly + { + protected: + + /// Displacement to target address (signed). + int32_t disp; + + uint32_t target; + + public: + /// Constructor + Jump(const char *mnem, MachInst _machInst, OpClass __opClass) + : PCDependentDisassembly(mnem, _machInst, __opClass), + disp(JMPTARG << 2) + { + } + + Addr branchTarget(ThreadContext *tc) const; + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; +}}; + +output decoder {{ + Addr + Branch::branchTarget(Addr branchPC) const + { + return branchPC + 4 + disp; + } + + Addr + Jump::branchTarget(ThreadContext *tc) const + { + Addr NPC = tc->readPC() + 4; + uint64_t Rb = tc->readIntReg(_srcRegIdx[0]); + return (Rb & ~3) | (NPC & 1); + } + + const std::string & + PCDependentDisassembly::disassemble(Addr pc, + const SymbolTable *symtab) const + { + if (!cachedDisassembly || + pc != cachedPC || symtab != cachedSymtab) + { + if (cachedDisassembly) + delete cachedDisassembly; + + cachedDisassembly = + new std::string(generateDisassembly(pc, symtab)); + cachedPC = pc; + cachedSymtab = symtab; + } + + return *cachedDisassembly; + } + + std::string + Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + std::stringstream ss; + + ccprintf(ss, "%-10s ", mnemonic); + + // There's only one register arg (RA), but it could be + // either a source (the condition for conditional + // branches) or a destination (the link reg for + // unconditional branches) + if (_numSrcRegs == 1) { + printReg(ss, _srcRegIdx[0]); + ss << ", "; + } else if(_numSrcRegs == 2) { + printReg(ss, _srcRegIdx[0]); + ss << ", "; + printReg(ss, _srcRegIdx[1]); + ss << ", "; + } + + Addr target = pc + 4 + disp; + + std::string str; + if (symtab && symtab->findSymbol(target, str)) + ss << str; + else + ccprintf(ss, "0x%x", target); + + return ss.str(); + } + + std::string + Jump::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + std::stringstream ss; + + ccprintf(ss, "%-10s ", mnemonic); + + if ( mnemonic == "jal" ) { + Addr npc = pc + 4; + ccprintf(ss,"0x%x",(npc & 0xF0000000) | disp); + } else if (_numSrcRegs == 0) { + std::string str; + if (symtab && symtab->findSymbol(disp, str)) + ss << str; + else + ccprintf(ss, "0x%x", disp); + } else if (_numSrcRegs == 1) { + printReg(ss, _srcRegIdx[0]); + } else if(_numSrcRegs == 2) { + printReg(ss, _srcRegIdx[0]); + ss << ", "; + printReg(ss, _srcRegIdx[1]); + } + + return ss.str(); + } +}}; + +def format Branch(code,*opt_flags) {{ + not_taken_code = ' NNPC = NNPC;\n' + not_taken_code += '} \n' + + #Build Instruction Flags + #Use Link & Likely Flags to Add Link/Condition Code + inst_flags = ('IsDirectControl', ) + for x in opt_flags: + if x == 'Link': + code += 'R31 = NNPC;\n' + elif x == 'Likely': + not_taken_code = ' NPC = NNPC;\n' + not_taken_code += ' NNPC = NNPC + 4;\n' + not_taken_code += '} \n' + inst_flags = ('IsCondDelaySlot', ) + else: + inst_flags += (x, ) + + if 'cond == 1' in code: + inst_flags += ('IsCondControl', ) + else: + inst_flags += ('IsUncondControl', ) + + #Condition code + code = 'bool cond;\n' + code + code += 'if (cond) {\n' + code += ' NNPC = NPC + disp;\n' + code += '} else {\n' + code += not_taken_code + + iop = InstObjParams(name, Name, 'Branch', CodeBlock(code), inst_flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + +def format Jump(code, *opt_flags) {{ + #Build Instruction Flags + #Use Link Flag to Add Link Code + inst_flags = ('IsIndirectControl', 'IsUncondControl') + for x in opt_flags: + if x == 'Link': + code = 'R31 = NNPC;\n' + code + elif x == 'ClearHazards': + code += '/* Code Needed to Clear Execute & Inst Hazards */\n' + else: + inst_flags += (x, ) + + iop = InstObjParams(name, Name, 'Jump', CodeBlock(code), inst_flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + + + + diff --git a/src/arch/mips/isa/formats/control.isa b/src/arch/mips/isa/formats/control.isa new file mode 100644 index 000000000..509ee7e87 --- /dev/null +++ b/src/arch/mips/isa/formats/control.isa @@ -0,0 +1,156 @@ +// -*- mode:c++ -*- + +// 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: Korey Sewell + +//////////////////////////////////////////////////////////////////// +// +// Integer operate instructions +// + +//Outputs to decoder.hh +output header {{ + + class Control : public MipsStaticInst + { + protected: + + /// Constructor + Control(const char *mnem, MachInst _machInst, OpClass __opClass) : + MipsStaticInst(mnem, _machInst, __opClass) + { + } + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; + + class CP0Control : public Control + { + protected: + + /// Constructor + CP0Control(const char *mnem, MachInst _machInst, OpClass __opClass) : + Control(mnem, _machInst, __opClass) + { + } + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; + + class CP1Control : public Control + { + protected: + + /// Constructor + CP1Control(const char *mnem, MachInst _machInst, OpClass __opClass) : + Control(mnem, _machInst, __opClass) + { + } + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; + +}}; + +//Outputs to decoder.cc +output decoder {{ + std::string Control::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + std::stringstream ss; + + ccprintf(ss, "%-10s ", mnemonic); + + if (mnemonic == "mfc0" || mnemonic == "mtc0") { + ccprintf(ss, "%-10s %d,%d,%d", mnemonic,RT,RD,SEL); + } else { + + // just print the first dest... if there's a second one, + // it's generally implicit + if (_numDestRegs > 0) { + printReg(ss, _destRegIdx[0]); + } + + ss << ", "; + + // just print the first two source regs... if there's + // a third one, it's a read-modify-write dest (Rc), + // e.g. for CMOVxx + if (_numSrcRegs > 0) { + printReg(ss, _srcRegIdx[0]); + } + + if (_numSrcRegs > 1) { + ss << ", "; + printReg(ss, _srcRegIdx[1]); + } + } + + return ss.str(); + } + + std::string CP0Control::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + std::stringstream ss; + ccprintf(ss, "%-10s r%d, r%d, %d", mnemonic, RT, RD, SEL); + return ss.str(); + } + + std::string CP1Control::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + std::stringstream ss; + ccprintf(ss, "%-10s r%d, f%d", mnemonic, RT, FS); + return ss.str(); + } + +}}; + +def format System(code, *flags) {{ + iop = InstObjParams(name, Name, 'Control', CodeBlock(code), flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + +def format CP0Control(code, *flags) {{ + iop = InstObjParams(name, Name, 'CP0Control', CodeBlock(code), flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + +def format CP1Control(code, *flags) {{ + iop = InstObjParams(name, Name, 'CP1Control', CodeBlock(code), flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + + diff --git a/src/arch/mips/isa/formats/formats.isa b/src/arch/mips/isa/formats/formats.isa new file mode 100644 index 000000000..4c3eec132 --- /dev/null +++ b/src/arch/mips/isa/formats/formats.isa @@ -0,0 +1,66 @@ +// -*- mode:c++ -*- + +// 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: Korey Sewell + +//Templates from this format are used later +//Include the basic format +##include "basic.isa" + +//Include the basic format +##include "noop.isa" + +//Include utility functions +##include "util.isa" + +//Include the control/cp0/cp1 formats +##include "control.isa" + +//Include the integer formats +##include "int.isa" + +//Include the floatOp format +##include "fp.isa" + +//Include the mem format +##include "mem.isa" + +//Include the mem format +##include "mt.isa" + +//Include the trap format +##include "trap.isa" + +//Include the branch format +##include "branch.isa" + +//Include the noop format +##include "unimp.isa" + +//Include the noop format +##include "unknown.isa" diff --git a/src/arch/mips/isa/formats/fp.isa b/src/arch/mips/isa/formats/fp.isa new file mode 100644 index 000000000..d05b04d0e --- /dev/null +++ b/src/arch/mips/isa/formats/fp.isa @@ -0,0 +1,369 @@ +// -*- mode:c++ -*- + +// 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: Korey Sewell + +//////////////////////////////////////////////////////////////////// +// +// Floating Point operate instructions +// + +output header {{ + /** + * Base class for FP operations. + */ + class FPOp : public MipsStaticInst + { + protected: + + /// Constructor + FPOp(const char *mnem, MachInst _machInst, OpClass __opClass) : MipsStaticInst(mnem, _machInst, __opClass) + { + } + + //std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; + + //needs function to check for fpEnable or not + }; + + class FPCompareOp : public FPOp + { + protected: + FPCompareOp(const char *mnem, MachInst _machInst, OpClass __opClass) : FPOp(mnem, _machInst, __opClass) + { + } + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; + + }; +}}; + +output decoder {{ + std::string FPCompareOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + std::stringstream ss; + + ccprintf(ss, "%-10s ", mnemonic); + + ccprintf(ss,"%d",CC); + + if(_numSrcRegs > 0) { + ss << ", "; + printReg(ss, _srcRegIdx[0]); + } + + if(_numSrcRegs > 1) { + ss << ", "; + printReg(ss, _srcRegIdx[1]); + } + + return ss.str(); + } +}}; + +output exec {{ + + //If any operand is Nan return the appropriate QNaN + template <class T> + bool + fpNanOperands(FPOp *inst, %(CPU_exec_context)s *xc, const T &src_type, + Trace::InstRecord *traceData) + { + uint64_t mips_nan = 0; + T src_op = 0; + int size = sizeof(src_op) * 8; + + for (int i = 0; i < inst->numSrcRegs(); i++) { + uint64_t src_bits = xc->readFloatRegBits(inst, 0, size); + + if (isNan(&src_bits, size) ) { + if (isSnan(&src_bits, size)) { + switch (size) + { + case 32: mips_nan = MIPS32_QNAN; break; + case 64: mips_nan = MIPS64_QNAN; break; + default: panic("Unsupported Floating Point Size (%d)", size); + } + } else { + mips_nan = src_bits; + } + + xc->setFloatRegBits(inst, 0, mips_nan, size); + if (traceData) { traceData->setData(mips_nan); } + return true; + } + } + return false; + } + + template <class T> + bool + fpInvalidOp(FPOp *inst, %(CPU_exec_context)s *cpu, const T dest_val, + Trace::InstRecord *traceData) + { + uint64_t mips_nan = 0; + T src_op = dest_val; + int size = sizeof(src_op) * 8; + + if (isNan(&src_op, size)) { + switch (size) + { + case 32: mips_nan = MIPS32_QNAN; break; + case 64: mips_nan = MIPS64_QNAN; break; + default: panic("Unsupported Floating Point Size (%d)", size); + } + + //Set value to QNAN + cpu->setFloatRegBits(inst, 0, mips_nan, size); + + //Read FCSR from FloatRegFile + uint32_t fcsr_bits = cpu->tc->readFloatRegBits(FCSR); + + //Write FCSR from FloatRegFile + cpu->tc->setFloatRegBits(FCSR, genInvalidVector(fcsr_bits)); + + if (traceData) { traceData->setData(mips_nan); } + return true; + } + + return false; + } + + void + fpResetCauseBits(%(CPU_exec_context)s *cpu) + { + //Read FCSR from FloatRegFile + uint32_t fcsr = cpu->tc->readFloatRegBits(FCSR); + + fcsr = bits(fcsr, 31, 18) << 18 | bits(fcsr, 11, 0); + + //Write FCSR from FloatRegFile + cpu->tc->setFloatRegBits(FCSR, fcsr); + } +}}; + +def template FloatingPointExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const + { + Fault fault = NoFault; + + %(fp_enable_check)s; + + //When is the right time to reset cause bits? + //start of every instruction or every cycle? + fpResetCauseBits(xc); + + %(op_decl)s; + %(op_rd)s; + + //Check if any FP operand is a NaN value + if (!fpNanOperands((FPOp*)this, xc, Fd, traceData)) { + %(code)s; + + //Change this code for Full-System/Sycall Emulation + //separation + //---- + //Should Full System-Mode throw a fault here? + //---- + //Check for IEEE 754 FP Exceptions + //fault = fpNanOperands((FPOp*)this, xc, Fd, traceData); + if (!fpInvalidOp((FPOp*)this, xc, Fd, traceData) && + fault == NoFault) + { + %(op_wb)s; + } + } + + return fault; + } +}}; + +// Primary format for float point operate instructions: +def format FloatOp(code, *flags) {{ + iop = InstObjParams(name, Name, 'FPOp', CodeBlock(code), flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = FloatingPointExecute.subst(iop) +}}; + +def format FloatCompareOp(cond_code, *flags) {{ + import sys + + code = 'bool cond;\n' + if '.sf' in cond_code or 'SinglePrecision' in flags: + if 'QnanException' in flags: + code += 'if (isQnan(&Fs.sf, 32) || isQnan(&Ft.sf, 32)) {\n' + code += '\tFCSR = genInvalidVector(FCSR);\n' + code += '\treturn NoFault;' + code += '}\n else ' + code += 'if (isNan(&Fs.sf, 32) || isNan(&Ft.sf, 32)) {\n' + elif '.df' in cond_code or 'DoublePrecision' in flags: + if 'QnanException' in flags: + code += 'if (isQnan(&Fs.df, 64) || isQnan(&Ft.df, 64)) {\n' + code += '\tFCSR = genInvalidVector(FCSR);\n' + code += '\treturn NoFault;' + code += '}\n else ' + code += 'if (isNan(&Fs.df, 64) || isNan(&Ft.df, 64)) {\n' + else: + sys.exit('Decoder Failed: Can\'t Determine Operand Type\n') + + if 'UnorderedTrue' in flags: + code += 'cond = 1;\n' + elif 'UnorderedFalse' in flags: + code += 'cond = 0;\n' + else: + sys.exit('Decoder Failed: Float Compare Instruction Needs A Unordered Flag\n') + + code += '} else {\n' + code += cond_code + '}' + code += 'FCSR = genCCVector(FCSR, CC, cond);\n' + + iop = InstObjParams(name, Name, 'FPCompareOp', CodeBlock(code)) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + +def format FloatConvertOp(code, *flags) {{ + import sys + + #Determine Source Type + convert = 'fpConvert(' + if '.sf' in code: + code = 'float ' + code + '\n' + convert += 'SINGLE_TO_' + elif '.df' in code: + code = 'double ' + code + '\n' + convert += 'DOUBLE_TO_' + elif '.uw' in code: + code = 'uint32_t ' + code + '\n' + convert += 'WORD_TO_' + elif '.ud' in code: + code = 'uint64_t ' + code + '\n' + convert += 'LONG_TO_' + else: + sys.exit("Error Determining Source Type for Conversion") + + #Determine Destination Type + if 'ToSingle' in flags: + code += 'Fd.uw = ' + convert + 'SINGLE, ' + elif 'ToDouble' in flags: + code += 'Fd.ud = ' + convert + 'DOUBLE, ' + elif 'ToWord' in flags: + code += 'Fd.uw = ' + convert + 'WORD, ' + elif 'ToLong' in flags: + code += 'Fd.ud = ' + convert + 'LONG, ' + else: + sys.exit("Error Determining Destination Type for Conversion") + + #Figure out how to round value + if 'Ceil' in flags: + code += 'ceil(val)); ' + elif 'Floor' in flags: + code += 'floor(val)); ' + elif 'Round' in flags: + code += 'roundFP(val, 0)); ' + elif 'Trunc' in flags: + code += 'truncFP(val));' + else: + code += 'val); ' + + iop = InstObjParams(name, Name, 'FPOp', CodeBlock(code)) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + +def format FloatAccOp(code, *flags) {{ + iop = InstObjParams(name, Name, 'FPOp', CodeBlock(code), flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + +// Primary format for float64 operate instructions: +def format Float64Op(code, *flags) {{ + iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + +def format FloatPSCompareOp(cond_code1, cond_code2, *flags) {{ + import sys + + code = 'bool cond1, cond2;\n' + code += 'bool code_block1, code_block2;\n' + code += 'code_block1 = code_block2 = true;\n' + + if 'QnanException' in flags: + code += 'if (isQnan(&Fs1.sf, 32) || isQnan(&Ft1.sf, 32)) {\n' + code += '\tFCSR = genInvalidVector(FCSR);\n' + code += 'code_block1 = false;' + code += '}\n' + code += 'if (isQnan(&Fs2.sf, 32) || isQnan(&Ft2.sf, 32)) {\n' + code += '\tFCSR = genInvalidVector(FCSR);\n' + code += 'code_block2 = false;' + code += '}\n' + + code += 'if (code_block1) {' + code += '\tif (isNan(&Fs1.sf, 32) || isNan(&Ft1.sf, 32)) {\n' + if 'UnorderedTrue' in flags: + code += 'cond1 = 1;\n' + elif 'UnorderedFalse' in flags: + code += 'cond1 = 0;\n' + else: + sys.exit('Decoder Failed: Float Compare Instruction Needs A Unordered Flag\n') + code += '} else {\n' + code += cond_code1 + code += 'FCSR = genCCVector(FCSR, CC, cond1);}\n}\n' + + code += 'if (code_block2) {' + code += '\tif (isNan(&Fs2.sf, 32) || isNan(&Ft2.sf, 32)) {\n' + if 'UnorderedTrue' in flags: + code += 'cond2 = 1;\n' + elif 'UnorderedFalse' in flags: + code += 'cond2 = 0;\n' + else: + sys.exit('Decoder Failed: Float Compare Instruction Needs A Unordered Flag\n') + code += '} else {\n' + code += cond_code2 + code += 'FCSR = genCCVector(FCSR, CC, cond2);}\n}' + + iop = InstObjParams(name, Name, 'FPCompareOp', CodeBlock(code)) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + diff --git a/src/arch/mips/isa/formats/int.isa b/src/arch/mips/isa/formats/int.isa new file mode 100644 index 000000000..7b5affb5c --- /dev/null +++ b/src/arch/mips/isa/formats/int.isa @@ -0,0 +1,270 @@ +// -*- mode:c++ -*- + +// 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: Korey Sewell + +//////////////////////////////////////////////////////////////////// +// +// Integer operate instructions +// +output header {{ +#include <iostream> + using namespace std; + /** + * Base class for integer operations. + */ + class IntOp : public MipsStaticInst + { + protected: + + /// Constructor + IntOp(const char *mnem, MachInst _machInst, OpClass __opClass) : + MipsStaticInst(mnem, _machInst, __opClass) + { + } + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; + + + class HiLoOp: public IntOp + { + protected: + + /// Constructor + HiLoOp(const char *mnem, MachInst _machInst, OpClass __opClass) : + IntOp(mnem, _machInst, __opClass) + { + } + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; + + class HiLoMiscOp: public HiLoOp + { + protected: + + /// Constructor + HiLoMiscOp(const char *mnem, MachInst _machInst, OpClass __opClass) : + HiLoOp(mnem, _machInst, __opClass) + { + } + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; + + + class IntImmOp : public MipsStaticInst + { + protected: + + int16_t imm; + int32_t sextImm; + uint32_t zextImm; + + /// Constructor + IntImmOp(const char *mnem, MachInst _machInst, OpClass __opClass) : + MipsStaticInst(mnem, _machInst, __opClass),imm(INTIMM), + sextImm(INTIMM),zextImm(0x0000FFFF & INTIMM) + { + //If Bit 15 is 1 then Sign Extend + int32_t temp = sextImm & 0x00008000; + if (temp > 0 && mnemonic != "lui") { + sextImm |= 0xFFFF0000; + } + } + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; + + + }; + +}}; + +// HiLo<Misc> instruction class execute method template. +// Mainly to get instruction trace data to print out +// correctly +def template HiLoExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const + { + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + %(code)s; + + if(fault == NoFault) + { + %(op_wb)s; + //If there are 2 Destination Registers then + //concatenate the values for the traceData + if(traceData && _numDestRegs == 2) { + uint64_t hilo_final_val = (uint64_t)HI << 32 | LO; + traceData->setData(hilo_final_val); + } + } + return fault; + } +}}; + +//Outputs to decoder.cc +output decoder {{ + std::string IntOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + std::stringstream ss; + + ccprintf(ss, "%-10s ", mnemonic); + + // just print the first dest... if there's a second one, + // it's generally implicit + if (_numDestRegs > 0) { + printReg(ss, _destRegIdx[0]); + ss << ", "; + } + + // just print the first two source regs... if there's + // a third one, it's a read-modify-write dest (Rc), + // e.g. for CMOVxx + if (_numSrcRegs > 0) { + printReg(ss, _srcRegIdx[0]); + } + + if (_numSrcRegs > 1) { + ss << ", "; + printReg(ss, _srcRegIdx[1]); + } + + return ss.str(); + } + + std::string HiLoOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + std::stringstream ss; + + ccprintf(ss, "%-10s ", mnemonic); + + //Destination Registers are implicit for HI/LO ops + if (_numSrcRegs > 0) { + printReg(ss, _srcRegIdx[0]); + } + + if (_numSrcRegs > 1) { + ss << ", "; + printReg(ss, _srcRegIdx[1]); + } + + return ss.str(); + } + + std::string HiLoMiscOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + std::stringstream ss; + + ccprintf(ss, "%-10s ", mnemonic); + + if (_numDestRegs > 0 && _destRegIdx[0] < 32) { + printReg(ss, _destRegIdx[0]); + } else if (_numSrcRegs > 0 && _srcRegIdx[0] < 32) { + printReg(ss, _srcRegIdx[0]); + } + + return ss.str(); + } + + std::string IntImmOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + std::stringstream ss; + + ccprintf(ss, "%-10s ", mnemonic); + + if (_numDestRegs > 0) { + printReg(ss, _destRegIdx[0]); + } + + ss << ", "; + + if (_numSrcRegs > 0) { + printReg(ss, _srcRegIdx[0]); + ss << ", "; + } + + if( mnemonic == "lui") + ccprintf(ss, "0x%x ", sextImm); + else + ss << (int) sextImm; + + return ss.str(); + } + +}}; + +def format IntOp(code, *opt_flags) {{ + iop = InstObjParams(name, Name, 'IntOp', CodeBlock(code), opt_flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = OperateNopCheckDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + +def format IntImmOp(code, *opt_flags) {{ + iop = InstObjParams(name, Name, 'IntImmOp', CodeBlock(code), opt_flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = OperateNopCheckDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + +def format HiLoOp(code, *opt_flags) {{ + if '.sd' in code: + code = 'int64_t ' + code + elif '.ud' in code: + code = 'uint64_t ' + code + + code += 'HI = val<63:32>;\n' + code += 'LO = val<31:0>;\n' + + iop = InstObjParams(name, Name, 'HiLoOp', CodeBlock(code), opt_flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = OperateNopCheckDecode.subst(iop) + exec_output = HiLoExecute.subst(iop) +}}; + +def format HiLoMiscOp(code, *opt_flags) {{ + iop = InstObjParams(name, Name, 'HiLoMiscOp', CodeBlock(code), opt_flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = OperateNopCheckDecode.subst(iop) + exec_output = HiLoExecute.subst(iop) +}}; + + + + + diff --git a/src/arch/mips/isa/formats/mem.isa b/src/arch/mips/isa/formats/mem.isa new file mode 100644 index 000000000..f52247056 --- /dev/null +++ b/src/arch/mips/isa/formats/mem.isa @@ -0,0 +1,577 @@ +// -*- mode:c++ -*- + +// Copyright (c) 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: Gabe Black +// Korey Sewell + +//////////////////////////////////////////////////////////////////// +// +// Memory-format instructions +// + +output header {{ + /** + * Base class for general Mips memory-format instructions. + */ + class Memory : public MipsStaticInst + { + protected: + + /// Memory request flags. See mem_req_base.hh. + unsigned memAccessFlags; + /// Pointer to EAComp object. + const StaticInstPtr eaCompPtr; + /// Pointer to MemAcc object. + const StaticInstPtr memAccPtr; + + /// Displacement for EA calculation (signed). + int32_t disp; + + /// Constructor + Memory(const char *mnem, MachInst _machInst, OpClass __opClass, + StaticInstPtr _eaCompPtr = nullStaticInstPtr, + StaticInstPtr _memAccPtr = nullStaticInstPtr) + : MipsStaticInst(mnem, _machInst, __opClass), + memAccessFlags(0), eaCompPtr(_eaCompPtr), memAccPtr(_memAccPtr), + disp(OFFSET) + { + //If Bit 15 is 1 then Sign Extend + int32_t temp = disp & 0x00008000; + + if (temp > 0) { + disp |= 0xFFFF0000; + } + } + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + + public: + + const StaticInstPtr &eaCompInst() const { return eaCompPtr; } + const StaticInstPtr &memAccInst() const { return memAccPtr; } + }; + +}}; + + +output decoder {{ + std::string + Memory::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + return csprintf("%-10s %c%d,%d(r%d)", mnemonic, + flags[IsFloating] ? 'f' : 'r', RT, disp, RS); + } + +}}; + +def template LoadStoreDeclare {{ + /** + * Static instruction class for "%(mnemonic)s". + */ + class %(class_name)s : public %(base_class)s + { + protected: + + /** + * "Fake" effective address computation class for "%(mnemonic)s". + */ + class EAComp : public %(base_class)s + { + public: + /// Constructor + EAComp(MachInst machInst); + + %(BasicExecDeclare)s + }; + + /** + * "Fake" memory access instruction class for "%(mnemonic)s". + */ + class MemAcc : public %(base_class)s + { + public: + /// Constructor + MemAcc(MachInst machInst); + + %(BasicExecDeclare)s + }; + + public: + + /// Constructor. + %(class_name)s(MachInst machInst); + + %(BasicExecDeclare)s + + %(InitiateAccDeclare)s + + %(CompleteAccDeclare)s + }; +}}; + + +def template InitiateAccDeclare {{ + Fault initiateAcc(%(CPU_exec_context)s *, Trace::InstRecord *) const; +}}; + + +def template CompleteAccDeclare {{ + Fault completeAcc(uint8_t *, %(CPU_exec_context)s *, Trace::InstRecord *) const; +}}; + + +def template LoadStoreConstructor {{ + /** TODO: change op_class to AddrGenOp or something (requires + * creating new member of OpClass enum in op_class.hh, updating + * config files, etc.). */ + inline %(class_name)s::EAComp::EAComp(MachInst machInst) + : %(base_class)s("%(mnemonic)s (EAComp)", machInst, IntAluOp) + { + %(ea_constructor)s; + } + + inline %(class_name)s::MemAcc::MemAcc(MachInst machInst) + : %(base_class)s("%(mnemonic)s (MemAcc)", machInst, %(op_class)s) + { + %(memacc_constructor)s; + } + + inline %(class_name)s::%(class_name)s(MachInst machInst) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + new EAComp(machInst), new MemAcc(machInst)) + { + %(constructor)s; + } +}}; + + +def template EACompExecute {{ + Fault + %(class_name)s::EAComp::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + %(code)s; + + if (fault == NoFault) { + %(op_wb)s; + xc->setEA(EA); + } + + return fault; + } +}}; + +def template LoadMemAccExecute {{ + Fault + %(class_name)s::MemAcc::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + EA = xc->getEA(); + + if (fault == NoFault) { + fault = xc->read(EA, (uint%(mem_acc_size)d_t&)Mem, memAccessFlags); + %(code)s; + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + + +def template LoadExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + %(ea_code)s; + + if (fault == NoFault) { + fault = xc->read(EA, (uint%(mem_acc_size)d_t&)Mem, memAccessFlags); + %(memacc_code)s; + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + + +def template LoadInitiateAcc {{ + Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_src_decl)s; + %(op_rd)s; + %(ea_code)s; + + if (fault == NoFault) { + fault = xc->read(EA, (uint%(mem_acc_size)d_t &)Mem, memAccessFlags); + } + + return fault; + } +}}; + + +def template LoadCompleteAcc {{ + Fault %(class_name)s::completeAcc(uint8_t *data, + %(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_decl)s; + + memcpy(&Mem, data, sizeof(Mem)); + + if (fault == NoFault) { + %(memacc_code)s; + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + + +def template StoreMemAccExecute {{ + Fault + %(class_name)s::MemAcc::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + uint64_t write_result = 0; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + EA = xc->getEA(); + + if (fault == NoFault) { + %(code)s; + } + + if (fault == NoFault) { + fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA, + memAccessFlags, &write_result); + if (traceData) { traceData->setData(Mem); } + } + + if (fault == NoFault) { + %(postacc_code)s; + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + + +def template StoreExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + uint64_t write_result = 0; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + %(ea_code)s; + + if (fault == NoFault) { + %(memacc_code)s; + } + + if (fault == NoFault) { + fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA, + memAccessFlags, &write_result); + if (traceData) { traceData->setData(Mem); } + } + + if (fault == NoFault) { + %(postacc_code)s; + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + +def template StoreInitiateAcc {{ + Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + uint64_t write_result = 0; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + %(ea_code)s; + + if (fault == NoFault) { + %(memacc_code)s; + } + + if (fault == NoFault) { + fault = xc->write((uint%(mem_acc_size)d_t&)Mem, EA, + memAccessFlags, &write_result); + if (traceData) { traceData->setData(Mem); } + } + + return fault; + } +}}; + + +def template StoreCompleteAcc {{ + Fault %(class_name)s::completeAcc(uint8_t *data, + %(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Fault fault = NoFault; + uint64_t write_result = 0; + + %(fp_enable_check)s; + %(op_dest_decl)s; + + memcpy(&write_result, data, sizeof(write_result)); + + if (fault == NoFault) { + %(postacc_code)s; + } + + if (fault == NoFault) { + %(op_wb)s; + } + + return fault; + } +}}; + + +def template MiscMemAccExecute {{ + Fault %(class_name)s::MemAcc::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + EA = xc->getEA(); + + if (fault == NoFault) { + %(code)s; + } + + return NoFault; + } +}}; + +def template MiscExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Addr EA; + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + %(ea_code)s; + + if (fault == NoFault) { + %(memacc_code)s; + } + + return NoFault; + } +}}; + +def template MiscInitiateAcc {{ + Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + panic("Misc instruction does not support split access method!"); + return NoFault; + } +}}; + + +def template MiscCompleteAcc {{ + Fault %(class_name)s::completeAcc(uint8_t *data, + %(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + panic("Misc instruction does not support split access method!"); + + return NoFault; + } +}}; + +// load instructions use Rt as dest, so check for +// Rt == 0 to detect nops +def template LoadNopCheckDecode {{ + { + MipsStaticInst *i = new %(class_name)s(machInst); + if (RT == 0) { + i = makeNop(i); + } + return i; + } +}}; + +def format LoadMemory(memacc_code, ea_code = {{ EA = Rs + disp; }}, + mem_flags = [], inst_flags = []) {{ + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, + decode_template = LoadNopCheckDecode, + exec_template_base = 'Load') +}}; + +def format StoreMemory(memacc_code, ea_code = {{ EA = Rs + disp; }}, + mem_flags = [], inst_flags = []) {{ + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, + exec_template_base = 'Store') +}}; + +def format LoadIndexedMemory(memacc_code, ea_code = {{ EA = Rs + Rt; }}, + mem_flags = [], inst_flags = []) {{ + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, + decode_template = LoadNopCheckDecode, + exec_template_base = 'Load') +}}; + +def format StoreIndexedMemory(memacc_code, ea_code = {{ EA = Rs + Rt; }}, + mem_flags = [], inst_flags = []) {{ + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, + exec_template_base = 'Store') +}}; + +def format LoadUnalignedMemory(memacc_code, ea_code = {{ EA = (Rs + disp) & ~3; }}, + mem_flags = [], inst_flags = []) {{ + decl_code = 'uint32_t mem_word = Mem.uw;\n' + decl_code += 'uint32_t unalign_addr = Rs + disp;\n' + decl_code += 'uint32_t byte_offset = unalign_addr & 3;\n' + decl_code += '#if BYTE_ORDER == BIG_ENDIAN\n' + decl_code += '\tbyte_offset ^= 3;\n' + decl_code += '#endif\n' + + memacc_code = decl_code + memacc_code + + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, + decode_template = LoadNopCheckDecode, + exec_template_base = 'Load') +}}; + +def format StoreUnalignedMemory(memacc_code, ea_code = {{ EA = (Rs + disp) & ~3; }}, + mem_flags = [], inst_flags = []) {{ + decl_code = 'uint32_t mem_word = 0;\n' + decl_code += 'uint32_t unaligned_addr = Rs + disp;\n' + decl_code += 'uint32_t byte_offset = unaligned_addr & 3;\n' + decl_code += '#if BYTE_ORDER == BIG_ENDIAN\n' + decl_code += '\tbyte_offset ^= 3;\n' + decl_code += '#endif\n' + decl_code += 'fault = xc->read(EA, (uint32_t&)mem_word, memAccessFlags);\n' + memacc_code = decl_code + memacc_code + '\nMem = mem_word;\n' + + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, + decode_template = LoadNopCheckDecode, + exec_template_base = 'Store') +}}; + +def format Prefetch(ea_code = {{ EA = Rs + disp; }}, + mem_flags = [], pf_flags = [], inst_flags = []) {{ + pf_mem_flags = mem_flags + pf_flags + ['NO_FAULT'] + pf_inst_flags = inst_flags + ['IsMemRef', 'IsLoad', + 'IsDataPrefetch', 'MemReadOp'] + + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name, ea_code, + 'xc->prefetch(EA, memAccessFlags);', + pf_mem_flags, pf_inst_flags, exec_template_base = 'Misc') + +}}; + +def format StoreCond(memacc_code, postacc_code, + ea_code = {{ EA = Rs + disp; }}, + mem_flags = [], inst_flags = []) {{ + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, + postacc_code, exec_template_base = 'Store') +}}; diff --git a/src/arch/mips/isa/formats/mt.isa b/src/arch/mips/isa/formats/mt.isa new file mode 100644 index 000000000..521b01123 --- /dev/null +++ b/src/arch/mips/isa/formats/mt.isa @@ -0,0 +1,81 @@ +// -*- mode:c++ -*- + +// 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: Korey Sewell + +//////////////////////////////////////////////////////////////////// +// +// MT instructions +// + +output header {{ + /** + * Base class for integer operations. + */ + class MT : public MipsStaticInst + { + protected: + + /// Constructor + MT(const char *mnem, MachInst _machInst, OpClass __opClass) : MipsStaticInst(mnem, _machInst, __opClass) + { + } + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; +}}; + +output decoder {{ + //Edit This Template When MT is Implemented + std::string MT::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + return "Disassembly of MT instruction\n"; + } +}}; + +def template MTExecute {{ + //Edit This Template When MT is Implemented + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const + { + //Write the resulting state to the execution context + %(op_wb)s; + + //Call into the trap handler with the appropriate fault + return No_Fault; + } +}}; + +// Primary format for integer operate instructions: +def format MipsMT() {{ + code = 'panic(\"Mips MT Is Currently Unimplemented.\");\n' + iop = InstObjParams(name, Name, 'MT', CodeBlock(code)) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; diff --git a/src/arch/mips/isa/formats/noop.isa b/src/arch/mips/isa/formats/noop.isa new file mode 100644 index 000000000..4fd8235e4 --- /dev/null +++ b/src/arch/mips/isa/formats/noop.isa @@ -0,0 +1,118 @@ +// -*- mode:c++ -*- + +// 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: Korey Sewell + +//////////////////////////////////////////////////////////////////// +// +// Nop +// + +output header {{ + /** + * Static instruction class for no-ops. This is a leaf class. + */ + class Nop : public MipsStaticInst + { + /// Disassembly of original instruction. + const std::string originalDisassembly; + + public: + /// Constructor + Nop(const std::string _originalDisassembly, MachInst _machInst) + : MipsStaticInst("nop", _machInst, No_OpClass), + originalDisassembly(_originalDisassembly) + { + flags[IsNop] = true; + } + + ~Nop() { } + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + + %(BasicExecDeclare)s + }; +}}; + +output decoder {{ + std::string Nop::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + return csprintf("%-10s %s", "nop", originalDisassembly); + } + + /// Helper function for decoding nops. Substitute Nop object + /// for original inst passed in as arg (and delete latter). + inline + MipsStaticInst * + makeNop(MipsStaticInst *inst) + { + MipsStaticInst *nop = new Nop(inst->disassemble(0), inst->machInst); + delete inst; + return nop; + } +}}; + +output exec {{ + Fault + Nop::execute(%(CPU_exec_context)s *, Trace::InstRecord *) const + { + return NoFault; + } +}}; + +// integer & FP operate instructions use RT as dest, so check for +// RT == 0 to detect nops +def template OperateNopCheckDecode {{ + { + MipsStaticInst *i = new %(class_name)s(machInst); + + //if (RD == 0) { + // i = makeNop(i); + //} + + return i; + } +}}; + + +// Like BasicOperate format, but generates NOP if RC/FC == 31 +def format BasicOperateWithNopCheck(code, *opt_args) {{ + iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), + opt_args) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = OperateNopCheckDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; + +def format Nop() {{ + decode_block = 'return new Nop(\"\",machInst);\n' +}}; + diff --git a/src/arch/mips/isa/formats/tlbop.isa b/src/arch/mips/isa/formats/tlbop.isa new file mode 100644 index 000000000..75ab71c48 --- /dev/null +++ b/src/arch/mips/isa/formats/tlbop.isa @@ -0,0 +1,80 @@ +// -*- mode:c++ -*- + +// 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: Korey Sewell + +//////////////////////////////////////////////////////////////////// +// +// TlbOp instructions +// + +output header {{ + /** + * Base class for integer operations. + */ + class TlbOp : public MipsStaticInst + { + protected: + + /// Constructor + TlbOp(const char *mnem, MachInst _machInst, OpClass __opClass) : MipsStaticInst(mnem, _machInst, __opClass) + { + } + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; +}}; + +output decoder {{ + std::string TlbOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + return "Disassembly of integer instruction\n"; + } +}}; + +def template TlbOpExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const + { + //Write the resulting state to the execution context + %(op_wb)s; + + //Call into the trap handler with the appropriate fault + return No_Fault; + } +}}; + +// Primary format for integer operate instructions: +def format TlbOp(code, *opt_flags) {{ + orig_code = code + cblk = CodeBlock(code) + iop = InstObjParams(name, Name, 'MipsStaticInst', cblk, opt_flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecodeWithMnemonic.subst(iop) + exec_output = TlbOpExecute.subst(iop) +}}; diff --git a/src/arch/mips/isa/formats/trap.isa b/src/arch/mips/isa/formats/trap.isa new file mode 100644 index 000000000..574b808cc --- /dev/null +++ b/src/arch/mips/isa/formats/trap.isa @@ -0,0 +1,81 @@ +// -*- mode:c++ -*- + +// 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: Korey Sewell + +//////////////////////////////////////////////////////////////////// +// +// Trap instructions +// + +output header {{ + /** + * Base class for integer operations. + */ + class Trap : public MipsStaticInst + { + protected: + + /// Constructor + Trap(const char *mnem, MachInst _machInst, OpClass __opClass) : MipsStaticInst(mnem, _machInst, __opClass) + { + } + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; +}}; + +output decoder {{ + std::string Trap::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + return "Disassembly of trap instruction\n"; + } +}}; + +def template TrapExecute {{ + //Edit This Template When Traps Are Implemented + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const + { + //Write the resulting state to the execution context + %(op_wb)s; + + //Call into the trap handler with the appropriate fault + return No_Fault; + } +}}; + +def format Trap(code, *flags) {{ + code = 'panic(\"' + code += 'Trap Exception Handler Is Currently Not Implemented.' + code += '\");' + iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; diff --git a/src/arch/mips/isa/formats/unimp.isa b/src/arch/mips/isa/formats/unimp.isa new file mode 100644 index 000000000..e17b5f832 --- /dev/null +++ b/src/arch/mips/isa/formats/unimp.isa @@ -0,0 +1,145 @@ +// -*- mode:c++ -*- + + +// Copyright (c) 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: Korey Sewell + +//////////////////////////////////////////////////////////////////// +// +// Unimplemented instructions +// + +output header {{ + /** + * Static instruction class for unimplemented instructions that + * cause simulator termination. Note that these are recognized + * (legal) instructions that the simulator does not support; the + * 'Unknown' class is used for unrecognized/illegal instructions. + * This is a leaf class. + */ + class FailUnimplemented : public MipsStaticInst + { + public: + /// Constructor + FailUnimplemented(const char *_mnemonic, MachInst _machInst) + : MipsStaticInst(_mnemonic, _machInst, No_OpClass) + { + // don't call execute() (which panics) if we're on a + // speculative path + flags[IsNonSpeculative] = true; + } + + %(BasicExecDeclare)s + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; + + /** + * Base class for unimplemented instructions that cause a warning + * to be printed (but do not terminate simulation). This + * implementation is a little screwy in that it will print a + * warning for each instance of a particular unimplemented machine + * instruction, not just for each unimplemented opcode. Should + * probably make the 'warned' flag a static member of the derived + * class. + */ + class WarnUnimplemented : public MipsStaticInst + { + private: + /// Have we warned on this instruction yet? + mutable bool warned; + + public: + /// Constructor + WarnUnimplemented(const char *_mnemonic, MachInst _machInst) + : MipsStaticInst(_mnemonic, _machInst, No_OpClass), warned(false) + { + // don't call execute() (which panics) if we're on a + // speculative path + flags[IsNonSpeculative] = true; + } + + %(BasicExecDeclare)s + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; +}}; + +output decoder {{ + std::string + FailUnimplemented::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + return csprintf("%-10s (unimplemented)", mnemonic); + } + + std::string + WarnUnimplemented::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + return csprintf("%-10s (unimplemented)", mnemonic); + } +}}; + +output exec {{ + Fault + FailUnimplemented::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + panic("attempt to execute unimplemented instruction '%s' " + "(inst 0x%08x, opcode 0x%x, binary:%s)", mnemonic, machInst, OPCODE, + inst2string(machInst)); + return new UnimplementedOpcodeFault; + } + + Fault + WarnUnimplemented::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + if (!warned) { + warn("\tinstruction '%s' unimplemented\n", mnemonic); + warned = true; + } + + return NoFault; + } +}}; + + +def format FailUnimpl() {{ + iop = InstObjParams(name, 'FailUnimplemented') + decode_block = BasicDecodeWithMnemonic.subst(iop) +}}; + +def format WarnUnimpl() {{ + iop = InstObjParams(name, 'WarnUnimplemented') + decode_block = BasicDecodeWithMnemonic.subst(iop) +}}; + diff --git a/src/arch/mips/isa/formats/unknown.isa b/src/arch/mips/isa/formats/unknown.isa new file mode 100644 index 000000000..41387adca --- /dev/null +++ b/src/arch/mips/isa/formats/unknown.isa @@ -0,0 +1,84 @@ +// -*- mode:c++ -*- + +// 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: Korey Sewell + +//////////////////////////////////////////////////////////////////// +// +// Unknown instructions +// + +output header {{ + /** + * Static instruction class for unknown (illegal) instructions. + * These cause simulator termination if they are executed in a + * non-speculative mode. This is a leaf class. + */ + class Unknown : public MipsStaticInst + { + public: + /// Constructor + Unknown(MachInst _machInst) + : MipsStaticInst("unknown", _machInst, No_OpClass) + { + // don't call execute() (which panics) if we're on a + // speculative path + flags[IsNonSpeculative] = true; + } + + %(BasicExecDeclare)s + + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const; + }; +}}; + +output decoder {{ + std::string + Unknown::generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + return csprintf("%-10s (inst 0x%x, opcode 0x%x, binary:%s)", + "unknown", machInst, OPCODE, inst2string(machInst)); + } +}}; + +output exec {{ + Fault + Unknown::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + panic("attempt to execute unknown instruction " + "(inst 0x%08x, opcode 0x%x, binary: %s)", machInst, OPCODE, inst2string(machInst)); + return new UnimplementedOpcodeFault; + } +}}; + +def format Unknown() {{ + decode_block = 'return new Unknown(machInst);\n' +}}; + diff --git a/src/arch/mips/isa/formats/util.isa b/src/arch/mips/isa/formats/util.isa new file mode 100644 index 000000000..b67a02d07 --- /dev/null +++ b/src/arch/mips/isa/formats/util.isa @@ -0,0 +1,183 @@ +// -*- mode:c++ -*- + +// 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 +// Korey Sewell + +let {{ +def LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags, + postacc_code = '', base_class = 'Memory', + decode_template = BasicDecode, exec_template_base = ''): + # Make sure flags are in lists (convert to lists if not). + mem_flags = makeList(mem_flags) + inst_flags = makeList(inst_flags) + + # add hook to get effective addresses into execution trace output. + ea_code += '\nif (traceData) { traceData->setAddr(EA); }\n' + + # generate code block objects + ea_cblk = CodeBlock(ea_code) + memacc_cblk = CodeBlock(memacc_code) + postacc_cblk = CodeBlock(postacc_code) + + # Some CPU models execute the memory operation as an atomic unit, + # while others want to separate them into an effective address + # computation and a memory access operation. As a result, we need + # to generate three StaticInst objects. Note that the latter two + # are nested inside the larger "atomic" one. + + # generate InstObjParams for EAComp object + ea_iop = InstObjParams(name, Name, base_class, ea_cblk, inst_flags) + + # generate InstObjParams for MemAcc object + memacc_iop = InstObjParams(name, Name, base_class, memacc_cblk, inst_flags) + # in the split execution model, the MemAcc portion is responsible + # for the post-access code. + memacc_iop.postacc_code = postacc_cblk.code + + # generate InstObjParams for InitiateAcc, CompleteAcc object + # The code used depends on the template being used + if (exec_template_base == 'Load'): + initiateacc_cblk = CodeBlock(ea_code + memacc_code) + completeacc_cblk = CodeBlock(memacc_code + postacc_code) + elif (exec_template_base == 'Store'): + initiateacc_cblk = CodeBlock(ea_code + memacc_code) + completeacc_cblk = CodeBlock(postacc_code) + else: + initiateacc_cblk = '' + completeacc_cblk = '' + + initiateacc_iop = InstObjParams(name, Name, base_class, initiateacc_cblk, + inst_flags) + + completeacc_iop = InstObjParams(name, Name, base_class, completeacc_cblk, + inst_flags) + + if (exec_template_base == 'Load'): + initiateacc_iop.ea_code = ea_cblk.code + initiateacc_iop.memacc_code = memacc_cblk.code + completeacc_iop.memacc_code = memacc_cblk.code + completeacc_iop.postacc_code = postacc_cblk.code + elif (exec_template_base == 'Store'): + initiateacc_iop.ea_code = ea_cblk.code + initiateacc_iop.memacc_code = memacc_cblk.code + completeacc_iop.postacc_code = postacc_cblk.code + + # generate InstObjParams for unified execution + cblk = CodeBlock(ea_code + memacc_code + postacc_code) + iop = InstObjParams(name, Name, base_class, cblk, inst_flags) + + iop.ea_constructor = ea_cblk.constructor + iop.ea_code = ea_cblk.code + iop.memacc_constructor = memacc_cblk.constructor + iop.memacc_code = memacc_cblk.code + iop.postacc_code = postacc_cblk.code + + if mem_flags: + s = '\n\tmemAccessFlags = ' + string.join(mem_flags, '|') + ';' + iop.constructor += s + memacc_iop.constructor += s + + # select templates + memAccExecTemplate = eval(exec_template_base + 'MemAccExecute') + fullExecTemplate = eval(exec_template_base + 'Execute') + initiateAccTemplate = eval(exec_template_base + 'InitiateAcc') + completeAccTemplate = eval(exec_template_base + 'CompleteAcc') + + # (header_output, decoder_output, decode_block, exec_output) + return (LoadStoreDeclare.subst(iop), LoadStoreConstructor.subst(iop), + decode_template.subst(iop), + EACompExecute.subst(ea_iop) + + memAccExecTemplate.subst(memacc_iop) + + fullExecTemplate.subst(iop) + + initiateAccTemplate.subst(initiateacc_iop) + + completeAccTemplate.subst(completeacc_iop)) +}}; + +output header {{ + std::string inst2string(MachInst machInst); +}}; + +output decoder {{ + +std::string inst2string(MachInst machInst) +{ + string str = ""; + uint32_t mask = 0x80000000; + + for(int i=0; i < 32; i++) { + if ((machInst & mask) == 0) { + str += "0"; + } else { + str += "1"; + } + + mask = mask >> 1; + } + + return str; +} + +}}; +output exec {{ + + using namespace MipsISA; + + /// CLEAR ALL CPU INST/EXE HAZARDS + inline void + clear_exe_inst_hazards() + { + //CODE HERE + } + + + /// Check "FP enabled" machine status bit. Called when executing any FP + /// instruction in full-system mode. + /// @retval Full-system mode: NoFault if FP is enabled, FenFault + /// if not. Non-full-system mode: always returns NoFault. +#if FULL_SYSTEM + inline Fault checkFpEnableFault(%(CPU_exec_context)s *xc) + { + Fault fault = NoFault; // dummy... this ipr access should not fault + if (!Mips34k::ICSR_FPE(xc->readIpr(MipsISA::IPR_ICSR, fault))) { + fault = FloatEnableFault; + } + return fault; + } +#else + inline Fault checkFpEnableFault(%(CPU_exec_context)s *xc) + { + return NoFault; + } +#endif + + + +}}; + + diff --git a/src/arch/mips/isa/includes.isa b/src/arch/mips/isa/includes.isa new file mode 100644 index 000000000..555cec255 --- /dev/null +++ b/src/arch/mips/isa/includes.isa @@ -0,0 +1,81 @@ +// -*- mode:c++ -*- + +// 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: Korey Sewell + +//////////////////////////////////////////////////////////////////// +// +// Output include file directives. +// + +output header {{ +#include <sstream> +#include <iostream> +#include <iomanip> + +#include "cpu/static_inst.hh" +#include "arch/mips/isa_traits.hh" +}}; + +output decoder {{ +#include "arch/mips/isa_traits.hh" +#include "base/cprintf.hh" +#include "base/loader/symtab.hh" +#include "cpu/thread_context.hh" +#include "arch/mips/faults.hh" +#include "arch/mips/isa_traits.hh" +#include "arch/mips/utility.hh" + +#include <math.h> +#if defined(linux) +#include <fenv.h> +#endif + +using namespace MipsISA; +}}; + +output exec {{ +#include "arch/mips/faults.hh" +#include "arch/mips/isa_traits.hh" +#include "arch/mips/utility.hh" + +#include <math.h> +#if defined(linux) +#include <fenv.h> +#endif + +#ifdef FULL_SYSTEM +//#include "arch/alpha/pseudo_inst.hh" +#endif +#include "cpu/base.hh" +#include "cpu/exetrace.hh" +#include "sim/sim_exit.hh" + +using namespace MipsISA; +}}; + diff --git a/src/arch/mips/isa/main.isa b/src/arch/mips/isa/main.isa new file mode 100644 index 000000000..9da3fc0db --- /dev/null +++ b/src/arch/mips/isa/main.isa @@ -0,0 +1,61 @@ +// -*- mode:c++ -*- + +// Copyright (c) 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: Korey Sewell + +//////////////////////////////////////////////////////////////////// +// +// MIPS ISA description file. +// +//////////////////////////////////////////////////////////////////// + +//Include the C++ include directives +##include "includes.isa" + +//////////////////////////////////////////////////////////////////// +// +// Namespace statement. Everything below this line will be in the +// MipsISAInst namespace. +// + +namespace MipsISA; + +//Include the bitfield definitions +##include "bitfields.isa" + +//Include the operand_types and operand definitions +##include "operands.isa" + +//Include the base class for mips instructions, and some support code +##include "base.isa" + +//Include the definitions for the instruction formats +##include "formats/formats.isa" + +//Include the decoder definition +##include "decoder.isa" diff --git a/src/arch/mips/isa/operands.isa b/src/arch/mips/isa/operands.isa new file mode 100644 index 000000000..316552ef4 --- /dev/null +++ b/src/arch/mips/isa/operands.isa @@ -0,0 +1,91 @@ +// -*- mode:c++ -*- + +// 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: Korey Sewell + +def operand_types {{ + 'sb' : ('signed int', 8), + 'ub' : ('unsigned int', 8), + 'sh' : ('signed int', 16), + 'uh' : ('unsigned int', 16), + 'sw' : ('signed int', 32), + 'uw' : ('unsigned int', 32), + 'sd' : ('signed int', 64), + 'ud' : ('unsigned int', 64), + 'sf' : ('float', 32), + 'df' : ('float', 64), + 'qf' : ('float', 128) +}}; + +def operands {{ + #General Purpose Integer Reg Operands + 'Rd': ('IntReg', 'uw', 'RD', 'IsInteger', 1), + 'Rs': ('IntReg', 'uw', 'RS', 'IsInteger', 2), + 'Rt': ('IntReg', 'uw', 'RT', 'IsInteger', 3), + + #Operands used for Link or Syscall Insts + 'R31': ('IntReg', 'uw','31','IsInteger', 4), + 'R2': ('IntReg', 'uw','2', 'IsInteger', 5), + + #Special Integer Reg operands + 'HI': ('IntReg', 'uw','32', 'IsInteger', 6), + 'LO': ('IntReg', 'uw','33', 'IsInteger', 7), + + #Immediate Value operand + 'IntImm': ('IntReg', 'uw', 'INTIMM', 'IsInteger', 3), + + #Floating Point Reg Operands + 'Fd': ('FloatReg', 'sf', 'FD', 'IsFloating', 1), + 'Fs': ('FloatReg', 'sf', 'FS', 'IsFloating', 2), + 'Ft': ('FloatReg', 'sf', 'FT', 'IsFloating', 3), + 'Fr': ('FloatReg', 'sf', 'FR', 'IsFloating', 3), + + #Special Floating Point Control Reg Operands + 'FIR': ('FloatReg', 'uw', '32', 'IsFloating', 1), + 'FCCR': ('FloatReg', 'uw', '33', 'IsFloating', 2), + 'FEXR': ('FloatReg', 'uw', '34', 'IsFloating', 3), + 'FENR': ('FloatReg', 'uw', '35', 'IsFloating', 3), + 'FCSR': ('FloatReg', 'uw', '36', 'IsFloating', 3), + + #Operands For Paired Singles FP Operations + 'Fd1': ('FloatReg', 'sf', 'FD', 'IsFloating', 4), + 'Fd2': ('FloatReg', 'sf', 'FD+1', 'IsFloating', 4), + 'Fs1': ('FloatReg', 'sf', 'FS', 'IsFloating', 5), + 'Fs2': ('FloatReg', 'sf', 'FS+1', 'IsFloating', 5), + 'Ft1': ('FloatReg', 'sf', 'FT', 'IsFloating', 6), + 'Ft2': ('FloatReg', 'sf', 'FT+1', 'IsFloating', 6), + 'Fr1': ('FloatReg', 'sf', 'FR', 'IsFloating', 7), + 'Fr2': ('FloatReg', 'sf', 'FR+1', 'IsFloating', 7), + + #Memory Operand + 'Mem': ('Mem', 'uw', None, ('IsMemRef', 'IsLoad', 'IsStore'), 4), + + #Program Counter Operands + 'NPC': ('NPC', 'uw', None, ( None, None, 'IsControl' ), 4), + 'NNPC':('NNPC', 'uw', None, ( None, None, 'IsControl' ), 4) +}}; diff --git a/src/arch/mips/isa_traits.cc b/src/arch/mips/isa_traits.cc new file mode 100644 index 000000000..9f3817a60 --- /dev/null +++ b/src/arch/mips/isa_traits.cc @@ -0,0 +1,163 @@ +/* + * Copyright (c) 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: Gabe Black + * Korey Sewell + */ + +#include "arch/mips/isa_traits.hh" +#include "config/full_system.hh" +#include "cpu/static_inst.hh" +#include "sim/serialize.hh" +#include "base/bitfield.hh" + +using namespace MipsISA; +using namespace std; + + +void +MipsISA::copyRegs(ThreadContext *src, ThreadContext *dest) +{ + panic("Copy Regs Not Implemented Yet\n"); + /*fpcr = xc->readMiscReg(MipsISA::Fpcr_DepTag); + uniq = xc->readMiscReg(MipsISA::Uniq_DepTag); + lock_flag = xc->readMiscReg(MipsISA::Lock_Flag_DepTag); + lock_addr = xc->readMiscReg(MipsISA::Lock_Addr_DepTag); + +#if FULL_SYSTEM + copyIprs(xc); + #endif*/ +} + +void +MipsISA::MiscRegFile::copyMiscRegs(ThreadContext *tc) +{ + panic("Copy Misc. Regs Not Implemented Yet\n"); + /*fpcr = xc->readMiscReg(MipsISA::Fpcr_DepTag); + uniq = xc->readMiscReg(MipsISA::Uniq_DepTag); + lock_flag = xc->readMiscReg(MipsISA::Lock_Flag_DepTag); + lock_addr = xc->readMiscReg(MipsISA::Lock_Addr_DepTag); + + #endif*/ +} + +#if FULL_SYSTEM + +static inline Addr +TruncPage(Addr addr) +{ return addr & ~(MipsISA::PageBytes - 1); } + +static inline Addr +RoundPage(Addr addr) +{ return (addr + MipsISA::PageBytes - 1) & ~(MipsISA::PageBytes - 1); } +#endif + +void +IntRegFile::serialize(std::ostream &os) +{ + SERIALIZE_ARRAY(regs, NumIntRegs); +} + +void +IntRegFile::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_ARRAY(regs, NumIntRegs); +} + +void +RegFile::serialize(std::ostream &os) +{ + intRegFile.serialize(os); + //SERIALIZE_ARRAY(floatRegFile.q, NumFloatRegs); + //SERIALIZE_SCALAR(miscRegs.fpcr); + //SERIALIZE_SCALAR(miscRegs.uniq); + //SERIALIZE_SCALAR(miscRegs.lock_flag); + //SERIALIZE_SCALAR(miscRegs.lock_addr); + SERIALIZE_SCALAR(pc); + SERIALIZE_SCALAR(npc); + SERIALIZE_SCALAR(nnpc); +#if FULL_SYSTEM + SERIALIZE_ARRAY(palregs, NumIntRegs); + SERIALIZE_ARRAY(ipr, NumInternalProcRegs); + SERIALIZE_SCALAR(intrflag); + SERIALIZE_SCALAR(pal_shadow); +#endif +} + + +void +RegFile::unserialize(Checkpoint *cp, const std::string §ion) +{ + intRegFile.unserialize(cp, section); + //UNSERIALIZE_ARRAY(floatRegFile.q, NumFloatRegs); + //UNSERIALIZE_SCALAR(miscRegs.fpcr); + //UNSERIALIZE_SCALAR(miscRegs.uniq); + //UNSERIALIZE_SCALAR(miscRegs.lock_flag); + //UNSERIALIZE_SCALAR(miscRegs.lock_addr); + UNSERIALIZE_SCALAR(pc); + UNSERIALIZE_SCALAR(npc); + UNSERIALIZE_SCALAR(nnpc); +#if FULL_SYSTEM + UNSERIALIZE_ARRAY(palregs, NumIntRegs); + UNSERIALIZE_ARRAY(ipr, NumInternalProcRegs); + UNSERIALIZE_SCALAR(intrflag); + UNSERIALIZE_SCALAR(pal_shadow); +#endif +} + + +#if FULL_SYSTEM +void +PTE::serialize(std::ostream &os) +{ + SERIALIZE_SCALAR(tag); + SERIALIZE_SCALAR(ppn); + SERIALIZE_SCALAR(xre); + SERIALIZE_SCALAR(xwe); + SERIALIZE_SCALAR(asn); + SERIALIZE_SCALAR(asma); + SERIALIZE_SCALAR(fonr); + SERIALIZE_SCALAR(fonw); + SERIALIZE_SCALAR(valid); +} + + +void +PTE::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_SCALAR(tag); + UNSERIALIZE_SCALAR(ppn); + UNSERIALIZE_SCALAR(xre); + UNSERIALIZE_SCALAR(xwe); + UNSERIALIZE_SCALAR(asn); + UNSERIALIZE_SCALAR(asma); + UNSERIALIZE_SCALAR(fonr); + UNSERIALIZE_SCALAR(fonw); + UNSERIALIZE_SCALAR(valid); +} + +#endif //FULL_SYSTEM diff --git a/src/arch/mips/isa_traits.hh b/src/arch/mips/isa_traits.hh new file mode 100644 index 000000000..dc8b6758a --- /dev/null +++ b/src/arch/mips/isa_traits.hh @@ -0,0 +1,202 @@ +/* + * Copyright (c) 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: Gabe Black + * Korey Sewell + */ + +#ifndef __ARCH_MIPS_ISA_TRAITS_HH__ +#define __ARCH_MIPS_ISA_TRAITS_HH__ + +#include "arch/mips/constants.hh" +#include "arch/mips/types.hh" +#include "arch/mips/regfile/regfile.hh" +#include "arch/mips/faults.hh" +#include "arch/mips/utility.hh" +#include "base/misc.hh" +#include "config/full_system.hh" +#include "sim/byteswap.hh" +#include "sim/host.hh" +#include "sim/faults.hh" + +#include <vector> + +class FastCPU; +class FullCPU; +class Checkpoint; +class ThreadContext; + +namespace LittleEndianGuest {}; + +#define TARGET_MIPS + +class StaticInst; +class StaticInstPtr; + +namespace MIPS34K { +int DTB_ASN_ASN(uint64_t reg); +int ITB_ASN_ASN(uint64_t reg); +}; + +#if !FULL_SYSTEM +class SyscallReturn { + public: + template <class T> + SyscallReturn(T v, bool s) + { + retval = (uint32_t)v; + success = s; + } + + template <class T> + SyscallReturn(T v) + { + success = (v >= 0); + retval = (uint32_t)v; + } + + ~SyscallReturn() {} + + SyscallReturn& operator=(const SyscallReturn& s) { + retval = s.retval; + success = s.success; + return *this; + } + + bool successful() { return success; } + uint64_t value() { return retval; } + + + private: + uint64_t retval; + bool success; +}; +#endif + +namespace MipsISA +{ + using namespace LittleEndianGuest; + + static inline void setSyscallReturn(SyscallReturn return_value, RegFile *regs) + { + if (return_value.successful()) { + // no error + regs->setIntReg(SyscallSuccessReg, 0); + regs->setIntReg(ReturnValueReg1, return_value.value()); + } else { + // got an error, return details + regs->setIntReg(SyscallSuccessReg, (IntReg) -1); + regs->setIntReg(ReturnValueReg1, -return_value.value()); + } + } + + StaticInstPtr decodeInst(ExtMachInst); + + static inline ExtMachInst + makeExtMI(MachInst inst, const uint64_t &pc) { +#if FULL_SYSTEM + ExtMachInst ext_inst = inst; + if (pc && 0x1) + return ext_inst|=(static_cast<ExtMachInst>(pc & 0x1) << 32); + else + return ext_inst; +#else + return ExtMachInst(inst); +#endif + } + + /** + * Function to insure ISA semantics about 0 registers. + * @param tc The thread context. + */ + template <class TC> + void zeroRegisters(TC *tc); + + const Addr MaxAddr = (Addr)-1; + + void copyRegs(ThreadContext *src, ThreadContext *dest); + + uint64_t fpConvert(double fp_val, ConvertType cvt_type); + double roundFP(double val, int digits); + double truncFP(double val); + bool getFPConditionCode(uint32_t fcsr_reg, int cc); + uint32_t makeCCVector(uint32_t fcsr, int num, bool val); + + // Machine operations + + void saveMachineReg(AnyReg &savereg, const RegFile ®_file, + int regnum); + + void restoreMachineReg(RegFile ®s, const AnyReg ®, + int regnum); + +#if 0 + static void serializeSpecialRegs(const Serializable::Proxy &proxy, + const RegFile ®s); + + static void unserializeSpecialRegs(const IniFile *db, + const std::string &category, + ConfigNode *node, + RegFile ®s); +#endif + + static inline Addr alignAddress(const Addr &addr, + unsigned int nbytes) { + return (addr & ~(nbytes - 1)); + } + + // Instruction address compression hooks + static inline Addr realPCToFetchPC(const Addr &addr) { + return addr; + } + + static inline Addr fetchPCToRealPC(const Addr &addr) { + return addr; + } + + // the size of "fetched" instructions (not necessarily the size + // of real instructions for PISA) + static inline size_t fetchInstSize() { + return sizeof(MachInst); + } + + static inline MachInst makeRegisterCopy(int dest, int src) { + panic("makeRegisterCopy not implemented"); + return 0; + } + +}; + +#if FULL_SYSTEM + +#include "arch/mips/mips34k.hh" + +#endif + +using namespace MipsISA; + +#endif // __ARCH_MIPS_ISA_TRAITS_HH__ diff --git a/src/arch/mips/linux/linux.cc b/src/arch/mips/linux/linux.cc new file mode 100644 index 000000000..26e3dd479 --- /dev/null +++ b/src/arch/mips/linux/linux.cc @@ -0,0 +1,72 @@ +/* + * 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: Korey Sewell + */ + +#include "arch/mips/linux/linux.hh" + +// open(2) flags translation table +OpenFlagTransTable MipsLinux::openFlagTable[] = { +#ifdef _MSC_VER + { MipsLinux::TGT_O_RDONLY, _O_RDONLY }, + { MipsLinux::TGT_O_WRONLY, _O_WRONLY }, + { MipsLinux::TGT_O_RDWR, _O_RDWR }, + { MipsLinux::TGT_O_APPEND, _O_APPEND }, + { MipsLinux::TGT_O_CREAT, _O_CREAT }, + { MipsLinux::TGT_O_TRUNC, _O_TRUNC }, + { MipsLinux::TGT_O_EXCL, _O_EXCL }, +#ifdef _O_NONBLOCK + { MipsLinux::TGT_O_NONBLOCK, _O_NONBLOCK }, +#endif +#ifdef _O_NOCTTY + { MipsLinux::TGT_O_NOCTTY, _O_NOCTTY }, +#endif +#ifdef _O_SYNC + { MipsLinux::TGT_O_SYNC, _O_SYNC }, +#endif +#else /* !_MSC_VER */ + { MipsLinux::TGT_O_RDONLY, O_RDONLY }, + { MipsLinux::TGT_O_WRONLY, O_WRONLY }, + { MipsLinux::TGT_O_RDWR, O_RDWR }, + { MipsLinux::TGT_O_APPEND, O_APPEND }, + { MipsLinux::TGT_O_CREAT, O_CREAT }, + { MipsLinux::TGT_O_TRUNC, O_TRUNC }, + { MipsLinux::TGT_O_EXCL, O_EXCL }, + { MipsLinux::TGT_O_NONBLOCK, O_NONBLOCK }, + { MipsLinux::TGT_O_NOCTTY, O_NOCTTY }, +#ifdef O_SYNC + { MipsLinux::TGT_O_SYNC, O_SYNC }, +#endif +#endif /* _MSC_VER */ +}; + +const int MipsLinux::NUM_OPEN_FLAGS = + (sizeof(MipsLinux::openFlagTable)/sizeof(MipsLinux::openFlagTable[0])); + + + diff --git a/src/arch/mips/linux/linux.hh b/src/arch/mips/linux/linux.hh new file mode 100644 index 000000000..f85935bb9 --- /dev/null +++ b/src/arch/mips/linux/linux.hh @@ -0,0 +1,126 @@ +/* + * 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: Korey Sewell + */ + +#ifndef __ARCH_MIPS_LINUX_LINUX_HH__ +#define __ARCH_MIPS_LINUX_LINUX_HH__ + +#include "kern/linux/linux.hh" + +class MipsLinux : public Linux +{ + public: + + /// This table maps the target open() flags to the corresponding + /// host open() flags. + static OpenFlagTransTable openFlagTable[]; + + /// Number of entries in openFlagTable[]. + static const int NUM_OPEN_FLAGS; + + //@{ + /// open(2) flag values. + static const int TGT_O_RDONLY = 0x00000000; //!< O_RDONLY + static const int TGT_O_WRONLY = 0x00000001; //!< O_WRONLY + static const int TGT_O_RDWR = 0x00000002; //!< O_RDWR + static const int TGT_O_NONBLOCK = 0x00000080; //!< O_NONBLOCK + static const int TGT_O_APPEND = 0x00000008; //!< O_APPEND + static const int TGT_O_CREAT = 0x00000100; //!< O_CREAT + static const int TGT_O_TRUNC = 0x00000200; //!< O_TRUNC + static const int TGT_O_EXCL = 0x00000400; //!< O_EXCL + static const int TGT_O_NOCTTY = 0x00000800; //!< O_NOCTTY + static const int TGT_O_SYNC = 0x00000010; //!< O_SYNC + static const int TGT_O_DRD = 0x00010000; //!< O_DRD + static const int TGT_O_DIRECTIO = 0x00020000; //!< O_DIRECTIO + static const int TGT_O_CACHE = 0x00002000; //!< O_CACHE + static const int TGT_O_DSYNC = 0x00008000; //!< O_DSYNC + static const int TGT_O_RSYNC = 0x00040000; //!< O_RSYNC + //@} + + /// For mmap(). + static const unsigned TGT_MAP_ANONYMOUS = 0x800; + + //@{ + /// For getsysinfo(). + static const unsigned GSI_PLATFORM_NAME = 103; //!< platform name as string + static const unsigned GSI_CPU_INFO = 59; //!< CPU information + static const unsigned GSI_PROC_TYPE = 60; //!< get proc_type + static const unsigned GSI_MAX_CPU = 30; //!< max # cpu's on this machine + static const unsigned GSI_CPUS_IN_BOX = 55; //!< number of CPUs in system + static const unsigned GSI_PHYSMEM = 19; //!< Physical memory in KB + static const unsigned GSI_CLK_TCK = 42; //!< clock freq in Hz + //@} + + //@{ + /// For getrusage(). + static const int TGT_RUSAGE_SELF = 0; + static const int TGT_RUSAGE_CHILDREN = -1; + static const int TGT_RUSAGE_BOTH = -2; + //@} + + //@{ + /// For setsysinfo(). + static const unsigned SSI_IEEE_FP_CONTROL = 14; //!< ieee_set_fp_control() + //@} + + //@{ + /// ioctl() command codes. + static const unsigned TIOCGETP = 0x7408; + static const unsigned TIOCSETP = 0x7409; + static const unsigned TIOCSETN = 0x740a; + static const unsigned TIOCSETC = 0x7411; + static const unsigned TIOCGETC = 0x7412; + static const unsigned FIONREAD = 0x467f; + static const unsigned TIOCISATTY = 0x5480; + static const unsigned TIOCGETS = 0x7413; + static const unsigned TIOCGETA = 0x7417; + //@} + + /// For table(). + static const int TBL_SYSINFO = 12; + + /// Resource enumeration for getrlimit(). + enum rlimit_resources { + TGT_RLIMIT_CPU = 0, + TGT_RLIMIT_FSIZE = 1, + TGT_RLIMIT_DATA = 2, + TGT_RLIMIT_STACK = 3, + TGT_RLIMIT_CORE = 4, + TGT_RLIMIT_NOFILE = 5, + TGT_RLIMIT_AS = 6, + TGT_RLIMIT_RSS = 7, + TGT_RLIMIT_VMEM = 7, + TGT_RLIMIT_NPROC = 8, + TGT_RLIMIT_MEMLOCK = 9, + TGT_RLIMIT_LOCKS = 10 + }; + +}; + +#endif diff --git a/src/arch/mips/linux/process.cc b/src/arch/mips/linux/process.cc new file mode 100644 index 000000000..17e735527 --- /dev/null +++ b/src/arch/mips/linux/process.cc @@ -0,0 +1,429 @@ +/* + * Copyright (c) 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: Korey Sewell + */ + +#include "arch/mips/linux/linux.hh" +#include "arch/mips/linux/process.hh" +#include "arch/mips/isa_traits.hh" + +#include "base/trace.hh" +#include "cpu/thread_context.hh" +#include "kern/linux/linux.hh" + +#include "sim/process.hh" +#include "sim/syscall_emul.hh" + +using namespace std; +using namespace MipsISA; + +/// Target uname() handler. +static SyscallReturn +unameFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + TypedBufferArg<Linux::utsname> name(tc->getSyscallArg(0)); + + strcpy(name->sysname, "Linux"); + strcpy(name->nodename, "m5.eecs.umich.edu"); + strcpy(name->release, "2.4.20"); + strcpy(name->version, "#1 Mon Aug 18 11:32:15 EDT 2003"); + strcpy(name->machine, "mips"); + + name.copyOut(tc->getMemPort()); + return 0; +} + +/// Target sys_getsysyinfo() handler. Even though this call is +/// borrowed from Tru64, the subcases that get used appear to be +/// different in practice from those used by Tru64 processes. +static SyscallReturn +sys_getsysinfoFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + unsigned op = tc->getSyscallArg(0); + // unsigned nbytes = tc->getSyscallArg(2); + + switch (op) { + + case 45: { // GSI_IEEE_FP_CONTROL + TypedBufferArg<uint64_t> fpcr(tc->getSyscallArg(1)); + // I don't think this exactly matches the HW FPCR + *fpcr = 0; + fpcr.copyOut(tc->getMemPort()); + return 0; + } + + default: + cerr << "sys_getsysinfo: unknown op " << op << endl; + abort(); + break; + } + + return 1; +} + +/// Target sys_setsysinfo() handler. +static SyscallReturn +sys_setsysinfoFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + unsigned op = tc->getSyscallArg(0); + // unsigned nbytes = tc->getSyscallArg(2); + + switch (op) { + + case 14: { // SSI_IEEE_FP_CONTROL + TypedBufferArg<uint64_t> fpcr(tc->getSyscallArg(1)); + // I don't think this exactly matches the HW FPCR + fpcr.copyIn(tc->getMemPort()); + DPRINTFR(SyscallVerbose, "sys_setsysinfo(SSI_IEEE_FP_CONTROL): " + " setting FPCR to 0x%x\n", gtoh(*(uint64_t*)fpcr)); + return 0; + } + + default: + cerr << "sys_setsysinfo: unknown op " << op << endl; + abort(); + break; + } + + return 1; +} + + +SyscallDesc MipsLinuxProcess::syscallDescs[] = { + /* 0 */ SyscallDesc("syscall", unimplementedFunc), + /* 1 */ SyscallDesc("exit", exitFunc), + /* 2 */ SyscallDesc("fork", unimplementedFunc), + /* 3 */ SyscallDesc("read", readFunc), + /* 4 */ SyscallDesc("write", writeFunc), + /* 5 */ SyscallDesc("open", openFunc<MipsLinux>), + /* 6 */ SyscallDesc("close", closeFunc), + /* 7 */ SyscallDesc("waitpid", unimplementedFunc), + /* 8 */ SyscallDesc("creat", unimplementedFunc), + /* 9 */ SyscallDesc("link", unimplementedFunc), + /* 10 */ SyscallDesc("unlink", unlinkFunc), + /* 11 */ SyscallDesc("execve", unimplementedFunc), + /* 12 */ SyscallDesc("chdir", unimplementedFunc), + /* 13 */ SyscallDesc("time", unimplementedFunc), + /* 14 */ SyscallDesc("mknod", unimplementedFunc), + /* 15 */ SyscallDesc("chmod", chmodFunc<MipsLinux>), + /* 16 */ SyscallDesc("lchown", chownFunc), + /* 17 */ SyscallDesc("break", obreakFunc), + /* 18 */ SyscallDesc("unused#18", unimplementedFunc), + /* 19 */ SyscallDesc("lseek", lseekFunc), + /* 20 */ SyscallDesc("getpid", getpidFunc), + /* 21 */ SyscallDesc("mount", unimplementedFunc), + /* 22 */ SyscallDesc("umount", unimplementedFunc), + /* 23 */ SyscallDesc("setuid", setuidFunc), + /* 24 */ SyscallDesc("getuid", getuidFunc), + /* 25 */ SyscallDesc("stime", unimplementedFunc), + /* 26 */ SyscallDesc("ptrace", unimplementedFunc), + /* 27 */ SyscallDesc("alarm", unimplementedFunc), + /* 28 */ SyscallDesc("unused#28", unimplementedFunc), + /* 29 */ SyscallDesc("pause", unimplementedFunc), + /* 30 */ SyscallDesc("utime", unimplementedFunc), + /* 31 */ SyscallDesc("stty", unimplementedFunc), + /* 32 */ SyscallDesc("gtty", unimplementedFunc), + /* 33 */ SyscallDesc("access", unimplementedFunc), + /* 34 */ SyscallDesc("nice", unimplementedFunc), + /* 35 */ SyscallDesc("ftime", unimplementedFunc), + /* 36 */ SyscallDesc("sync", unimplementedFunc), + /* 37 */ SyscallDesc("kill", ignoreFunc), + /* 38 */ SyscallDesc("rename", unimplementedFunc), + /* 39 */ SyscallDesc("mkdir", unimplementedFunc), + /* 40 */ SyscallDesc("rmdir", unimplementedFunc), + /* 41 */ SyscallDesc("dup", unimplementedFunc), + /* 42 */ SyscallDesc("pipe", unimplementedFunc), + /* 43 */ SyscallDesc("times", unimplementedFunc), + /* 44 */ SyscallDesc("prof", unimplementedFunc), + /* 45 */ SyscallDesc("brk", obreakFunc), + /* 46 */ SyscallDesc("setgid", unimplementedFunc), + /* 47 */ SyscallDesc("getgid", getgidFunc), + /* 48 */ SyscallDesc("signal", ignoreFunc), + /* 49 */ SyscallDesc("geteuid", geteuidFunc), + /* 50 */ SyscallDesc("getegid", getegidFunc), + /* 51 */ SyscallDesc("acct", unimplementedFunc), + /* 52 */ SyscallDesc("umount2", unimplementedFunc), + /* 53 */ SyscallDesc("lock", unimplementedFunc), + /* 54 */ SyscallDesc("ioctl", ioctlFunc<MipsLinux>), + /* 55 */ SyscallDesc("fcntl", fcntlFunc), + /* 56 */ SyscallDesc("mpx", unimplementedFunc), + /* 57 */ SyscallDesc("setpgid", unimplementedFunc), + /* 58 */ SyscallDesc("ulimit", unimplementedFunc), + /* 59 */ SyscallDesc("unused#59", unimplementedFunc), + /* 60 */ SyscallDesc("umask", unimplementedFunc), + /* 61 */ SyscallDesc("chroot", unimplementedFunc), + /* 62 */ SyscallDesc("ustat", unimplementedFunc), + /* 63 */ SyscallDesc("dup2", unimplementedFunc), + /* 64 */ SyscallDesc("getppid", getpagesizeFunc), + /* 65 */ SyscallDesc("getpgrp", unimplementedFunc), + /* 66 */ SyscallDesc("setsid", unimplementedFunc), + /* 67 */ SyscallDesc("sigaction",unimplementedFunc), + /* 68 */ SyscallDesc("sgetmask", unimplementedFunc), + /* 69 */ SyscallDesc("ssetmask", unimplementedFunc), + /* 70 */ SyscallDesc("setreuid", unimplementedFunc), + /* 71 */ SyscallDesc("setregid", unimplementedFunc), + /* 72 */ SyscallDesc("sigsuspend", unimplementedFunc), + /* 73 */ SyscallDesc("sigpending", unimplementedFunc), + /* 74 */ SyscallDesc("sethostname", ignoreFunc), + /* 75 */ SyscallDesc("setrlimit", unimplementedFunc), + /* 76 */ SyscallDesc("getrlimit", unimplementedFunc), + /* 77 */ SyscallDesc("getrusage", unimplementedFunc), + /* 78 */ SyscallDesc("gettimeofday", unimplementedFunc), + /* 79 */ SyscallDesc("settimeofday", unimplementedFunc), + /* 80 */ SyscallDesc("getgroups", unimplementedFunc), + /* 81 */ SyscallDesc("setgroups", unimplementedFunc), + /* 82 */ SyscallDesc("reserved#82", unimplementedFunc), + /* 83 */ SyscallDesc("symlink", unimplementedFunc), + /* 84 */ SyscallDesc("unused#84", unimplementedFunc), + /* 85 */ SyscallDesc("readlink", unimplementedFunc), + /* 86 */ SyscallDesc("uselib", unimplementedFunc), + /* 87 */ SyscallDesc("swapon", gethostnameFunc), + /* 88 */ SyscallDesc("reboot", unimplementedFunc), + /* 89 */ SyscallDesc("readdir", unimplementedFunc), + /* 90 */ SyscallDesc("mmap", mmapFunc<MipsLinux>), + /* 91 */ SyscallDesc("munmap",munmapFunc), + /* 92 */ SyscallDesc("truncate", truncateFunc), + /* 93 */ SyscallDesc("ftruncate", ftruncateFunc), + /* 94 */ SyscallDesc("fchmod", unimplementedFunc), + /* 95 */ SyscallDesc("fchown", unimplementedFunc), + /* 96 */ SyscallDesc("getpriority", unimplementedFunc), + /* 97 */ SyscallDesc("setpriority", unimplementedFunc), + /* 98 */ SyscallDesc("profil", unimplementedFunc), + /* 99 */ SyscallDesc("statfs", unimplementedFunc), + /* 100 */ SyscallDesc("fstatfs", unimplementedFunc), + /* 101 */ SyscallDesc("ioperm", unimplementedFunc), + /* 102 */ SyscallDesc("socketcall", unimplementedFunc), + /* 103 */ SyscallDesc("syslog", unimplementedFunc), + /* 104 */ SyscallDesc("setitimer", unimplementedFunc), + /* 105 */ SyscallDesc("getitimer", unimplementedFunc), + /* 106 */ SyscallDesc("stat", statFunc<MipsLinux>), + /* 107 */ SyscallDesc("lstat", unimplementedFunc), + /* 108 */ SyscallDesc("fstat", fstatFunc<MipsLinux>), + /* 109 */ SyscallDesc("unused#109", unimplementedFunc), + /* 110 */ SyscallDesc("iopl", unimplementedFunc), + /* 111 */ SyscallDesc("vhangup", unimplementedFunc), + /* 112 */ SyscallDesc("idle", ignoreFunc), + /* 113 */ SyscallDesc("vm86", unimplementedFunc), + /* 114 */ SyscallDesc("wait4", unimplementedFunc), + /* 115 */ SyscallDesc("swapoff", unimplementedFunc), + /* 116 */ SyscallDesc("sysinfo", unimplementedFunc), + /* 117 */ SyscallDesc("ipc", unimplementedFunc), + /* 118 */ SyscallDesc("fsync", unimplementedFunc), + /* 119 */ SyscallDesc("sigreturn", unimplementedFunc), + /* 120 */ SyscallDesc("clone", unimplementedFunc), + /* 121 */ SyscallDesc("setdomainname", unimplementedFunc), + /* 122 */ SyscallDesc("uname", unameFunc), + /* 123 */ SyscallDesc("modify_ldt", unimplementedFunc), + /* 124 */ SyscallDesc("adjtimex", unimplementedFunc), + /* 125 */ SyscallDesc("mprotect", ignoreFunc), + /* 126 */ SyscallDesc("sigprocmask", unimplementedFunc), + /* 127 */ SyscallDesc("create_module", unimplementedFunc), + /* 128 */ SyscallDesc("init_module", unimplementedFunc), + /* 129 */ SyscallDesc("delete_module", unimplementedFunc), + /* 130 */ SyscallDesc("get_kernel_syms", unimplementedFunc), + /* 131 */ SyscallDesc("quotactl", unimplementedFunc), + /* 132 */ SyscallDesc("getpgid", unimplementedFunc), + /* 133 */ SyscallDesc("fchdir", unimplementedFunc), + /* 134 */ SyscallDesc("bdflush", unimplementedFunc), + /* 135 */ SyscallDesc("sysfs", unimplementedFunc), + /* 136 */ SyscallDesc("personality", unimplementedFunc), + /* 137 */ SyscallDesc("afs_syscall", unimplementedFunc), + /* 138 */ SyscallDesc("setfsuid", unimplementedFunc), + /* 139 */ SyscallDesc("setfsgid", unimplementedFunc), + /* 140 */ SyscallDesc("llseek", unimplementedFunc), + /* 141 */ SyscallDesc("getdents", unimplementedFunc), + /* 142 */ SyscallDesc("newselect", unimplementedFunc), + /* 143 */ SyscallDesc("flock", unimplementedFunc), + /* 144 */ SyscallDesc("msync", unimplementedFunc), + /* 145 */ SyscallDesc("readv", unimplementedFunc), + /* 146 */ SyscallDesc("writev", writevFunc<MipsLinux>), + /* 147 */ SyscallDesc("cacheflush", unimplementedFunc), + /* 148 */ SyscallDesc("cachectl", unimplementedFunc), + /* 149 */ SyscallDesc("sysmips", unimplementedFunc), + /* 150 */ SyscallDesc("unused#150", unimplementedFunc), + /* 151 */ SyscallDesc("getsid", unimplementedFunc), + /* 152 */ SyscallDesc("fdatasync", unimplementedFunc), + /* 153 */ SyscallDesc("sysctl", unimplementedFunc), + /* 154 */ SyscallDesc("mlock", unimplementedFunc), + /* 155 */ SyscallDesc("munlock", unimplementedFunc), + /* 156 */ SyscallDesc("mlockall", unimplementedFunc), + /* 157 */ SyscallDesc("munlockall", unimplementedFunc), + /* 158 */ SyscallDesc("sched_setparam", unimplementedFunc), + /* 159 */ SyscallDesc("sched_getparam", unimplementedFunc), + /* 160 */ SyscallDesc("sched_setscheduler", unimplementedFunc), + /* 161 */ SyscallDesc("sched_getscheduler", unimplementedFunc), + /* 162 */ SyscallDesc("sched_yield", unimplementedFunc), + /* 163 */ SyscallDesc("sched_get_prioritymax", unimplementedFunc), + /* 164 */ SyscallDesc("sched_get_priority_min", unimplementedFunc), + /* 165 */ SyscallDesc("sched_rr_get_interval", unimplementedFunc), + /* 166 */ SyscallDesc("nanosleep", unimplementedFunc), + /* 167 */ SyscallDesc("mremap", unimplementedFunc), + /* 168 */ SyscallDesc("accept", unimplementedFunc), + /* 169 */ SyscallDesc("bind", unimplementedFunc), + /* 170 */ SyscallDesc("connect", unimplementedFunc), + /* 171 */ SyscallDesc("getpeername", unimplementedFunc), + /* 172 */ SyscallDesc("getsockname", unimplementedFunc), + /* 173 */ SyscallDesc("getsockopt", unimplementedFunc), + /* 174 */ SyscallDesc("listen", unimplementedFunc), + /* 175 */ SyscallDesc("recv", unimplementedFunc), + /* 176 */ SyscallDesc("recvmsg", unimplementedFunc), + /* 177 */ SyscallDesc("send", unimplementedFunc), + /* 178 */ SyscallDesc("sendmsg", ignoreFunc), + /* 179 */ SyscallDesc("sendto", unimplementedFunc), + /* 180 */ SyscallDesc("setsockopt", unimplementedFunc), + /* 181 */ SyscallDesc("shutdown", unimplementedFunc), + /* 182 */ SyscallDesc("unknown #182", unimplementedFunc), + /* 183 */ SyscallDesc("socket", ignoreFunc), + /* 184 */ SyscallDesc("socketpair", unimplementedFunc), + /* 185 */ SyscallDesc("setresuid", unimplementedFunc), + /* 186 */ SyscallDesc("getresuid", unimplementedFunc), + /* 187 */ SyscallDesc("query_module", unimplementedFunc), + /* 188 */ SyscallDesc("poll", unimplementedFunc), + /* 189 */ SyscallDesc("nfsservctl", unimplementedFunc), + /* 190 */ SyscallDesc("setresgid", unimplementedFunc), + /* 191 */ SyscallDesc("getresgid", unimplementedFunc), + /* 192 */ SyscallDesc("prctl", unimplementedFunc), + /* 193 */ SyscallDesc("rt_sigreturn", unimplementedFunc), + /* 194 */ SyscallDesc("rt_sigaction", ignoreFunc), + /* 195 */ SyscallDesc("rt_sigprocmask", ignoreFunc), + /* 196 */ SyscallDesc("rt_sigpending", unimplementedFunc), + /* 197 */ SyscallDesc("rt_sigtimedwait", unimplementedFunc), + /* 198 */ SyscallDesc("rt_sigqueueinfo", ignoreFunc), + /* 199 */ SyscallDesc("rt_sigsuspend", unimplementedFunc), + /* 200 */ SyscallDesc("pread64", unimplementedFunc), + /* 201 */ SyscallDesc("pwrite64", unimplementedFunc), + /* 202 */ SyscallDesc("chown", unimplementedFunc), + /* 203 */ SyscallDesc("getcwd", unimplementedFunc), + /* 204 */ SyscallDesc("capget", unimplementedFunc), + /* 205 */ SyscallDesc("capset", unimplementedFunc), + /* 206 */ SyscallDesc("sigalstack", unimplementedFunc), + /* 207 */ SyscallDesc("sendfile", unimplementedFunc), + /* 208 */ SyscallDesc("getpmsg", unimplementedFunc), + /* 209 */ SyscallDesc("putpmsg", unimplementedFunc), + /* 210 */ SyscallDesc("mmap2", unimplementedFunc), + /* 211 */ SyscallDesc("truncate64", unimplementedFunc), + /* 212 */ SyscallDesc("ftruncate64", unimplementedFunc), + /* 213 */ SyscallDesc("stat64", unimplementedFunc), + /* 214 */ SyscallDesc("lstat64", lstat64Func<MipsLinux>), + /* 215 */ SyscallDesc("fstat64", fstat64Func<MipsLinux>), + /* 216 */ SyscallDesc("pivot_root", unimplementedFunc), + /* 217 */ SyscallDesc("mincore", unimplementedFunc), + /* 218 */ SyscallDesc("madvise", unimplementedFunc), + /* 219 */ SyscallDesc("getdents64", unimplementedFunc), + /* 220 */ SyscallDesc("fcntl64", fcntl64Func), + /* 221 */ SyscallDesc("reserved#221", unimplementedFunc), + /* 222 */ SyscallDesc("gettid", unimplementedFunc), + /* 223 */ SyscallDesc("readahead", unimplementedFunc), + /* 224 */ SyscallDesc("setxattr", unimplementedFunc), + /* 225 */ SyscallDesc("lsetxattr", unimplementedFunc), + /* 226 */ SyscallDesc("fsetxattr", unimplementedFunc), + /* 227 */ SyscallDesc("getxattr", unimplementedFunc), + /* 228 */ SyscallDesc("lgetxattr", unimplementedFunc), + /* 229 */ SyscallDesc("fgetxattr", unimplementedFunc), + /* 230 */ SyscallDesc("listxattr", unimplementedFunc), + /* 231 */ SyscallDesc("llistxattr", unimplementedFunc), + /* 232 */ SyscallDesc("flistxattr", unimplementedFunc), + /* 233 */ SyscallDesc("removexattr", unimplementedFunc), + /* 234 */ SyscallDesc("lremovexattr", unimplementedFunc), + /* 235 */ SyscallDesc("fremovexattr", ignoreFunc), + /* 236 */ SyscallDesc("tkill", unimplementedFunc), + /* 237 */ SyscallDesc("sendfile64", unimplementedFunc), + /* 238 */ SyscallDesc("futex", unimplementedFunc), + /* 239 */ SyscallDesc("sched_setaffinity", unimplementedFunc), + /* 240 */ SyscallDesc("sched_getaffinity", unimplementedFunc), + /* 241 */ SyscallDesc("io_setup", unimplementedFunc), + /* 242 */ SyscallDesc("io_destroy", unimplementedFunc), + /* 243 */ SyscallDesc("io_getevents", unimplementedFunc), + /* 244 */ SyscallDesc("io_submit", unimplementedFunc), + /* 245 */ SyscallDesc("io_cancel", unimplementedFunc), + /* 246 */ SyscallDesc("exit_group", exitFunc), + /* 247 */ SyscallDesc("lookup_dcookie", unimplementedFunc), + /* 248 */ SyscallDesc("epoll_create", unimplementedFunc), + /* 249 */ SyscallDesc("epoll_ctl", unimplementedFunc), + /* 250 */ SyscallDesc("epoll_wait", unimplementedFunc), + /* 251 */ SyscallDesc("remap_file_pages", unimplementedFunc), + /* 252 */ SyscallDesc("set_tid_address", unimplementedFunc), + /* 253 */ SyscallDesc("restart_syscall", unimplementedFunc), + /* 254 */ SyscallDesc("fadvise64", unimplementedFunc), + /* 255 */ SyscallDesc("statfs64", unimplementedFunc), + /* 256 */ SyscallDesc("fstafs64", unimplementedFunc), + /* 257 */ SyscallDesc("timer_create", sys_getsysinfoFunc), + /* 258 */ SyscallDesc("timer_settime", sys_setsysinfoFunc), + /* 259 */ SyscallDesc("timer_gettime", unimplementedFunc), + /* 260 */ SyscallDesc("timer_getoverrun", unimplementedFunc), + /* 261 */ SyscallDesc("timer_delete", unimplementedFunc), + /* 262 */ SyscallDesc("clock_settime", unimplementedFunc), + /* 263 */ SyscallDesc("clock_gettime", unimplementedFunc), + /* 264 */ SyscallDesc("clock_getres", unimplementedFunc), + /* 265 */ SyscallDesc("clock_nanosleep", unimplementedFunc), + /* 266 */ SyscallDesc("tgkill", unimplementedFunc), + /* 267 */ SyscallDesc("utimes", unimplementedFunc), + /* 268 */ SyscallDesc("mbind", unimplementedFunc), + /* 269 */ SyscallDesc("get_mempolicy", unimplementedFunc), + /* 270 */ SyscallDesc("set_mempolicy", unimplementedFunc), + /* 271 */ SyscallDesc("mq_open", unimplementedFunc), + /* 272 */ SyscallDesc("mq_unlink", unimplementedFunc), + /* 273 */ SyscallDesc("mq_timedsend", unimplementedFunc), + /* 274 */ SyscallDesc("mq_timedreceive", unimplementedFunc), + /* 275 */ SyscallDesc("mq_notify", unimplementedFunc), + /* 276 */ SyscallDesc("mq_getsetattr", unimplementedFunc), + /* 277 */ SyscallDesc("vserver", unimplementedFunc), + /* 278 */ SyscallDesc("waitid", unimplementedFunc), + /* 279 */ SyscallDesc("unknown #279", unimplementedFunc), + /* 280 */ SyscallDesc("add_key", unimplementedFunc), + /* 281 */ SyscallDesc("request_key", unimplementedFunc), + /* 282 */ SyscallDesc("keyctl", unimplementedFunc), +}; + +MipsLinuxProcess::MipsLinuxProcess(const std::string &name, + ObjectFile *objFile, + System *system, + int stdin_fd, + int stdout_fd, + int stderr_fd, + std::vector<std::string> &argv, + std::vector<std::string> &envp) + : MipsLiveProcess(name, objFile, system, stdin_fd, stdout_fd, stderr_fd, + argv, envp), + Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc)) +{ } + +SyscallDesc* +MipsLinuxProcess::getDesc(int callnum) +{ + //MIPS32 syscalls are in the range of 4000 - 4999 + int m5_sys_idx = callnum - 4000; + + if (m5_sys_idx < 0 || m5_sys_idx > Num_Syscall_Descs) + return NULL; + + return &syscallDescs[m5_sys_idx]; +} diff --git a/src/arch/mips/linux/process.hh b/src/arch/mips/linux/process.hh new file mode 100644 index 000000000..68da3227b --- /dev/null +++ b/src/arch/mips/linux/process.hh @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2003-2004 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. + */ + +#ifndef __MIPS_LINUX_PROCESS_HH__ +#define __MIPS_LINUX_PROCESS_HH__ + +#include "arch/mips/process.hh" + + +/// A process with emulated Mips/Linux syscalls. +class MipsLinuxProcess : public MipsLiveProcess +{ + public: + /// Constructor. + MipsLinuxProcess(const std::string &name, + ObjectFile *objFile, + System *system, + int stdin_fd, int stdout_fd, int stderr_fd, + std::vector<std::string> &argv, + std::vector<std::string> &envp); + + virtual SyscallDesc* getDesc(int callnum); + + /// The target system's hostname. + static const char *hostname; + + /// Array of syscall descriptors, indexed by call number. + static SyscallDesc syscallDescs[]; + + const int Num_Syscall_Descs; +}; + + +#endif // __MIPS_LINUX_PROCESS_HH__ diff --git a/src/arch/mips/process.cc b/src/arch/mips/process.cc new file mode 100644 index 000000000..6f2c88f69 --- /dev/null +++ b/src/arch/mips/process.cc @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2003-2004 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 + * Ali Saidi + * Korey Sewell + */ + +#include "arch/mips/isa_traits.hh" +#include "arch/mips/process.hh" +#include "arch/mips/linux/process.hh" +#include "base/loader/object_file.hh" +#include "base/misc.hh" +#include "cpu/thread_context.hh" +#include "sim/builder.hh" +#include "sim/system.hh" + +using namespace std; +using namespace MipsISA; + + +MipsLiveProcess * +MipsLiveProcess::create(const std::string &nm, System *system, int stdin_fd, + int stdout_fd, int stderr_fd, std::string executable, + std::vector<std::string> &argv, std::vector<std::string> &envp) +{ + MipsLiveProcess *process = NULL; + + ObjectFile *objFile = createObjectFile(executable); + if (objFile == NULL) { + fatal("Can't load object file %s", executable); + } + + + if (objFile->getArch() != ObjectFile::Mips) + fatal("Object file does not match MIPS architecture."); + + switch (objFile->getOpSys()) { + case ObjectFile::Linux: + process = new MipsLinuxProcess(nm, objFile, system, + stdin_fd, stdout_fd, stderr_fd, + argv, envp); + break; + + default: + fatal("Unknown/unsupported operating system."); + } + + if (process == NULL) + fatal("Unknown error creating process object."); + return process; +} + +MipsLiveProcess::MipsLiveProcess(const std::string &nm, ObjectFile *objFile, + System *_system, int stdin_fd, int stdout_fd, int stderr_fd, + std::vector<std::string> &argv, std::vector<std::string> &envp) + : LiveProcess(nm, objFile, _system, stdin_fd, stdout_fd, stderr_fd, + argv, envp) +{ + // Set up stack. On MIPS, stack starts at the top of kuseg + // user address space. MIPS stack grows down from here + stack_base = 0x7FFFFFFF; + + // Set pointer for next thread stack. Reserve 8M for main stack. + next_thread_stack_base = stack_base - (8 * 1024 * 1024); + + // Set up break point (Top of Heap) + brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize(); + brk_point = roundUp(brk_point, VMPageSize); + + // Set up region for mmaps. For now, start at bottom of kuseg space. + mmap_start = mmap_end = 0x10000; +} + +void +MipsLiveProcess::startup() +{ + argsInit(MachineBytes, VMPageSize); +} + + + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(MipsLiveProcess) + + VectorParam<string> cmd; + Param<string> executable; + Param<string> input; + Param<string> output; + VectorParam<string> env; + SimObjectParam<System *> system; + +END_DECLARE_SIM_OBJECT_PARAMS(MipsLiveProcess) + + +BEGIN_INIT_SIM_OBJECT_PARAMS(MipsLiveProcess) + + INIT_PARAM(cmd, "command line (executable plus arguments)"), + INIT_PARAM(executable, "executable (overrides cmd[0] if set)"), + INIT_PARAM(input, "filename for stdin (dflt: use sim stdin)"), + INIT_PARAM(output, "filename for stdout/stderr (dflt: use sim stdout)"), + INIT_PARAM(env, "environment settings"), + INIT_PARAM(system, "system") + +END_INIT_SIM_OBJECT_PARAMS(MipsLiveProcess) + + +CREATE_SIM_OBJECT(MipsLiveProcess) +{ + string in = input; + string out = output; + + // initialize file descriptors to default: same as simulator + int stdin_fd, stdout_fd, stderr_fd; + + if (in == "stdin" || in == "cin") + stdin_fd = STDIN_FILENO; + else + stdin_fd = Process::openInputFile(input); + + if (out == "stdout" || out == "cout") + stdout_fd = STDOUT_FILENO; + else if (out == "stderr" || out == "cerr") + stdout_fd = STDERR_FILENO; + else + stdout_fd = Process::openOutputFile(out); + + stderr_fd = (stdout_fd != STDOUT_FILENO) ? stdout_fd : STDERR_FILENO; + + return MipsLiveProcess::create(getInstanceName(), system, + stdin_fd, stdout_fd, stderr_fd, + (string)executable == "" ? cmd[0] : executable, + cmd, env); +} + + +REGISTER_SIM_OBJECT("MipsLiveProcess", MipsLiveProcess) + + diff --git a/src/arch/mips/process.hh b/src/arch/mips/process.hh new file mode 100644 index 000000000..dae891125 --- /dev/null +++ b/src/arch/mips/process.hh @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2003-2004 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 + * Ali Saidi + * Korey Sewell + */ + +#ifndef __MIPS_PROCESS_HH__ +#define __MIPS_PROCESS_HH__ + +#include <string> +#include <vector> +#include "sim/process.hh" + +class LiveProcess; +class ObjectFile; +class System; + +class MipsLiveProcess : public LiveProcess +{ + protected: + MipsLiveProcess(const std::string &nm, ObjectFile *objFile, + System *_system, int stdin_fd, int stdout_fd, int stderr_fd, + std::vector<std::string> &argv, + std::vector<std::string> &envp); + + void startup(); + + public: + // this function is used to create the LiveProcess object, since + // we can't tell which subclass of LiveProcess to use until we + // open and look at the object file. + static MipsLiveProcess *create(const std::string &nm, + System *_system, + int stdin_fd, int stdout_fd, int stderr_fd, + std::string executable, + std::vector<std::string> &argv, + std::vector<std::string> &envp); + +}; + + +#endif // __MIPS_PROCESS_HH__ diff --git a/src/arch/mips/regfile/float_regfile.hh b/src/arch/mips/regfile/float_regfile.hh new file mode 100644 index 000000000..d1a60298a --- /dev/null +++ b/src/arch/mips/regfile/float_regfile.hh @@ -0,0 +1,160 @@ +/* + * Copyright (c) 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: Korey Sewell + */ + +#ifndef __ARCH_MIPS_FLOAT_REGFILE_HH__ +#define __ARCH_MIPS_FLOAT_REGFILE_HH__ + +#include "arch/mips/types.hh" +#include "arch/mips/constants.hh" +#include "base/misc.hh" +#include "config/full_system.hh" +#include "sim/byteswap.hh" +#include "sim/faults.hh" +#include "sim/host.hh" + +class Checkpoint; +class ThreadContext; +class Regfile; + +namespace MipsISA +{ + class FloatRegFile + { + protected: + FloatReg32 regs[NumFloatRegs]; + + public: + + void clear() + { + bzero(regs, sizeof(regs)); + } + + double readReg(int floatReg, int width) + { + switch(width) + { + case SingleWidth: + { + void *float_ptr = ®s[floatReg]; + return *(float *) float_ptr; + } + + case DoubleWidth: + { + uint64_t double_val = (FloatReg64)regs[floatReg + 1] << 32 | regs[floatReg]; + void *double_ptr = &double_val; + return *(double *) double_ptr; + } + + default: + panic("Attempted to read a %d bit floating point register!", width); + } + } + + FloatRegBits readRegBits(int floatReg, int width) + { + if (floatReg < NumFloatArchRegs - 1) { + switch(width) + { + case SingleWidth: + return regs[floatReg]; + + case DoubleWidth: + return (FloatReg64)regs[floatReg + 1] << 32 | regs[floatReg]; + + default: + panic("Attempted to read a %d bit floating point register!", width); + } + } else { + if (width > SingleWidth) + assert("Control Regs are only 32 bits wide"); + + return regs[floatReg]; + } + } + + Fault setReg(int floatReg, const FloatReg &val, int width) + { + switch(width) + { + case SingleWidth: + { + float temp = val; + void *float_ptr = &temp; + regs[floatReg] = *(FloatReg32 *) float_ptr; + break; + } + + case DoubleWidth: + { + const void *double_ptr = &val; + FloatReg64 temp_double = *(FloatReg64 *) double_ptr; + regs[floatReg + 1] = temp_double >> 32; + regs[floatReg] = 0x0000FFFF & temp_double; + break; + } + + default: + panic("Attempted to read a %d bit floating point register!", width); + } + + return NoFault; + } + + Fault setRegBits(int floatReg, const FloatRegBits &val, int width) + { + using namespace std; + + switch(width) + { + case SingleWidth: + regs[floatReg] = val; + break; + + case DoubleWidth: + regs[floatReg + 1] = val >> 32; + regs[floatReg] = val; + break; + + default: + panic("Attempted to read a %d bit floating point register!", width); + } + return NoFault; + } + + void serialize(std::ostream &os); + + void unserialize(Checkpoint *cp, const std::string §ion); + }; + +} // namespace MipsISA + +#endif diff --git a/src/arch/mips/regfile/int_regfile.hh b/src/arch/mips/regfile/int_regfile.hh new file mode 100644 index 000000000..dc82a3c26 --- /dev/null +++ b/src/arch/mips/regfile/int_regfile.hh @@ -0,0 +1,75 @@ +/* + * Copyright (c) 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: Korey Sewell + */ + +#ifndef __ARCH_MIPS_INT_REGFILE_HH__ +#define __ARCH_MIPS_INT_REGFILE_HH__ + +#include "arch/mips/types.hh" +#include "arch/mips/constants.hh" +#include "base/misc.hh" +#include "sim/faults.hh" + +class Checkpoint; +class ThreadContext; +class Regfile; + +namespace MipsISA +{ + class IntRegFile + { + protected: + IntReg regs[NumIntRegs]; + + public: + IntReg readReg(int intReg) + { + return regs[intReg]; + } + + Fault setReg(int intReg, const IntReg &val) + { + regs[intReg] = val; + return NoFault; + } + + void serialize(std::ostream &os); + + void unserialize(Checkpoint *cp, const std::string §ion); + + }; + + enum MiscIntRegNums { + HI = NumIntArchRegs, + LO + }; + +} // namespace MipsISA + +#endif diff --git a/src/arch/mips/regfile/misc_regfile.hh b/src/arch/mips/regfile/misc_regfile.hh new file mode 100644 index 000000000..f8aeab8cb --- /dev/null +++ b/src/arch/mips/regfile/misc_regfile.hh @@ -0,0 +1,98 @@ +/* + * Copyright (c) 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: Korey Sewell + */ + +#ifndef __ARCH_MIPS_MISC_REGFILE_HH__ +#define __ARCH_MIPS_MISC_REGFILE_HH__ + +#include "arch/mips/types.hh" +#include "arch/mips/constants.hh" +#include "sim/faults.hh" + +class Checkpoint; +class ThreadContext; +class Regfile; + +namespace MipsISA +{ + class MiscRegFile { + + protected: + uint64_t fpcr; // floating point condition codes + uint64_t uniq; // process-unique register + bool lock_flag; // lock flag for LL/SC + Addr lock_addr; // lock address for LL/SC + + MiscReg miscRegFile[NumMiscRegs]; + + public: + //These functions should be removed once the simplescalar cpu model + //has been replaced. + int getInstAsid(); + int getDataAsid(); + + void copyMiscRegs(ThreadContext *tc); + + MiscReg readReg(int misc_reg) + { + return miscRegFile[misc_reg]; + } + + MiscReg readRegWithEffect(int misc_reg, Fault &fault, ThreadContext *tc) + { + return miscRegFile[misc_reg]; + } + + Fault setReg(int misc_reg, const MiscReg &val) + { + miscRegFile[misc_reg] = val; return NoFault; + } + + Fault setRegWithEffect(int misc_reg, const MiscReg &val, + ThreadContext *tc) + { + miscRegFile[misc_reg] = val; return NoFault; + } + +#if FULL_SYSTEM + void clearIprs() { } + + protected: + InternalProcReg ipr[NumInternalProcRegs]; // Internal processor regs + + private: + MiscReg readIpr(int idx, Fault &fault, ThreadContext *tc) { } + + Fault setIpr(int idx, uint64_t val, ThreadContext *tc) { } +#endif + friend class RegFile; + }; +} // namespace MipsISA + +#endif diff --git a/src/arch/mips/regfile/regfile.hh b/src/arch/mips/regfile/regfile.hh new file mode 100644 index 000000000..af61e62cd --- /dev/null +++ b/src/arch/mips/regfile/regfile.hh @@ -0,0 +1,201 @@ +/* + * Copyright (c) 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: Korey Sewell + */ + +#ifndef __ARCH_MIPS_REGFILE_HH__ +#define __ARCH_MIPS_REGFILE_HH__ + +#include "arch/mips/types.hh" +#include "arch/mips/constants.hh" +#include "arch/mips/regfile/int_regfile.hh" +#include "arch/mips/regfile/float_regfile.hh" +#include "arch/mips/regfile/misc_regfile.hh" +#include "sim/faults.hh" + +class Checkpoint; +class ThreadContext; + +namespace MipsISA +{ + class RegFile { + protected: + IntRegFile intRegFile; // (signed) integer register file + FloatRegFile floatRegFile; // floating point register file + MiscRegFile miscRegFile; // control register file + + public: + + void clear() + { + bzero(&intRegFile, sizeof(intRegFile)); + bzero(&floatRegFile, sizeof(floatRegFile)); + bzero(&miscRegFile, sizeof(miscRegFile)); + } + + MiscReg readMiscReg(int miscReg) + { + return miscRegFile.readReg(miscReg); + } + + MiscReg readMiscRegWithEffect(int miscReg, + Fault &fault, ThreadContext *tc) + { + fault = NoFault; + return miscRegFile.readRegWithEffect(miscReg, fault, tc); + } + + Fault setMiscReg(int miscReg, const MiscReg &val) + { + return miscRegFile.setReg(miscReg, val); + } + + Fault setMiscRegWithEffect(int miscReg, const MiscReg &val, + ThreadContext * tc) + { + return miscRegFile.setRegWithEffect(miscReg, val, tc); + } + + FloatReg readFloatReg(int floatReg) + { + return floatRegFile.readReg(floatReg,SingleWidth); + } + + FloatReg readFloatReg(int floatReg, int width) + { + return floatRegFile.readReg(floatReg,width); + } + + FloatRegBits readFloatRegBits(int floatReg) + { + return floatRegFile.readRegBits(floatReg,SingleWidth); + } + + FloatRegBits readFloatRegBits(int floatReg, int width) + { + return floatRegFile.readRegBits(floatReg,width); + } + + Fault setFloatReg(int floatReg, const FloatReg &val) + { + return floatRegFile.setReg(floatReg, val, SingleWidth); + } + + Fault setFloatReg(int floatReg, const FloatReg &val, int width) + { + return floatRegFile.setReg(floatReg, val, width); + } + + Fault setFloatRegBits(int floatReg, const FloatRegBits &val) + { + return floatRegFile.setRegBits(floatReg, val, SingleWidth); + } + + Fault setFloatRegBits(int floatReg, const FloatRegBits &val, int width) + { + return floatRegFile.setRegBits(floatReg, val, width); + } + + IntReg readIntReg(int intReg) + { + return intRegFile.readReg(intReg); + } + + Fault setIntReg(int intReg, const IntReg &val) + { + return intRegFile.setReg(intReg, val); + } + protected: + + Addr pc; // program counter + Addr npc; // next-cycle program counter + Addr nnpc; // next-next-cycle program counter + // used to implement branch delay slot + // not real register + public: + Addr readPC() + { + return pc; + } + + void setPC(Addr val) + { + pc = val; + } + + Addr readNextPC() + { + return npc; + } + + void setNextPC(Addr val) + { + npc = val; + } + + Addr readNextNPC() + { + return nnpc; + } + + void setNextNPC(Addr val) + { + nnpc = val; + } + + +#if FULL_SYSTEM + IntReg palregs[NumIntRegs]; // PAL shadow registers + InternalProcReg ipr[NumInternalProcRegs]; // internal processor regs + int intrflag; // interrupt flag + bool pal_shadow; // using pal_shadow registers + inline int instAsid() { return MIPS34K::ITB_ASN_ASN(ipr[IPR_ITB_ASN]); } + inline int dataAsid() { return MIPS34K::DTB_ASN_ASN(ipr[IPR_DTB_ASN]); } +#endif // FULL_SYSTEM + + void serialize(std::ostream &os); + void unserialize(Checkpoint *cp, const std::string §ion); + + typedef int ContextParam; + typedef int ContextVal; + + void changeContext(ContextParam param, ContextVal val) + { + } + }; + + void copyRegs(ThreadContext *src, ThreadContext *dest); + + void copyMiscRegs(ThreadContext *src, ThreadContext *dest); + +#if FULL_SYSTEM + void copyIprs(ThreadContext *src, ThreadContext *dest); +#endif +} // namespace MipsISA + +#endif diff --git a/src/arch/mips/stacktrace.hh b/src/arch/mips/stacktrace.hh new file mode 100644 index 000000000..38767cef7 --- /dev/null +++ b/src/arch/mips/stacktrace.hh @@ -0,0 +1,121 @@ +/* + * Copyright (c) 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 __ARCH_ALPHA_STACKTRACE_HH__ +#define __ARCH_ALPHA_STACKTRACE_HH__ + +#include "base/trace.hh" +#include "cpu/static_inst.hh" + +class ThreadContext; +class StackTrace; + +class ProcessInfo +{ + private: + ThreadContext *tc; + + int thread_info_size; + int task_struct_size; + int task_off; + int pid_off; + int name_off; + + public: + ProcessInfo(ThreadContext *_tc); + + Addr task(Addr ksp) const; + int pid(Addr ksp) const; + std::string name(Addr ksp) const; +}; + +class StackTrace +{ + protected: + typedef TheISA::MachInst MachInst; + private: + ThreadContext *tc; + std::vector<Addr> stack; + + private: + bool isEntry(Addr addr); + bool decodePrologue(Addr sp, Addr callpc, Addr func, int &size, Addr &ra); + bool decodeSave(MachInst inst, int ®, int &disp); + bool decodeStack(MachInst inst, int &disp); + + void trace(ThreadContext *tc, bool is_call); + + public: + StackTrace(); + StackTrace(ThreadContext *tc, StaticInstPtr inst); + ~StackTrace(); + + void clear() + { + tc = 0; + stack.clear(); + } + + bool valid() const { return tc != NULL; } + bool trace(ThreadContext *tc, StaticInstPtr inst); + + public: + const std::vector<Addr> &getstack() const { return stack; } + + static const int user = 1; + static const int console = 2; + static const int unknown = 3; + +#if TRACING_ON + private: + void dump(); + + public: + void dprintf() { if (DTRACE(Stack)) dump(); } +#else + public: + void dprintf() {} +#endif +}; + +inline bool +StackTrace::trace(ThreadContext *tc, StaticInstPtr inst) +{ + if (!inst->isCall() && !inst->isReturn()) + return false; + + if (valid()) + clear(); + + trace(tc, !inst->isReturn()); + return true; +} + +#endif // __ARCH_ALPHA_STACKTRACE_HH__ diff --git a/src/arch/mips/types.hh b/src/arch/mips/types.hh new file mode 100644 index 000000000..7cd2eed0c --- /dev/null +++ b/src/arch/mips/types.hh @@ -0,0 +1,94 @@ +/* + * Copyright (c) 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: Korey Sewell + */ + +#ifndef __ARCH_MIPS_TYPES_HH__ +#define __ARCH_MIPS_TYPES_HH__ + +#include "sim/host.hh" + +namespace MipsISA +{ + typedef uint32_t MachInst; + typedef uint64_t ExtMachInst; + typedef uint8_t RegIndex; + + typedef uint32_t IntReg; + + // floating point register file entry type + typedef double FloatReg; + typedef uint32_t FloatReg32; + typedef uint64_t FloatReg64; + typedef uint64_t FloatRegBits; + + // cop-0/cop-1 system control register + typedef uint64_t MiscReg; + typedef uint64_t InternalProcReg; + + typedef union { + IntReg intreg; + FloatReg fpreg; + MiscReg ctrlreg; + } AnyReg; + + //used in FP convert & round function + enum ConvertType{ + SINGLE_TO_DOUBLE, + SINGLE_TO_WORD, + SINGLE_TO_LONG, + + DOUBLE_TO_SINGLE, + DOUBLE_TO_WORD, + DOUBLE_TO_LONG, + + LONG_TO_SINGLE, + LONG_TO_DOUBLE, + LONG_TO_WORD, + LONG_TO_PS, + + WORD_TO_SINGLE, + WORD_TO_DOUBLE, + WORD_TO_LONG, + WORD_TO_PS, + + PL_TO_SINGLE, + PU_TO_SINGLE + }; + + //used in FP convert & round function + enum RoundMode{ + RND_ZERO, + RND_DOWN, + RND_UP, + RND_NEAREST + }; + +} // namespace MipsISA + +#endif diff --git a/src/arch/mips/utility.cc b/src/arch/mips/utility.cc new file mode 100644 index 000000000..e7455fdbf --- /dev/null +++ b/src/arch/mips/utility.cc @@ -0,0 +1,202 @@ +/* + * 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: Korey Sewell + */ + +#include "arch/mips/isa_traits.hh" +#include "arch/mips/utility.hh" +#include "config/full_system.hh" +#include "cpu/static_inst.hh" +#include "sim/serialize.hh" +#include "base/bitfield.hh" + +using namespace MipsISA; +using namespace std; + +uint64_t +MipsISA::fpConvert(ConvertType cvt_type, double fp_val) +{ + + switch (cvt_type) + { + case SINGLE_TO_DOUBLE: + { + double sdouble_val = fp_val; + void *sdouble_ptr = &sdouble_val; + uint64_t sdp_bits = *(uint64_t *) sdouble_ptr; + return sdp_bits; + } + + case SINGLE_TO_WORD: + { + int32_t sword_val = (int32_t) fp_val; + void *sword_ptr = &sword_val; + uint64_t sword_bits= *(uint32_t *) sword_ptr; + return sword_bits; + } + + case WORD_TO_SINGLE: + { + float wfloat_val = fp_val; + void *wfloat_ptr = &wfloat_val; + uint64_t wfloat_bits = *(uint32_t *) wfloat_ptr; + return wfloat_bits; + } + + case WORD_TO_DOUBLE: + { + double wdouble_val = fp_val; + void *wdouble_ptr = &wdouble_val; + uint64_t wdp_bits = *(uint64_t *) wdouble_ptr; + return wdp_bits; + } + + default: + panic("Invalid Floating Point Conversion Type (%d). See \"types.hh\" for List of Conversions\n",cvt_type); + return 0; + } +} + +double +MipsISA::roundFP(double val, int digits) +{ + double digit_offset = pow(10.0,digits); + val = val * digit_offset; + val = val + 0.5; + val = floor(val); + val = val / digit_offset; + return val; +} + +double +MipsISA::truncFP(double val) +{ + int trunc_val = (int) val; + return (double) trunc_val; +} + +bool +MipsISA::getCondCode(uint32_t fcsr, int cc_idx) +{ + int shift = (cc_idx == 0) ? 23 : cc_idx + 24; + bool cc_val = (fcsr >> shift) & 0x00000001; + return cc_val; +} + +uint32_t +MipsISA::genCCVector(uint32_t fcsr, int cc_num, uint32_t cc_val) +{ + int cc_idx = (cc_num == 0) ? 23 : cc_num + 24; + + fcsr = bits(fcsr, 31, cc_idx + 1) << cc_idx + 1 | + cc_val << cc_idx | + bits(fcsr, cc_idx - 1, 0); + + return fcsr; +} + +uint32_t +MipsISA::genInvalidVector(uint32_t fcsr_bits) +{ + //Set FCSR invalid in "flag" field + int invalid_offset = Invalid + Flag_Field; + fcsr_bits = fcsr_bits | (1 << invalid_offset); + + //Set FCSR invalid in "cause" flag + int cause_offset = Invalid + Cause_Field; + fcsr_bits = fcsr_bits | (1 << cause_offset); + + return fcsr_bits; +} + +bool +MipsISA::isNan(void *val_ptr, int size) +{ + switch (size) + { + case 32: + { + uint32_t val_bits = *(uint32_t *) val_ptr; + return (bits(val_bits, 30, 23) == 0xFF); + } + + case 64: + { + uint64_t val_bits = *(uint64_t *) val_ptr; + return (bits(val_bits, 62, 52) == 0x7FF); + } + + default: + panic("Type unsupported. Size mismatch\n"); + } +} + + +bool +MipsISA::isQnan(void *val_ptr, int size) +{ + switch (size) + { + case 32: + { + uint32_t val_bits = *(uint32_t *) val_ptr; + return (bits(val_bits, 30, 22) == 0x1FE); + } + + case 64: + { + uint64_t val_bits = *(uint64_t *) val_ptr; + return (bits(val_bits, 62, 51) == 0xFFE); + } + + default: + panic("Type unsupported. Size mismatch\n"); + } +} + +bool +MipsISA::isSnan(void *val_ptr, int size) +{ + switch (size) + { + case 32: + { + uint32_t val_bits = *(uint32_t *) val_ptr; + return (bits(val_bits, 30, 22) == 0x1FF); + } + + case 64: + { + uint64_t val_bits = *(uint64_t *) val_ptr; + return (bits(val_bits, 62, 51) == 0xFFF); + } + + default: + panic("Type unsupported. Size mismatch\n"); + } +} diff --git a/src/arch/mips/utility.hh b/src/arch/mips/utility.hh new file mode 100644 index 000000000..c5c69ddcd --- /dev/null +++ b/src/arch/mips/utility.hh @@ -0,0 +1,57 @@ +/* + * Copyright (c) 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: Nathan Binkert + * Steve Reinhardt + */ + +#ifndef __ARCH_MIPS_UTILITY_HH__ +#define __ARCH_MIPS_UTILITY_HH__ + +#include "arch/mips/types.hh" +#include "arch/mips/constants.hh" +#include "base/misc.hh" +#include "sim/host.hh" + +namespace MipsISA { + + //Floating Point Utility Functions + uint64_t fpConvert(ConvertType cvt_type, double fp_val); + double roundFP(double val, int digits); + double truncFP(double val); + + bool getCondCode(uint32_t fcsr, int cc); + uint32_t genCCVector(uint32_t fcsr, int num, uint32_t cc_val); + uint32_t genInvalidVector(uint32_t fcsr); + + bool isNan(void *val_ptr, int size); + bool isQnan(void *val_ptr, int size); + bool isSnan(void *val_ptr, int size); +}; + + +#endif diff --git a/src/arch/sparc/SConscript b/src/arch/sparc/SConscript new file mode 100644 index 000000000..e7a8278db --- /dev/null +++ b/src/arch/sparc/SConscript @@ -0,0 +1,83 @@ +# -*- mode:python -*- + +# Copyright (c) 2004-2005 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Gabe Black +# Steve Reinhardt + +import os +import sys +from os.path import isdir + +# Import build environment variable from SConstruct. +Import('env') + +################################################### +# +# Define needed sources. +# +################################################### + +# Base sources used by all configurations. +base_sources = Split(''' + faults.cc + isa_traits.cc + ''') + +# Full-system sources +full_system_sources = Split(''' + vtophys.cc + ua2005.cc + ''') + +# Syscall emulation (non-full-system) sources +syscall_emulation_sources = Split(''' + linux/linux.cc + linux/process.cc + solaris/solaris.cc + solaris/process.cc + process.cc + ''') + +sources = base_sources + +if env['FULL_SYSTEM']: + sources += full_system_sources +else: + sources += syscall_emulation_sources + +# Convert file names to SCons File objects. This takes care of the +# path relative to the top of the directory tree. +sources = [File(s) for s in sources] + +# Add in files generated by the ISA description. +isa_desc_files = env.ISADesc('isa/main.isa') +# Only non-header files need to be compiled. +isa_desc_sources = [f for f in isa_desc_files if not f.path.endswith('.hh')] +sources += isa_desc_sources + +Return('sources') diff --git a/src/arch/sparc/faults.cc b/src/arch/sparc/faults.cc new file mode 100644 index 000000000..57b4d4d86 --- /dev/null +++ b/src/arch/sparc/faults.cc @@ -0,0 +1,258 @@ +/* + * Copyright (c) 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: Gabe Black + * Kevin Lim + */ + +#include "arch/sparc/faults.hh" +#include "cpu/thread_context.hh" +#include "cpu/base.hh" +#include "base/trace.hh" + +namespace SparcISA +{ + +FaultName InternalProcessorError::_name = "intprocerr"; +TrapType InternalProcessorError::_trapType = 0x029; +FaultPriority InternalProcessorError::_priority = 4; +FaultStat InternalProcessorError::_count; + +FaultName MemAddressNotAligned::_name = "unalign"; +TrapType MemAddressNotAligned::_trapType = 0x034; +FaultPriority MemAddressNotAligned::_priority = 10; +FaultStat MemAddressNotAligned::_count; + +FaultName PowerOnReset::_name = "pow_reset"; +TrapType PowerOnReset::_trapType = 0x001; +FaultPriority PowerOnReset::_priority = 0; +FaultStat PowerOnReset::_count; + +FaultName WatchDogReset::_name = "watch_dog_reset"; +TrapType WatchDogReset::_trapType = 0x002; +FaultPriority WatchDogReset::_priority = 1; +FaultStat WatchDogReset::_count; + +FaultName ExternallyInitiatedReset::_name = "extern_reset"; +TrapType ExternallyInitiatedReset::_trapType = 0x003; +FaultPriority ExternallyInitiatedReset::_priority = 1; +FaultStat ExternallyInitiatedReset::_count; + +FaultName SoftwareInitiatedReset::_name = "software_reset"; +TrapType SoftwareInitiatedReset::_trapType = 0x004; +FaultPriority SoftwareInitiatedReset::_priority = 1; +FaultStat SoftwareInitiatedReset::_count; + +FaultName REDStateException::_name = "red_counte"; +TrapType REDStateException::_trapType = 0x005; +FaultPriority REDStateException::_priority = 1; +FaultStat REDStateException::_count; + +FaultName InstructionAccessException::_name = "inst_access"; +TrapType InstructionAccessException::_trapType = 0x008; +FaultPriority InstructionAccessException::_priority = 5; +FaultStat InstructionAccessException::_count; + +FaultName InstructionAccessMMUMiss::_name = "inst_mmu"; +TrapType InstructionAccessMMUMiss::_trapType = 0x009; +FaultPriority InstructionAccessMMUMiss::_priority = 2; +FaultStat InstructionAccessMMUMiss::_count; + +FaultName InstructionAccessError::_name = "inst_error"; +TrapType InstructionAccessError::_trapType = 0x00A; +FaultPriority InstructionAccessError::_priority = 3; +FaultStat InstructionAccessError::_count; + +FaultName IllegalInstruction::_name = "illegal_inst"; +TrapType IllegalInstruction::_trapType = 0x010; +FaultPriority IllegalInstruction::_priority = 7; +FaultStat IllegalInstruction::_count; + +FaultName PrivilegedOpcode::_name = "priv_opcode"; +TrapType PrivilegedOpcode::_trapType = 0x011; +FaultPriority PrivilegedOpcode::_priority = 6; +FaultStat PrivilegedOpcode::_count; + +FaultName UnimplementedLDD::_name = "unimp_ldd"; +TrapType UnimplementedLDD::_trapType = 0x012; +FaultPriority UnimplementedLDD::_priority = 6; +FaultStat UnimplementedLDD::_count; + +FaultName UnimplementedSTD::_name = "unimp_std"; +TrapType UnimplementedSTD::_trapType = 0x013; +FaultPriority UnimplementedSTD::_priority = 6; +FaultStat UnimplementedSTD::_count; + +FaultName FpDisabled::_name = "fp_disabled"; +TrapType FpDisabled::_trapType = 0x020; +FaultPriority FpDisabled::_priority = 8; +FaultStat FpDisabled::_count; + +FaultName FpExceptionIEEE754::_name = "fp_754"; +TrapType FpExceptionIEEE754::_trapType = 0x021; +FaultPriority FpExceptionIEEE754::_priority = 11; +FaultStat FpExceptionIEEE754::_count; + +FaultName FpExceptionOther::_name = "fp_other"; +TrapType FpExceptionOther::_trapType = 0x022; +FaultPriority FpExceptionOther::_priority = 11; +FaultStat FpExceptionOther::_count; + +FaultName TagOverflow::_name = "tag_overflow"; +TrapType TagOverflow::_trapType = 0x023; +FaultPriority TagOverflow::_priority = 14; +FaultStat TagOverflow::_count; + +FaultName DivisionByZero::_name = "div_by_zero"; +TrapType DivisionByZero::_trapType = 0x028; +FaultPriority DivisionByZero::_priority = 15; +FaultStat DivisionByZero::_count; + +FaultName DataAccessException::_name = "data_access"; +TrapType DataAccessException::_trapType = 0x030; +FaultPriority DataAccessException::_priority = 12; +FaultStat DataAccessException::_count; + +FaultName DataAccessMMUMiss::_name = "data_mmu"; +TrapType DataAccessMMUMiss::_trapType = 0x031; +FaultPriority DataAccessMMUMiss::_priority = 12; +FaultStat DataAccessMMUMiss::_count; + +FaultName DataAccessError::_name = "data_error"; +TrapType DataAccessError::_trapType = 0x032; +FaultPriority DataAccessError::_priority = 12; +FaultStat DataAccessError::_count; + +FaultName DataAccessProtection::_name = "data_protection"; +TrapType DataAccessProtection::_trapType = 0x033; +FaultPriority DataAccessProtection::_priority = 12; +FaultStat DataAccessProtection::_count; + +FaultName LDDFMemAddressNotAligned::_name = "unalign_lddf"; +TrapType LDDFMemAddressNotAligned::_trapType = 0x035; +FaultPriority LDDFMemAddressNotAligned::_priority = 10; +FaultStat LDDFMemAddressNotAligned::_count; + +FaultName STDFMemAddressNotAligned::_name = "unalign_stdf"; +TrapType STDFMemAddressNotAligned::_trapType = 0x036; +FaultPriority STDFMemAddressNotAligned::_priority = 10; +FaultStat STDFMemAddressNotAligned::_count; + +FaultName PrivilegedAction::_name = "priv_action"; +TrapType PrivilegedAction::_trapType = 0x037; +FaultPriority PrivilegedAction::_priority = 11; +FaultStat PrivilegedAction::_count; + +FaultName LDQFMemAddressNotAligned::_name = "unalign_ldqf"; +TrapType LDQFMemAddressNotAligned::_trapType = 0x038; +FaultPriority LDQFMemAddressNotAligned::_priority = 10; +FaultStat LDQFMemAddressNotAligned::_count; + +FaultName STQFMemAddressNotAligned::_name = "unalign_stqf"; +TrapType STQFMemAddressNotAligned::_trapType = 0x039; +FaultPriority STQFMemAddressNotAligned::_priority = 10; +FaultStat STQFMemAddressNotAligned::_count; + +FaultName AsyncDataError::_name = "async_data"; +TrapType AsyncDataError::_trapType = 0x040; +FaultPriority AsyncDataError::_priority = 2; +FaultStat AsyncDataError::_count; + +FaultName CleanWindow::_name = "clean_win"; +TrapType CleanWindow::_trapType = 0x024; +FaultPriority CleanWindow::_priority = 10; +FaultStat CleanWindow::_count; + +//The enumerated faults + +FaultName InterruptLevelN::_name = "interrupt_n"; +TrapType InterruptLevelN::_baseTrapType = 0x041; +FaultStat InterruptLevelN::_count; + +FaultName SpillNNormal::_name = "spill_n_normal"; +TrapType SpillNNormal::_baseTrapType = 0x080; +FaultPriority SpillNNormal::_priority = 9; +FaultStat SpillNNormal::_count; + +FaultName SpillNOther::_name = "spill_n_other"; +TrapType SpillNOther::_baseTrapType = 0x0A0; +FaultPriority SpillNOther::_priority = 9; +FaultStat SpillNOther::_count; + +FaultName FillNNormal::_name = "fill_n_normal"; +TrapType FillNNormal::_baseTrapType = 0x0C0; +FaultPriority FillNNormal::_priority = 9; +FaultStat FillNNormal::_count; + +FaultName FillNOther::_name = "fill_n_other"; +TrapType FillNOther::_baseTrapType = 0x0E0; +FaultPriority FillNOther::_priority = 9; +FaultStat FillNOther::_count; + +FaultName TrapInstruction::_name = "trap_inst_n"; +TrapType TrapInstruction::_baseTrapType = 0x100; +FaultPriority TrapInstruction::_priority = 16; +FaultStat TrapInstruction::_count; + +#if FULL_SYSTEM + +void SparcFault::invoke(ThreadContext * tc) +{ + FaultBase::invoke(tc); + countStat()++; + + //Use the SPARC trap state machine + /*// exception restart address + if (setRestartAddress() || !tc->inPalMode()) + tc->setMiscReg(AlphaISA::IPR_EXC_ADDR, tc->regs.pc); + + if (skipFaultingInstruction()) { + // traps... skip faulting instruction. + tc->setMiscReg(AlphaISA::IPR_EXC_ADDR, + tc->readMiscReg(AlphaISA::IPR_EXC_ADDR) + 4); + } + + if (!tc->inPalMode()) + AlphaISA::swap_palshadow(&(tc->regs), true); + + tc->regs.pc = tc->readMiscReg(AlphaISA::IPR_PAL_BASE) + vect(); + tc->regs.npc = tc->regs.pc + sizeof(MachInst);*/ +} + +#endif + +#if !FULL_SYSTEM + +void TrapInstruction::invoke(ThreadContext * tc) +{ + tc->syscall(syscall_num); +} + +#endif + +} // namespace SparcISA + diff --git a/src/arch/sparc/faults.hh b/src/arch/sparc/faults.hh new file mode 100644 index 000000000..9f595a28b --- /dev/null +++ b/src/arch/sparc/faults.hh @@ -0,0 +1,594 @@ +/* + * Copyright (c) 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: Gabe Black + * Kevin Lim + */ + +#ifndef __ALPHA_FAULTS_HH__ +#define __ALPHA_FAULTS_HH__ + +#include "sim/faults.hh" + +// The design of the "name" and "vect" functions is in sim/faults.hh + +namespace SparcISA +{ + +typedef const uint32_t TrapType; +typedef const uint32_t FaultPriority; + +class SparcFault : public FaultBase +{ + public: +#if FULL_SYSTEM + void invoke(ThreadContext * tc); +#endif + virtual TrapType trapType() = 0; + virtual FaultPriority priority() = 0; + virtual FaultStat & countStat() = 0; +}; + +class InternalProcessorError : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} + bool isMachineCheckFault() {return true;} +}; + +class MemAddressNotAligned : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} + bool isAlignmentFault() {return true;} +}; + +static inline Fault genMachineCheckFault() +{ + return new InternalProcessorError; +} + +static inline Fault genAlignmentFault() +{ + return new MemAddressNotAligned; +} + +class PowerOnReset : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class WatchDogReset : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class ExternallyInitiatedReset : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class SoftwareInitiatedReset : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class REDStateException : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class InstructionAccessException : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class InstructionAccessMMUMiss : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class InstructionAccessError : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class IllegalInstruction : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class PrivilegedOpcode : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class UnimplementedLDD : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class UnimplementedSTD : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class FpDisabled : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class FpExceptionIEEE754 : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class FpExceptionOther : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class TagOverflow : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class DivisionByZero : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class DataAccessException : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class DataAccessMMUMiss : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class DataAccessError : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class DataAccessProtection : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class LDDFMemAddressNotAligned : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class STDFMemAddressNotAligned : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class PrivilegedAction : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class LDQFMemAddressNotAligned : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class STQFMemAddressNotAligned : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class AsyncDataError : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class CleanWindow : public SparcFault +{ + private: + static FaultName _name; + static TrapType _trapType; + static FaultPriority _priority; + static FaultStat _count; + public: + FaultName name() {return _name;} + TrapType trapType() {return _trapType;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class EnumeratedFault : public SparcFault +{ + protected: + uint32_t _n; + virtual TrapType baseTrapType() = 0; + public: + EnumeratedFault(uint32_t n) : SparcFault() {_n = n;} + TrapType trapType() {return baseTrapType() + _n;} +}; + +class InterruptLevelN : public EnumeratedFault +{ + private: + static FaultName _name; + static TrapType _baseTrapType; + static FaultStat _count; + TrapType baseTrapType() {return _baseTrapType;} + public: + InterruptLevelN(uint32_t n) : EnumeratedFault(n) {;} + FaultName name() {return _name;} + FaultPriority priority() {return 32 - _n;} + FaultStat & countStat() {return _count;} +}; + +class SpillNNormal : public EnumeratedFault +{ + private: + static FaultName _name; + static TrapType _baseTrapType; + static FaultPriority _priority; + static FaultStat _count; + TrapType baseTrapType() {return _baseTrapType;} + public: + SpillNNormal(uint32_t n) : EnumeratedFault(n) {;} + FaultName name() {return _name;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class SpillNOther : public EnumeratedFault +{ + private: + static FaultName _name; + static TrapType _baseTrapType; + static FaultPriority _priority; + static FaultStat _count; + TrapType baseTrapType() {return _baseTrapType;} + public: + SpillNOther(uint32_t n) : EnumeratedFault(n) {;} + FaultName name() {return _name;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class FillNNormal : public EnumeratedFault +{ + private: + static FaultName _name; + static TrapType _baseTrapType; + static FaultPriority _priority; + static FaultStat _count; + TrapType baseTrapType() {return _baseTrapType;} + public: + FillNNormal(uint32_t n) : EnumeratedFault(n) {;} + FaultName name() {return _name;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class FillNOther : public EnumeratedFault +{ + private: + static FaultName _name; + static TrapType _baseTrapType; + static FaultPriority _priority; + static FaultStat _count; + TrapType baseTrapType() {return _baseTrapType;} + public: + FillNOther(uint32_t n) : EnumeratedFault(n) {;} + FaultName name() {return _name;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +}; + +class TrapInstruction : public EnumeratedFault +{ + private: + static FaultName _name; + static TrapType _baseTrapType; + static FaultPriority _priority; + static FaultStat _count; + uint64_t syscall_num; + TrapType baseTrapType() {return _baseTrapType;} + public: + TrapInstruction(uint32_t n, uint64_t syscall) : + EnumeratedFault(n), syscall_num(syscall) {;} + FaultName name() {return _name;} + FaultPriority priority() {return _priority;} + FaultStat & countStat() {return _count;} +#if !FULL_SYSTEM + void invoke(ThreadContext * tc); +#endif +}; + +} // SparcISA namespace + +#endif // __FAULTS_HH__ diff --git a/src/arch/sparc/isa/base.isa b/src/arch/sparc/isa/base.isa new file mode 100644 index 000000000..02f7cf61a --- /dev/null +++ b/src/arch/sparc/isa/base.isa @@ -0,0 +1,252 @@ +// 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 +// Gabe Black +// Steve Reinhardt + +//////////////////////////////////////////////////////////////////// +// +// Base class for sparc instructions, and some support functions +// + +output header {{ + + union CondCodes + { + struct + { + uint8_t c:1; + uint8_t v:1; + uint8_t z:1; + uint8_t n:1; + }; + uint32_t bits; + }; + + enum CondTest + { + Always=0x8, + Never=0x0, + NotEqual=0x9, + Equal=0x1, + Greater=0xA, + LessOrEqual=0x2, + GreaterOrEqual=0xB, + Less=0x3, + GreaterUnsigned=0xC, + LessOrEqualUnsigned=0x4, + CarryClear=0xD, + CarrySet=0x5, + Positive=0xE, + Negative=0x6, + OverflowClear=0xF, + OverflowSet=0x7 + }; + + extern char * CondTestAbbrev[]; + + /** + * Base class for all SPARC static instructions. + */ + class SparcStaticInst : public StaticInst + { + protected: + // Constructor. + SparcStaticInst(const char *mnem, + MachInst _machInst, OpClass __opClass) + : StaticInst(mnem, _machInst, __opClass) + { + } + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + + void printReg(std::ostream &os, int reg) const; + }; + + bool passesCondition(uint32_t codes, uint32_t condition); + + inline int64_t sign_ext(uint64_t data, int origWidth) + { + int shiftAmount = 64 - origWidth; + return (((int64_t)data) << shiftAmount) >> shiftAmount; + } +}}; + +output decoder {{ + + char * CondTestAbbrev[] = + { + "nev", //Never + "e", //Equal + "le", //Less or Equal + "l", //Less + "leu", //Less or Equal Unsigned + "c", //Carry set + "n", //Negative + "o", //Overflow set + "a", //Always + "ne", //Not Equal + "g", //Greater + "ge", //Greater or Equal + "gu", //Greater Unsigned + "cc", //Carry clear + "p", //Positive + "oc" //Overflow Clear + }; +}}; + +def template ROrImmDecode {{ + { + return (I ? (SparcStaticInst *)(new %(class_name)sImm(machInst)) + : (SparcStaticInst *)(new %(class_name)s(machInst))); + } +}}; + +let {{ + def splitOutImm(code): + matcher = re.compile(r'Rs(?P<rNum>\d)_or_imm(?P<iNum>\d+)(?P<typeQual>\.\w+)?') + rOrImmMatch = matcher.search(code) + if (rOrImmMatch == None): + return (False, code, '', '', '') + rString = rOrImmMatch.group("rNum") + if (rOrImmMatch.group("typeQual") != None): + rString += rOrImmMatch.group("typeQual") + iString = rOrImmMatch.group("iNum") + orig_code = code + code = matcher.sub('Rs' + rString, orig_code) + imm_code = matcher.sub('imm', orig_code) + return (True, code, imm_code, rString, iString) +}}; + +output decoder {{ + + inline void printMnemonic(std::ostream &os, const char * mnemonic) + { + ccprintf(os, "\t%s ", mnemonic); + } + + void + SparcStaticInst::printReg(std::ostream &os, int reg) const + { + const int MaxGlobal = 8; + const int MaxOutput = 16; + const int MaxLocal = 24; + const int MaxInput = 32; + if (reg == FramePointerReg) + ccprintf(os, "%%fp"); + else if (reg == StackPointerReg) + ccprintf(os, "%%sp"); + else if(reg < MaxGlobal) + ccprintf(os, "%%g%d", reg); + else if(reg < MaxOutput) + ccprintf(os, "%%o%d", reg - MaxGlobal); + else if(reg < MaxLocal) + ccprintf(os, "%%l%d", reg - MaxOutput); + else if(reg < MaxInput) + ccprintf(os, "%%i%d", reg - MaxLocal); + else { + ccprintf(os, "%%f%d", reg - FP_Base_DepTag); + } + } + + std::string SparcStaticInst::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream ss; + + printMnemonic(ss, mnemonic); + + // just print the first two source regs... if there's + // a third one, it's a read-modify-write dest (Rc), + // e.g. for CMOVxx + if(_numSrcRegs > 0) + { + printReg(ss, _srcRegIdx[0]); + } + if(_numSrcRegs > 1) + { + ss << ","; + printReg(ss, _srcRegIdx[1]); + } + + // just print the first dest... if there's a second one, + // it's generally implicit + if(_numDestRegs > 0) + { + if(_numSrcRegs > 0) + ss << ","; + printReg(ss, _destRegIdx[0]); + } + + return ss.str(); + } + + bool passesCondition(uint32_t codes, uint32_t condition) + { + CondCodes condCodes; + condCodes.bits = codes; + switch(condition) + { + case Always: + return true; + case Never: + return false; + case NotEqual: + return !condCodes.z; + case Equal: + return condCodes.z; + case Greater: + return !(condCodes.z | (condCodes.n ^ condCodes.v)); + case LessOrEqual: + return condCodes.z | (condCodes.n ^ condCodes.v); + case GreaterOrEqual: + return !(condCodes.n ^ condCodes.v); + case Less: + return (condCodes.n ^ condCodes.v); + case GreaterUnsigned: + return !(condCodes.c | condCodes.z); + case LessOrEqualUnsigned: + return (condCodes.c | condCodes.z); + case CarryClear: + return !condCodes.c; + case CarrySet: + return condCodes.c; + case Positive: + return !condCodes.n; + case Negative: + return condCodes.n; + case OverflowClear: + return !condCodes.v; + case OverflowSet: + return condCodes.v; + } + panic("Tried testing condition nonexistant " + "condition code %d", condition); + } +}}; + diff --git a/src/arch/sparc/isa/bitfields.isa b/src/arch/sparc/isa/bitfields.isa new file mode 100644 index 000000000..27f52fa29 --- /dev/null +++ b/src/arch/sparc/isa/bitfields.isa @@ -0,0 +1,78 @@ +// 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 +// Gabe Black +// Steve Reinhardt + +//////////////////////////////////////////////////////////////////// +// +// Bitfield definitions. +// + +// Bitfields are shared liberally between instruction formats, so they are +// simply defined alphabetically + +def bitfield A <29>; +def bitfield BPCC <21:20>; // for BPcc & FBPcc +def bitfield FCMPCC <26:56>; // for FCMP & FCMPEa +def bitfield FMOVCC <13:11>; // for FMOVcc +def bitfield CC <12:11>; // for MOVcc & Tcc +def bitfield MOVCC3 <18>; // also for MOVcc +def bitfield CMASK <6:4>; +def bitfield COND2 <28:25>; +def bitfield COND4 <17:14>; +def bitfield D16HI <21:20>; +def bitfield D16LO <13:0>; +def bitfield DISP19 <18:0>; +def bitfield DISP22 <21:0>; +def bitfield DISP30 <29:0>; +def bitfield FCN <29:26>; +def bitfield I <13>; +def bitfield IMM_ASI <12:5>; +def bitfield IMM22 <21:0>; +def bitfield MMASK <3:0>; +def bitfield OP <31:30>; +def bitfield OP2 <24:22>; +def bitfield OP3 <24:19>; +def bitfield OPF <13:5>; +def bitfield OPF_CC <13:11>; +def bitfield OPF_LOW5 <9:5>; +def bitfield OPF_LOW6 <10:5>; +def bitfield P <19>; +def bitfield RCOND2 <27:25>; +def bitfield RCOND3 <12:10>; +def bitfield RCOND4 <12:10>; +def bitfield RD <29:25>; +def bitfield RS1 <18:14>; +def bitfield RS2 <4:0>; +def bitfield SHCNT32 <4:0>; +def bitfield SHCNT64 <5:0>; +def bitfield SIMM10 <9:0>; +def bitfield SIMM11 <10:0>; +def bitfield SIMM13 <12:0>; +def bitfield SW_TRAP <7:0>; +def bitfield X <12>; diff --git a/src/arch/sparc/isa/decoder.isa b/src/arch/sparc/isa/decoder.isa new file mode 100644 index 000000000..fa8832920 --- /dev/null +++ b/src/arch/sparc/isa/decoder.isa @@ -0,0 +1,669 @@ +// 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 +// Gabe Black +// Steve Reinhardt + +//////////////////////////////////////////////////////////////////// +// +// The actual decoder specification +// + +decode OP default Unknown::unknown() +{ + 0x0: decode OP2 + { + //Throw an illegal instruction acception + 0x0: Trap::illtrap({{fault = new IllegalInstruction;}}); + 0x1: decode BPCC + { + format Branch19 + { + 0x0: bpcci({{ + if(passesCondition(Ccr<3:0>, COND2)) + NNPC = xc->readPC() + disp; + else + handle_annul + }}); + 0x2: bpccx({{ + if(passesCondition(Ccr<7:4>, COND2)) + NNPC = xc->readPC() + disp; + else + handle_annul + }}); + } + } + 0x2: Branch22::bicc({{ + if(passesCondition(Ccr<3:0>, COND2)) + NNPC = xc->readPC() + disp; + else + handle_annul + }}); + 0x3: decode RCOND2 + { + format BranchSplit + { + 0x1: bpreq({{ + if(Rs1.sdw == 0) + NNPC = xc->readPC() + disp; + else + handle_annul + }}); + 0x2: bprle({{ + if(Rs1.sdw <= 0) + NNPC = xc->readPC() + disp; + else + handle_annul + }}); + 0x3: bprl({{ + if(Rs1.sdw < 0) + NNPC = xc->readPC() + disp; + else + handle_annul + }}); + 0x5: bprne({{ + if(Rs1.sdw != 0) + NNPC = xc->readPC() + disp; + else + handle_annul + }}); + 0x6: bprg({{ + if(Rs1.sdw > 0) + NNPC = xc->readPC() + disp; + else + handle_annul + }}); + 0x7: bprge({{ + if(Rs1.sdw >= 0) + NNPC = xc->readPC() + disp; + else + handle_annul + }}); + } + } + //SETHI (or NOP if rd == 0 and imm == 0) + 0x4: SetHi::sethi({{Rd = imm;}}); + 0x5: Trap::fbpfcc({{fault = new FpDisabled;}}); + 0x6: Trap::fbfcc({{fault = new FpDisabled;}}); + } + 0x1: Branch30::call({{ + R15 = xc->readPC(); + NNPC = R15 + disp; + }}); + 0x2: decode OP3 { + format IntOp { + 0x00: add({{Rd = Rs1.sdw + Rs2_or_imm13;}}); + 0x01: and({{Rd = Rs1.udw & Rs2_or_imm13;}}); + 0x02: or({{Rd = Rs1.udw | Rs2_or_imm13;}}); + 0x03: xor({{Rd = Rs1.udw ^ Rs2_or_imm13;}}); + 0x04: sub({{Rd = Rs1.sdw - Rs2_or_imm13;}}); + 0x05: andn({{Rd = Rs1.udw & ~Rs2_or_imm13;}}); + 0x06: orn({{Rd = Rs1.udw | ~Rs2_or_imm13;}}); + 0x07: xnor({{Rd = ~(Rs1.udw ^ Rs2_or_imm13);}}); + 0x08: addc({{Rd = Rs1.sdw + Rs2_or_imm13 + Ccr<0:0>;}}); + 0x09: mulx({{Rd = Rs1 * Rs2_or_imm13;}}); + 0x0A: umul({{ + Rd = Rs1.udw<31:0> * Rs2_or_imm13<31:0>; + Y = Rd<63:32>; + }}); + 0x0B: smul({{ + Rd.sdw = Rs1.sdw<31:0> * Rs2_or_imm13<31:0>; + Y = Rd.sdw; + }}); + 0x0C: subc({{Rd.sdw = Rs1.sdw + (~Rs2_or_imm13) + 1 + Ccr<0:0>}}); + 0x0D: udivx({{ + if(Rs2_or_imm13 == 0) fault = new DivisionByZero; + else Rd.udw = Rs1.udw / Rs2_or_imm13; + }}); + 0x0E: udiv({{ + if(Rs2_or_imm13 == 0) fault = new DivisionByZero; + else + { + Rd.udw = ((Y << 32) | Rs1.udw<31:0>) / Rs2_or_imm13; + if(Rd.udw >> 32 != 0) + Rd.udw = 0xFFFFFFFF; + } + }}); + 0x0F: sdiv({{ + if(Rs2_or_imm13.sdw == 0) + fault = new DivisionByZero; + else + { + Rd.udw = ((int64_t)((Y << 32) | Rs1.sdw<31:0>)) / Rs2_or_imm13.sdw; + if(Rd.udw<63:31> != 0) + Rd.udw = 0x7FFFFFFF; + else if(Rd.udw<63:> && Rd.udw<62:31> != 0xFFFFFFFF) + Rd.udw = 0xFFFFFFFF80000000ULL; + } + }}); + } + format IntOpCc { + 0x10: addcc({{ + int64_t resTemp, val2 = Rs2_or_imm13; + Rd = resTemp = Rs1 + val2;}}, + {{(Rs1<31:0> + val2<31:0>)<32:>}}, + {{Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>}}, + {{(Rs1<63:1> + val2<63:1> + (Rs1 & val2)<0:>)<63:>}}, + {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}} + ); + 0x11: IntOpCcRes::andcc({{Rd = Rs1 & Rs2_or_imm13;}}); + 0x12: IntOpCcRes::orcc({{Rd = Rs1 | Rs2_or_imm13;}}); + 0x13: IntOpCcRes::xorcc({{Rd = Rs1 ^ Rs2_or_imm13;}}); + 0x14: subcc({{ + int64_t val2 = Rs2_or_imm13; + Rd = Rs1 - val2;}}, + {{(~(Rs1<31:0> + (~val2)<31:0> + 1))<32:>}}, + {{(Rs1<31:> != val2<31:>) && (Rs1<31:> != Rd<31:>)}}, + {{(~(Rs1<63:1> + (~val2)<63:1> + + (Rs1 | ~val2)<0:>))<63:>}}, + {{Rs1<63:> != val2<63:> && Rs1<63:> != Rd<63:>}} + ); + 0x15: IntOpCcRes::andncc({{Rd = Rs1 & ~Rs2_or_imm13;}}); + 0x16: IntOpCcRes::orncc({{Rd = Rs1 | ~Rs2_or_imm13;}}); + 0x17: IntOpCcRes::xnorcc({{Rd = ~(Rs1 ^ Rs2_or_imm13);}}); + 0x18: addccc({{ + int64_t resTemp, val2 = Rs2_or_imm13; + int64_t carryin = Ccr<0:0>; + Rd = resTemp = Rs1 + val2 + carryin;}}, + {{(Rs1<31:0> + val2<31:0> + carryin)<32:>}}, + {{Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>}}, + {{(Rs1<63:1> + val2<63:1> + + ((Rs1 & val2) | (carryin & (Rs1 | val2)))<0:>)<63:>}}, + {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}} + ); + 0x1A: umulcc({{ + uint64_t resTemp; + Rd = resTemp = Rs1.udw<31:0> * Rs2_or_imm13.udw<31:0>; + Y = resTemp<63:32>;}}, + {{0}},{{0}},{{0}},{{0}}); + 0x1B: smulcc({{ + int64_t resTemp; + Rd = resTemp = Rs1.sdw<31:0> * Rs2_or_imm13.sdw<31:0>; + Y = resTemp<63:32>;}}, + {{0}},{{0}},{{0}},{{0}}); + 0x1C: subccc({{ + int64_t resTemp, val2 = Rs2_or_imm13; + int64_t carryin = Ccr<0:0>; + Rd = resTemp = Rs1 + ~(val2 + carryin) + 1;}}, + {{(~((Rs1<31:0> + (~(val2 + carryin))<31:0> + 1))<32:>)}}, + {{Rs1<31:> != val2<31:> && Rs1<31:> != resTemp<31:>}}, + {{(~((Rs1<63:1> + (~(val2 + carryin))<63:1>) + (Rs1<0:> + (~(val2+carryin))<0:> + 1)<63:1>))<63:>}}, + {{Rs1<63:> != val2<63:> && Rs1<63:> != resTemp<63:>}} + ); + 0x1D: udivxcc({{ + if(Rs2_or_imm13.udw == 0) fault = new DivisionByZero; + else Rd = Rs1.udw / Rs2_or_imm13.udw;}} + ,{{0}},{{0}},{{0}},{{0}}); + 0x1E: udivcc({{ + uint32_t resTemp, val2 = Rs2_or_imm13.udw; + int32_t overflow; + if(val2 == 0) fault = new DivisionByZero; + else + { + resTemp = (uint64_t)((Y << 32) | Rs1.udw<31:0>) / val2; + overflow = (resTemp<63:32> != 0); + if(overflow) Rd = resTemp = 0xFFFFFFFF; + else Rd = resTemp; + } }}, + {{0}}, + {{overflow}}, + {{0}}, + {{0}} + ); + 0x1F: sdivcc({{ + int32_t resTemp, val2 = Rs2_or_imm13.sdw; + int32_t overflow, underflow; + if(val2 == 0) fault = new DivisionByZero; + else + { + Rd = resTemp = (int64_t)((Y << 32) | Rs1.sdw<31:0>) / val2; + overflow = (resTemp<63:31> != 0); + underflow = (resTemp<63:> && resTemp<62:31> != 0xFFFFFFFF); + if(overflow) Rd = resTemp = 0x7FFFFFFF; + else if(underflow) Rd = resTemp = 0xFFFFFFFF80000000ULL; + else Rd = resTemp; + } }}, + {{0}}, + {{overflow || underflow}}, + {{0}}, + {{0}} + ); + 0x20: taddcc({{ + int64_t resTemp, val2 = Rs2_or_imm13; + Rd = resTemp = Rs1 + val2; + int32_t overflow = Rs1<1:0> || val2<1:0> || (Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>);}}, + {{((Rs1 & 0xFFFFFFFF + val2 & 0xFFFFFFFF) >> 31)}}, + {{overflow}}, + {{((Rs1 >> 1) + (val2 >> 1) + (Rs1 & val2 & 0x1))<63:>}}, + {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}} + ); + 0x21: tsubcc({{ + int64_t resTemp, val2 = Rs2_or_imm13; + Rd = resTemp = Rs1 + val2; + int32_t overflow = Rs1<1:0> || val2<1:0> || (Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>);}}, + {{(Rs1 & 0xFFFFFFFF + val2 & 0xFFFFFFFF) >> 31}}, + {{overflow}}, + {{((Rs1 >> 1) + (val2 >> 1) + (Rs1 & val2 & 0x1))<63:>}}, + {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}} + ); + 0x22: taddcctv({{ + int64_t resTemp, val2 = Rs2_or_imm13; + Rd = resTemp = Rs1 + val2; + int32_t overflow = Rs1<1:0> || val2<1:0> || (Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>); + if(overflow) fault = new TagOverflow;}}, + {{((Rs1 & 0xFFFFFFFF + val2 & 0xFFFFFFFF) >> 31)}}, + {{overflow}}, + {{((Rs1 >> 1) + (val2 >> 1) + (Rs1 & val2 & 0x1))<63:>}}, + {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}} + ); + 0x23: tsubcctv({{ + int64_t resTemp, val2 = Rs2_or_imm13; + Rd = resTemp = Rs1 + val2; + int32_t overflow = Rs1<1:0> || val2<1:0> || (Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>); + if(overflow) fault = new TagOverflow;}}, + {{((Rs1 & 0xFFFFFFFF + val2 & 0xFFFFFFFF) >> 31)}}, + {{overflow}}, + {{((Rs1 >> 1) + (val2 >> 1) + (Rs1 & val2 & 0x1))<63:>}}, + {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}} + ); + 0x24: mulscc({{ + int64_t resTemp, multiplicand = Rs2_or_imm13; + int32_t multiplier = Rs1<31:0>; + int32_t savedLSB = Rs1<0:>; + multiplier = multiplier<31:1> | + ((Ccr<3:3> + ^ Ccr<1:1>) << 32); + if(!Y<0:>) + multiplicand = 0; + Rd = resTemp = multiplicand + multiplier; + Y = Y<31:1> | (savedLSB << 31);}}, + {{((multiplicand & 0xFFFFFFFF + multiplier & 0xFFFFFFFF) >> 31)}}, + {{multiplicand<31:> == multiplier<31:> && multiplier<31:> != resTemp<31:>}}, + {{((multiplicand >> 1) + (multiplier >> 1) + (multiplicand & multiplier & 0x1))<63:>}}, + {{multiplicand<63:> == multiplier<63:> && multiplier<63:> != resTemp<63:>}} + ); + } + format IntOp + { + 0x25: decode X { + 0x0: sll({{Rd = Rs1 << (I ? SHCNT32 : Rs2<4:0>);}}); + 0x1: sllx({{Rd = Rs1 << (I ? SHCNT64 : Rs2<5:0>);}}); + } + 0x26: decode X { + 0x0: srl({{Rd = Rs1.uw >> (I ? SHCNT32 : Rs2<4:0>);}}); + 0x1: srlx({{Rd = Rs1.udw >> (I ? SHCNT64 : Rs2<5:0>);}}); + } + 0x27: decode X { + 0x0: sra({{Rd = Rs1.sw >> (I ? SHCNT32 : Rs2<4:0>);}}); + 0x1: srax({{Rd = Rs1.sdw >> (I ? SHCNT64 : Rs2<5:0>);}}); + } + // XXX might want a format rdipr thing here + 0x28: rdasr({{ + Rd = xc->readMiscRegWithEffect(RS1 + AsrStart, fault); + }}); + 0x29: rdhpr({{ + // XXX Need to protect with format that traps non-priv/priv + // access + Rd = xc->readMiscRegWithEffect(RS1 + HprStart, fault); + }}); + 0x2A: rdpr({{ + // XXX Need to protect with format that traps non-priv + // access + Rd = xc->readMiscRegWithEffect(RS1 + PrStart, fault); + }}); + 0x2B: BasicOperate::flushw({{ + if(NWindows - 2 - Cansave == 0) + { + if(Otherwin) + fault = new SpillNOther(Wstate<5:3>); + else + fault = new SpillNNormal(Wstate<2:0>); + } + }}); + 0x2C: decode MOVCC3 + { + 0x0: Trap::movccfcc({{fault = new FpDisabled;}}); + 0x1: decode CC + { + 0x0: movcci({{ + if(passesCondition(Ccr<3:0>, COND4)) + Rd = Rs2_or_imm11; + else + Rd = Rd; + }}); + 0x2: movccx({{ + if(passesCondition(Ccr<7:4>, COND4)) + Rd = Rs2_or_imm11; + else + Rd = Rd; + }}); + } + } + 0x2D: sdivx({{ + if(Rs2_or_imm13.sdw == 0) fault = new DivisionByZero; + else Rd.sdw = Rs1.sdw / Rs2_or_imm13.sdw; + }}); + 0x2E: decode RS1 { + 0x0: IntOp::popc({{ + int64_t count = 0; + uint64_t temp = Rs2_or_imm13; + //Count the 1s in the front 4bits until none are left + uint8_t oneBits[] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4}; + while(temp) + { + count += oneBits[temp & 0xF]; + temp = temp >> 4; + } + Rd = count; + }}); + } + 0x2F: decode RCOND3 + { + 0x1: movreq({{Rd = (Rs1.sdw == 0) ? Rs2_or_imm10 : Rd;}}); + 0x2: movrle({{Rd = (Rs1.sdw <= 0) ? Rs2_or_imm10 : Rd;}}); + 0x3: movrl({{Rd = (Rs1.sdw < 0) ? Rs2_or_imm10 : Rd;}}); + 0x5: movrne({{Rd = (Rs1.sdw != 0) ? Rs2_or_imm10 : Rd;}}); + 0x6: movrg({{Rd = (Rs1.sdw > 0) ? Rs2_or_imm10 : Rd;}}); + 0x7: movrge({{Rd = (Rs1.sdw >= 0) ? Rs2_or_imm10 : Rd;}}); + } + 0x30: wrasr({{ + xc->setMiscRegWithEffect(RD + AsrStart, Rs1 ^ Rs2_or_imm13); + }}); + 0x31: decode FCN { + 0x0: BasicOperate::saved({{/*Boogy Boogy*/}}); + 0x1: BasicOperate::restored({{/*Boogy Boogy*/}}); + } + 0x32: wrpr({{ + // XXX Need to protect with format that traps non-priv + // access + xc->setMiscRegWithEffect(RD + PrStart, Rs1 ^ Rs2_or_imm13); + }}); + 0x33: wrhpr({{ + // XXX Need to protect with format that traps non-priv/priv + // access + xc->setMiscRegWithEffect(RD + HprStart, Rs1 ^ Rs2_or_imm13); + }}); + 0x34: Trap::fpop1({{fault = new FpDisabled;}}); + 0x35: Trap::fpop2({{fault = new FpDisabled;}}); + 0x38: Branch::jmpl({{ + Addr target = Rs1 + Rs2_or_imm13; + if(target & 0x3) + fault = new MemAddressNotAligned; + else + { + Rd = xc->readPC(); + NNPC = target; + } + }}); + 0x39: Branch::return({{ + //If both MemAddressNotAligned and + //a fill trap happen, it's not clear + //which one should be returned. + Addr target = Rs1 + Rs2_or_imm13; + if(target & 0x3) + fault = new MemAddressNotAligned; + else + NNPC = target; + if(fault == NoFault) + { + //CWP should be set directly so that it always happens + //Also, this will allow writing to the new window and + //reading from the old one + Cwp = (Cwp - 1 + NWindows) % NWindows; + if(Canrestore == 0) + { + if(Otherwin) + fault = new FillNOther(Wstate<5:3>); + else + fault = new FillNNormal(Wstate<2:0>); + } + else + { + Rd = Rs1 + Rs2_or_imm13; + Cansave = Cansave + 1; + Canrestore = Canrestore - 1; + } + //This is here to make sure the CWP is written + //no matter what. This ensures that the results + //are written in the new window as well. + xc->setMiscRegWithEffect(MISCREG_CWP, Cwp); + } + }}); + 0x3A: decode CC + { + 0x0: Trap::tcci({{ + if(passesCondition(Ccr<3:0>, COND2)) + { + int lTrapNum = I ? (Rs1 + SW_TRAP) : (Rs1 + Rs2); + DPRINTF(Sparc, "The trap number is %d\n", lTrapNum); +#if FULL_SYSTEM + fault = new TrapInstruction(lTrapNum); +#else + DPRINTF(Sparc, "The syscall number is %d\n", R1); + xc->syscall(R1); +#endif + } + }}); + 0x2: Trap::tccx({{ + if(passesCondition(Ccr<7:4>, COND2)) + { + int lTrapNum = I ? (Rs1 + SW_TRAP) : (Rs1 + Rs2); + DPRINTF(Sparc, "The trap number is %d\n", lTrapNum); +#if FULL_SYSTEM + fault = new TrapInstruction(lTrapNum); +#else + DPRINTF(Sparc, "The syscall number is %d\n", R1); + xc->syscall(R1); +#endif + } + }}); + } + 0x3B: Nop::flush({{/*Instruction memory flush*/}}); + 0x3C: save({{ + //CWP should be set directly so that it always happens + //Also, this will allow writing to the new window and + //reading from the old one + if(Cansave == 0) + { + if(Otherwin) + fault = new SpillNOther(Wstate<5:3>); + else + fault = new SpillNNormal(Wstate<2:0>); + Cwp = (Cwp + 2) % NWindows; + } + else if(Cleanwin - Canrestore == 0) + { + Cwp = (Cwp + 1) % NWindows; + fault = new CleanWindow; + } + else + { + Cwp = (Cwp + 1) % NWindows; + Rd = Rs1 + Rs2_or_imm13; + Cansave = Cansave - 1; + Canrestore = Canrestore + 1; + } + //This is here to make sure the CWP is written + //no matter what. This ensures that the results + //are written in the new window as well. + xc->setMiscRegWithEffect(MISCREG_CWP, Cwp); + }}); + 0x3D: restore({{ + //CWP should be set directly so that it always happens + //Also, this will allow writing to the new window and + //reading from the old one + Cwp = (Cwp - 1 + NWindows) % NWindows; + if(Canrestore == 0) + { + if(Otherwin) + fault = new FillNOther(Wstate<5:3>); + else + fault = new FillNNormal(Wstate<2:0>); + } + else + { + Rd = Rs1 + Rs2_or_imm13; + Cansave = Cansave + 1; + Canrestore = Canrestore - 1; + } + //This is here to make sure the CWP is written + //no matter what. This ensures that the results + //are written in the new window as well. + xc->setMiscRegWithEffect(MISCREG_CWP, Cwp); + }}); + 0x3E: decode FCN { + 0x0: Priv::done({{ + if(Tl == 0) + return new IllegalInstruction; + + Cwp = Tstate<4:0>; + Pstate = Tstate<20:8>; + Asi = Tstate<31:24>; + Ccr = Tstate<39:32>; + Gl = Tstate<42:40>; + NPC = Tnpc; + NNPC = Tnpc + 4; + Tl = Tl - 1; + }}); + 0x1: BasicOperate::retry({{ + if(Tl == 0) + return new IllegalInstruction; + Cwp = Tstate<4:0>; + Pstate = Tstate<20:8>; + Asi = Tstate<31:24>; + Ccr = Tstate<39:32>; + Gl = Tstate<42:40>; + NPC = Tpc; + NNPC = Tnpc + 4; + Tl = Tl - 1; + }}); + } + } + } + 0x3: decode OP3 { + format Load { + 0x00: lduw({{Rd = Mem;}}, {{32}}); + 0x01: ldub({{Rd = Mem;}}, {{8}}); + 0x02: lduh({{Rd = Mem;}}, {{16}}); + 0x03: ldd({{ + uint64_t val = Mem; + RdLow = val<31:0>; + RdHigh = val<63:32>; + }}, {{64}}); + } + format Store { + 0x04: stw({{Mem = Rd.sw;}}, {{32}}); + 0x05: stb({{Mem = Rd.sb;}}, {{8}}); + 0x06: sth({{Mem = Rd.shw;}}, {{16}}); + 0x07: std({{Mem = RdLow<31:0> | RdHigh<31:0> << 32;}}, {{64}}); + } + format Load { + 0x08: ldsw({{Rd = (int32_t)Mem;}}, {{32}}); + 0x09: ldsb({{Rd = (int8_t)Mem;}}, {{8}}); + 0x0A: ldsh({{Rd = (int16_t)Mem;}}, {{16}}); + 0x0B: ldx({{Rd = (int64_t)Mem;}}, {{64}}); + 0x0D: ldstub({{ + Rd = Mem; + Mem = 0xFF; + }}, {{8}}); + } + 0x0E: Store::stx({{Mem = Rd}}, {{64}}); + 0x0F: LoadStore::swap({{ + uint32_t temp = Rd; + Rd = Mem; + Mem = temp; + }}, {{32}}); + format Load { + 0x10: lduwa({{Rd = Mem;}}, {{32}}); + 0x11: lduba({{Rd = Mem;}}, {{8}}); + 0x12: lduha({{Rd = Mem;}}, {{16}}); + 0x13: ldda({{ + uint64_t val = Mem; + RdLow = val<31:0>; + RdHigh = val<63:32>; + }}, {{64}}); + } + format Store { + 0x14: stwa({{Mem = Rd;}}, {{32}}); + 0x15: stba({{Mem = Rd;}}, {{8}}); + 0x16: stha({{Mem = Rd;}}, {{16}}); + 0x17: stda({{Mem = RdLow<31:0> | RdHigh<31:0> << 32;}}, {{64}}); + } + format Load { + 0x18: ldswa({{Rd = (int32_t)Mem;}}, {{32}}); + 0x19: ldsba({{Rd = (int8_t)Mem;}}, {{8}}); + 0x1A: ldsha({{Rd = (int16_t)Mem;}}, {{16}}); + 0x1B: ldxa({{Rd = (int64_t)Mem;}}, {{64}}); + } + 0x1D: LoadStore::ldstuba({{ + Rd = Mem; + Mem = 0xFF; + }}, {{8}}); + 0x1E: Store::stxa({{Mem = Rd}}, {{64}}); + 0x1F: LoadStore::swapa({{ + uint32_t temp = Rd; + Rd = Mem; + Mem = temp; + }}, {{32}}); + format Trap { + 0x20: ldf({{fault = new FpDisabled;}}); + 0x21: decode X { + 0x0: Load::ldfsr({{Fsr = Mem<31:0> | Fsr<63:32>;}}, {{32}}); + 0x1: Load::ldxfsr({{Fsr = Mem;}}, {{64}}); + } + 0x22: ldqf({{fault = new FpDisabled;}}); + 0x23: lddf({{fault = new FpDisabled;}}); + 0x24: stf({{fault = new FpDisabled;}}); + 0x25: decode X { + 0x0: Store::stfsr({{Mem = Fsr<31:0>;}}, {{32}}); + 0x1: Store::stxfsr({{Mem = Fsr;}}, {{64}}); + } + 0x26: stqf({{fault = new FpDisabled;}}); + 0x27: stdf({{fault = new FpDisabled;}}); + 0x2D: Nop::prefetch({{ }}); + 0x30: ldfa({{return new FpDisabled;}}); + 0x32: ldqfa({{fault = new FpDisabled;}}); + 0x33: lddfa({{fault = new FpDisabled;}}); + 0x34: stfa({{fault = new FpDisabled;}}); + 0x35: stqfa({{fault = new FpDisabled;}}); + 0x36: stdfa({{fault = new FpDisabled;}}); + 0x3C: Cas::casa({{ + uint64_t val = Mem.uw; + if(Rs2.uw == val) + Mem.uw = Rd.uw; + Rd.uw = val; + }}); + 0x3D: Nop::prefetcha({{ }}); + 0x3E: Cas::casxa({{ + uint64_t val = Mem.udw; + if(Rs2 == val) + Mem.udw = Rd; + Rd = val; + }}); + } + } +} diff --git a/src/arch/sparc/isa/formats.isa b/src/arch/sparc/isa/formats.isa new file mode 100644 index 000000000..17d68061b --- /dev/null +++ b/src/arch/sparc/isa/formats.isa @@ -0,0 +1,28 @@ +//Include the basic format +//Templates from this format are used later +##include "formats/basic.isa" + +//Include the noop format +##include "formats/nop.isa" + +//Include the integerOp and integerOpCc format +##include "formats/integerop.isa" + +//Include the memory format +##include "formats/mem.isa" + +//Include the compare and swap format +##include "formats/cas.isa" + +//Include the trap format +##include "formats/trap.isa" + +//Include the "unknown" format +##include "formats/unknown.isa" + +//Include the priveleged mode format +##include "formats/priv.isa" + +//Include the branch format +##include "formats/branch.isa" + diff --git a/src/arch/sparc/isa/formats/basic.isa b/src/arch/sparc/isa/formats/basic.isa new file mode 100644 index 000000000..60432cb6b --- /dev/null +++ b/src/arch/sparc/isa/formats/basic.isa @@ -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: Ali Saidi +// Gabe Black +// Steve Reinhardt + +// Declarations for execute() methods. +def template BasicExecDeclare {{ + Fault execute(%(CPU_exec_context)s *, Trace::InstRecord *) const; +}}; + +// Basic instruction class declaration template. +def template BasicDeclare {{ + /** + * Static instruction class for "%(mnemonic)s". + */ + class %(class_name)s : public %(base_class)s + { + public: + // Constructor. + %(class_name)s(MachInst machInst); + %(BasicExecDeclare)s + }; +}}; + +// Basic instruction class constructor template. +def template BasicConstructor {{ + inline %(class_name)s::%(class_name)s(MachInst machInst) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s) + { + %(constructor)s; + } +}}; + +// Basic instruction class execute method template. +def template BasicExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Fault fault = NoFault; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + %(code)s; + + if(fault == NoFault) + { + %(op_wb)s; + } + return fault; + } +}}; + +// Basic decode template. +def template BasicDecode {{ + return new %(class_name)s(machInst); +}}; + +// Basic decode template, passing mnemonic in as string arg to constructor. +def template BasicDecodeWithMnemonic {{ + return new %(class_name)s("%(mnemonic)s", machInst); +}}; + +// The most basic instruction format... used only for a few misc. insts +def format BasicOperate(code, *flags) {{ + iop = InstObjParams(name, Name, 'SparcStaticInst', + CodeBlock(code), flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) +}}; diff --git a/src/arch/sparc/isa/formats/branch.isa b/src/arch/sparc/isa/formats/branch.isa new file mode 100644 index 000000000..7d46ce739 --- /dev/null +++ b/src/arch/sparc/isa/formats/branch.isa @@ -0,0 +1,337 @@ +// 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: Gabe Black +// Steve Reinhardt + +//////////////////////////////////////////////////////////////////// +// +// Branch instructions +// + +output header {{ + /** + * Base class for branch operations. + */ + class Branch : public SparcStaticInst + { + protected: + // Constructor + Branch(const char *mnem, MachInst _machInst, OpClass __opClass) : + SparcStaticInst(mnem, _machInst, __opClass) + { + } + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + }; + + /** + * Base class for branch operations with an immediate displacement. + */ + class BranchDisp : public Branch + { + protected: + // Constructor + BranchDisp(const char *mnem, MachInst _machInst, + OpClass __opClass) : + Branch(mnem, _machInst, __opClass) + { + } + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + + int32_t disp; + }; + + /** + * Base class for branches with 19 bit displacements. + */ + class Branch19 : public BranchDisp + { + protected: + // Constructor + Branch19(const char *mnem, MachInst _machInst, + OpClass __opClass) : + BranchDisp(mnem, _machInst, __opClass) + { + disp = sign_ext(DISP19 << 2, 21); + } + }; + + /** + * Base class for branches with 22 bit displacements. + */ + class Branch22 : public BranchDisp + { + protected: + // Constructor + Branch22(const char *mnem, MachInst _machInst, + OpClass __opClass) : + BranchDisp(mnem, _machInst, __opClass) + { + disp = sign_ext(DISP22 << 2, 24); + } + }; + + /** + * Base class for branches with 30 bit displacements. + */ + class Branch30 : public BranchDisp + { + protected: + // Constructor + Branch30(const char *mnem, MachInst _machInst, + OpClass __opClass) : + BranchDisp(mnem, _machInst, __opClass) + { + disp = sign_ext(DISP30 << 2, 32); + } + }; + + /** + * Base class for 16bit split displacements. + */ + class BranchSplit : public BranchDisp + { + protected: + // Constructor + BranchSplit(const char *mnem, MachInst _machInst, + OpClass __opClass) : + BranchDisp(mnem, _machInst, __opClass) + { + disp = sign_ext((D16HI << 16) | (D16LO << 2), 18); + } + }; + + /** + * Base class for branches that use an immediate and a register to + * compute their displacements. + */ + class BranchImm13 : public Branch + { + protected: + // Constructor + BranchImm13(const char *mnem, MachInst _machInst, OpClass __opClass) : + Branch(mnem, _machInst, __opClass), imm(sign_ext(SIMM13, 13)) + { + } + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + + int32_t imm; + }; +}}; + +output decoder {{ + std::string Branch::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream response; + + printMnemonic(response, mnemonic); + + if (_numSrcRegs > 0) + { + printReg(response, _srcRegIdx[0]); + for(int x = 1; x < _numSrcRegs; x++) + { + response << ", "; + printReg(response, _srcRegIdx[x]); + } + } + + if (_numDestRegs > 0) + { + if(_numSrcRegs > 0) + response << ", "; + printReg(response, _destRegIdx[0]); + } + + return response.str(); + } + + std::string BranchImm13::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream response; + + printMnemonic(response, mnemonic); + + if (_numSrcRegs > 0) + { + printReg(response, _srcRegIdx[0]); + for(int x = 1; x < _numSrcRegs; x++) + { + response << ", "; + printReg(response, _srcRegIdx[x]); + } + } + + if(_numSrcRegs > 0) + response << ", "; + + ccprintf(response, "0x%x", imm); + + if (_numDestRegs > 0) + { + response << ", "; + printReg(response, _destRegIdx[0]); + } + + return response.str(); + } + + std::string BranchDisp::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream response; + std::string symbol; + Addr symbolAddr; + + Addr target = disp + pc; + + printMnemonic(response, mnemonic); + ccprintf(response, "0x%x", target); + + if(symtab->findNearestSymbol(target, symbol, symbolAddr)) + { + ccprintf(response, " <%s", symbol); + if(symbolAddr != target) + ccprintf(response, "+%d>", target - symbolAddr); + else + ccprintf(response, ">"); + } + + return response.str(); + } +}}; + +def template BranchExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + //Attempt to execute the instruction + Fault fault = NoFault; + + %(op_decl)s; + %(op_rd)s; + + NNPC = xc->readNextNPC(); + %(code)s; + + if(fault == NoFault) + { + //Write the resulting state to the execution context + %(op_wb)s; + } + + return fault; + } +}}; + +let {{ + handle_annul = ''' + { + if(A) + { + NPC = xc->readNextNPC(); + NNPC = NPC + 4; + } + else + { + NPC = xc->readNextPC(); + NNPC = xc->readNextNPC(); + } + }''' +}}; + +// Primary format for branch instructions: +def format Branch(code, *opt_flags) {{ + code = re.sub(r'handle_annul', handle_annul, code) + (usesImm, code, immCode, + rString, iString) = splitOutImm(code) + iop = InstObjParams(name, Name, 'Branch', code, opt_flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + exec_output = BranchExecute.subst(iop) + if usesImm: + imm_iop = InstObjParams(name, Name + 'Imm', 'BranchImm' + iString, + immCode, opt_flags) + header_output += BasicDeclare.subst(imm_iop) + decoder_output += BasicConstructor.subst(imm_iop) + exec_output += BranchExecute.subst(imm_iop) + decode_block = ROrImmDecode.subst(iop) + else: + decode_block = BasicDecode.subst(iop) +}}; + +// Primary format for branch instructions: +def format Branch19(code, *opt_flags) {{ + code = re.sub(r'handle_annul', handle_annul, code) + codeBlk = CodeBlock(code) + iop = InstObjParams(name, Name, 'Branch19', codeBlk, opt_flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + exec_output = BranchExecute.subst(iop) + decode_block = BasicDecode.subst(iop) +}}; + +// Primary format for branch instructions: +def format Branch22(code, *opt_flags) {{ + code = re.sub(r'handle_annul', handle_annul, code) + codeBlk = CodeBlock(code) + iop = InstObjParams(name, Name, 'Branch22', codeBlk, opt_flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + exec_output = BranchExecute.subst(iop) + decode_block = BasicDecode.subst(iop) +}}; + +// Primary format for branch instructions: +def format Branch30(code, *opt_flags) {{ + code = re.sub(r'handle_annul', handle_annul, code) + codeBlk = CodeBlock(code) + iop = InstObjParams(name, Name, 'Branch30', codeBlk, opt_flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + exec_output = BranchExecute.subst(iop) + decode_block = BasicDecode.subst(iop) +}}; + +// Primary format for branch instructions: +def format BranchSplit(code, *opt_flags) {{ + code = re.sub(r'handle_annul', handle_annul, code) + codeBlk = CodeBlock(code) + iop = InstObjParams(name, Name, 'BranchSplit', codeBlk, opt_flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + exec_output = BranchExecute.subst(iop) + decode_block = BasicDecode.subst(iop) +}}; + diff --git a/src/arch/sparc/isa/formats/integerop.isa b/src/arch/sparc/isa/formats/integerop.isa new file mode 100644 index 000000000..1894ce541 --- /dev/null +++ b/src/arch/sparc/isa/formats/integerop.isa @@ -0,0 +1,395 @@ +// 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 +// Gabe Black +// Steve Reinhardt + +//////////////////////////////////////////////////////////////////// +// +// Integer operate instructions +// + +output header {{ + /** + * Base class for integer operations. + */ + class IntOp : public SparcStaticInst + { + protected: + // Constructor + IntOp(const char *mnem, ExtMachInst _machInst, + OpClass __opClass) : + SparcStaticInst(mnem, _machInst, __opClass) + { + } + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + + virtual bool printPseudoOps(std::ostream &os, Addr pc, + const SymbolTable *symtab) const; + }; + + /** + * Base class for immediate integer operations. + */ + class IntOpImm : public IntOp + { + protected: + // Constructor + IntOpImm(const char *mnem, ExtMachInst _machInst, + OpClass __opClass) : + IntOp(mnem, _machInst, __opClass) + { + } + + int32_t imm; + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + + virtual bool printPseudoOps(std::ostream &os, Addr pc, + const SymbolTable *symtab) const; + }; + + /** + * Base class for 10 bit immediate integer operations. + */ + class IntOpImm10 : public IntOpImm + { + protected: + // Constructor + IntOpImm10(const char *mnem, ExtMachInst _machInst, + OpClass __opClass) : + IntOpImm(mnem, _machInst, __opClass) + { + imm = sign_ext(SIMM10, 10); + } + }; + + /** + * Base class for 11 bit immediate integer operations. + */ + class IntOpImm11 : public IntOpImm + { + protected: + // Constructor + IntOpImm11(const char *mnem, ExtMachInst _machInst, + OpClass __opClass) : + IntOpImm(mnem, _machInst, __opClass) + { + imm = sign_ext(SIMM11, 11); + } + }; + + /** + * Base class for 13 bit immediate integer operations. + */ + class IntOpImm13 : public IntOpImm + { + protected: + // Constructor + IntOpImm13(const char *mnem, ExtMachInst _machInst, + OpClass __opClass) : + IntOpImm(mnem, _machInst, __opClass) + { + imm = sign_ext(SIMM13, 13); + } + }; + + /** + * Base class for sethi. + */ + class SetHi : public IntOpImm + { + protected: + // Constructor + SetHi(const char *mnem, ExtMachInst _machInst, + OpClass __opClass) : + IntOpImm(mnem, _machInst, __opClass) + { + imm = (IMM22 << 10) & 0xFFFFFC00; + } + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + }; +}}; + +def template SetHiDecode {{ + { + if(RD == 0 && IMM22 == 0) + return (SparcStaticInst *)(new Nop("nop", machInst, No_OpClass)); + else + return (SparcStaticInst *)(new %(class_name)s(machInst)); + } +}}; + +output decoder {{ + + bool IntOp::printPseudoOps(std::ostream &os, Addr pc, + const SymbolTable *symbab) const + { + if(!strcmp(mnemonic, "or") && _srcRegIdx[0] == 0) + { + printMnemonic(os, "mov"); + if(_numSrcRegs > 0) + printReg(os, _srcRegIdx[1]); + ccprintf(os, ", "); + if(_numDestRegs > 0) + printReg(os, _destRegIdx[0]); + + return true; + } + return false; + } + + bool IntOpImm::printPseudoOps(std::ostream &os, Addr pc, + const SymbolTable *symbab) const + { + if(!strcmp(mnemonic, "or")) + { + if(_srcRegIdx[0] == 0) + { + if(imm == 0) + { + printMnemonic(os, "clr"); + if(_numDestRegs > 0) + printReg(os, _destRegIdx[0]); + return true; + } + else + { + printMnemonic(os, "mov"); + ccprintf(os, ", 0x%x, ", imm); + if(_numDestRegs > 0) + printReg(os, _destRegIdx[0]); + return true; + } + } + else if(imm == 0) + { + printMnemonic(os, "mov"); + if(_numSrcRegs > 0) + printReg(os, _srcRegIdx[0]); + ccprintf(os, ", "); + if(_numDestRegs > 0) + printReg(os, _destRegIdx[0]); + return true; + } + } + return false; + } + + std::string IntOp::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream response; + + if(!printPseudoOps(response, pc, symtab)) + { + printMnemonic(response, mnemonic); + if (_numSrcRegs > 0) + { + printReg(response, _srcRegIdx[0]); + for(int x = 1; x < _numSrcRegs; x++) + { + response << ", "; + printReg(response, _srcRegIdx[x]); + } + } + if (_numDestRegs > 0) + { + if(_numSrcRegs > 0) + response << ", "; + printReg(response, _destRegIdx[0]); + } + } + return response.str(); + } + + std::string IntOpImm::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream response; + + if(!printPseudoOps(response, pc, symtab)) + { + printMnemonic(response, mnemonic); + if (_numSrcRegs > 0) + { + printReg(response, _srcRegIdx[0]); + for(int x = 1; x < _numSrcRegs - 1; x++) + { + response << ", "; + printReg(response, _srcRegIdx[x]); + } + } + if(_numSrcRegs > 0) + response << ", "; + ccprintf(response, "0x%x", imm); + if (_numDestRegs > 0) + { + response << ", "; + printReg(response, _destRegIdx[0]); + } + } + return response.str(); + } + + std::string SetHi::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream response; + + printMnemonic(response, mnemonic); + if(_numSrcRegs > 0) + response << ", "; + ccprintf(response, "%%hi(0x%x), ", imm); + printReg(response, _destRegIdx[0]); + return response.str(); + } +}}; + +def template IntOpExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Fault fault = NoFault; + + %(op_decl)s; + %(op_rd)s; + %(code)s; + + //Write the resulting state to the execution context + if(fault == NoFault) + { + %(cc_code)s; + %(op_wb)s; + } + return fault; + } +}}; + +let {{ + def doIntFormat(code, ccCode, name, Name, opt_flags): + (usesImm, code, immCode, + rString, iString) = splitOutImm(code) + iop = InstObjParams(name, Name, 'IntOp', code, + opt_flags, ("cc_code", ccCode)) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + exec_output = IntOpExecute.subst(iop) + if usesImm: + imm_iop = InstObjParams(name, Name + 'Imm', 'IntOpImm' + iString, + immCode, opt_flags, ("cc_code", ccCode)) + header_output += BasicDeclare.subst(imm_iop) + decoder_output += BasicConstructor.subst(imm_iop) + exec_output += IntOpExecute.subst(imm_iop) + decode_block = ROrImmDecode.subst(iop) + else: + decode_block = BasicDecode.subst(iop) + return (header_output, decoder_output, exec_output, decode_block) + + calcCcCode = ''' + uint8_t tmp_ccriccc; + uint8_t tmp_ccriccv; + uint8_t tmp_ccriccz; + uint8_t tmp_ccriccn; + uint8_t tmp_ccrxccc; + uint8_t tmp_ccrxccv; + uint8_t tmp_ccrxccz; + uint8_t tmp_ccrxccn; + + tmp_ccriccn = (Rd >> 31) & 1; + tmp_ccriccz = ((Rd & 0xFFFFFFFF) == 0); + tmp_ccrxccn = (Rd >> 63) & 1; + tmp_ccrxccz = (Rd == 0); + tmp_ccriccv = %(ivValue)s & 1; + tmp_ccriccc = %(icValue)s & 1; + tmp_ccrxccv = %(xvValue)s & 1; + tmp_ccrxccc = %(xcValue)s & 1; + + Ccr = tmp_ccriccc | tmp_ccriccv << 1 | + tmp_ccriccz << 2 | tmp_ccriccn << 3| + tmp_ccrxccc << 4 | tmp_ccrxccv << 5| + tmp_ccrxccz << 6| tmp_ccrxccn << 7; + + + DPRINTF(Sparc, "in = %%d\\n", (uint16_t)tmp_ccriccn); + DPRINTF(Sparc, "iz = %%d\\n", (uint16_t)tmp_ccriccz); + DPRINTF(Sparc, "xn = %%d\\n", (uint16_t)tmp_ccrxccn); + DPRINTF(Sparc, "xz = %%d\\n", (uint16_t)tmp_ccrxccz); + DPRINTF(Sparc, "iv = %%d\\n", (uint16_t)tmp_ccriccv); + DPRINTF(Sparc, "ic = %%d\\n", (uint16_t)tmp_ccriccc); + DPRINTF(Sparc, "xv = %%d\\n", (uint16_t)tmp_ccrxccv); + DPRINTF(Sparc, "xc = %%d\\n", (uint16_t)tmp_ccrxccc); + ''' +}}; + +// Primary format for integer operate instructions: +def format IntOp(code, *opt_flags) {{ + ccCode = '' + (header_output, + decoder_output, + exec_output, + decode_block) = doIntFormat(code, ccCode, + name, Name, opt_flags) +}}; + +// Primary format for integer operate instructions: +def format IntOpCc(code, icValue, ivValue, xcValue, xvValue, *opt_flags) {{ + ccCode = calcCcCode % vars() + (header_output, + decoder_output, + exec_output, + decode_block) = doIntFormat(code, ccCode, + name, Name, opt_flags) +}}; + +// Primary format for integer operate instructions: +def format IntOpCcRes(code, *opt_flags) {{ + ccCode = calcCcCode % {"icValue":"0", + "ivValue":"0", + "xcValue":"0", + "xvValue":"0"} + (header_output, + decoder_output, + exec_output, + decode_block) = doIntFormat(code, ccCode, + name, Name, opt_flags) +}}; + +def format SetHi(code, *opt_flags) {{ + iop = InstObjParams(name, Name, 'SetHi', + code, opt_flags, ("cc_code", '')) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + exec_output = IntOpExecute.subst(iop) + decode_block = SetHiDecode.subst(iop) +}}; + diff --git a/src/arch/sparc/isa/formats/mem.isa b/src/arch/sparc/isa/formats/mem.isa new file mode 100644 index 000000000..12dae57e5 --- /dev/null +++ b/src/arch/sparc/isa/formats/mem.isa @@ -0,0 +1,171 @@ +//////////////////////////////////////////////////////////////////// +// +// Mem instructions +// + +output header {{ + /** + * Base class for memory operations. + */ + class Mem : public SparcStaticInst + { + protected: + + // Constructor + Mem(const char *mnem, ExtMachInst _machInst, OpClass __opClass) : + SparcStaticInst(mnem, _machInst, __opClass) + { + } + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + }; + + /** + * Class for memory operations which use an immediate offset. + */ + class MemImm : public Mem + { + protected: + + // Constructor + MemImm(const char *mnem, ExtMachInst _machInst, OpClass __opClass) : + Mem(mnem, _machInst, __opClass) + { + imm = sign_ext(SIMM13, 13); + } + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + + int32_t imm; + }; +}}; + +output decoder {{ + std::string Mem::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream response; + bool load = flags[IsLoad]; + bool save = flags[IsStore]; + + printMnemonic(response, mnemonic); + if(save) + { + printReg(response, _srcRegIdx[0]); + ccprintf(response, ", "); + } + ccprintf(response, "[ "); + printReg(response, _srcRegIdx[!save ? 0 : 1]); + ccprintf(response, " + "); + printReg(response, _srcRegIdx[!save ? 1 : 2]); + ccprintf(response, " ]"); + if(load) + { + ccprintf(response, ", "); + printReg(response, _destRegIdx[0]); + } + + return response.str(); + } + + std::string MemImm::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream response; + bool load = flags[IsLoad]; + bool save = flags[IsStore]; + + printMnemonic(response, mnemonic); + if(save) + { + printReg(response, _srcRegIdx[0]); + ccprintf(response, ", "); + } + ccprintf(response, "[ "); + printReg(response, _srcRegIdx[!save ? 0 : 1]); + if(imm >= 0) + ccprintf(response, " + 0x%x ]", imm); + else + ccprintf(response, " + -0x%x ]", -imm); + if(load) + { + ccprintf(response, ", "); + printReg(response, _destRegIdx[0]); + } + + return response.str(); + } +}}; + +def template MemExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Fault fault = NoFault; + Addr EA; + %(op_decl)s; + %(op_rd)s; + %(ea_code)s; + DPRINTF(Sparc, "The address is 0x%x\n", EA); + %(load)s; + %(code)s; + %(store)s; + + if(fault == NoFault) + { + //Write the resulting state to the execution context + %(op_wb)s; + } + + return fault; + } +}}; + +let {{ + # Leave memAccessFlags at 0 for now + loadString = "xc->read(EA, (uint%(width)s_t&)Mem, 0);" + storeString = "uint64_t write_result = 0; \ + xc->write((uint%(width)s_t)Mem, EA, 0, &write_result);" + + def doMemFormat(code, load, store, name, Name, opt_flags): + addrCalcReg = 'EA = Rs1 + Rs2;' + addrCalcImm = 'EA = Rs1 + imm;' + iop = InstObjParams(name, Name, 'Mem', code, + opt_flags, ("ea_code", addrCalcReg), + ("load", load), ("store", store)) + iop_imm = InstObjParams(name, Name + 'Imm', 'MemImm', code, + opt_flags, ("ea_code", addrCalcImm), + ("load", load), ("store", store)) + header_output = BasicDeclare.subst(iop) + BasicDeclare.subst(iop_imm) + decoder_output = BasicConstructor.subst(iop) + BasicConstructor.subst(iop_imm) + decode_block = ROrImmDecode.subst(iop) + exec_output = MemExecute.subst(iop) + MemExecute.subst(iop_imm) + return (header_output, decoder_output, exec_output, decode_block) +}}; + +def format Load(code, width, *opt_flags) {{ + (header_output, + decoder_output, + exec_output, + decode_block) = doMemFormat(code, + loadString % {"width":width}, '', name, Name, opt_flags) +}}; + +def format Store(code, width, *opt_flags) {{ + (header_output, + decoder_output, + exec_output, + decode_block) = doMemFormat(code, '', + storeString % {"width":width}, name, Name, opt_flags) +}}; + +def format LoadStore(code, width, *opt_flags) {{ + (header_output, + decoder_output, + exec_output, + decode_block) = doMemFormat(code, + loadString % {"width":width}, storeString % {"width":width}, + name, Name, opt_flags) +}}; diff --git a/src/arch/sparc/isa/formats/nop.isa b/src/arch/sparc/isa/formats/nop.isa new file mode 100644 index 000000000..37ef2e8d0 --- /dev/null +++ b/src/arch/sparc/isa/formats/nop.isa @@ -0,0 +1,98 @@ +// 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: Gabe Black +// Steve Reinhardt + +//////////////////////////////////////////////////////////////////// +// +// Nop instruction +// + +// Per-cpu-model nop execute method. +def template NopExec {{ + + Fault execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const + { + // Nothing to see here, move along + return NoFault; + } +}}; + +output header {{ + /** + * Nop class. + */ + class Nop : public SparcStaticInst + { + public: + // Constructor + Nop(const char *mnem, ExtMachInst _machInst, OpClass __opClass) : + SparcStaticInst(mnem, _machInst, __opClass) + { + } + + // All Nop instructions do the same thing, so this can be + // defined here. Nops can be defined directly, so there + // needs to be a default implementation. Interpolate via + // template so i gets expanded to a set of + // cpu-model-specific functions. + %(NopExec)s + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + }; +}}; + +output decoder {{ + std::string Nop::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream response; + printMnemonic(response, mnemonic); + return response.str(); + } +}}; + +def template NopExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + //Nothing to see here, move along + return NoFault; + } +}}; + +// Primary format for integer operate instructions: +def format Nop(code, *opt_flags) {{ + orig_code = code + cblk = CodeBlock(code) + iop = InstObjParams(name, Name, 'Nop', cblk, opt_flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = NopExecute.subst(iop) +}}; diff --git a/src/arch/sparc/isa/formats/priv.isa b/src/arch/sparc/isa/formats/priv.isa new file mode 100644 index 000000000..7df59d736 --- /dev/null +++ b/src/arch/sparc/isa/formats/priv.isa @@ -0,0 +1,125 @@ +// 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 +// Gabe Black +// Steve Reinhardt + +//////////////////////////////////////////////////////////////////// +// +// Privilege mode instructions +// + +output header {{ + /** + * Base class for privelege mode operations. + */ + class Priv : public SparcStaticInst + { + protected: + // Constructor + Priv(const char *mnem, ExtMachInst _machInst, OpClass __opClass) : + SparcStaticInst(mnem, _machInst, __opClass) + { + } + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + }; + + /** + * Base class for privelege mode operations with immediates. + */ + class PrivImm : public Priv + { + protected: + // Constructor + PrivImm(const char *mnem, ExtMachInst _machInst, + OpClass __opClass) : + Priv(mnem, _machInst, __opClass), imm(SIMM13) + { + } + + int32_t imm; + }; + +}}; + +output decoder {{ + std::string Priv::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + return "Privileged Instruction"; + } +}}; + +def template PrivExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + %(op_decl)s; + %(op_rd)s; + + //If the processor isn't in privileged mode, fault out right away + if(%(check)s) + return new PrivilegedAction; + + %(code)s; + %(op_wb)s; + return NoFault; + } +}}; + +let {{ + def doPrivFormat(code, checkCode, name, Name, opt_flags): + (usesImm, code, immCode, + rString, iString) = splitOutImm(code) + iop = InstObjParams(name, Name, 'Priv', code, + opt_flags, ("check", checkCode)) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + exec_output = PrivExecute.subst(iop) + if usesImm: + imm_iop = InstObjParams(name, Name + 'Imm', 'PrivImm', + immCode, opt_flags, ("check", checkCode)) + header_output += BasicDeclare.subst(imm_iop) + decoder_output += BasicConstructor.subst(imm_iop) + exec_output += PrivExecute.subst(imm_iop) + decode_block = ROrImmDecode.subst(iop) + else: + decode_block = BasicDecode.subst(iop) + return (header_output, decoder_output, exec_output, decode_block) +}}; + +// Primary format for integer operate instructions: +def format Priv(code, *opt_flags) {{ + checkCode = "((xc->readMiscReg(PrStart + MISCREG_PSTATE))<2:2>)" + (header_output, decoder_output, + exec_output, decode_block) = doPrivFormat(code, + checkCode, name, Name, opt_flags) +}}; + + diff --git a/src/arch/sparc/isa/formats/trap.isa b/src/arch/sparc/isa/formats/trap.isa new file mode 100644 index 000000000..04d467cfe --- /dev/null +++ b/src/arch/sparc/isa/formats/trap.isa @@ -0,0 +1,93 @@ +// 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: Gabe Black +// Steve Reinhardt + +//////////////////////////////////////////////////////////////////// +// +// Trap instructions +// + +output header {{ + /** + * Base class for trap instructions, + * or instructions that always fault. + */ + class Trap : public SparcStaticInst + { + protected: + + // Constructor + Trap(const char *mnem, ExtMachInst _machInst, OpClass __opClass) : + SparcStaticInst(mnem, _machInst, __opClass), trapNum(SW_TRAP) + { + } + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + + int trapNum; + }; +}}; + +output decoder {{ + std::string Trap::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream response; + + printMnemonic(response, mnemonic); + ccprintf(response, " "); + printReg(response, _srcRegIdx[0]); + ccprintf(response, ", 0x%x", trapNum); + ccprintf(response, ", or "); + printReg(response, _srcRegIdx[1]); + return response.str(); + } +}}; + +def template TrapExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + Fault fault = NoFault; + %(op_decl)s; + %(op_rd)s; + %(code)s + return fault; + } +}}; + +def format Trap(code, *opt_flags) {{ + orig_code = code + cblk = CodeBlock(code) + iop = InstObjParams(name, Name, 'Trap', cblk, opt_flags) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = TrapExecute.subst(iop) +}}; diff --git a/src/arch/sparc/isa/formats/unknown.isa b/src/arch/sparc/isa/formats/unknown.isa new file mode 100644 index 000000000..8541d6a62 --- /dev/null +++ b/src/arch/sparc/isa/formats/unknown.isa @@ -0,0 +1,75 @@ +// 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: Gabe Black +// Steve Reinhardt + +//////////////////////////////////////////////////////////////////// +// +// Unknown instructions +// + +output header {{ + /** + * Class for Unknown/Illegal instructions + */ + class Unknown : public SparcStaticInst + { + public: + + // Constructor + Unknown(ExtMachInst _machInst) : + SparcStaticInst("unknown", _machInst, No_OpClass) + { + } + + %(BasicExecDeclare)s + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + + }; +}}; + +output decoder {{ + std::string Unknown::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + return "Unknown instruction"; + } +}}; + +output exec {{ + Fault Unknown::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + return new IllegalInstruction; + } +}}; + +def format Unknown() {{ + decode_block = 'return new Unknown(machInst);\n' +}}; diff --git a/src/arch/sparc/isa/includes.isa b/src/arch/sparc/isa/includes.isa new file mode 100644 index 000000000..40afb3722 --- /dev/null +++ b/src/arch/sparc/isa/includes.isa @@ -0,0 +1,76 @@ +// 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 +// Gabe Black +// Steve Reinhardt + +//////////////////////////////////////////////////////////////////// +// +// Output include file directives. +// + +output header {{ +#include <sstream> +#include <iostream> +#include <iomanip> + +#include "cpu/static_inst.hh" +#include "arch/sparc/faults.hh" +#include "mem/request.hh" // some constructors use MemReq flags +#include "arch/sparc/isa_traits.hh" +#include "arch/sparc/regfile.hh" +}}; + +output decoder {{ +#include "base/cprintf.hh" +#include "base/loader/symtab.hh" +#include "cpu/thread_context.hh" // for Jump::branchTarget() + +#include <math.h> +#if defined(linux) +#include <fenv.h> +#endif + +using namespace SparcISA; +}}; + +output exec {{ +#include <math.h> +#if defined(linux) +#include <fenv.h> +#endif + +#ifdef FULL_SYSTEM +//#include "sim/pseudo_inst.hh" +#endif +#include "cpu/base.hh" +#include "cpu/exetrace.hh" +#include "sim/sim_exit.hh" + +using namespace SparcISA; +}}; + diff --git a/src/arch/sparc/isa/main.isa b/src/arch/sparc/isa/main.isa new file mode 100644 index 000000000..14acf54fa --- /dev/null +++ b/src/arch/sparc/isa/main.isa @@ -0,0 +1,61 @@ +// -*- mode:c++ -*- + +// Copyright (c) 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: Korey Sewell + +//////////////////////////////////////////////////////////////////// +// +// SPARC ISA description file. +// +//////////////////////////////////////////////////////////////////// + +//Include the C++ include directives +##include "includes.isa" + +//////////////////////////////////////////////////////////////////// +// +// Namespace statement. Everything below this line will be in the +// SparcISAInst namespace. +// + +namespace SparcISA; + +//Include the bitfield definitions +##include "bitfields.isa" + +//Include the operand_types and operand definitions +##include "operands.isa" + +//Include the base class for sparc instructions, and some support code +##include "base.isa" + +//Include the definitions for the instruction formats +##include "formats.isa" + +//Include the decoder definition +##include "decoder.isa" diff --git a/src/arch/sparc/isa/operands.isa b/src/arch/sparc/isa/operands.isa new file mode 100644 index 000000000..9e5c783e8 --- /dev/null +++ b/src/arch/sparc/isa/operands.isa @@ -0,0 +1,88 @@ +// 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 +// Gabe Black +// Steve Reinhardt + +def operand_types {{ + 'sb' : ('signed int', 8), + 'ub' : ('unsigned int', 8), + 'shw' : ('signed int', 16), + 'uhw' : ('unsigned int', 16), + 'sw' : ('signed int', 32), + 'uw' : ('unsigned int', 32), + 'sdw' : ('signed int', 64), + 'udw' : ('unsigned int', 64), + 'sf' : ('float', 32), + 'df' : ('float', 64), + 'qf' : ('float', 128) +}}; + +def operands {{ + # Int regs default to unsigned, but code should not count on this. + # For clarity, descriptions that depend on unsigned behavior should + # explicitly specify '.uq'. + 'Rd': ('IntReg', 'udw', 'RD', 'IsInteger', 1), + 'RdLow': ('IntReg', 'udw', 'RD & (~1)', 'IsInteger', 2), + 'RdHigh': ('IntReg', 'udw', 'RD | 1', 'IsInteger', 3), + 'Rs1': ('IntReg', 'udw', 'RS1', 'IsInteger', 4), + 'Rs2': ('IntReg', 'udw', 'RS2', 'IsInteger', 5), + #'Fa': ('FloatReg', 'df', 'FA', 'IsFloating', 1), + #'Fb': ('FloatReg', 'df', 'FB', 'IsFloating', 2), + #'Fc': ('FloatReg', 'df', 'FC', 'IsFloating', 3), + 'Mem': ('Mem', 'udw', None, ('IsMemRef', 'IsLoad', 'IsStore'), 4), + 'NPC': ('NPC', 'udw', None, ( None, None, 'IsControl' ), 4), + 'NNPC': ('NNPC', 'udw', None, (None, None, 'IsControl' ), 4), + #'Runiq': ('ControlReg', 'uq', 'Uniq', None, 1), + #'FPCR': ('ControlReg', 'uq', 'Fpcr', None, 1), + 'R0': ('IntReg', 'udw', '0', None, 6), + 'R1': ('IntReg', 'udw', '1', None, 7), + 'R15': ('IntReg', 'udw', '15', 'IsInteger', 8), + 'R16': ('IntReg', 'udw', '16', None, 9), + + # Control registers + 'Y': ('ControlReg', 'udw', 'MISCREG_Y', None, 12), + 'Ccr': ('ControlReg', 'udw', 'MISCREG_CCR', None, 17), + 'Asi': ('ControlReg', 'udw', 'MISCREG_ASI', None, 26), + + 'Tpc': ('ControlReg', 'udw', 'MISCREG_TPC', None, 28), + 'Tnpc': ('ControlReg', 'udw', 'MISCREG_TNPC', None, 28), + 'Tstate': ('ControlReg', 'udw', 'MISCREG_TSTATE', None, 28), + 'Pstate': ('ControlReg', 'udw', 'MISCREG_PSTATE', None, 1), + 'Tl': ('ControlReg', 'udw', 'MISCREG_TL', None, 27), + + 'Cwp': ('ControlReg', 'udw', 'MISCREG_CWP', None, 15), + 'Cansave': ('ControlReg', 'udw', 'MISCREG_CANSAVE', None, 34), + 'Canrestore': ('ControlReg', 'udw', 'MISCREG_CANRESTORE', None, 35), + 'Cleanwin': ('ControlReg', 'udw', 'MISCREG_CLEANWIN', None, 37), + 'Otherwin': ('ControlReg', 'udw', 'MISCREG_OTHERWIN', None, 36), + 'Wstate': ('ControlReg', 'udw', 'MISCREG_WSTATE', None, 38), + 'Gl': ('ControlReg', 'udw', 'MISCREG_GL', None, 12), + + 'Fsr': ('ControlReg', 'udw', 'MISCREG_FSR', None, 47) + +}}; diff --git a/src/arch/sparc/isa_traits.hh b/src/arch/sparc/isa_traits.hh new file mode 100644 index 000000000..346f7b730 --- /dev/null +++ b/src/arch/sparc/isa_traits.hh @@ -0,0 +1,193 @@ +/* + * Copyright (c) 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: Korey Sewell + * Gabe Black + */ + +#ifndef __ARCH_SPARC_ISA_TRAITS_HH__ +#define __ARCH_SPARC_ISA_TRAITS_HH__ + +#include "base/misc.hh" +#include "config/full_system.hh" +#include "sim/host.hh" + +class ThreadContext; +class FastCPU; +//class FullCPU; +class Checkpoint; + +class StaticInst; +class StaticInstPtr; + +namespace BigEndianGuest {} + +#if !FULL_SYSTEM +class SyscallReturn +{ + public: + template <class T> + SyscallReturn(T v, bool s) + { + retval = (uint64_t)v; + success = s; + } + + template <class T> + SyscallReturn(T v) + { + success = (v >= 0); + retval = (uint64_t)v; + } + + ~SyscallReturn() {} + + SyscallReturn& operator=(const SyscallReturn& s) + { + retval = s.retval; + success = s.success; + return *this; + } + + bool successful() { return success; } + uint64_t value() { return retval; } + + private: + uint64_t retval; + bool success; +}; + +#endif + +#if FULL_SYSTEM +#include "arch/sparc/isa_fullsys_traits.hh" +#endif + +namespace SparcISA +{ + + // These enumerate all the registers for dependence tracking. + enum DependenceTags { + // 0..31 are the integer regs 0..31 + // 32..63 are the FP regs 0..31, i.e. use (reg + FP_Base_DepTag) + FP_Base_DepTag = 32, + Ctrl_Base_DepTag = 96, + //XXX These are here solely to get compilation and won't work + Fpcr_DepTag = 0, + Uniq_DepTag = 0 + }; + + //This makes sure the big endian versions of certain functions are used. + using namespace BigEndianGuest; + + typedef uint32_t MachInst; + typedef uint64_t ExtMachInst; + + const int NumIntRegs = 32; + const int NumFloatRegs = 64; + const int NumMiscRegs = 32; + + // semantically meaningful register indices + const int ZeroReg = 0; // architecturally meaningful + // the rest of these depend on the ABI + const int StackPointerReg = 14; + const int ReturnAddressReg = 31; // post call, precall is 15 + const int ReturnValueReg = 8; // Post return, 24 is pre-return. + const int FramePointerReg = 30; + const int ArgumentReg0 = 8; + const int ArgumentReg1 = 9; + const int ArgumentReg2 = 10; + const int ArgumentReg3 = 11; + const int ArgumentReg4 = 12; + const int ArgumentReg5 = 13; + // Some OS syscall use a second register (o1) to return a second value + const int SyscallPseudoReturnReg = ArgumentReg1; + + //XXX These numbers are bogus + const int MaxInstSrcRegs = 8; + const int MaxInstDestRegs = 9; + + typedef uint64_t IntReg; + + // control register file contents + typedef uint64_t MiscReg; + + typedef double FloatReg; + typedef uint64_t FloatRegBits; + + //8K. This value is implmentation specific; and should probably + //be somewhere else. + const int LogVMPageSize = 13; + const int VMPageSize = (1 << LogVMPageSize); + + //Why does both the previous set of constants and this one exist? + const int PageShift = 13; + const int PageBytes = ULL(1) << PageShift; + + const int BranchPredAddrShiftAmt = 2; + + const int MachineBytes = 8; + const int WordBytes = 4; + const int HalfwordBytes = 2; + const int ByteBytes = 1; + + void serialize(std::ostream & os); + + void unserialize(Checkpoint *cp, const std::string §ion); + + StaticInstPtr decodeInst(ExtMachInst); + + // return a no-op instruction... used for instruction fetch faults + extern const MachInst NoopMachInst; +} + +#include "arch/sparc/regfile.hh" + +namespace SparcISA +{ + +#if !FULL_SYSTEM + static inline void setSyscallReturn(SyscallReturn return_value, + RegFile *regs) + { + // check for error condition. SPARC syscall convention is to + // indicate success/failure in reg the carry bit of the ccr + // and put the return value itself in the standard return value reg (). + if (return_value.successful()) { + // no error, clear XCC.C + regs->setMiscReg(MISCREG_CCR, regs->readMiscReg(MISCREG_CCR) & 0xEF); + regs->setIntReg(ReturnValueReg, return_value.value()); + } else { + // got an error, set XCC.C + regs->setMiscReg(MISCREG_CCR, regs->readMiscReg(MISCREG_CCR) | 0x10); + regs->setIntReg(ReturnValueReg, return_value.value()); + } + } +#endif +}; + +#endif // __ARCH_SPARC_ISA_TRAITS_HH__ diff --git a/src/arch/sparc/linux/linux.cc b/src/arch/sparc/linux/linux.cc new file mode 100644 index 000000000..ae6ffbc2a --- /dev/null +++ b/src/arch/sparc/linux/linux.cc @@ -0,0 +1,70 @@ +/* + * Copyright (c) 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: Gabe Black + */ + +#include "arch/sparc/linux/linux.hh" + +// open(2) flags translation table +OpenFlagTransTable SparcLinux::openFlagTable[] = { +#ifdef _MSC_VER + { SparcLinux::TGT_O_RDONLY, _O_RDONLY }, + { SparcLinux::TGT_O_WRONLY, _O_WRONLY }, + { SparcLinux::TGT_O_RDWR, _O_RDWR }, + { SparcLinux::TGT_O_APPEND, _O_APPEND }, + { SparcLinux::TGT_O_CREAT, _O_CREAT }, + { SparcLinux::TGT_O_TRUNC, _O_TRUNC }, + { SparcLinux::TGT_O_EXCL, _O_EXCL }, +#ifdef _O_NONBLOCK + { SparcLinux::TGT_O_NONBLOCK, _O_NONBLOCK }, +#endif +#ifdef _O_NOCTTY + { SparcLinux::TGT_O_NOCTTY, _O_NOCTTY }, +#endif +#ifdef _O_SYNC + { SparcLinux::TGT_O_SYNC, _O_SYNC }, +#endif +#else /* !_MSC_VER */ + { SparcLinux::TGT_O_RDONLY, O_RDONLY }, + { SparcLinux::TGT_O_WRONLY, O_WRONLY }, + { SparcLinux::TGT_O_RDWR, O_RDWR }, + { SparcLinux::TGT_O_APPEND, O_APPEND }, + { SparcLinux::TGT_O_CREAT, O_CREAT }, + { SparcLinux::TGT_O_TRUNC, O_TRUNC }, + { SparcLinux::TGT_O_EXCL, O_EXCL }, + { SparcLinux::TGT_O_NONBLOCK, O_NONBLOCK }, + { SparcLinux::TGT_O_NOCTTY, O_NOCTTY }, +#ifdef O_SYNC + { SparcLinux::TGT_O_SYNC, O_SYNC }, +#endif +#endif /* _MSC_VER */ +}; + +const int SparcLinux::NUM_OPEN_FLAGS = + (sizeof(SparcLinux::openFlagTable)/sizeof(SparcLinux::openFlagTable[0])); + diff --git a/src/arch/sparc/linux/linux.hh b/src/arch/sparc/linux/linux.hh new file mode 100644 index 000000000..926c2cb77 --- /dev/null +++ b/src/arch/sparc/linux/linux.hh @@ -0,0 +1,63 @@ +/* + * Copyright (c) 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: Gabe Black + */ + +#ifndef __ARCH_SPARC_LINUX_LINUX_HH__ +#define __ARCH_SPARC_LINUX_LINUX_HH__ + +#include "kern/linux/linux.hh" + +class SparcLinux : public Linux +{ + public: + + static OpenFlagTransTable openFlagTable[]; + + static const int TGT_O_RDONLY = 0x00000000; //!< O_RDONLY + static const int TGT_O_WRONLY = 0x00000001; //!< O_WRONLY + static const int TGT_O_RDWR = 0x00000002; //!< O_RDWR + static const int TGT_O_NONBLOCK = 0x00004000; //!< O_NONBLOCK + static const int TGT_O_APPEND = 0x00000008; //!< O_APPEND + static const int TGT_O_CREAT = 0x00000200; //!< O_CREAT + static const int TGT_O_TRUNC = 0x00000400; //!< O_TRUNC + static const int TGT_O_EXCL = 0x00000800; //!< O_EXCL + static const int TGT_O_NOCTTY = 0x00008000; //!< O_NOCTTY + static const int TGT_O_SYNC = 0x00002000; //!< O_SYNC +// static const int TGT_O_DRD = 0x00010000; //!< O_DRD +// static const int TGT_O_DIRECTIO = 0x00020000; //!< O_DIRECTIO +// static const int TGT_O_CACHE = 0x00002000; //!< O_CACHE +// static const int TGT_O_DSYNC = 0x00008000; //!< O_DSYNC +// static const int TGT_O_RSYNC = 0x00040000; //!< O_RSYNC + + static const int NUM_OPEN_FLAGS; + + static const unsigned TGT_MAP_ANONYMOUS = 0x20; +}; + +#endif diff --git a/src/arch/sparc/linux/process.cc b/src/arch/sparc/linux/process.cc new file mode 100644 index 000000000..e27255e67 --- /dev/null +++ b/src/arch/sparc/linux/process.cc @@ -0,0 +1,411 @@ +/* + * Copyright (c) 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 Reinhardt + * Gabe Black + * Ali Saidi + */ + +#include "arch/sparc/isa_traits.hh" +#include "arch/sparc/linux/process.hh" +#include "arch/sparc/regfile.hh" + +#include "base/trace.hh" +#include "cpu/thread_context.hh" +#include "kern/linux/linux.hh" + +#include "sim/process.hh" +#include "sim/syscall_emul.hh" + +using namespace std; +using namespace SparcISA; + + +/// Target uname() handler. +static SyscallReturn +unameFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + TypedBufferArg<Linux::utsname> name(tc->getSyscallArg(0)); + + strcpy(name->sysname, "Linux"); + strcpy(name->nodename, "m5.eecs.umich.edu"); + strcpy(name->release, "2.4.20"); + strcpy(name->version, "#1 Mon Aug 18 11:32:15 EDT 2003"); + strcpy(name->machine, "sparc"); + + name.copyOut(tc->getMemPort()); + + return 0; +} + + +SyscallReturn SparcISA::getresuidFunc(SyscallDesc *desc, int num, + Process *p, ThreadContext *tc) +{ + const IntReg id = htog(100); + Addr ruid = tc->getSyscallArg(0); + Addr euid = tc->getSyscallArg(1); + Addr suid = tc->getSyscallArg(2); + //Handle the EFAULT case + //Set the ruid + if(ruid) + { + BufferArg ruidBuff(ruid, sizeof(IntReg)); + memcpy(ruidBuff.bufferPtr(), &id, sizeof(IntReg)); + ruidBuff.copyOut(tc->getMemPort()); + } + //Set the euid + if(euid) + { + BufferArg euidBuff(euid, sizeof(IntReg)); + memcpy(euidBuff.bufferPtr(), &id, sizeof(IntReg)); + euidBuff.copyOut(tc->getMemPort()); + } + //Set the suid + if(suid) + { + BufferArg suidBuff(suid, sizeof(IntReg)); + memcpy(suidBuff.bufferPtr(), &id, sizeof(IntReg)); + suidBuff.copyOut(tc->getMemPort()); + } + return 0; +} + +SyscallDesc SparcLinuxProcess::syscallDescs[] = { + /* 0 */ SyscallDesc("restart_syscall", unimplementedFunc), + /* 1 */ SyscallDesc("exit", exitFunc), + /* 2 */ SyscallDesc("fork", unimplementedFunc), + /* 3 */ SyscallDesc("read", readFunc), + /* 4 */ SyscallDesc("write", writeFunc), + /* 5 */ SyscallDesc("open", openFunc<SparcLinux>), + /* 6 */ SyscallDesc("close", closeFunc), + /* 7 */ SyscallDesc("wait4", unimplementedFunc), + /* 8 */ SyscallDesc("creat", unimplementedFunc), + /* 9 */ SyscallDesc("link", unimplementedFunc), + /* 10 */ SyscallDesc("unlink", unlinkFunc), + /* 11 */ SyscallDesc("execv", unimplementedFunc), + /* 12 */ SyscallDesc("chdir", unimplementedFunc), + /* 13 */ SyscallDesc("chown", chownFunc), + /* 14 */ SyscallDesc("mknod", unimplementedFunc), + /* 15 */ SyscallDesc("chmod", chmodFunc<Linux>), + /* 16 */ SyscallDesc("lchown", unimplementedFunc), + /* 17 */ SyscallDesc("brk", obreakFunc), + /* 18 */ SyscallDesc("perfctr", unimplementedFunc), + /* 19 */ SyscallDesc("lseek", lseekFunc), + /* 20 */ SyscallDesc("getpid", getpidFunc), + /* 21 */ SyscallDesc("capget", unimplementedFunc), + /* 22 */ SyscallDesc("capset", unimplementedFunc), + /* 23 */ SyscallDesc("setuid", setuidFunc), + /* 24 */ SyscallDesc("getuid", getuidFunc), + /* 25 */ SyscallDesc("time", unimplementedFunc), + /* 26 */ SyscallDesc("ptrace", unimplementedFunc), + /* 27 */ SyscallDesc("alarm", unimplementedFunc), + /* 28 */ SyscallDesc("sigaltstack", unimplementedFunc), + /* 29 */ SyscallDesc("pause", unimplementedFunc), + /* 30 */ SyscallDesc("utime", unimplementedFunc), + /* 31 */ SyscallDesc("lchown32", unimplementedFunc), + /* 32 */ SyscallDesc("fchown32", unimplementedFunc), + /* 33 */ SyscallDesc("access", unimplementedFunc), + /* 34 */ SyscallDesc("nice", unimplementedFunc), + /* 35 */ SyscallDesc("chown32", unimplementedFunc), + /* 36 */ SyscallDesc("sync", unimplementedFunc), + /* 37 */ SyscallDesc("kill", unimplementedFunc), + /* 38 */ SyscallDesc("stat", unimplementedFunc), + /* 39 */ SyscallDesc("sendfile", unimplementedFunc), + /* 40 */ SyscallDesc("lstat", unimplementedFunc), + /* 41 */ SyscallDesc("dup", unimplementedFunc), + /* 42 */ SyscallDesc("pipe", pipePseudoFunc), + /* 43 */ SyscallDesc("times", unimplementedFunc), + /* 44 */ SyscallDesc("getuid32", unimplementedFunc), + /* 45 */ SyscallDesc("umount2", unimplementedFunc), + /* 46 */ SyscallDesc("setgid", unimplementedFunc), + /* 47 */ SyscallDesc("getgid", getgidFunc), + /* 48 */ SyscallDesc("signal", unimplementedFunc), + /* 49 */ SyscallDesc("geteuid", geteuidFunc), + /* 50 */ SyscallDesc("getegid", getegidFunc), + /* 51 */ SyscallDesc("acct", unimplementedFunc), + /* 52 */ SyscallDesc("memory_ordering", unimplementedFunc), + /* 53 */ SyscallDesc("getgid32", unimplementedFunc), + /* 54 */ SyscallDesc("ioctl", unimplementedFunc), + /* 55 */ SyscallDesc("reboot", unimplementedFunc), + /* 56 */ SyscallDesc("mmap2", unimplementedFunc), + /* 57 */ SyscallDesc("symlink", unimplementedFunc), + /* 58 */ SyscallDesc("readlink", unimplementedFunc), + /* 59 */ SyscallDesc("execve", unimplementedFunc), + /* 60 */ SyscallDesc("umask", unimplementedFunc), + /* 61 */ SyscallDesc("chroot", unimplementedFunc), + /* 62 */ SyscallDesc("fstat", fstatFunc<SparcLinux>), + /* 63 */ SyscallDesc("fstat64", unimplementedFunc), + /* 64 */ SyscallDesc("getpagesize", unimplementedFunc), + /* 65 */ SyscallDesc("msync", unimplementedFunc), + /* 66 */ SyscallDesc("vfork", unimplementedFunc), + /* 67 */ SyscallDesc("pread64", unimplementedFunc), + /* 68 */ SyscallDesc("pwrite64", unimplementedFunc), + /* 69 */ SyscallDesc("geteuid32", unimplementedFunc), + /* 70 */ SyscallDesc("getdgid32", unimplementedFunc), + /* 71 */ SyscallDesc("mmap", mmapFunc<SparcLinux>), + /* 72 */ SyscallDesc("setreuid32", unimplementedFunc), + /* 73 */ SyscallDesc("munmap", munmapFunc), + /* 74 */ SyscallDesc("mprotect", unimplementedFunc), + /* 75 */ SyscallDesc("madvise", unimplementedFunc), + /* 76 */ SyscallDesc("vhangup", unimplementedFunc), + /* 77 */ SyscallDesc("truncate64", unimplementedFunc), + /* 78 */ SyscallDesc("mincore", unimplementedFunc), + /* 79 */ SyscallDesc("getgroups", unimplementedFunc), + /* 80 */ SyscallDesc("setgroups", unimplementedFunc), + /* 81 */ SyscallDesc("getpgrp", unimplementedFunc), + /* 82 */ SyscallDesc("setgroups32", unimplementedFunc), + /* 83 */ SyscallDesc("setitimer", unimplementedFunc), + /* 84 */ SyscallDesc("ftruncate64", unimplementedFunc), + /* 85 */ SyscallDesc("swapon", unimplementedFunc), + /* 86 */ SyscallDesc("getitimer", unimplementedFunc), + /* 87 */ SyscallDesc("setuid32", unimplementedFunc), + /* 88 */ SyscallDesc("sethostname", unimplementedFunc), + /* 89 */ SyscallDesc("setgid32", unimplementedFunc), + /* 90 */ SyscallDesc("dup2", unimplementedFunc), + /* 91 */ SyscallDesc("setfsuid32", unimplementedFunc), + /* 92 */ SyscallDesc("fcntl", unimplementedFunc), + /* 93 */ SyscallDesc("select", unimplementedFunc), + /* 94 */ SyscallDesc("setfsgid32", unimplementedFunc), + /* 95 */ SyscallDesc("fsync", unimplementedFunc), + /* 96 */ SyscallDesc("setpriority", unimplementedFunc), + /* 97 */ SyscallDesc("socket", unimplementedFunc), + /* 98 */ SyscallDesc("connect", unimplementedFunc), + /* 99 */ SyscallDesc("accept", unimplementedFunc), + /* 100 */ SyscallDesc("getpriority", unimplementedFunc), + /* 101 */ SyscallDesc("rt_sigreturn", unimplementedFunc), + /* 102 */ SyscallDesc("rt_sigaction", unimplementedFunc), + /* 103 */ SyscallDesc("rt_sigprocmask", unimplementedFunc), + /* 104 */ SyscallDesc("rt_sigpending", unimplementedFunc), + /* 105 */ SyscallDesc("rt_sigtimedwait", unimplementedFunc), + /* 106 */ SyscallDesc("rt_sigqueueinfo", unimplementedFunc), + /* 107 */ SyscallDesc("rt_sigsuspend", unimplementedFunc), + /* 108 */ SyscallDesc("setresuid", unimplementedFunc), + /* 109 */ SyscallDesc("getresuid", getresuidFunc), + /* 110 */ SyscallDesc("setresgid", unimplementedFunc), + /* 111 */ SyscallDesc("getresgid", unimplementedFunc), + /* 112 */ SyscallDesc("setregid32", unimplementedFunc), + /* 113 */ SyscallDesc("recvmsg", unimplementedFunc), + /* 114 */ SyscallDesc("sendmsg", unimplementedFunc), + /* 115 */ SyscallDesc("getgroups32", unimplementedFunc), + /* 116 */ SyscallDesc("gettimeofday", unimplementedFunc), + /* 117 */ SyscallDesc("getrusage", unimplementedFunc), + /* 118 */ SyscallDesc("getsockopt", unimplementedFunc), + /* 119 */ SyscallDesc("getcwd", unimplementedFunc), + /* 120 */ SyscallDesc("readv", unimplementedFunc), + /* 121 */ SyscallDesc("writev", unimplementedFunc), + /* 122 */ SyscallDesc("settimeofday", unimplementedFunc), + /* 123 */ SyscallDesc("fchown", unimplementedFunc), + /* 124 */ SyscallDesc("fchmod", unimplementedFunc), + /* 125 */ SyscallDesc("recvfrom", unimplementedFunc), + /* 126 */ SyscallDesc("setreuid", unimplementedFunc), + /* 127 */ SyscallDesc("setregid", unimplementedFunc), + /* 128 */ SyscallDesc("rename", unimplementedFunc), + /* 129 */ SyscallDesc("truncate", unimplementedFunc), + /* 130 */ SyscallDesc("ftruncate", unimplementedFunc), + /* 131 */ SyscallDesc("flock", unimplementedFunc), + /* 132 */ SyscallDesc("lstat64", unimplementedFunc), + /* 133 */ SyscallDesc("sendto", unimplementedFunc), + /* 134 */ SyscallDesc("shutdown", unimplementedFunc), + /* 135 */ SyscallDesc("socketpair", unimplementedFunc), + /* 136 */ SyscallDesc("mkdir", unimplementedFunc), + /* 137 */ SyscallDesc("rmdir", unimplementedFunc), + /* 138 */ SyscallDesc("utimes", unimplementedFunc), + /* 139 */ SyscallDesc("stat64", unimplementedFunc), + /* 140 */ SyscallDesc("sendfile64", unimplementedFunc), + /* 141 */ SyscallDesc("getpeername", unimplementedFunc), + /* 142 */ SyscallDesc("futex", unimplementedFunc), + /* 143 */ SyscallDesc("gettid", unimplementedFunc), + /* 144 */ SyscallDesc("getrlimit", unimplementedFunc), + /* 145 */ SyscallDesc("setrlimit", unimplementedFunc), + /* 146 */ SyscallDesc("pivot_root", unimplementedFunc), + /* 147 */ SyscallDesc("prctl", unimplementedFunc), + /* 148 */ SyscallDesc("pciconfig_read", unimplementedFunc), + /* 149 */ SyscallDesc("pciconfig_write", unimplementedFunc), + /* 150 */ SyscallDesc("getsockname", unimplementedFunc), + /* 151 */ SyscallDesc("inotify_init", unimplementedFunc), + /* 152 */ SyscallDesc("inotify_add_watch", unimplementedFunc), + /* 153 */ SyscallDesc("poll", unimplementedFunc), + /* 154 */ SyscallDesc("getdents64", unimplementedFunc), + /* 155 */ SyscallDesc("fcntl64", unimplementedFunc), + /* 156 */ SyscallDesc("inotify_rm_watch", unimplementedFunc), + /* 157 */ SyscallDesc("statfs", unimplementedFunc), + /* 158 */ SyscallDesc("fstatfs", unimplementedFunc), + /* 159 */ SyscallDesc("umount", unimplementedFunc), + /* 160 */ SyscallDesc("sched_set_affinity", unimplementedFunc), + /* 161 */ SyscallDesc("sched_get_affinity", unimplementedFunc), + /* 162 */ SyscallDesc("getdomainname", unimplementedFunc), + /* 163 */ SyscallDesc("setdomainname", unimplementedFunc), + /* 164 */ SyscallDesc("utrap_install", unimplementedFunc), + /* 165 */ SyscallDesc("quotactl", unimplementedFunc), + /* 166 */ SyscallDesc("set_tid_address", unimplementedFunc), + /* 167 */ SyscallDesc("mount", unimplementedFunc), + /* 168 */ SyscallDesc("ustat", unimplementedFunc), + /* 169 */ SyscallDesc("setxattr", unimplementedFunc), + /* 170 */ SyscallDesc("lsetxattr", unimplementedFunc), + /* 171 */ SyscallDesc("fsetxattr", unimplementedFunc), + /* 172 */ SyscallDesc("getxattr", unimplementedFunc), + /* 173 */ SyscallDesc("lgetxattr", unimplementedFunc), + /* 174 */ SyscallDesc("getdents", unimplementedFunc), + /* 175 */ SyscallDesc("setsid", unimplementedFunc), + /* 176 */ SyscallDesc("fchdir", unimplementedFunc), + /* 177 */ SyscallDesc("fgetxattr", unimplementedFunc), + /* 178 */ SyscallDesc("listxattr", unimplementedFunc), + /* 179 */ SyscallDesc("llistxattr", unimplementedFunc), + /* 180 */ SyscallDesc("flistxattr", unimplementedFunc), + /* 181 */ SyscallDesc("removexattr", unimplementedFunc), + /* 182 */ SyscallDesc("lremovexattr", unimplementedFunc), + /* 183 */ SyscallDesc("sigpending", unimplementedFunc), + /* 184 */ SyscallDesc("query_module", unimplementedFunc), + /* 185 */ SyscallDesc("setpgid", unimplementedFunc), + /* 186 */ SyscallDesc("fremovexattr", unimplementedFunc), + /* 187 */ SyscallDesc("tkill", unimplementedFunc), + /* 188 */ SyscallDesc("exit_group", exitFunc), + /* 189 */ SyscallDesc("uname", unameFunc), + /* 190 */ SyscallDesc("init_module", unimplementedFunc), + /* 191 */ SyscallDesc("personality", unimplementedFunc), + /* 192 */ SyscallDesc("remap_file_pages", unimplementedFunc), + /* 193 */ SyscallDesc("epoll_create", unimplementedFunc), + /* 194 */ SyscallDesc("epoll_ctl", unimplementedFunc), + /* 195 */ SyscallDesc("epoll_wait", unimplementedFunc), + /* 196 */ SyscallDesc("ioprio_set", unimplementedFunc), + /* 197 */ SyscallDesc("getppid", getppidFunc), + /* 198 */ SyscallDesc("sigaction", unimplementedFunc), + /* 199 */ SyscallDesc("sgetmask", unimplementedFunc), + /* 200 */ SyscallDesc("ssetmask", unimplementedFunc), + /* 201 */ SyscallDesc("sigsuspend", unimplementedFunc), + /* 202 */ SyscallDesc("oldlstat", unimplementedFunc), + /* 203 */ SyscallDesc("uselib", unimplementedFunc), + /* 204 */ SyscallDesc("readdir", unimplementedFunc), + /* 205 */ SyscallDesc("readahead", unimplementedFunc), + /* 206 */ SyscallDesc("socketcall", unimplementedFunc), + /* 207 */ SyscallDesc("syslog", unimplementedFunc), + /* 208 */ SyscallDesc("lookup_dcookie", unimplementedFunc), + /* 209 */ SyscallDesc("fadvise64", unimplementedFunc), + /* 210 */ SyscallDesc("fadvise64_64", unimplementedFunc), + /* 211 */ SyscallDesc("tgkill", unimplementedFunc), + /* 212 */ SyscallDesc("waitpid", unimplementedFunc), + /* 213 */ SyscallDesc("swapoff", unimplementedFunc), + /* 214 */ SyscallDesc("sysinfo", unimplementedFunc), + /* 215 */ SyscallDesc("ipc", unimplementedFunc), + /* 216 */ SyscallDesc("sigreturn", unimplementedFunc), + /* 217 */ SyscallDesc("clone", unimplementedFunc), + /* 218 */ SyscallDesc("ioprio_get", unimplementedFunc), + /* 219 */ SyscallDesc("adjtimex", unimplementedFunc), + /* 220 */ SyscallDesc("sigprocmask", unimplementedFunc), + /* 221 */ SyscallDesc("create_module", unimplementedFunc), + /* 222 */ SyscallDesc("delete_module", unimplementedFunc), + /* 223 */ SyscallDesc("get_kernel_syms", unimplementedFunc), + /* 224 */ SyscallDesc("getpgid", unimplementedFunc), + /* 225 */ SyscallDesc("bdflush", unimplementedFunc), + /* 226 */ SyscallDesc("sysfs", unimplementedFunc), + /* 227 */ SyscallDesc("afs_syscall", unimplementedFunc), + /* 228 */ SyscallDesc("setfsuid", unimplementedFunc), + /* 229 */ SyscallDesc("setfsgid", unimplementedFunc), + /* 230 */ SyscallDesc("_newselect", unimplementedFunc), + /* 231 */ SyscallDesc("time", unimplementedFunc), + /* 232 */ SyscallDesc("oldstat", unimplementedFunc), + /* 233 */ SyscallDesc("stime", unimplementedFunc), + /* 234 */ SyscallDesc("statfs64", unimplementedFunc), + /* 235 */ SyscallDesc("fstatfs64", unimplementedFunc), + /* 236 */ SyscallDesc("_llseek", unimplementedFunc), + /* 237 */ SyscallDesc("mlock", unimplementedFunc), + /* 238 */ SyscallDesc("munlock", unimplementedFunc), + /* 239 */ SyscallDesc("mlockall", unimplementedFunc), + /* 240 */ SyscallDesc("munlockall", unimplementedFunc), + /* 241 */ SyscallDesc("sched_setparam", unimplementedFunc), + /* 242 */ SyscallDesc("sched_getparam", unimplementedFunc), + /* 243 */ SyscallDesc("sched_setscheduler", unimplementedFunc), + /* 244 */ SyscallDesc("sched_getscheduler", unimplementedFunc), + /* 245 */ SyscallDesc("sched_yield", unimplementedFunc), + /* 246 */ SyscallDesc("sched_get_priority_max", unimplementedFunc), + /* 247 */ SyscallDesc("sched_get_priority_min", unimplementedFunc), + /* 248 */ SyscallDesc("sched_rr_get_interval", unimplementedFunc), + /* 249 */ SyscallDesc("nanosleep", unimplementedFunc), + /* 250 */ SyscallDesc("mremap", unimplementedFunc), + /* 251 */ SyscallDesc("_sysctl", unimplementedFunc), + /* 252 */ SyscallDesc("getsid", unimplementedFunc), + /* 253 */ SyscallDesc("fdatasync", unimplementedFunc), + /* 254 */ SyscallDesc("nfsservctl", unimplementedFunc), + /* 255 */ SyscallDesc("aplib", unimplementedFunc), + /* 256 */ SyscallDesc("clock_settime", unimplementedFunc), + /* 257 */ SyscallDesc("clock_gettime", unimplementedFunc), + /* 258 */ SyscallDesc("clock_getres", unimplementedFunc), + /* 259 */ SyscallDesc("clock_nanosleep", unimplementedFunc), + /* 260 */ SyscallDesc("sched_getaffinity", unimplementedFunc), + /* 261 */ SyscallDesc("sched_setaffinity", unimplementedFunc), + /* 262 */ SyscallDesc("timer_settime", unimplementedFunc), + /* 263 */ SyscallDesc("timer_gettime", unimplementedFunc), + /* 264 */ SyscallDesc("timer_getoverrun", unimplementedFunc), + /* 265 */ SyscallDesc("timer_delete", unimplementedFunc), + /* 266 */ SyscallDesc("timer_create", unimplementedFunc), + /* 267 */ SyscallDesc("vserver", unimplementedFunc), + /* 268 */ SyscallDesc("io_setup", unimplementedFunc), + /* 269 */ SyscallDesc("io_destroy", unimplementedFunc), + /* 270 */ SyscallDesc("io_submit", unimplementedFunc), + /* 271 */ SyscallDesc("io_cancel", unimplementedFunc), + /* 272 */ SyscallDesc("io_getevents", unimplementedFunc), + /* 273 */ SyscallDesc("mq_open", unimplementedFunc), + /* 274 */ SyscallDesc("mq_unlink", unimplementedFunc), + /* 275 */ SyscallDesc("mq_timedsend", unimplementedFunc), + /* 276 */ SyscallDesc("mq_timedreceive", unimplementedFunc), + /* 277 */ SyscallDesc("mq_notify", unimplementedFunc), + /* 278 */ SyscallDesc("mq_getsetattr", unimplementedFunc), + /* 279 */ SyscallDesc("waitid", unimplementedFunc), + /* 280 */ SyscallDesc("sys_setaltroot", unimplementedFunc), + /* 281 */ SyscallDesc("add_key", unimplementedFunc), + /* 282 */ SyscallDesc("request_key", unimplementedFunc), + /* 283 */ SyscallDesc("keyctl", unimplementedFunc) +}; + +SparcLinuxProcess::SparcLinuxProcess(const std::string &name, + ObjectFile *objFile, + System * system, + int stdin_fd, + int stdout_fd, + int stderr_fd, + std::vector<std::string> &argv, + std::vector<std::string> &envp) + : SparcLiveProcess(name, objFile, system, + stdin_fd, stdout_fd, stderr_fd, argv, envp), + Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc)) +{ + // The sparc syscall table must be <= 284 entries because that is all there + // is space for. + assert(Num_Syscall_Descs <= 284); +} + + + +SyscallDesc* +SparcLinuxProcess::getDesc(int callnum) +{ + if (callnum < 0 || callnum > Num_Syscall_Descs) + return NULL; + return &syscallDescs[callnum]; +} diff --git a/src/arch/sparc/linux/process.hh b/src/arch/sparc/linux/process.hh new file mode 100644 index 000000000..f4819ba84 --- /dev/null +++ b/src/arch/sparc/linux/process.hh @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2003-2004 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 + */ + +#ifndef __SPARC_LINUX_PROCESS_HH__ +#define __SPARC_LINUX_PROCESS_HH__ + +#include "arch/sparc/linux/linux.hh" +#include "arch/sparc/process.hh" +#include "sim/process.hh" + +namespace SparcISA { + +/// A process with emulated SPARC/Linux syscalls. +class SparcLinuxProcess : public SparcLiveProcess +{ + public: + /// Constructor. + SparcLinuxProcess(const std::string &name, + ObjectFile *objFile, + System * system, + int stdin_fd, int stdout_fd, int stderr_fd, + std::vector<std::string> &argv, + std::vector<std::string> &envp); + + virtual SyscallDesc* getDesc(int callnum); + + /// The target system's hostname. + static const char *hostname; + + /// Array of syscall descriptors, indexed by call number. + static SyscallDesc syscallDescs[]; + + const int Num_Syscall_Descs; +}; + +SyscallReturn getresuidFunc(SyscallDesc *desc, int num, + Process *p, ThreadContext *tc); + +} // namespace SparcISA +#endif // __ALPHA_LINUX_PROCESS_HH__ diff --git a/src/arch/sparc/process.cc b/src/arch/sparc/process.cc new file mode 100644 index 000000000..633c202ca --- /dev/null +++ b/src/arch/sparc/process.cc @@ -0,0 +1,382 @@ +/* + * Copyright (c) 2003-2004 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 + * Ali Saidi + */ + +#include "arch/sparc/isa_traits.hh" +#include "arch/sparc/process.hh" +#include "arch/sparc/linux/process.hh" +#include "arch/sparc/solaris/process.hh" +#include "base/loader/object_file.hh" +#include "base/misc.hh" +#include "cpu/thread_context.hh" +#include "mem/page_table.hh" +#include "mem/translating_port.hh" +#include "sim/builder.hh" +#include "sim/system.hh" + +using namespace std; +using namespace SparcISA; + +SparcLiveProcess * +SparcLiveProcess::create(const std::string &nm, System *system, int stdin_fd, + int stdout_fd, int stderr_fd, std::string executable, + std::vector<std::string> &argv, std::vector<std::string> &envp) +{ + SparcLiveProcess *process = NULL; + + ObjectFile *objFile = createObjectFile(executable); + if (objFile == NULL) { + fatal("Can't load object file %s", executable); + } + + + if (objFile->getArch() != ObjectFile::SPARC) + fatal("Object file with arch %x does not match architecture %x.", + objFile->getArch(), ObjectFile::SPARC); + switch (objFile->getOpSys()) { + case ObjectFile::Linux: + process = new SparcLinuxProcess(nm, objFile, system, + stdin_fd, stdout_fd, stderr_fd, + argv, envp); + break; + + + case ObjectFile::Solaris: + process = new SparcSolarisProcess(nm, objFile, system, + stdin_fd, stdout_fd, stderr_fd, + argv, envp); + break; + default: + fatal("Unknown/unsupported operating system."); + } + + if (process == NULL) + fatal("Unknown error creating process object."); + return process; +} + +SparcLiveProcess::SparcLiveProcess(const std::string &nm, ObjectFile *objFile, + System *_system, int stdin_fd, int stdout_fd, int stderr_fd, + std::vector<std::string> &argv, std::vector<std::string> &envp) + : LiveProcess(nm, objFile, _system, stdin_fd, stdout_fd, stderr_fd, + argv, envp) +{ + + // XXX all the below need to be updated for SPARC - Ali + brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize(); + brk_point = roundUp(brk_point, VMPageSize); + + // Set up stack. On SPARC Linux, stack goes from the top of memory + // downward, less the hole for the kernel address space. + stack_base = ((Addr)0x80000000000ULL); + + // Set up region for mmaps. Tru64 seems to start just above 0 and + // grow up from there. + mmap_start = mmap_end = 0x800000; + + // Set pointer for next thread stack. Reserve 8M for main stack. + next_thread_stack_base = stack_base - (8 * 1024 * 1024); +} + +void +SparcLiveProcess::startup() +{ + argsInit(MachineBytes, VMPageSize); + + //From the SPARC ABI + + //The process runs in user mode + threadContexts[0]->setMiscRegWithEffect(MISCREG_PSTATE, 0x02); + + //Setup default FP state + threadContexts[0]->setMiscReg(MISCREG_FSR, 0); + + threadContexts[0]->setMiscReg(MISCREG_TICK, 0); + // + /* + * Register window management registers + */ + + //No windows contain info from other programs + threadContexts[0]->setMiscRegWithEffect(MISCREG_OTHERWIN, 0); + //There are no windows to pop + threadContexts[0]->setMiscRegWithEffect(MISCREG_CANRESTORE, 0); + //All windows are available to save into + threadContexts[0]->setMiscRegWithEffect(MISCREG_CANSAVE, NWindows - 2); + //All windows are "clean" + threadContexts[0]->setMiscRegWithEffect(MISCREG_CLEANWIN, NWindows); + //Start with register window 0 + threadContexts[0]->setMiscRegWithEffect(MISCREG_CWP, 0); +} + +m5_auxv_t buildAuxVect(int64_t type, int64_t val) +{ + m5_auxv_t result; + result.a_type = TheISA::htog(type); + result.a_val = TheISA::htog(val); + return result; +} + +void +SparcLiveProcess::argsInit(int intSize, int pageSize) +{ + Process::startup(); + + Addr alignmentMask = ~(intSize - 1); + + // load object file into target memory + objFile->loadSections(initVirtMem); + + //These are the auxilliary vector types + enum auxTypes + { + SPARC_AT_HWCAP = 16, + SPARC_AT_PAGESZ = 6, + SPARC_AT_CLKTCK = 17, + SPARC_AT_PHDR = 3, + SPARC_AT_PHENT = 4, + SPARC_AT_PHNUM = 5, + SPARC_AT_BASE = 7, + SPARC_AT_FLAGS = 8, + SPARC_AT_ENTRY = 9, + SPARC_AT_UID = 11, + SPARC_AT_EUID = 12, + SPARC_AT_GID = 13, + SPARC_AT_EGID = 14 + }; + + enum hardwareCaps + { + M5_HWCAP_SPARC_FLUSH = 1, + M5_HWCAP_SPARC_STBAR = 2, + M5_HWCAP_SPARC_SWAP = 4, + M5_HWCAP_SPARC_MULDIV = 8, + M5_HWCAP_SPARC_V9 = 16, + //This one should technically only be set + //if there is a cheetah or cheetah_plus tlb, + //but we'll use it all the time + M5_HWCAP_SPARC_ULTRA3 = 32 + }; + + const int64_t hwcap = + M5_HWCAP_SPARC_FLUSH | + M5_HWCAP_SPARC_STBAR | + M5_HWCAP_SPARC_SWAP | + M5_HWCAP_SPARC_MULDIV | + M5_HWCAP_SPARC_V9 | + M5_HWCAP_SPARC_ULTRA3; + + //Setup the auxilliary vectors. These will already have + //endian conversion. + auxv.push_back(buildAuxVect(SPARC_AT_EGID, 100)); + auxv.push_back(buildAuxVect(SPARC_AT_GID, 100)); + auxv.push_back(buildAuxVect(SPARC_AT_EUID, 100)); + auxv.push_back(buildAuxVect(SPARC_AT_UID, 100)); + //This would work, but the entry point is a protected member + //auxv.push_back(buildAuxVect(SPARC_AT_ENTRY, objFile->entry)); + auxv.push_back(buildAuxVect(SPARC_AT_FLAGS, 0)); + //This is the address of the elf "interpreter", which I don't + //think we currently set up. It should be set to 0 (I think) + //auxv.push_back(buildAuxVect(SPARC_AT_BASE, 0)); + //This is the number of headers which were in the original elf + //file. This information isn't avaibale by this point. + //auxv.push_back(buildAuxVect(SPARC_AT_PHNUM, 3)); + //This is the size of a program header entry. This isn't easy + //to compute here. + //auxv.push_back(buildAuxVect(SPARC_AT_PHENT, blah)); + //This is should be set to load_addr (whatever that is) + + //e_phoff. I think it's a pointer to the program headers. + //auxv.push_back(buildAuxVect(SPARC_AT_PHDR, blah)); + //This should be easy to get right, but I won't set it for now + //auxv.push_back(buildAuxVect(SPARC_AT_CLKTCK, blah)); + auxv.push_back(buildAuxVect(SPARC_AT_PAGESZ, SparcISA::VMPageSize)); + auxv.push_back(buildAuxVect(SPARC_AT_HWCAP, hwcap)); + + //Figure out how big the initial stack needs to be + + //Each auxilliary vector is two 8 byte words + int aux_data_size = 2 * intSize * auxv.size(); + int env_data_size = 0; + for (int i = 0; i < envp.size(); ++i) { + env_data_size += envp[i].size() + 1; + } + int arg_data_size = 0; + for (int i = 0; i < argv.size(); ++i) { + arg_data_size += argv[i].size() + 1; + } + + int aux_array_size = intSize * 2 * (auxv.size() + 1); + + int argv_array_size = intSize * (argv.size() + 1); + int envp_array_size = intSize * (envp.size() + 1); + + int argc_size = intSize; + int window_save_size = intSize * 16; + + int info_block_size = + (aux_data_size + + env_data_size + + arg_data_size + + ~alignmentMask) & alignmentMask; + + int info_block_padding = + info_block_size - + aux_data_size - + env_data_size - + arg_data_size; + + int space_needed = + info_block_size + + aux_array_size + + envp_array_size + + argv_array_size + + argc_size + + window_save_size; + + stack_min = stack_base - space_needed; + stack_min &= alignmentMask; + stack_size = stack_base - stack_min; + + // map memory + pTable->allocate(roundDown(stack_min, pageSize), + roundUp(stack_size, pageSize)); + + // map out initial stack contents + Addr aux_data_base = stack_base - aux_data_size - info_block_padding; + Addr env_data_base = aux_data_base - env_data_size; + Addr arg_data_base = env_data_base - arg_data_size; + Addr auxv_array_base = arg_data_base - aux_array_size; + Addr envp_array_base = auxv_array_base - envp_array_size; + Addr argv_array_base = envp_array_base - argv_array_size; + Addr argc_base = argv_array_base - argc_size; + Addr window_save_base = argc_base - window_save_size; + + DPRINTF(Sparc, "The addresses of items on the initial stack:\n"); + DPRINTF(Sparc, "0x%x - aux data\n", aux_data_base); + DPRINTF(Sparc, "0x%x - env data\n", env_data_base); + DPRINTF(Sparc, "0x%x - arg data\n", arg_data_base); + DPRINTF(Sparc, "0x%x - auxv array\n", auxv_array_base); + DPRINTF(Sparc, "0x%x - envp array\n", envp_array_base); + DPRINTF(Sparc, "0x%x - argv array\n", argv_array_base); + DPRINTF(Sparc, "0x%x - argc \n", argc_base); + DPRINTF(Sparc, "0x%x - window save\n", window_save_base); + DPRINTF(Sparc, "0x%x - stack min\n", stack_min); + + // write contents to stack + uint64_t argc = argv.size(); + uint64_t guestArgc = TheISA::htog(argc); + + //Copy the aux stuff + for(int x = 0; x < auxv.size(); x++) + { + initVirtMem->writeBlob(auxv_array_base + x * 2 * intSize, + (uint8_t*)&(auxv[x].a_type), intSize); + initVirtMem->writeBlob(auxv_array_base + (x * 2 + 1) * intSize, + (uint8_t*)&(auxv[x].a_val), intSize); + } + //Write out the terminating zeroed auxilliary vector + const uint64_t zero = 0; + initVirtMem->writeBlob(auxv_array_base + 2 * intSize * auxv.size(), + (uint8_t*)&zero, 2 * intSize); + + copyStringArray(envp, envp_array_base, env_data_base, initVirtMem); + copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem); + + initVirtMem->writeBlob(argc_base, (uint8_t*)&guestArgc, intSize); + + threadContexts[0]->setIntReg(ArgumentReg0, argc); + threadContexts[0]->setIntReg(ArgumentReg1, argv_array_base); + threadContexts[0]->setIntReg(StackPointerReg, stack_min - StackBias); + + Addr prog_entry = objFile->entryPoint(); + threadContexts[0]->setPC(prog_entry); + threadContexts[0]->setNextPC(prog_entry + sizeof(MachInst)); + threadContexts[0]->setNextNPC(prog_entry + (2 * sizeof(MachInst))); + +// num_processes++; +} + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(SparcLiveProcess) + + VectorParam<string> cmd; + Param<string> executable; + Param<string> input; + Param<string> output; + VectorParam<string> env; + SimObjectParam<System *> system; + +END_DECLARE_SIM_OBJECT_PARAMS(SparcLiveProcess) + + +BEGIN_INIT_SIM_OBJECT_PARAMS(SparcLiveProcess) + + INIT_PARAM(cmd, "command line (executable plus arguments)"), + INIT_PARAM(executable, "executable (overrides cmd[0] if set)"), + INIT_PARAM(input, "filename for stdin (dflt: use sim stdin)"), + INIT_PARAM(output, "filename for stdout/stderr (dflt: use sim stdout)"), + INIT_PARAM(env, "environment settings"), + INIT_PARAM(system, "system") + +END_INIT_SIM_OBJECT_PARAMS(SparcLiveProcess) + + +CREATE_SIM_OBJECT(SparcLiveProcess) +{ + string in = input; + string out = output; + + // initialize file descriptors to default: same as simulator + int stdin_fd, stdout_fd, stderr_fd; + + if (in == "stdin" || in == "cin") + stdin_fd = STDIN_FILENO; + else + stdin_fd = Process::openInputFile(input); + + if (out == "stdout" || out == "cout") + stdout_fd = STDOUT_FILENO; + else if (out == "stderr" || out == "cerr") + stdout_fd = STDERR_FILENO; + else + stdout_fd = Process::openOutputFile(out); + + stderr_fd = (stdout_fd != STDOUT_FILENO) ? stdout_fd : STDERR_FILENO; + + return SparcLiveProcess::create(getInstanceName(), system, + stdin_fd, stdout_fd, stderr_fd, + (string)executable == "" ? cmd[0] : executable, + cmd, env); +} + + +REGISTER_SIM_OBJECT("SparcLiveProcess", SparcLiveProcess) + + diff --git a/src/arch/sparc/process.hh b/src/arch/sparc/process.hh new file mode 100644 index 000000000..db5e64352 --- /dev/null +++ b/src/arch/sparc/process.hh @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2003-2004 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 + * Ali Saidi + */ + +#ifndef __SPARC_PROCESS_HH__ +#define __SPARC_PROCESS_HH__ + +#include <string> +#include <vector> +#include "sim/process.hh" + +class ObjectFile; +class System; + +typedef struct +{ + int64_t a_type; + union { + int64_t a_val; + Addr a_ptr; + Addr a_fcn; + }; +} m5_auxv_t; + +class SparcLiveProcess : public LiveProcess +{ + protected: + + static const Addr StackBias = 2047; + + std::vector<m5_auxv_t> auxv; + + SparcLiveProcess(const std::string &nm, ObjectFile *objFile, + System *_system, int stdin_fd, int stdout_fd, int stderr_fd, + std::vector<std::string> &argv, + std::vector<std::string> &envp); + + void startup(); + + public: + // this function is used to create the LiveProcess object, since + // we can't tell which subclass of LiveProcess to use until we + // open and look at the object file. + static SparcLiveProcess *create(const std::string &nm, + System *_system, + int stdin_fd, int stdout_fd, int stderr_fd, + std::string executable, + std::vector<std::string> &argv, + std::vector<std::string> &envp); + + void argsInit(int intSize, int pageSize); + +}; + +#endif // __SPARC_PROCESS_HH__ diff --git a/src/arch/sparc/regfile.hh b/src/arch/sparc/regfile.hh new file mode 100644 index 000000000..cbeb3c7b9 --- /dev/null +++ b/src/arch/sparc/regfile.hh @@ -0,0 +1,872 @@ +/* + * Copyright (c) 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: Gabe Black + * Ali Saidi + */ + +#ifndef __ARCH_SPARC_REGFILE_HH__ +#define __ARCH_SPARC_REGFILE_HH__ + +#include "arch/sparc/exceptions.hh" +#include "arch/sparc/faults.hh" +#include "base/trace.hh" +#include "sim/byteswap.hh" +#include "cpu/cpuevent.hh" +#include "sim/host.hh" + +class Checkpoint; + +namespace SparcISA +{ + + typedef uint8_t RegIndex; + + // MAXTL - maximum trap level + const int MaxPTL = 2; + const int MaxTL = 6; + const int MaxGL = 3; + const int MaxPGL = 2; + + // NWINDOWS - number of register windows, can be 3 to 32 + const int NWindows = 32; + + + const int AsrStart = 0; + const int PrStart = 32; + const int HprStart = 64; + const int MiscStart = 96; + + const uint64_t Bit64 = (1ULL << 63); + + class IntRegFile + { + protected: + static const int FrameOffsetBits = 3; + static const int FrameNumBits = 2; + + static const int RegsPerFrame = 1 << FrameOffsetBits; + static const int FrameNumMask = + (FrameNumBits == sizeof(int)) ? + (unsigned int)(-1) : + (1 << FrameNumBits) - 1; + static const int FrameOffsetMask = + (FrameOffsetBits == sizeof(int)) ? + (unsigned int)(-1) : + (1 << FrameOffsetBits) - 1; + + IntReg regGlobals[MaxGL][RegsPerFrame]; + IntReg regSegments[2 * NWindows][RegsPerFrame]; + + enum regFrame {Globals, Outputs, Locals, Inputs, NumFrames}; + + IntReg * regView[NumFrames]; + + static const int RegGlobalOffset = 0; + static const int FrameOffset = MaxGL * RegsPerFrame; + int offset[NumFrames]; + + public: + + int flattenIndex(int reg) + { + int flatIndex = offset[reg >> FrameOffsetBits] + | (reg & FrameOffsetMask); + DPRINTF(Sparc, "Flattened index %d into %d.\n", reg, flatIndex); + return flatIndex; + } + + void clear() + { + int x; + for (x = 0; x < MaxGL; x++) + memset(regGlobals[x], 0, sizeof(regGlobals[x])); + for(int x = 0; x < 2 * NWindows; x++) + bzero(regSegments[x], sizeof(regSegments[x])); + } + + IntRegFile() + { + offset[Globals] = 0; + regView[Globals] = regGlobals[0]; + setCWP(0); + clear(); + } + + IntReg readReg(int intReg) + { + IntReg val = + regView[intReg >> FrameOffsetBits][intReg & FrameOffsetMask]; + DPRINTF(Sparc, "Read register %d = 0x%x\n", intReg, val); + return val; + } + + Fault setReg(int intReg, const IntReg &val) + { + if(intReg) + DPRINTF(Sparc, "Wrote register %d = 0x%x\n", intReg, val); + regView[intReg >> FrameOffsetBits][intReg & FrameOffsetMask] = val; + return NoFault; + } + + //This doesn't effect the actual CWP register. + //It's purpose is to adjust the view of the register file + //to what it would be if CWP = cwp. + void setCWP(int cwp) + { + int index = ((NWindows - cwp) % NWindows) * 2; + offset[Outputs] = FrameOffset + (index * RegsPerFrame); + offset[Locals] = FrameOffset + ((index+1) * RegsPerFrame); + offset[Inputs] = FrameOffset + + (((index+2) % (NWindows * 2)) * RegsPerFrame); + regView[Outputs] = regSegments[index]; + regView[Locals] = regSegments[index+1]; + regView[Inputs] = regSegments[(index+2) % (NWindows * 2)]; + + DPRINTF(Sparc, "Changed the CWP value to %d\n", cwp); + } + + void setGlobals(int gl) + { + + DPRINTF(Sparc, "Now using %d globals", gl); + + regView[Globals] = regGlobals[gl]; + offset[Globals] = RegGlobalOffset + gl * RegsPerFrame; + } + + void serialize(std::ostream &os); + + void unserialize(Checkpoint *cp, const std::string §ion); + }; + + typedef float float32_t; + typedef double float64_t; + //FIXME long double refers to a 10 byte float, rather than a + //16 byte float as required. This data type may have to be emulated. + typedef double float128_t; + + class FloatRegFile + { + public: + static const int SingleWidth = 32; + static const int DoubleWidth = 64; + static const int QuadWidth = 128; + + protected: + + //Since the floating point registers overlap each other, + //A generic storage space is used. The float to be returned is + //pulled from the appropriate section of this region. + char regSpace[SingleWidth / 8 * NumFloatRegs]; + + public: + + void clear() + { + bzero(regSpace, sizeof(regSpace)); + } + + FloatReg readReg(int floatReg, int width) + { + //In each of these cases, we have to copy the value into a temporary + //variable. This is because we may otherwise try to access an + //unaligned portion of memory. + switch(width) + { + case SingleWidth: + float32_t result32; + memcpy(&result32, regSpace + 4 * floatReg, width); + return htog(result32); + case DoubleWidth: + float64_t result64; + memcpy(&result64, regSpace + 4 * floatReg, width); + return htog(result64); + case QuadWidth: + float128_t result128; + memcpy(&result128, regSpace + 4 * floatReg, width); + return htog(result128); + default: + panic("Attempted to read a %d bit floating point register!", width); + } + } + + FloatRegBits readRegBits(int floatReg, int width) + { + //In each of these cases, we have to copy the value into a temporary + //variable. This is because we may otherwise try to access an + //unaligned portion of memory. + switch(width) + { + case SingleWidth: + uint32_t result32; + memcpy(&result32, regSpace + 4 * floatReg, width); + return htog(result32); + case DoubleWidth: + uint64_t result64; + memcpy(&result64, regSpace + 4 * floatReg, width); + return htog(result64); + case QuadWidth: + uint64_t result128; + memcpy(&result128, regSpace + 4 * floatReg, width); + return htog(result128); + default: + panic("Attempted to read a %d bit floating point register!", width); + } + } + + Fault setReg(int floatReg, const FloatReg &val, int width) + { + //In each of these cases, we have to copy the value into a temporary + //variable. This is because we may otherwise try to access an + //unaligned portion of memory. + + uint32_t result32; + uint64_t result64; + switch(width) + { + case SingleWidth: + result32 = gtoh((uint32_t)val); + memcpy(regSpace + 4 * floatReg, &result32, width); + break; + case DoubleWidth: + result64 = gtoh((uint64_t)val); + memcpy(regSpace + 4 * floatReg, &result64, width); + break; + case QuadWidth: + panic("Quad width FP not implemented."); + break; + default: + panic("Attempted to read a %d bit floating point register!", width); + } + return NoFault; + } + + Fault setRegBits(int floatReg, const FloatRegBits &val, int width) + { + //In each of these cases, we have to copy the value into a temporary + //variable. This is because we may otherwise try to access an + //unaligned portion of memory. + uint32_t result32; + uint64_t result64; + switch(width) + { + case SingleWidth: + result32 = gtoh((uint32_t)val); + memcpy(regSpace + 4 * floatReg, &result32, width); + break; + case DoubleWidth: + result64 = gtoh((uint64_t)val); + memcpy(regSpace + 4 * floatReg, &result64, width); + break; + case QuadWidth: + panic("Quad width FP not implemented."); + break; + default: + panic("Attempted to read a %d bit floating point register!", width); + } + return NoFault; + } + + void serialize(std::ostream &os); + + void unserialize(Checkpoint *cp, const std::string §ion); + }; + + enum MiscRegIndex + { + /** Ancillary State Registers */ + MISCREG_Y = AsrStart + 0, + MISCREG_CCR = AsrStart + 2, + MISCREG_ASI = AsrStart + 3, + MISCREG_TICK = AsrStart + 4, + MISCREG_PC = AsrStart + 5, + MISCREG_FPRS = AsrStart + 6, + MISCREG_PCR = AsrStart + 16, + MISCREG_PIC = AsrStart + 17, + MISCREG_GSR = AsrStart + 19, + MISCREG_SOFTINT_SET = AsrStart + 20, + MISCREG_SOFTINT_CLR = AsrStart + 21, + MISCREG_SOFTINT = AsrStart + 22, + MISCREG_TICK_CMPR = AsrStart + 23, + MISCREG_STICK = AsrStart + 24, + MISCREG_STICK_CMPR = AsrStart + 25, + + /** Privilged Registers */ + MISCREG_TPC = PrStart + 0, + MISCREG_TNPC = PrStart + 1, + MISCREG_TSTATE = PrStart + 2, + MISCREG_TT = PrStart + 3, + MISCREG_PRIVTICK = PrStart + 4, + MISCREG_TBA = PrStart + 5, + MISCREG_PSTATE = PrStart + 6, + MISCREG_TL = PrStart + 7, + MISCREG_PIL = PrStart + 8, + MISCREG_CWP = PrStart + 9, + MISCREG_CANSAVE = PrStart + 10, + MISCREG_CANRESTORE = PrStart + 11, + MISCREG_CLEANWIN = PrStart + 12, + MISCREG_OTHERWIN = PrStart + 13, + MISCREG_WSTATE = PrStart + 14, + MISCREG_GL = PrStart + 16, + + /** Hyper privileged registers */ + MISCREG_HPSTATE = HprStart + 0, + MISCREG_HTSTATE = HprStart + 1, + MISCREG_HINTP = HprStart + 3, + MISCREG_HTBA = HprStart + 5, + MISCREG_HVER = HprStart + 6, + MISCREG_STRAND_STS_REG = HprStart + 16, + MISCREG_HSTICK_CMPR = HprStart + 31, + + /** Floating Point Status Register */ + MISCREG_FSR = MiscStart + 0 + + }; + + // The control registers, broken out into fields + class MiscRegFile + { + private: + + /* ASR Registers */ + union { + uint64_t y; // Y (used in obsolete multiplication) + struct { + uint64_t value:32; // The actual value stored in y + uint64_t :32; // reserved bits + } yFields; + }; + union { + uint8_t ccr; // Condition Code Register + struct { + union { + uint8_t icc:4; // 32-bit condition codes + struct { + uint8_t c:1; // Carry + uint8_t v:1; // Overflow + uint8_t z:1; // Zero + uint8_t n:1; // Negative + } iccFields; + }; + union { + uint8_t xcc:4; // 64-bit condition codes + struct { + uint8_t c:1; // Carry + uint8_t v:1; // Overflow + uint8_t z:1; // Zero + uint8_t n:1; // Negative + } xccFields; + }; + } ccrFields; + }; + uint8_t asi; // Address Space Identifier + union { + uint64_t tick; // Hardware clock-tick counter + struct { + int64_t counter:63; // Clock-tick count + uint64_t npt:1; // Non-priveleged trap + } tickFields; + }; + union { + uint8_t fprs; // Floating-Point Register State + struct { + uint8_t dl:1; // Dirty lower + uint8_t du:1; // Dirty upper + uint8_t fef:1; // FPRS enable floating-Point + } fprsFields; + }; + union { + uint64_t softint; + struct { + uint64_t tm:1; + uint64_t int_level:14; + uint64_t sm:1; + } softintFields; + }; + union { + uint64_t tick_cmpr; // Hardware tick compare registers + struct { + uint64_t tick_cmpr:63; // Clock-tick count + uint64_t int_dis:1; // Non-priveleged trap + } tick_cmprFields; + }; + union { + uint64_t stick; // Hardware clock-tick counter + struct { + int64_t :63; // Not used, storage in SparcSystem + uint64_t npt:1; // Non-priveleged trap + } stickFields; + }; + union { + uint64_t stick_cmpr; // Hardware tick compare registers + struct { + uint64_t tick_cmpr:63; // Clock-tick count + uint64_t int_dis:1; // Non-priveleged trap + } stick_cmprFields; + }; + + + /* Privileged Registers */ + uint64_t tpc[MaxTL]; // Trap Program Counter (value from + // previous trap level) + uint64_t tnpc[MaxTL]; // Trap Next Program Counter (value from + // previous trap level) + union { + uint64_t tstate[MaxTL]; // Trap State + struct { + //Values are from previous trap level + uint64_t cwp:5; // Current Window Pointer + uint64_t :3; // Reserved bits + uint64_t pstate:13; // Process State + uint64_t :3; // Reserved bits + uint64_t asi:8; // Address Space Identifier + uint64_t ccr:8; // Condition Code Register + uint64_t gl:8; // Global level + } tstateFields[MaxTL]; + }; + uint16_t tt[MaxTL]; // Trap Type (Type of trap which occured + // on the previous level) + uint64_t tba; // Trap Base Address + + union { + uint16_t pstate; // Process State Register + struct { + uint16_t :1; // reserved + uint16_t ie:1; // Interrupt enable + uint16_t priv:1; // Privelege mode + uint16_t am:1; // Address mask + uint16_t pef:1; // PSTATE enable floating-point + uint16_t :1; // reserved2 + uint16_t mm:2; // Memory Model + uint16_t tle:1; // Trap little-endian + uint16_t cle:1; // Current little-endian + } pstateFields; + }; + uint8_t tl; // Trap Level + uint8_t pil; // Process Interrupt Register + uint8_t cwp; // Current Window Pointer + uint8_t cansave; // Savable windows + uint8_t canrestore; // Restorable windows + uint8_t cleanwin; // Clean windows + uint8_t otherwin; // Other windows + union { + uint8_t wstate; // Window State + struct { + uint8_t normal:3; // Bits TT<4:2> are set to on a normal + // register window trap + uint8_t other:3; // Bits TT<4:2> are set to on an "otherwin" + // register window trap + } wstateFields; + }; + uint8_t gl; // Global level register + + + /** Hyperprivileged Registers */ + union { + uint64_t hpstate; // Hyperprivileged State Register + struct { + uint8_t tlz: 1; + uint8_t :1; + uint8_t hpriv:1; + uint8_t :2; + uint8_t red:1; + uint8_t :4; + uint8_t ibe:1; + uint8_t id:1; + } hpstateFields; + }; + + uint64_t htstate[MaxTL]; // Hyperprivileged Trap State Register + uint64_t hintp; + uint64_t htba; // Hyperprivileged Trap Base Address register + union { + uint64_t hstick_cmpr; // Hardware tick compare registers + struct { + uint64_t tick_cmpr:63; // Clock-tick count + uint64_t int_dis:1; // Non-priveleged trap + } hstick_cmprFields; + }; + + uint64_t strandStatusReg; // Per strand status register + + + /** Floating point misc registers. */ + union { + uint64_t fsr; // Floating-Point State Register + struct { + union { + uint64_t cexc:5; // Current excpetion + struct { + uint64_t nxc:1; // Inexact + uint64_t dzc:1; // Divide by zero + uint64_t ufc:1; // Underflow + uint64_t ofc:1; // Overflow + uint64_t nvc:1; // Invalid operand + } cexcFields; + }; + union { + uint64_t aexc:5; // Accrued exception + struct { + uint64_t nxc:1; // Inexact + uint64_t dzc:1; // Divide by zero + uint64_t ufc:1; // Underflow + uint64_t ofc:1; // Overflow + uint64_t nvc:1; // Invalid operand + } aexcFields; + }; + uint64_t fcc0:2; // Floating-Point condtion codes + uint64_t :1; // Reserved bits + uint64_t qne:1; // Deferred trap queue not empty + // with no queue, it should read 0 + uint64_t ftt:3; // Floating-Point trap type + uint64_t ver:3; // Version (of the FPU) + uint64_t :2; // Reserved bits + uint64_t ns:1; // Nonstandard floating point + union { + uint64_t tem:5; // Trap Enable Mask + struct { + uint64_t nxm:1; // Inexact + uint64_t dzm:1; // Divide by zero + uint64_t ufm:1; // Underflow + uint64_t ofm:1; // Overflow + uint64_t nvm:1; // Invalid operand + } temFields; + }; + uint64_t :2; // Reserved bits + uint64_t rd:2; // Rounding direction + uint64_t fcc1:2; // Floating-Point condition codes + uint64_t fcc2:2; // Floating-Point condition codes + uint64_t fcc3:2; // Floating-Point condition codes + uint64_t :26; // Reserved bits + } fsrFields; + }; + + // These need to check the int_dis field and if 0 then + // set appropriate bit in softint and checkinterrutps on the cpu +#if FULL_SYSTEM + /** Process a tick compare event and generate an interrupt on the cpu if + * appropriate. */ + void processTickCompare(ThreadContext *tc); + void processSTickCompare(ThreadContext *tc); + void processHSTickCompare(ThreadContext *tc); + + typedef CpuEventWrapper<MiscRegFile, + &MiscRegFile::processTickCompare> TickCompareEvent; + TickCompareEvent *tickCompare; + + typedef CpuEventWrapper<MiscRegFile, + &MiscRegFile::processSTickCompare> STickCompareEvent; + STickCompareEvent *sTickCompare; + + typedef CpuEventWrapper<MiscRegFile, + &MiscRegFile::processHSTickCompare> HSTickCompareEvent; + HSTickCompareEvent *hSTickCompare; + + /** Fullsystem only register version of ReadRegWithEffect() */ + MiscReg readFSRegWithEffect(int miscReg, Fault &fault, ThreadContext *tc); + /** Fullsystem only register version of SetRegWithEffect() */ + Fault setFSRegWithEffect(int miscReg, const MiscReg &val, + ThreadContext * tc); +#endif + public: + + void reset() + { + pstateFields.pef = 0; //No FPU + //pstateFields.pef = 1; //FPU +#if FULL_SYSTEM + //For SPARC, when a system is first started, there is a power + //on reset Trap which sets the processor into the following state. + //Bits that aren't set aren't defined on startup. + tl = MaxTL; + gl = MaxGL; + + tickFields.counter = 0; //The TICK register is unreadable bya + tickFields.npt = 1; //The TICK register is unreadable by by !priv + + softint = 0; // Clear all the soft interrupt bits + tick_cmprFields.int_dis = 1; // disable timer compare interrupts + tick_cmprFields.tick_cmpr = 0; // Reset to 0 for pretty printing + stickFields.npt = 1; //The TICK register is unreadable by by !priv + stick_cmprFields.int_dis = 1; // disable timer compare interrupts + stick_cmprFields.tick_cmpr = 0; // Reset to 0 for pretty printing + + + tt[tl] = power_on_reset; + pstate = 0; // fields 0 but pef + pstateFields.pef = 1; + + hpstate = 0; + hpstateFields.red = 1; + hpstateFields.hpriv = 1; + hpstateFields.tlz = 0; // this is a guess + + hintp = 0; // no interrupts pending + hstick_cmprFields.int_dis = 1; // disable timer compare interrupts + hstick_cmprFields.tick_cmpr = 0; // Reset to 0 for pretty printing + +#else +/* //This sets up the initial state of the processor for usermode processes + pstateFields.priv = 0; //Process runs in user mode + pstateFields.ie = 1; //Interrupts are enabled + fsrFields.rd = 0; //Round to nearest + fsrFields.tem = 0; //Floating point traps not enabled + fsrFields.ns = 0; //Non standard mode off + fsrFields.qne = 0; //Floating point queue is empty + fsrFields.aexc = 0; //No accrued exceptions + fsrFields.cexc = 0; //No current exceptions + + //Register window management registers + otherwin = 0; //No windows contain info from other programs + canrestore = 0; //There are no windows to pop + cansave = MaxTL - 2; //All windows are available to save into + cleanwin = MaxTL;*/ +#endif + } + + MiscRegFile() + { + reset(); + } + + /** read a value out of an either an SE or FS IPR. No checking is done + * about SE vs. FS as this is mostly used to copy the regfile. Thus more + * register are copied that are necessary for FS. However this prevents + * a bunch of ifdefs and is rarely called so is not performance + * criticial. */ + MiscReg readReg(int miscReg); + + /** Read a value from an IPR. Only the SE iprs are here and the rest + * are are readFSRegWithEffect (which is called by readRegWithEffect()). + * Checking is done for permission based on state bits in the miscreg + * file. */ + MiscReg readRegWithEffect(int miscReg, Fault &fault, ThreadContext *tc); + + /** write a value into an either an SE or FS IPR. No checking is done + * about SE vs. FS as this is mostly used to copy the regfile. Thus more + * register are copied that are necessary for FS. However this prevents + * a bunch of ifdefs and is rarely called so is not performance + * criticial.*/ + Fault setReg(int miscReg, const MiscReg &val); + + /** Write a value into an IPR. Only the SE iprs are here and the rest + * are are setFSRegWithEffect (which is called by setRegWithEffect()). + * Checking is done for permission based on state bits in the miscreg + * file. */ + Fault setRegWithEffect(int miscReg, + const MiscReg &val, ThreadContext * tc); + + void serialize(std::ostream & os); + + void unserialize(Checkpoint * cp, const std::string & section); + + void copyMiscRegs(ThreadContext * tc); + + bool isHyperPriv() { return hpstateFields.hpriv; } + bool isPriv() { return hpstateFields.hpriv || pstateFields.priv; } + bool isNonPriv() { return !isPriv(); } + }; + + typedef union + { + IntReg intreg; + FloatReg fpreg; + MiscReg ctrlreg; + } AnyReg; + + class RegFile + { + protected: + Addr pc; // Program Counter + Addr npc; // Next Program Counter + Addr nnpc; + + public: + Addr readPC() + { + return pc; + } + + void setPC(Addr val) + { + pc = val; + } + + Addr readNextPC() + { + return npc; + } + + void setNextPC(Addr val) + { + npc = val; + } + + Addr readNextNPC() + { + return nnpc; + } + + void setNextNPC(Addr val) + { + nnpc = val; + } + + protected: + IntRegFile intRegFile; // integer register file + FloatRegFile floatRegFile; // floating point register file + MiscRegFile miscRegFile; // control register file + + public: + + void clear() + { + intRegFile.clear(); + floatRegFile.clear(); + } + + int FlattenIntIndex(int reg) + { + return intRegFile.flattenIndex(reg); + } + + MiscReg readMiscReg(int miscReg) + { + return miscRegFile.readReg(miscReg); + } + + MiscReg readMiscRegWithEffect(int miscReg, + Fault &fault, ThreadContext *tc) + { + return miscRegFile.readRegWithEffect(miscReg, fault, tc); + } + + Fault setMiscReg(int miscReg, const MiscReg &val) + { + return miscRegFile.setReg(miscReg, val); + } + + Fault setMiscRegWithEffect(int miscReg, const MiscReg &val, + ThreadContext * tc) + { + return miscRegFile.setRegWithEffect(miscReg, val, tc); + } + + FloatReg readFloatReg(int floatReg, int width) + { + return floatRegFile.readReg(floatReg, width); + } + + FloatReg readFloatReg(int floatReg) + { + //Use the "natural" width of a single float + return floatRegFile.readReg(floatReg, FloatRegFile::SingleWidth); + } + + FloatRegBits readFloatRegBits(int floatReg, int width) + { + return floatRegFile.readRegBits(floatReg, width); + } + + FloatRegBits readFloatRegBits(int floatReg) + { + //Use the "natural" width of a single float + return floatRegFile.readRegBits(floatReg, + FloatRegFile::SingleWidth); + } + + Fault setFloatReg(int floatReg, const FloatReg &val, int width) + { + return floatRegFile.setReg(floatReg, val, width); + } + + Fault setFloatReg(int floatReg, const FloatReg &val) + { + //Use the "natural" width of a single float + return setFloatReg(floatReg, val, FloatRegFile::SingleWidth); + } + + Fault setFloatRegBits(int floatReg, const FloatRegBits &val, int width) + { + return floatRegFile.setRegBits(floatReg, val, width); + } + + Fault setFloatRegBits(int floatReg, const FloatRegBits &val) + { + //Use the "natural" width of a single float + return floatRegFile.setRegBits(floatReg, val, + FloatRegFile::SingleWidth); + } + + IntReg readIntReg(int intReg) + { + return intRegFile.readReg(intReg); + } + + Fault setIntReg(int intReg, const IntReg &val) + { + return intRegFile.setReg(intReg, val); + } + + void serialize(std::ostream &os); + void unserialize(Checkpoint *cp, const std::string §ion); + + public: + + enum ContextParam + { + CONTEXT_CWP, + CONTEXT_GLOBALS + }; + typedef int ContextVal; + + void changeContext(ContextParam param, ContextVal val) + { + switch(param) + { + case CONTEXT_CWP: + intRegFile.setCWP(val); + break; + case CONTEXT_GLOBALS: + intRegFile.setGlobals(val); + break; + default: + panic("Tried to set illegal context parameter in the SPARC regfile.\n"); + } + } + }; + + void copyRegs(ThreadContext *src, ThreadContext *dest); + + void copyMiscRegs(ThreadContext *src, ThreadContext *dest); + + int InterruptLevel(uint64_t softint); + +} // namespace SparcISA + +#endif diff --git a/src/arch/sparc/solaris/process.cc b/src/arch/sparc/solaris/process.cc new file mode 100644 index 000000000..af0550910 --- /dev/null +++ b/src/arch/sparc/solaris/process.cc @@ -0,0 +1,349 @@ +/* + * Copyright (c) 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: Ali Saidi + */ + +#include "arch/sparc/isa_traits.hh" +#include "arch/sparc/solaris/process.hh" +#include "arch/sparc/regfile.hh" + +#include "base/trace.hh" +#include "cpu/thread_context.hh" +#include "kern/solaris/solaris.hh" + +#include "sim/process.hh" +#include "sim/syscall_emul.hh" + +using namespace std; +using namespace SparcISA; + + +/// Target uname() handler. +static SyscallReturn +unameFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + TypedBufferArg<Solaris::utsname> name(tc->getSyscallArg(0)); + + strcpy(name->sysname, "SunOS"); + strcpy(name->nodename, "m5.eecs.umich.edu"); + strcpy(name->release, "5.9"); //?? do we want this or something newer? + strcpy(name->version, "Generic_118558-21"); + strcpy(name->machine, "sun4u"); + + name.copyOut(tc->getMemPort()); + + return 0; +} + + +SyscallDesc SparcSolarisProcess::syscallDescs[] = { + /* 0 */ SyscallDesc("syscall", unimplementedFunc), + /* 1 */ SyscallDesc("exit", exitFunc), + /* 2 */ SyscallDesc("fork", unimplementedFunc), + /* 3 */ SyscallDesc("read", readFunc), + /* 4 */ SyscallDesc("write", writeFunc), + /* 5 */ SyscallDesc("open", openFunc<SparcSolaris>), + /* 6 */ SyscallDesc("close", closeFunc), + /* 7 */ SyscallDesc("wait", unimplementedFunc), + /* 8 */ SyscallDesc("creat", unimplementedFunc), + /* 9 */ SyscallDesc("link", unimplementedFunc), + /* 10 */ SyscallDesc("unlink", unlinkFunc), + /* 11 */ SyscallDesc("exec", unimplementedFunc), + /* 12 */ SyscallDesc("chdir", unimplementedFunc), + /* 13 */ SyscallDesc("time", unimplementedFunc), + /* 14 */ SyscallDesc("mknod", unimplementedFunc), + /* 15 */ SyscallDesc("chmod", chmodFunc<Solaris>), + /* 16 */ SyscallDesc("chown", chownFunc), + /* 17 */ SyscallDesc("brk", obreakFunc), + /* 18 */ SyscallDesc("stat", unimplementedFunc), + /* 19 */ SyscallDesc("lseek", lseekFunc), + /* 20 */ SyscallDesc("getpid", getpidFunc), + /* 21 */ SyscallDesc("mount", unimplementedFunc), + /* 22 */ SyscallDesc("umount", unimplementedFunc), + /* 23 */ SyscallDesc("setuid", setuidFunc), + /* 24 */ SyscallDesc("getuid", getuidFunc), + /* 25 */ SyscallDesc("stime", unimplementedFunc), + /* 26 */ SyscallDesc("pcsample", unimplementedFunc), + /* 27 */ SyscallDesc("alarm", unimplementedFunc), + /* 28 */ SyscallDesc("fstat", fstatFunc<SparcSolaris>), + /* 29 */ SyscallDesc("pause", unimplementedFunc), + /* 30 */ SyscallDesc("utime", unimplementedFunc), + /* 31 */ SyscallDesc("stty", unimplementedFunc), + /* 32 */ SyscallDesc("gtty", unimplementedFunc), + /* 33 */ SyscallDesc("access", unimplementedFunc), + /* 34 */ SyscallDesc("nice", unimplementedFunc), + /* 35 */ SyscallDesc("statfs", unimplementedFunc), + /* 36 */ SyscallDesc("sync", unimplementedFunc), + /* 37 */ SyscallDesc("kill", unimplementedFunc), + /* 38 */ SyscallDesc("fstatfs", unimplementedFunc), + /* 39 */ SyscallDesc("pgrpsys", unimplementedFunc), + /* 40 */ SyscallDesc("xenix", unimplementedFunc), + /* 41 */ SyscallDesc("dup", unimplementedFunc), + /* 42 */ SyscallDesc("pipe", pipePseudoFunc), + /* 43 */ SyscallDesc("times", unimplementedFunc), + /* 44 */ SyscallDesc("profil", unimplementedFunc), + /* 45 */ SyscallDesc("plock", unimplementedFunc), + /* 46 */ SyscallDesc("setgid", unimplementedFunc), + /* 47 */ SyscallDesc("getgid", getgidFunc), + /* 48 */ SyscallDesc("signal", unimplementedFunc), + /* 49 */ SyscallDesc("msgsys", unimplementedFunc), + /* 50 */ SyscallDesc("syssun", unimplementedFunc), + /* 51 */ SyscallDesc("acct", unimplementedFunc), + /* 52 */ SyscallDesc("shmsys", unimplementedFunc), + /* 53 */ SyscallDesc("semsys", unimplementedFunc), + /* 54 */ SyscallDesc("ioctl", unimplementedFunc), + /* 55 */ SyscallDesc("uadmin", unimplementedFunc), + /* 56 */ SyscallDesc("RESERVED", unimplementedFunc), + /* 57 */ SyscallDesc("utssys", unimplementedFunc), + /* 58 */ SyscallDesc("fdsync", unimplementedFunc), + /* 59 */ SyscallDesc("execve", unimplementedFunc), + /* 60 */ SyscallDesc("umask", unimplementedFunc), + /* 61 */ SyscallDesc("chroot", unimplementedFunc), + /* 62 */ SyscallDesc("fcntl", unimplementedFunc), + /* 63 */ SyscallDesc("ulimit", unimplementedFunc), + /* 64 */ SyscallDesc("reserved_64", unimplementedFunc), + /* 65 */ SyscallDesc("reserved_65", unimplementedFunc), + /* 66 */ SyscallDesc("reserved_66", unimplementedFunc), + /* 67 */ SyscallDesc("reserved_67", unimplementedFunc), + /* 68 */ SyscallDesc("reserved_68", unimplementedFunc), + /* 69 */ SyscallDesc("reserved_69", unimplementedFunc), + /* 70 */ SyscallDesc("tasksys", unimplementedFunc), + /* 71 */ SyscallDesc("acctctl", unimplementedFunc), + /* 72 */ SyscallDesc("reserved_72", unimplementedFunc), + /* 73 */ SyscallDesc("getpagesizes", unimplementedFunc), + /* 74 */ SyscallDesc("rctlsys", unimplementedFunc), + /* 75 */ SyscallDesc("issetugid", unimplementedFunc), + /* 76 */ SyscallDesc("fsat", unimplementedFunc), + /* 77 */ SyscallDesc("lwp_park", unimplementedFunc), + /* 78 */ SyscallDesc("sendfilev", unimplementedFunc), + /* 79 */ SyscallDesc("rmdir", unimplementedFunc), + /* 80 */ SyscallDesc("mkdir", unimplementedFunc), + /* 81 */ SyscallDesc("getdents", unimplementedFunc), + /* 82 */ SyscallDesc("reserved_82", unimplementedFunc), + /* 83 */ SyscallDesc("reserved_83", unimplementedFunc), + /* 84 */ SyscallDesc("sysfs", unimplementedFunc), + /* 85 */ SyscallDesc("getmsg", unimplementedFunc), + /* 86 */ SyscallDesc("putmsg", unimplementedFunc), + /* 87 */ SyscallDesc("poll", unimplementedFunc), + /* 88 */ SyscallDesc("lstat", unimplementedFunc), + /* 89 */ SyscallDesc("symlink", unimplementedFunc), + /* 90 */ SyscallDesc("readlink", unimplementedFunc), + /* 91 */ SyscallDesc("setgroups", unimplementedFunc), + /* 92 */ SyscallDesc("getgroups", unimplementedFunc), + /* 93 */ SyscallDesc("fchmod", unimplementedFunc), + /* 94 */ SyscallDesc("fchown", unimplementedFunc), + /* 95 */ SyscallDesc("sigprocmask", unimplementedFunc), + /* 96 */ SyscallDesc("sigsuspend", unimplementedFunc), + /* 97 */ SyscallDesc("sigaltstack", unimplementedFunc), + /* 98 */ SyscallDesc("sigaction", unimplementedFunc), + /* 99 */ SyscallDesc("sigpending", unimplementedFunc), + /* 100 */ SyscallDesc("context", unimplementedFunc), + /* 101 */ SyscallDesc("evsys", unimplementedFunc), + /* 102 */ SyscallDesc("evtrapret", unimplementedFunc), + /* 103 */ SyscallDesc("statvfs", unimplementedFunc), + /* 104 */ SyscallDesc("fstatvfs", unimplementedFunc), + /* 105 */ SyscallDesc("getloadavg", unimplementedFunc), + /* 106 */ SyscallDesc("nfssys", unimplementedFunc), + /* 107 */ SyscallDesc("waitsys", unimplementedFunc), + /* 108 */ SyscallDesc("sigsendsys", unimplementedFunc), + /* 109 */ SyscallDesc("hrtsys", unimplementedFunc), + /* 110 */ SyscallDesc("acancel", unimplementedFunc), + /* 111 */ SyscallDesc("async", unimplementedFunc), + /* 112 */ SyscallDesc("priocntlsys", unimplementedFunc), + /* 113 */ SyscallDesc("pathconf", unimplementedFunc), + /* 114 */ SyscallDesc("mincore", unimplementedFunc), + /* 115 */ SyscallDesc("mmap", mmapFunc<SparcSolaris>), + /* 116 */ SyscallDesc("mprotect", unimplementedFunc), + /* 117 */ SyscallDesc("munmap", munmapFunc), + /* 118 */ SyscallDesc("fpathconf", unimplementedFunc), + /* 119 */ SyscallDesc("vfork", unimplementedFunc), + /* 120 */ SyscallDesc("fchdir", unimplementedFunc), + /* 121 */ SyscallDesc("readv", unimplementedFunc), + /* 122 */ SyscallDesc("writev", unimplementedFunc), + /* 123 */ SyscallDesc("xstat", unimplementedFunc), + /* 124 */ SyscallDesc("lxstat", unimplementedFunc), + /* 125 */ SyscallDesc("fxstat", unimplementedFunc), + /* 126 */ SyscallDesc("xmknod", unimplementedFunc), + /* 127 */ SyscallDesc("clocal", unimplementedFunc), + /* 128 */ SyscallDesc("setrlimit", unimplementedFunc), + /* 129 */ SyscallDesc("getrlimit", unimplementedFunc), + /* 130 */ SyscallDesc("lchown", unimplementedFunc), + /* 131 */ SyscallDesc("memcntl", unimplementedFunc), + /* 132 */ SyscallDesc("getpmsg", unimplementedFunc), + /* 133 */ SyscallDesc("putpmsg", unimplementedFunc), + /* 134 */ SyscallDesc("rename", unimplementedFunc), + /* 135 */ SyscallDesc("uname", unameFunc), + /* 136 */ SyscallDesc("setegid", unimplementedFunc), + /* 137 */ SyscallDesc("sysconfig", unimplementedFunc), + /* 138 */ SyscallDesc("adjtime", unimplementedFunc), + /* 139 */ SyscallDesc("systeminfo", unimplementedFunc), + /* 140 */ SyscallDesc("reserved_140", unimplementedFunc), + /* 141 */ SyscallDesc("seteuid", unimplementedFunc), + /* 142 */ SyscallDesc("vtrace", unimplementedFunc), + /* 143 */ SyscallDesc("fork1", unimplementedFunc), + /* 144 */ SyscallDesc("sigtimedwait", unimplementedFunc), + /* 145 */ SyscallDesc("lwp_info", unimplementedFunc), + /* 146 */ SyscallDesc("yield", unimplementedFunc), + /* 147 */ SyscallDesc("lwp_sema_wait", unimplementedFunc), + /* 148 */ SyscallDesc("lwp_sema_post", unimplementedFunc), + /* 149 */ SyscallDesc("lwp_sema_trywait", unimplementedFunc), + /* 150 */ SyscallDesc("lwp_detach", unimplementedFunc), + /* 151 */ SyscallDesc("corectl", unimplementedFunc), + /* 152 */ SyscallDesc("modctl", unimplementedFunc), + /* 153 */ SyscallDesc("fchroot", unimplementedFunc), + /* 154 */ SyscallDesc("utimes", unimplementedFunc), + /* 155 */ SyscallDesc("vhangup", unimplementedFunc), + /* 156 */ SyscallDesc("gettimeofday", unimplementedFunc), + /* 157 */ SyscallDesc("getitimer", unimplementedFunc), + /* 158 */ SyscallDesc("setitimer", unimplementedFunc), + /* 159 */ SyscallDesc("lwp_create", unimplementedFunc), + /* 160 */ SyscallDesc("lwp_exit", unimplementedFunc), + /* 161 */ SyscallDesc("lwp_suspend", unimplementedFunc), + /* 162 */ SyscallDesc("lwp_continue", unimplementedFunc), + /* 163 */ SyscallDesc("lwp_kill", unimplementedFunc), + /* 164 */ SyscallDesc("lwp_self", unimplementedFunc), + /* 165 */ SyscallDesc("lwp_setprivate", unimplementedFunc), + /* 166 */ SyscallDesc("lwp_getprivate", unimplementedFunc), + /* 167 */ SyscallDesc("lwp_wait", unimplementedFunc), + /* 168 */ SyscallDesc("lwp_mutex_wakeup", unimplementedFunc), + /* 169 */ SyscallDesc("lwp_mutex_lock", unimplementedFunc), + /* 170 */ SyscallDesc("lwp_cond_wait", unimplementedFunc), + /* 171 */ SyscallDesc("lwp_cond_signal", unimplementedFunc), + /* 172 */ SyscallDesc("lwp_cond_broadcast", unimplementedFunc), + /* 173 */ SyscallDesc("pread", unimplementedFunc), + /* 174 */ SyscallDesc("pwrite", unimplementedFunc), + /* 175 */ SyscallDesc("llseek", unimplementedFunc), + /* 176 */ SyscallDesc("inst_sync", unimplementedFunc), + /* 177 */ SyscallDesc("srmlimitsys", unimplementedFunc), + /* 178 */ SyscallDesc("kaio", unimplementedFunc), + /* 179 */ SyscallDesc("cpc", unimplementedFunc), + /* 180 */ SyscallDesc("lgrpsys_meminfosys", unimplementedFunc), + /* 181 */ SyscallDesc("rusagesys", unimplementedFunc), + /* 182 */ SyscallDesc("reserved_182", unimplementedFunc), + /* 183 */ SyscallDesc("reserved_183", unimplementedFunc), + /* 184 */ SyscallDesc("tsolsys", unimplementedFunc), + /* 185 */ SyscallDesc("acl", unimplementedFunc), + /* 186 */ SyscallDesc("auditsys", unimplementedFunc), + /* 187 */ SyscallDesc("processor_bind", unimplementedFunc), + /* 188 */ SyscallDesc("processor_info", unimplementedFunc), + /* 189 */ SyscallDesc("p_online", unimplementedFunc), + /* 190 */ SyscallDesc("sigqueue", unimplementedFunc), + /* 191 */ SyscallDesc("clock_gettime", unimplementedFunc), + /* 192 */ SyscallDesc("clock_settime", unimplementedFunc), + /* 193 */ SyscallDesc("clock_getres", unimplementedFunc), + /* 194 */ SyscallDesc("timer_create", unimplementedFunc), + /* 195 */ SyscallDesc("timer_delete", unimplementedFunc), + /* 196 */ SyscallDesc("timer_settime", unimplementedFunc), + /* 197 */ SyscallDesc("timer_gettime", unimplementedFunc), + /* 198 */ SyscallDesc("timer_getoverrun", unimplementedFunc), + /* 199 */ SyscallDesc("nanosleep", unimplementedFunc), + /* 200 */ SyscallDesc("facl", unimplementedFunc), + /* 201 */ SyscallDesc("door", unimplementedFunc), + /* 202 */ SyscallDesc("setreuid", unimplementedFunc), + /* 203 */ SyscallDesc("setregid", unimplementedFunc), + /* 204 */ SyscallDesc("install_utrap", unimplementedFunc), + /* 205 */ SyscallDesc("signotify", unimplementedFunc), + /* 206 */ SyscallDesc("schedctl", unimplementedFunc), + /* 207 */ SyscallDesc("pset", unimplementedFunc), + /* 208 */ SyscallDesc("sparc_utrap_install", unimplementedFunc), + /* 209 */ SyscallDesc("resolvepath", unimplementedFunc), + /* 210 */ SyscallDesc("signotifywait", unimplementedFunc), + /* 211 */ SyscallDesc("lwp_sigredirect", unimplementedFunc), + /* 212 */ SyscallDesc("lwp_alarm", unimplementedFunc), + /* 213 */ SyscallDesc("getdents64", unimplementedFunc), + /* 214 */ SyscallDesc("mmap64", unimplementedFunc), + /* 215 */ SyscallDesc("stat64", unimplementedFunc), + /* 216 */ SyscallDesc("lstat64", unimplementedFunc), + /* 217 */ SyscallDesc("fstat64", unimplementedFunc), + /* 218 */ SyscallDesc("statvfs64", unimplementedFunc), + /* 219 */ SyscallDesc("fstatvfs64", unimplementedFunc), + /* 220 */ SyscallDesc("setrlimit64", unimplementedFunc), + /* 221 */ SyscallDesc("getrlimit64", unimplementedFunc), + /* 222 */ SyscallDesc("pread64", unimplementedFunc), + /* 223 */ SyscallDesc("pwrite64", unimplementedFunc), + /* 224 */ SyscallDesc("creat64", unimplementedFunc), + /* 225 */ SyscallDesc("open64", unimplementedFunc), + /* 226 */ SyscallDesc("rpcsys", unimplementedFunc), + /* 227 */ SyscallDesc("reserved_227", unimplementedFunc), + /* 228 */ SyscallDesc("reserved_228", unimplementedFunc), + /* 229 */ SyscallDesc("reserved_229", unimplementedFunc), + /* 230 */ SyscallDesc("so_socket", unimplementedFunc), + /* 231 */ SyscallDesc("so_socketpair", unimplementedFunc), + /* 232 */ SyscallDesc("bind", unimplementedFunc), + /* 233 */ SyscallDesc("listen", unimplementedFunc), + /* 234 */ SyscallDesc("accept", unimplementedFunc), + /* 235 */ SyscallDesc("connect", unimplementedFunc), + /* 236 */ SyscallDesc("shutdown", unimplementedFunc), + /* 237 */ SyscallDesc("recv", unimplementedFunc), + /* 238 */ SyscallDesc("recvfrom", unimplementedFunc), + /* 239 */ SyscallDesc("recvmsg", unimplementedFunc), + /* 240 */ SyscallDesc("send", unimplementedFunc), + /* 241 */ SyscallDesc("sendmsg", unimplementedFunc), + /* 242 */ SyscallDesc("sendto", unimplementedFunc), + /* 243 */ SyscallDesc("getpeername", unimplementedFunc), + /* 244 */ SyscallDesc("getsockname", unimplementedFunc), + /* 245 */ SyscallDesc("getsockopt", unimplementedFunc), + /* 246 */ SyscallDesc("setsockopt", unimplementedFunc), + /* 247 */ SyscallDesc("sockconfig", unimplementedFunc), + /* 248 */ SyscallDesc("ntp_gettime", unimplementedFunc), + /* 249 */ SyscallDesc("ntp_adjtime", unimplementedFunc), + /* 250 */ SyscallDesc("lwp_mutex_unlock", unimplementedFunc), + /* 251 */ SyscallDesc("lwp_mutex_trylock", unimplementedFunc), + /* 252 */ SyscallDesc("lwp_mutex_init", unimplementedFunc), + /* 253 */ SyscallDesc("cladm", unimplementedFunc), + /* 254 */ SyscallDesc("lwp_sigtimedwait", unimplementedFunc), + /* 255 */ SyscallDesc("umount2", unimplementedFunc) +}; + +SparcSolarisProcess::SparcSolarisProcess(const std::string &name, + ObjectFile *objFile, + System * system, + int stdin_fd, + int stdout_fd, + int stderr_fd, + std::vector<std::string> &argv, + std::vector<std::string> &envp) + : SparcLiveProcess(name, objFile, system, + stdin_fd, stdout_fd, stderr_fd, argv, envp), + Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc)) +{ + // The sparc syscall table must be <= 284 entries because that is all there + // is space for. + assert(Num_Syscall_Descs <= 284); +} + + + +SyscallDesc* +SparcSolarisProcess::getDesc(int callnum) +{ + if (callnum < 0 || callnum > Num_Syscall_Descs) + return NULL; + return &syscallDescs[callnum]; +} diff --git a/src/arch/sparc/solaris/process.hh b/src/arch/sparc/solaris/process.hh new file mode 100644 index 000000000..3c0d7eba7 --- /dev/null +++ b/src/arch/sparc/solaris/process.hh @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2003-2004 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 __SPARC_SOLARIS_PROCESS_HH__ +#define __SPARC_SOLARIS_PROCESS_HH__ + +#include "arch/sparc/solaris/solaris.hh" +#include "arch/sparc/process.hh" +#include "sim/process.hh" + +namespace SparcISA { + +/// A process with emulated SPARC/Solaris syscalls. +class SparcSolarisProcess : public SparcLiveProcess +{ + public: + /// Constructor. + SparcSolarisProcess(const std::string &name, + ObjectFile *objFile, + System * system, + int stdin_fd, int stdout_fd, int stderr_fd, + std::vector<std::string> &argv, + std::vector<std::string> &envp); + + virtual SyscallDesc* getDesc(int callnum); + + /// The target system's hostname. + static const char *hostname; + + /// Array of syscall descriptors, indexed by call number. + static SyscallDesc syscallDescs[]; + + const int Num_Syscall_Descs; +}; + + +} // namespace SparcISA +#endif // __ALPHA_SOLARIS_PROCESS_HH__ diff --git a/src/arch/sparc/solaris/solaris.cc b/src/arch/sparc/solaris/solaris.cc new file mode 100644 index 000000000..c588925b0 --- /dev/null +++ b/src/arch/sparc/solaris/solaris.cc @@ -0,0 +1,76 @@ +/* + * Copyright (c) 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: Ali Saidi + */ + +#include "arch/sparc/solaris/solaris.hh" + +// open(2) flags translation table +OpenFlagTransTable SparcSolaris::openFlagTable[] = { +#ifdef _MSC_VER + { SparcSolaris::TGT_O_RDONLY, _O_RDONLY }, + { SparcSolaris::TGT_O_WRONLY, _O_WRONLY }, + { SparcSolaris::TGT_O_RDWR, _O_RDWR }, + { SparcSolaris::TGT_O_APPEND, _O_APPEND }, + { SparcSolaris::TGT_O_CREAT, _O_CREAT }, + { SparcSolaris::TGT_O_TRUNC, _O_TRUNC }, + { SparcSolaris::TGT_O_EXCL, _O_EXCL }, +#ifdef _O_NONBLOCK + { SparcSolaris::TGT_O_NONBLOCK, _O_NONBLOCK }, + { SparcSolaris::TGT_O_NDELAY , _O_NONBLOCK }, +#endif +#ifdef _O_NOCTTY + { SparcSolaris::TGT_O_NOCTTY, _O_NOCTTY }, +#endif +#ifdef _O_SYNC + { SparcSolaris::TGT_O_SYNC, _O_SYNC }, + { SparcSolaris::TGT_O_DSYNC, _O_SYNC }, + { SparcSolaris::TGT_O_RSYNC, _O_SYNC }, +#endif +#else /* !_MSC_VER */ + { SparcSolaris::TGT_O_RDONLY, O_RDONLY }, + { SparcSolaris::TGT_O_WRONLY, O_WRONLY }, + { SparcSolaris::TGT_O_RDWR, O_RDWR }, + { SparcSolaris::TGT_O_APPEND, O_APPEND }, + { SparcSolaris::TGT_O_CREAT, O_CREAT }, + { SparcSolaris::TGT_O_TRUNC, O_TRUNC }, + { SparcSolaris::TGT_O_EXCL, O_EXCL }, + { SparcSolaris::TGT_O_NONBLOCK, O_NONBLOCK }, + { SparcSolaris::TGT_O_NDELAY , O_NONBLOCK }, + { SparcSolaris::TGT_O_NOCTTY, O_NOCTTY }, +#ifdef O_SYNC + { SparcSolaris::TGT_O_SYNC, O_SYNC }, + { SparcSolaris::TGT_O_DSYNC, O_SYNC }, + { SparcSolaris::TGT_O_RSYNC, O_SYNC }, +#endif +#endif /* _MSC_VER */ +}; + +const int SparcSolaris::NUM_OPEN_FLAGS = + (sizeof(SparcSolaris::openFlagTable)/sizeof(SparcSolaris::openFlagTable[0])); + diff --git a/src/arch/sparc/solaris/solaris.hh b/src/arch/sparc/solaris/solaris.hh new file mode 100644 index 000000000..0564faba4 --- /dev/null +++ b/src/arch/sparc/solaris/solaris.hh @@ -0,0 +1,64 @@ +/* + * Copyright (c) 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: Ali Saidi + */ + +#ifndef __ARCH_SPARC_SOLARIS_SOLARIS_HH__ +#define __ARCH_SPARC_SOLARIS_SOLARIS_HH__ + +#include "kern/solaris/solaris.hh" + +class SparcSolaris : public Solaris +{ + public: + + static OpenFlagTransTable openFlagTable[]; + + static const int TGT_O_RDONLY = 0x00000000; //!< O_RDONLY + static const int TGT_O_WRONLY = 0x00000001; //!< O_WRONLY + static const int TGT_O_RDWR = 0x00000002; //!< O_RDWR + static const int TGT_O_NDELAY = 0x00000004; //!< O_NONBLOCK + static const int TGT_O_APPEND = 0x00000008; //!< O_APPEND + static const int TGT_O_SYNC = 0x00000010; //!< O_SYNC + static const int TGT_O_DSYNC = 0x00000040; //!< O_SYNC + static const int TGT_O_RSYNC = 0x00008000; //!< O_SYNC + static const int TGT_O_NONBLOCK = 0x00000080; //!< O_NONBLOCK + static const int TGT_O_PRIV = 0x00001000; //?? + static const int TGT_O_LARGEFILE = 0x00002000; //?? + static const int TGT_O_CREAT = 0x00000100; //!< O_CREAT + static const int TGT_O_TRUNC = 0x00000200; //!< O_TRUNC + static const int TGT_O_EXCL = 0x00000400; //!< O_EXCL + static const int TGT_O_NOCTTY = 0x00000800; //!< O_NOCTTY + static const int TGT_O_XATTR = 0x00004000; //?? + + static const int NUM_OPEN_FLAGS; + + static const unsigned TGT_MAP_ANONYMOUS = 0x100; +}; + +#endif diff --git a/src/arch/sparc/stacktrace.hh b/src/arch/sparc/stacktrace.hh new file mode 100644 index 000000000..d12aee211 --- /dev/null +++ b/src/arch/sparc/stacktrace.hh @@ -0,0 +1,121 @@ +/* + * Copyright (c) 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 + */ + +#ifndef __ARCH_ALPHA_STACKTRACE_HH__ +#define __ARCH_ALPHA_STACKTRACE_HH__ + +#include "base/trace.hh" +#include "cpu/static_inst.hh" + +class ThreadContext; +class StackTrace; + +class ProcessInfo +{ + private: + ThreadContext *tc; + + int thread_info_size; + int task_struct_size; + int task_off; + int pid_off; + int name_off; + + public: + ProcessInfo(ThreadContext *_tc); + + Addr task(Addr ksp) const; + int pid(Addr ksp) const; + std::string name(Addr ksp) const; +}; + +class StackTrace +{ + protected: + typedef TheISA::MachInst MachInst; + private: + ThreadContext *tc; + std::vector<Addr> stack; + + private: + bool isEntry(Addr addr); + bool decodePrologue(Addr sp, Addr callpc, Addr func, int &size, Addr &ra); + bool decodeSave(MachInst inst, int ®, int &disp); + bool decodeStack(MachInst inst, int &disp); + + void trace(ThreadContext *tc, bool is_call); + + public: + StackTrace(); + StackTrace(ThreadContext *tc, StaticInstPtr inst); + ~StackTrace(); + + void clear() + { + tc = 0; + stack.clear(); + } + + bool valid() const { return tc != NULL; } + bool trace(ThreadContext *tc, StaticInstPtr inst); + + public: + const std::vector<Addr> &getstack() const { return stack; } + + static const int user = 1; + static const int console = 2; + static const int unknown = 3; + +#if TRACING_ON + private: + void dump(); + + public: + void dprintf() { if (DTRACE(Stack)) dump(); } +#else + public: + void dprintf() {} +#endif +}; + +inline bool +StackTrace::trace(ThreadContext *tc, StaticInstPtr inst) +{ + if (!inst->isCall() && !inst->isReturn()) + return false; + + if (valid()) + clear(); + + trace(tc, !inst->isReturn()); + return true; +} + +#endif // __ARCH_ALPHA_STACKTRACE_HH__ diff --git a/src/arch/sparc/system.cc b/src/arch/sparc/system.cc new file mode 100644 index 000000000..e197e7918 --- /dev/null +++ b/src/arch/sparc/system.cc @@ -0,0 +1,203 @@ +/* + * 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: Ali Saidi + */ + +#include "arch/sparc/system.hh" +#include "arch/vtophys.hh" +#include "base/remote_gdb.hh" +#include "base/loader/object_file.hh" +#include "base/loader/symtab.hh" +#include "base/trace.hh" +#include "mem/physical.hh" +#include "sim/byteswap.hh" +#include "sim/builder.hh" + + +using namespace BigEndianGuest; + +SparcSystem::SparcSystem(Params *p) + : System(p), sysTick(0) + +{ + resetSymtab = new SymbolTable; + hypervisorSymtab = new SymbolTable; + openbootSymtab = new SymbolTable; + + + /** + * Load the boot code, and hypervisor into memory. + */ + // Read the reset binary + reset = createObjectFile(params()->reset_bin); + if (reset == NULL) + fatal("Could not load reset binary %s", params()->reset_bin); + + // Read the openboot binary + openboot = createObjectFile(params()->openboot_bin); + if (openboot == NULL) + fatal("Could not load openboot bianry %s", params()->openboot_bin); + + // Read the hypervisor binary + hypervisor = createObjectFile(params()->hypervisor_bin); + if (hypervisor == NULL) + fatal("Could not load hypervisor binary %s", params()->hypervisor_bin); + + + // Load reset binary into memory + reset->loadSections(&functionalPort, SparcISA::LoadAddrMask); + // Load the openboot binary + openboot->loadSections(&functionalPort, SparcISA::LoadAddrMask); + // Load the hypervisor binary + hypervisor->loadSections(&functionalPort, SparcISA::LoadAddrMask); + + // load symbols + if (!reset->loadGlobalSymbols(reset)) + panic("could not load reset symbols\n"); + + if (!openboot->loadGlobalSymbols(openbootSymtab)) + panic("could not load openboot symbols\n"); + + if (!hypervisor->loadLocalSymbols(hypervisorSymtab)) + panic("could not load hypervisor symbols\n"); + + // load symbols into debug table + if (!reset->loadGlobalSymbols(debugSymbolTable)) + panic("could not load reset symbols\n"); + + if (!openboot->loadGlobalSymbols(debugSymbolTable)) + panic("could not load openboot symbols\n"); + + if (!hypervisor->loadLocalSymbols(debugSymbolTable)) + panic("could not load hypervisor symbols\n"); + + + // @todo any fixup code over writing data in binaries on setting break + // events on functions should happen here. + +} + +SparcSystem::~SparcSystem() +{ + delete resetSymtab; + delete hypervisorSymtab; + delete openbootSymtab; + delete reset; + delete openboot; + delete hypervisor; +} + +bool +SparcSystem::breakpoint() +{ + panic("Need to implement"); +} + +void +SparcSystem::serialize(std::ostream &os) +{ + System::serialize(os); + resetSymtab->serialize("reset_symtab", os); + hypervisorSymtab->serialize("hypervisor_symtab", os); + openbootSymtab->serialize("openboot_symtab", os); +} + + +void +SparcSystem::unserialize(Checkpoint *cp, const std::string §ion) +{ + System::unserialize(cp,section); + resetSymtab->unserialize("reset_symtab", cp, section); + hypervisorSymtab->unserialize("hypervisor_symtab", cp, section); + openbootSymtab->unserialize("openboot_symtab", cp, section); +} + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(SparcSystem) + + SimObjectParam<PhysicalMemory *> physmem; + + Param<std::string> kernel; + Param<std::string> reset_bin; + Param<std::string> hypervisor_bin; + Param<std::string> openboot_bin; + + Param<std::string> boot_osflags; + Param<std::string> readfile; + Param<unsigned int> init_param; + + Param<bool> bin; + VectorParam<std::string> binned_fns; + Param<bool> bin_int; + +END_DECLARE_SIM_OBJECT_PARAMS(SparcSystem) + +BEGIN_INIT_SIM_OBJECT_PARAMS(SparcSystem) + + INIT_PARAM(boot_cpu_frequency, "Frequency of the boot CPU"), + INIT_PARAM(physmem, "phsyical memory"), + INIT_PARAM(kernel, "file that contains the kernel code"), + INIT_PARAM(reset_bin, "file that contains the reset code"), + INIT_PARAM(hypervisor_bin, "file that contains the hypervisor code"), + INIT_PARAM(openboot_bin, "file that contains the openboot code"), + INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot", + "a"), + INIT_PARAM_DFLT(readfile, "file to read startup script from", ""), + INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0), + INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 34), + INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10), + INIT_PARAM_DFLT(bin, "is this system to be binned", false), + INIT_PARAM(binned_fns, "functions to be broken down and binned"), + INIT_PARAM_DFLT(bin_int, "is interrupt code binned seperately?", true) + +END_INIT_SIM_OBJECT_PARAMS(SparcSystem) + +CREATE_SIM_OBJECT(SparcSystem) +{ + SparcSystem::Params *p = new SparcSystem::Params; + p->name = getInstanceName(); + p->boot_cpu_frequency = boot_cpu_frequency; + p->physmem = physmem; + p->kernel_path = kernel; + p->reset_bin = reset_bin; + p->hypervisor_bin = hypervisor_bin; + p->openboot_bin = openboot_bin; + p->boot_osflags = boot_osflags; + p->init_param = init_param; + p->readfile = readfile; + p->system_type = system_type; + p->system_rev = system_rev; + p->bin = bin; + p->binned_fns = binned_fns; + p->bin_int = bin_int; + return new SparcSystem(p); +} + +REGISTER_SIM_OBJECT("SparcSystem", SparcSystem) + + diff --git a/src/arch/sparc/system.hh b/src/arch/sparc/system.hh new file mode 100644 index 000000000..614707f6c --- /dev/null +++ b/src/arch/sparc/system.hh @@ -0,0 +1,119 @@ +/* + * 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: Ali Saidi + */ + +#ifndef __ARCH_SPARC_SYSTEM_HH__ +#define __ARCH_SPARC_SYSTEM_HH__ + +#include <string> +#include <vector> + +#include "base/loader/symtab.hh" +#include "cpu/pc_event.hh" +#include "kern/system_events.hh" +#include "sim/sim_object.hh" +#include "sim/system.hh" + +class SparcSystem : public System +{ + public: + struct Params : public System::Params + { + std::string reset_bin; + std::string hypervison_bin; + std::string openboot_bin; + std::string boot_osflags; + uint64_t system_type; + uint64_t system_rev; + }; + + SparcSystem(Params *p); + + ~SparcSystem(); + + virtual bool breakpoint(); + +/** + * Serialization stuff + */ + public: + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + + /** reset binary symbol table */ + SymbolTable *resetSymtab; + + /** hypervison binary symbol table */ + SymbolTable *hypervisorSymtab; + + /** openboot symbol table */ + SymbolTable *openbootSymtab; + + /** Object pointer for the reset binary */ + ObjectFile *reset; + + /** Object pointer for the hypervisor code */ + ObjectFile *hypervisor; + + /** Object pointer for the openboot code */ + ObjectFile *openboot; + + /** System Tick for syncronized tick across all cpus. */ + Tick sysTick; + + protected: + const Params *params() const { return (const Params *)_params; } + + /** Add a function-based event to reset binary. */ + template <class T> + T *SparcSystem::addResetFuncEvent(const char *lbl) + { + return addFuncEvent<T>(resetSymtab, lbl); + } + + /** Add a function-based event to the hypervisor. */ + template <class T> + T *SparcSystem::addHypervisorFuncEvent(const char *lbl) + { + return addFuncEvent<T>(hypervisorSymtab, lbl); + } + + /** Add a function-based event to the openboot. */ + template <class T> + T *SparcSystem::addOpenbootFuncEvent(const char *lbl) + { + return addFuncEvent<T>(openbootSymtab, lbl); + } + + virtual Addr fixFuncEventAddr(Addr addr); + +}; + +#endif + diff --git a/src/arch/sparc/tlb.hh b/src/arch/sparc/tlb.hh new file mode 100644 index 000000000..35ff08b43 --- /dev/null +++ b/src/arch/sparc/tlb.hh @@ -0,0 +1,35 @@ +/* + * 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 __ARCH_SPARC_TLB_HH__ +#define __ARCH_SPARC_TLB_HH__ + + +#endif // __ARCH_SPARC_TLB_HH__ diff --git a/src/arch/sparc/ua2005.cc b/src/arch/sparc/ua2005.cc new file mode 100644 index 000000000..b89d48663 --- /dev/null +++ b/src/arch/sparc/ua2005.cc @@ -0,0 +1,224 @@ +/* + * 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 "arch/sparc/regfile.hh" + +Fault +SparcISA::MiscRegFile::setFSRegWithEffect(int miscReg, const MiscReg &val, + ThreadContext *tc) +{ + int64_t time; + SparcSystem *sys; + switch (miscReg) { + /** Full system only ASRs */ + case MISCREG_SOFTINT: + if (isNonPriv()) + return new PrivilegedOpcode; + // Check if we are going to interrupt because of something + int oldLevel = InterruptLevel(softint); + int newLevel = InterruptLevel(val); + setReg(miscReg, val); + if (newLevel > oldLevel) + ; // MUST DO SOMETHING HERE TO TELL CPU TO LOOK FOR INTERRUPTS XXX + //tc->getCpuPtr()->checkInterrupts = true; + return NoFault; + + case MISCREG_SOFTINT_CLR: + return setRegWithEffect(miscReg, ~val & softint, tc); + case MISCREG_SOFTINT_SET: + return setRegWithEffect(miscReg, val | softint, tc); + + case MISCREG_TICK_CMPR: + if (isNonPriv()) + return new PrivilegedOpcode; + if (tickCompare == NULL) + tickCompare = new TickCompareEvent(this, tc); + setReg(miscReg, val); + if (tick_cmprFields.int_dis && tickCompare.scheduled()) + tickCompare.deschedule(); + time = tick_cmprFields.tick_cmpr - tickFields.counter; + if (!tick_cmprFields.int_dis && time > 0) + tickCompare.schedule(time * tc->getCpuPtr()->cycles(1)); + return NoFault; + + case MISCREG_STICK: + if (isNonPriv()) + return new PrivilegedOpcode; + if (isPriv()) + return new PrivilegedAction; + sys = dynamic_cast<SparcSystem*>(tc->getSystemPtr()); + assert(sys != NULL); + sys->sysTick = curTick/Clock::Int::ns - val & ~Bit64; + stickFields.npt = val & Bit64 ? 1 : 0; + return NoFault; + + case MISCREG_STICK_CMPR: + if (isNonPriv()) + return new PrivilegedOpcode; + if (sTickCompare == NULL) + sTickCompare = new STickCompareEvent(this, tc); + sys = dynamic_cast<SparcSystem*>(tc->getSystemPtr()); + assert(sys != NULL); + setReg(miscReg, val); + if (stick_cmprFields.int_dis && sTickCompare.scheduled()) + sTickCompare.deschedule(); + time = stick_cmprFields.tick_cmpr - sys->sysTick; + if (!stick_cmprFields.int_dis && time > 0) + sTickCompare.schedule(time * Clock::Int::ns); + return NoFault; + + /** Fullsystem only Priv registers. */ + case MISCREG_PIL: + if (FULL_SYSTEM) { + setReg(miscReg, val); + //tc->getCpuPtr()->checkInterrupts; + // MUST DO SOMETHING HERE TO TELL CPU TO LOOK FOR INTERRUPTS XXX + return NoFault; + } else + panic("PIL not implemented for syscall emulation\n"); + + /** Hyper privileged registers */ + case MISCREG_HPSTATE: + case MISCREG_HINTP: + setReg(miscReg, val); + return NoFault; + case MISCREG_HTSTATE: + if (tl == 0) + return new IllegalInstruction; + setReg(miscReg, val); + return NoFault; + + case MISCREG_HTBA: + // clear lower 7 bits on writes. + setReg(miscReg, val & ULL(~0x7FFF)); + return NoFault; + + case MISCREG_STRAND_STS_REG: + setReg(miscReg, strandStatusReg); + return NoFault; + case MISCREG_HSTICK_CMPR: + if (isNonPriv()) + return new PrivilegedOpcode; + if (hSTickCompare == NULL) + hSTickCompare = new HSTickCompareEvent(this, tc); + sys = dynamic_cast<SparcSystem*>(tc->getSystemPtr()); + assert(sys != NULL); + setReg(miscReg, val); + if (hstick_cmprFields.int_dis && hSTickCompare.scheduled()) + hSTickCompare.deschedule(); + int64_t time = hstick_cmprFields.tick_cmpr - sys->sysTick; + if (!hstick_cmprFields.int_dis && time > 0) + hSTickCompare.schedule(time * Clock::Int::ns); + return NoFault; + default: + return new IllegalInstruction; + } +} + +MiscReg +MiscRegFile::readFSRegWithEffect(int miscReg, Fault &fault, ThreadContext * tc) +{ + switch (miscReg) { + + /** Privileged registers. */ + case MISCREG_SOFTINT: + if (isNonPriv()) { + fault = new PrivilegedOpcode; + return 0; + } + return readReg(miscReg); + case MISCREG_TICK_CMPR: + if (isNonPriv()) { + fault = new PrivilegedOpcode; + return 0; + } + return readReg(miscReg); + case MISCREG_STICK: + SparcSystem *sys; + if (stickFields.npt && !isNonPriv()) { + fault = new PrivilegedAction; + return 0; + } + sys = dynamic_cast<SparcSystem*>(tc->getSystemPtr()); + assert(sys != NULL); + return curTick/Clock::Int::ns - sys->sysTick | stickFields.npt << 63; + case MISCREG_STICK_CMPR: + if (isNonPriv()) { + fault = new PrivilegedOpcode; + return 0; + } + return readReg(miscReg); + + + /** Hyper privileged registers */ + case MISCREG_HPSTATE: + case MISCREG_HINTP: + return readReg(miscReg); + case MISCREG_HTSTATE: + if (tl == 0) { + fault = new IllegalInstruction; + return 0; + } + return readReg(miscReg); + + case MISCREG_HTBA: + return readReg(miscReg) & ULL(~0x7FFF); + case MISCREG_HVER: + return NWindows | MaxTL << 8 | MaxGL << 16; + case MISCREG_STRAND_STS_REG: + return strandStatusReg; + case MISCREG_HSTICK_CMPR: + return hstick_cmpr; + + default: + fault = new IllegalInstruction; + return 0; + } +} + +void +MiscRegFile::processTickCompare(ThreadContext *tc) +{ + panic("tick compare not implemented\n"); +} + +void +MiscRegFile::processSTickCompare(ThreadContext *tc) +{ + panic("tick compare not implemented\n"); +} + +void +MiscRegFile::processHSTickCompare(ThreadContext *tc) +{ + panic("tick compare not implemented\n"); +} + +}; // namespace SparcISA diff --git a/src/arch/sparc/utility.hh b/src/arch/sparc/utility.hh new file mode 100644 index 000000000..f1c071148 --- /dev/null +++ b/src/arch/sparc/utility.hh @@ -0,0 +1,91 @@ +/* + * Copyright (c) 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: Gabe Black + */ + +#ifndef __ARCH_SPARC_UTILITY_HH__ +#define __ARCH_SPARC_UTILITY_HH__ + +#include "arch/sparc/isa_traits.hh" +#include "base/misc.hh" + +namespace SparcISA +{ + inline ExtMachInst + makeExtMI(MachInst inst, const Addr &pc) { + return ExtMachInst(inst); + } + + inline bool isCallerSaveIntegerRegister(unsigned int reg) { + panic("register classification not implemented"); + return false; + } + + inline bool isCalleeSaveIntegerRegister(unsigned int reg) { + panic("register classification not implemented"); + return false; + } + + inline bool isCallerSaveFloatRegister(unsigned int reg) { + panic("register classification not implemented"); + return false; + } + + inline bool isCalleeSaveFloatRegister(unsigned int reg) { + panic("register classification not implemented"); + return false; + } + + // Instruction address compression hooks + inline Addr realPCToFetchPC(const Addr &addr) + { + return addr; + } + + inline Addr fetchPCToRealPC(const Addr &addr) + { + return addr; + } + + // the size of "fetched" instructions (not necessarily the size + // of real instructions for PISA) + inline size_t fetchInstSize() + { + return sizeof(MachInst); + } + + /** + * Function to insure ISA semantics about 0 registers. + * @param tc The thread context. + */ + template <class TC> + void zeroRegisters(TC *tc); + +} // namespace SparcISA + +#endif diff --git a/src/arch/sparc/vtophys.cc b/src/arch/sparc/vtophys.cc new file mode 100644 index 000000000..f7fd92c15 --- /dev/null +++ b/src/arch/sparc/vtophys.cc @@ -0,0 +1,166 @@ +/* + * 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 + * Steve Reinhardt + * Ali Saidi + */ + +#include <string> + +#include "arch/alpha/ev5.hh" +#include "arch/alpha/vtophys.hh" +#include "base/chunk_generator.hh" +#include "base/trace.hh" +#include "cpu/thread_context.hh" +#include "mem/vport.hh" + +using namespace std; +using namespace AlphaISA; + +AlphaISA::PageTableEntry +AlphaISA::kernel_pte_lookup(FunctionalPort *mem, Addr ptbr, AlphaISA::VAddr vaddr) +{ + Addr level1_pte = ptbr + vaddr.level1(); + AlphaISA::PageTableEntry level1 = mem->read<uint64_t>(level1_pte); + if (!level1.valid()) { + DPRINTF(VtoPhys, "level 1 PTE not valid, va = %#\n", vaddr); + return 0; + } + + Addr level2_pte = level1.paddr() + vaddr.level2(); + AlphaISA::PageTableEntry level2 = mem->read<uint64_t>(level2_pte); + if (!level2.valid()) { + DPRINTF(VtoPhys, "level 2 PTE not valid, va = %#x\n", vaddr); + return 0; + } + + Addr level3_pte = level2.paddr() + vaddr.level3(); + AlphaISA::PageTableEntry level3 = mem->read<uint64_t>(level3_pte); + if (!level3.valid()) { + DPRINTF(VtoPhys, "level 3 PTE not valid, va = %#x\n", vaddr); + return 0; + } + return level3; +} + +Addr +AlphaISA::vtophys(Addr vaddr) +{ + Addr paddr = 0; + if (AlphaISA::IsUSeg(vaddr)) + DPRINTF(VtoPhys, "vtophys: invalid vaddr %#x", vaddr); + else if (AlphaISA::IsK0Seg(vaddr)) + paddr = AlphaISA::K0Seg2Phys(vaddr); + else + panic("vtophys: ptbr is not set on virtual lookup"); + + DPRINTF(VtoPhys, "vtophys(%#x) -> %#x\n", vaddr, paddr); + + return paddr; +} + +Addr +AlphaISA::vtophys(ThreadContext *tc, Addr addr) +{ + AlphaISA::VAddr vaddr = addr; + Addr ptbr = tc->readMiscReg(AlphaISA::IPR_PALtemp20); + Addr paddr = 0; + //@todo Andrew couldn't remember why he commented some of this code + //so I put it back in. Perhaps something to do with gdb debugging? + if (AlphaISA::PcPAL(vaddr) && (vaddr < EV5::PalMax)) { + paddr = vaddr & ~ULL(1); + } else { + if (AlphaISA::IsK0Seg(vaddr)) { + paddr = AlphaISA::K0Seg2Phys(vaddr); + } else if (!ptbr) { + paddr = vaddr; + } else { + AlphaISA::PageTableEntry pte = + kernel_pte_lookup(tc->getPhysPort(), ptbr, vaddr); + if (pte.valid()) + paddr = pte.paddr() | vaddr.offset(); + } + } + + + DPRINTF(VtoPhys, "vtophys(%#x) -> %#x\n", vaddr, paddr); + + return paddr; +} + + +void +AlphaISA::CopyOut(ThreadContext *tc, void *dest, Addr src, size_t cplen) +{ + uint8_t *dst = (uint8_t *)dest; + VirtualPort *vp = tc->getVirtPort(tc); + + vp->readBlob(src, dst, cplen); + + tc->delVirtPort(vp); + +} + +void +AlphaISA::CopyIn(ThreadContext *tc, Addr dest, void *source, size_t cplen) +{ + uint8_t *src = (uint8_t *)source; + VirtualPort *vp = tc->getVirtPort(tc); + + vp->writeBlob(dest, src, cplen); + + tc->delVirtPort(vp); +} + +void +AlphaISA::CopyStringOut(ThreadContext *tc, char *dst, Addr vaddr, size_t maxlen) +{ + int len = 0; + VirtualPort *vp = tc->getVirtPort(tc); + + do { + vp->readBlob(vaddr++, (uint8_t*)dst++, 1); + len++; + } while (len < maxlen && dst[len] != 0 ); + + tc->delVirtPort(vp); + dst[len] = 0; +} + +void +AlphaISA::CopyStringIn(ThreadContext *tc, char *src, Addr vaddr) +{ + VirtualPort *vp = tc->getVirtPort(tc); + for (ChunkGenerator gen(vaddr, strlen(src), AlphaISA::PageBytes); !gen.done(); + gen.next()) + { + vp->writeBlob(gen.addr(), (uint8_t*)src, gen.size()); + src += gen.size(); + } + tc->delVirtPort(vp); +} diff --git a/src/arch/sparc/vtophys.hh b/src/arch/sparc/vtophys.hh new file mode 100644 index 000000000..bf2b757d6 --- /dev/null +++ b/src/arch/sparc/vtophys.hh @@ -0,0 +1,55 @@ +/* + * 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 + * Steve Reinhardt + */ + +#ifndef __ARCH_SPARC_VTOPHYS_H__ +#define __ARCH_SPARC_VTOPHYS_H__ + +#include "arch/sparc/isa_traits.hh" + +class ThreadContext; +class FunctionalPort; + +namespace SparcISA { + +PageTableEntry +kernel_pte_lookup(FunctionalPort *mem, Addr ptbr, SparcISA::VAddr vaddr); + +Addr vtophys(Addr vaddr); +Addr vtophys(ThreadContext *tc, Addr vaddr); + +void CopyOut(ThreadContext *tc, void *dst, Addr src, size_t len); +void CopyIn(ThreadContext *tc, Addr dst, void *src, size_t len); +void CopyStringOut(ThreadContext *tc, char *dst, Addr vaddr, size_t maxlen); +void CopyStringIn(ThreadContext *tc, char *src, Addr vaddr); + +}; +#endif // __ARCH_SPARC_VTOPHYS_H__ + diff --git a/src/base/bitfield.hh b/src/base/bitfield.hh new file mode 100644 index 000000000..f4e49aa8d --- /dev/null +++ b/src/base/bitfield.hh @@ -0,0 +1,72 @@ +/* + * Copyright (c) 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 Reinhardt + * Nathan Binkert + */ + +#ifndef __BASE_BITFIELD_HH__ +#define __BASE_BITFIELD_HH__ + +#include "sim/host.hh" + +/** + * Generate a 64-bit mask of 'nbits' 1s, right justified. + */ +inline uint64_t +mask(int nbits) +{ + return (nbits == 64) ? (uint64_t)-1LL : (1ULL << nbits) - 1; +} + + +/** + * Extract the bitfield from position 'first' to 'last' (inclusive) + * from 'val' and right justify it. MSB is numbered 63, LSB is 0. + */ +template <class T> +inline +T +bits(T val, int first, int last) +{ + int nbits = first - last + 1; + return (val >> last) & mask(nbits); +} + +/** + * Sign-extend an N-bit value to 64 bits. + */ +template <int N> +inline +int64_t +sext(uint64_t val) +{ + int sign_bit = bits(val, N-1, N-1); + return sign_bit ? (val | ~mask(N)) : val; +} + +#endif // __BASE_BITFIELD_HH__ diff --git a/src/base/callback.hh b/src/base/callback.hh new file mode 100644 index 000000000..a39d7df20 --- /dev/null +++ b/src/base/callback.hh @@ -0,0 +1,124 @@ +/* + * Copyright (c) 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: Nathan Binkert + */ + +#ifndef __CALLBACK_HH__ +#define __CALLBACK_HH__ + +#include <list> + +/** + * Generic callback class. This base class provides a virtual process + * function that gets called when the callback queue is processed. + */ +class Callback +{ + public: + /** + * virtualize the destructor to make sure that the correct one + * gets called. + */ + virtual ~Callback() {} + + /** + * virtual process function that is invoked when the callback + * queue is executed. + */ + virtual void process() = 0; +}; + +class CallbackQueue +{ + protected: + /** + * Simple typedef for the data structure that stores all of the + * callbacks. + */ + typedef std::list<Callback *> queue; + + /** + * List of all callbacks. To be called in fifo order. + */ + queue callbacks; + + public: + /** + * Add a callback to the end of the queue + * @param callback the callback to be added to the queue + */ + void add(Callback *callback) + { + callbacks.push_back(callback); + } + + /** + * Find out if there are any callbacks in the queue + */ + bool empty() const { return callbacks.empty(); } + + /** + * process all callbacks + */ + void process() + { + queue::iterator i = callbacks.begin(); + queue::iterator end = callbacks.end(); + + while (i != end) { + (*i)->process(); + ++i; + } + } + + /** + * clear the callback queue + */ + void clear() + { + callbacks.clear(); + } +}; + +/// Helper template class to turn a simple class member function into +/// a callback. +template <class T, void (T::* F)()> +class MakeCallback : public Callback +{ + private: + T *object; + + public: + MakeCallback(T *o) + : object(o) + { } + + void process() { (object->*F)(); } +}; + +#endif // __CALLBACK_HH__ diff --git a/src/base/chunk_generator.hh b/src/base/chunk_generator.hh new file mode 100644 index 000000000..e9d5355ca --- /dev/null +++ b/src/base/chunk_generator.hh @@ -0,0 +1,143 @@ +/* + * 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 + */ + +#ifndef __BASE__CHUNK_GENERATOR_HH__ +#define __BASE__CHUNK_GENERATOR_HH__ + +/** + * @file + * Declaration and inline definition of ChunkGenerator object. + */ + +#include <algorithm> +#include "base/intmath.hh" +#include "arch/isa_traits.hh" // for Addr + +/** + * This class takes an arbitrary memory region (address/length pair) + * and generates a series of appropriately (e.g. block- or page-) + * aligned chunks covering the same region. + * + * Example usage: + +\code + for (ChunkGenerator gen(addr, size, chunkSize); !gen.done(); gen.next()) { + doSomethingChunky(gen.addr(), gen.size()); + } +\endcode + */ +class ChunkGenerator +{ + private: + /** The starting address of the current chunk. */ + Addr curAddr; + /** The starting address of the next chunk (after the current one). */ + Addr nextAddr; + /** The size of the current chunk (in bytes). */ + int curSize; + /** The number of bytes remaining in the region after the current chunk. */ + int sizeLeft; + /** The start address so we can calculate offset in writing block. */ + const Addr startAddr; + /** The maximum chunk size, e.g., the cache block size or page size. */ + const int chunkSize; + + public: + /** + * Constructor. + * @param startAddr The starting address of the region. + * @param totalSize The total size of the region. + * @param _chunkSize The size/alignment of chunks into which + * the region should be decomposed. + */ + ChunkGenerator(Addr _startAddr, int totalSize, int _chunkSize) + : startAddr(_startAddr), chunkSize(_chunkSize) + { + // chunkSize must be a power of two + assert(chunkSize == 0 || isPowerOf2(chunkSize)); + + // set up initial chunk. + curAddr = startAddr; + + if (chunkSize == 0) //Special Case, if we see 0, assume no chuncking + { + nextAddr = startAddr + totalSize; + } + else + { + // nextAddr should be *next* chunk start + nextAddr = roundUp(startAddr, chunkSize); + if (curAddr == nextAddr) { + // ... even if startAddr is already chunk-aligned + nextAddr += chunkSize; + } + } + + // how many bytes are left between curAddr and the end of this chunk? + int left_in_chunk = nextAddr - curAddr; + curSize = std::min(totalSize, left_in_chunk); + sizeLeft = totalSize - curSize; + } + + /** Return starting address of current chunk. */ + Addr addr() { return curAddr; } + /** Return size in bytes of current chunk. */ + int size() { return curSize; } + + /** Number of bytes we have already chunked up. */ + int complete() { return curAddr - startAddr; } + /** + * Are we done? That is, did the last call to next() advance + * past the end of the region? + * @return True if yes, false if more to go. + */ + bool done() { return (curSize == 0); } + + /** + * Advance generator to next chunk. + * @return True if successful, false if unsuccessful + * (because we were at the last chunk). + */ + bool next() + { + if (sizeLeft == 0) { + curSize = 0; + return false; + } + + curAddr = nextAddr; + curSize = std::min(sizeLeft, chunkSize); + sizeLeft -= curSize; + nextAddr += curSize; + return true; + } +}; + +#endif // __BASE__CHUNK_GENERATOR_HH__ diff --git a/src/base/circlebuf.cc b/src/base/circlebuf.cc new file mode 100644 index 000000000..a0c015671 --- /dev/null +++ b/src/base/circlebuf.cc @@ -0,0 +1,215 @@ +/* + * 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 + */ + +#include <algorithm> +#include <string> + +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include "base/circlebuf.hh" +#include "base/cprintf.hh" +#include "base/intmath.hh" + +using namespace std; + +CircleBuf::CircleBuf(int l) + : _rollover(false), _buflen(l), _size(0), _start(0), _stop(0) +{ + _buf = new char[_buflen]; +} + +CircleBuf::~CircleBuf() +{ + if (_buf) + delete [] _buf; +} + +void +CircleBuf::dump() +{ + cprintf("start = %10d, stop = %10d, buflen = %10d\n", + _start, _stop, _buflen); + fflush(stdout); + ::write(STDOUT_FILENO, _buf, _buflen); + ::write(STDOUT_FILENO, "<\n", 2); +} + +void +CircleBuf::flush() +{ + _start = 0; + _stop = 0; + _rollover = false; +} + +void +CircleBuf::read(char *b, int len) +{ + _size -= len; + if (_size < 0) + _size = 0; + + if (_stop > _start) { + len = min(len, _stop - _start); + memcpy(b, _buf + _start, len); + _start += len; + } + else { + int endlen = _buflen - _start; + if (endlen > len) { + memcpy(b, _buf + _start, len); + _start += len; + } + else { + memcpy(b, _buf + _start, endlen); + _start = min(len - endlen, _stop); + memcpy(b + endlen, _buf, _start); + } + } +} + +void +CircleBuf::read(int fd, int len) +{ + _size -= len; + if (_size < 0) + _size = 0; + + if (_stop > _start) { + len = min(len, _stop - _start); + ::write(fd, _buf + _start, len); + _start += len; + } + else { + int endlen = _buflen - _start; + if (endlen > len) { + ::write(fd, _buf + _start, len); + _start += len; + } + else { + ::write(fd, _buf + _start, endlen); + _start = min(len - endlen, _stop); + ::write(fd, _buf, _start); + } + } +} + +void +CircleBuf::read(int fd) +{ + _size = 0; + + if (_stop > _start) { + ::write(fd, _buf + _start, _stop - _start); + } + else { + ::write(fd, _buf + _start, _buflen - _start); + ::write(fd, _buf, _stop); + } + + _start = _stop; +} + +void +CircleBuf::read(ostream &out) +{ + _size = 0; + + if (_stop > _start) { + out.write(_buf + _start, _stop - _start); + } + else { + out.write(_buf + _start, _buflen - _start); + out.write(_buf, _stop); + } + + _start = _stop; +} + +void +CircleBuf::readall(int fd) +{ + if (_rollover) + ::write(fd, _buf + _stop, _buflen - _stop); + + ::write(fd, _buf, _stop); + _start = _stop; +} + +void +CircleBuf::write(char b) +{ + write(&b, 1); +} + +void +CircleBuf::write(const char *b) +{ + write(b, strlen(b)); +} + +void +CircleBuf::write(const char *b, int len) +{ + if (len <= 0) + return; + + _size += len; + if (_size > _buflen) + _size = _buflen; + + int old_start = _start; + int old_stop = _stop; + + if (len >= _buflen) { + _start = 0; + _stop = _buflen; + _rollover = true; + memcpy(_buf, b + (len - _buflen), _buflen); + return; + } + + if (_stop + len <= _buflen) { + memcpy(_buf + _stop, b, len); + _stop += len; + } else { + int end_len = _buflen - old_stop; + _stop = len - end_len; + memcpy(_buf + old_stop, b, end_len); + memcpy(_buf, b + end_len, _stop); + _rollover = true; + } + + if (old_start > old_stop && old_start < _stop || + old_start < old_stop && _stop < old_stop) + _start = _stop + 1; +} diff --git a/src/base/circlebuf.hh b/src/base/circlebuf.hh new file mode 100644 index 000000000..66583b7db --- /dev/null +++ b/src/base/circlebuf.hh @@ -0,0 +1,64 @@ +/* + * 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 + */ + +#ifndef __CIRCLEBUF_HH__ +#define __CIRCLEBUF_HH__ + +#include <iosfwd> + +class CircleBuf +{ + protected: + char *_buf; + bool _rollover; + int _buflen; + int _size; + int _start; + int _stop; + + public: + explicit CircleBuf(int l); + ~CircleBuf(); + + bool empty() const { return _size == 0; } + int size() const { return _size; } + void dump(); + void flush(); + void read(char *b, int len); + void read(int fd, int len); + void read(int fd); + void read(std::ostream &out); + void readall(int fd); + void write(char b); + void write(const char *b); + void write(const char *b, int len); +}; + +#endif // __CIRCLEBUF_HH__ diff --git a/src/base/compression/lzss_compression.cc b/src/base/compression/lzss_compression.cc new file mode 100644 index 000000000..eb35fb8f1 --- /dev/null +++ b/src/base/compression/lzss_compression.cc @@ -0,0 +1,173 @@ +/* + * Copyright (c) 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: Erik Hallnor + */ + +/** @file + * LZSSCompression definitions. + */ + +#include <assert.h> + +#include "base/compression/lzss_compression.hh" + +#include "base/misc.hh" //for fatal + +void +LZSSCompression::findSubString(uint8_t *src, int back, int size, uint16_t &L, + uint16_t &P) +{ + int front = 0; + int max_length = size - back; + L = 0; + P = back - 1; + while (front < back) { + while (src[front] != src[back] && front < back) ++front; + if (front >= back) { + return; + } + int i = 1; + while (src[front+i] == src[back+i] && i < max_length) ++i; + if (i >= L) { + L = i; + P = front; + } + if (src[front+i] != src[back+i-1]) { + // can't find a longer substring until past this point. + front += i; + } else { + ++front; + } + } +} + +int +LZSSCompression::emitByte(uint8_t *dest, uint8_t byte) +{ + if ((byte >> 5 & 0x7) == 0 || (byte >> 5 & 0x7) == 7) { + // If the top 3 bits are the same, emit 00<6bits> + dest[0] = byte & 0x3f; + return 1; + } else { + // emit 01XXXXXX <8 bits> + dest[0] = 0x40; + dest[1] = byte; + return 2; + } +} + +void +LZSSCompression::emitString(uint8_t *dest, uint16_t P, uint16_t L) +{ + // Emit 1<7P> <5P><3L> <8L> + dest[0] = 1<<7 | (P >> 5 & 0x7f); + dest[1] = ((P & 0x1f) << 3) | (L>>8 & 0x3); + dest[2] = L & 0xFF; +} + +int +LZSSCompression::compress(uint8_t *dest, uint8_t *src, int size) +{ + if (size > 4096) { + fatal("Compression can only handle block sizes of 4096 bytes or less"); + } + + // Encode the first byte. + int dest_index = emitByte(dest, src[0]); + int i = 1; + // A 11 bit field + uint16_t L; + // A 12 bit field + uint16_t P = 0; + + while (i < size && dest_index < size) { + L = 0; + + if (dest_index+3 >= size) { + dest_index = size; + continue; + } + + if (i == size - 1) { + // Output the character + dest_index += emitByte(&dest[dest_index], src[i]); + ++i; + continue; + } + findSubString(src, i, size, L, P); + if (L > 1) { + // Output the string reference + emitString(&dest[dest_index], P, L); + dest_index += 3; + i = i+L; + } else { + // Output the character + dest_index += emitByte(&dest[dest_index], src[i]); + ++i; + } + } + + if (dest_index >= size) { + // Have expansion instead of compression, just copy. + memcpy(dest,src,size); + return size; + } + return dest_index; +} + +int +LZSSCompression::uncompress(uint8_t *dest, uint8_t *src, int size) +{ + int index = 0; + int i = 0; + while (i < size) { + if (src[i] & 1<<7 ) { + // We have a string + // Extract P + int start = (src[i] & 0x3f)<<5 | ((src[i+1] >> 3) & 0x1f); + // Extract L + int len = (src[i+1] & 0x07)<<8 | src[i+2]; + i += 3; + for (int j = start; j < start+len; ++j) { + dest[index++] = dest[j]; + } + } else { + // We have a character + if (src[i] & 1<<6) { + // Value is in the next byte + dest[index++] = src[i+1]; + i += 2; + } else { + // just extend the lower 6 bits + dest[index++] = (src[i] & 0x3f) | ((src[i] & 1<<5) ? 0xC0 : 0); + ++i; + } + } + } + return index; +} diff --git a/src/base/compression/lzss_compression.hh b/src/base/compression/lzss_compression.hh new file mode 100644 index 000000000..35e4dcb3f --- /dev/null +++ b/src/base/compression/lzss_compression.hh @@ -0,0 +1,103 @@ +/* + * Copyright (c) 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: Erik Hallnor + */ + +#ifndef __LZSS_COMPRESSION_HH__ +#define __LZSS_COMPRESSION_HH__ + +/** @file + * LZSSCompression declarations. + */ + +#include "sim/host.hh" // for uint8_t + +/** + * Simple LZSS compression scheme. + */ +class LZSSCompression +{ + /** + * Finds the longest substring for the given offset. + * @param src The source block that we search for substrings. + * @param back The larger offset. + * @param size The size of the source block. + * @param L The length of the largest substring. + * @param P The starting offset of the largest substring. + */ + void findSubString(uint8_t *src, int back, int size, uint16_t &L, + uint16_t &P); + + /** + * Emit an encoded byte to the compressed data array. If the 2 high + * order bits can be signed extended, use 1 byte encoding, if not use 2 + * bytes. + * @param dest The compressed data. + * @param byte The byte to emit. + * @return The number of bytes used to encode. + */ + int emitByte(uint8_t *dest, uint8_t byte); + + /** + * Emit a string reference to the compressed data array. A string reference + * always uses 3 bytes. 1 flag bit, 12 bits for the starting position, and + * 11 bits for the length of the string. This allows compression of 4096 + * byte blocks with string lengths of up to 2048 bytes. + * @param dest The compressed data. + * @param P The starting position in the uncompressed data. + * @param L The length in bytes of the string. + */ + void emitString(uint8_t *dest, uint16_t P, uint16_t L); + + public: + /** + * Compresses the source block and stores it in the destination block. If + * the compressed block grows to larger than the source block, it aborts + * and just performs a copy. + * @param dest The destination block. + * @param src The block to be compressed. + * @param size The size of the source block. + * @return The size of the compressed block. + * + * @pre Destination has enough storage to hold the compressed block. + */ + int compress(uint8_t *dest, uint8_t *src, int size); + + /** + * Unompresses the source block and stores it in the destination block. + * @param dest The destination block. + * @param src The block to be uncompressed. + * @param size The size of the source block. + * @return The size of the uncompressed block. + * + * @pre Destination has enough storage to hold the uncompressed block. + */ + int uncompress(uint8_t *dest, uint8_t *src, int size); +}; + +#endif //__LZSS_COMPRESSION_HH__ diff --git a/src/base/compression/null_compression.hh b/src/base/compression/null_compression.hh new file mode 100644 index 000000000..5a582d828 --- /dev/null +++ b/src/base/compression/null_compression.hh @@ -0,0 +1,79 @@ +/* + * Copyright (c) 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: Erik Hallnor + * Nathan Binkert + */ + +#ifndef __BASE_COMPRESSION_NULL_COMPRESSION_HH__ +#define __BASE_COMPRESSION_NULL_COMPRESSION_HH__ + +/** + * @file + * This file defines a doNothing compression algorithm. + */ + +#include "base/misc.hh" // for fatal() +#include "sim/host.hh" + + +/** + * A dummy compression class to use when no data compression is desired. + */ +class NullCompression +{ + public: + /** + * Uncompress the data, causes a fatal since no data should be compressed. + * @param dest The output buffer. + * @param src The compressed data. + * @param size The number of bytes in src. + * + * @retval The size of the uncompressed data. + */ + static int uncompress(uint8_t * dest, uint8_t *src, int size) + { + fatal("Can't uncompress data"); + } + + /** + * Compress the data, just returns the source data. + * @param dest The output buffer. + * @param src The data to be compressed. + * @param size The number of bytes in src. + * + * @retval The size of the compressed data. + */ + + static int compress(uint8_t *dest, uint8_t *src, int size) + { + memcpy(dest,src,size); + return size; + } +}; + +#endif //__BASE_COMPRESSION_NULL_COMPRESSION_HH__ diff --git a/src/base/cprintf.cc b/src/base/cprintf.cc new file mode 100644 index 000000000..dd8ce858b --- /dev/null +++ b/src/base/cprintf.cc @@ -0,0 +1,270 @@ +/* + * 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 + */ + +#include <cassert> +#include <iomanip> +#include <iostream> +#include <sstream> + +#include "base/cprintf.hh" + +using namespace std; + +namespace cp { + +ArgList::~ArgList() +{ + while (!objects.empty()) { + delete objects.front(); + objects.pop_front(); + } +} + +void +ArgList::dump(const string &format) +{ + list_t::iterator iter = objects.begin(); + list_t::iterator end = objects.end(); + + const char *p = format.c_str(); + + stream->fill(' '); + stream->flags((ios::fmtflags)0); + + while (*p) { + switch (*p) { + case '%': { + if (p[1] == '%') { + *stream << '%'; + p += 2; + continue; + } + + Format fmt; + bool done = false; + bool end_number = false; + bool have_precision = false; + int number = 0; + + while (!done) { + ++p; + if (*p >= '0' && *p <= '9') { + if (end_number) + continue; + } else if (number > 0) + end_number = true; + + switch (*p) { + case 's': + fmt.format = Format::string; + done = true; + break; + + case 'c': + fmt.format = Format::character; + done = true; + break; + + case 'l': + continue; + + case 'p': + fmt.format = Format::integer; + fmt.base = Format::hex; + fmt.alternate_form = true; + done = true; + break; + + case 'X': + fmt.uppercase = true; + case 'x': + fmt.base = Format::hex; + fmt.format = Format::integer; + done = true; + break; + + case 'o': + fmt.base = Format::oct; + fmt.format = Format::integer; + done = true; + break; + + case 'd': + case 'i': + case 'u': + fmt.format = Format::integer; + done = true; + break; + + case 'G': + fmt.uppercase = true; + case 'g': + fmt.format = Format::floating; + fmt.float_format = Format::best; + done = true; + break; + + case 'E': + fmt.uppercase = true; + case 'e': + fmt.format = Format::floating; + fmt.float_format = Format::scientific; + done = true; + break; + + case 'f': + fmt.format = Format::floating; + fmt.float_format = Format::fixed; + done = true; + break; + + case 'n': + *stream << "we don't do %n!!!\n"; + done = true; + break; + + case '#': + fmt.alternate_form = true; + break; + + case '-': + fmt.flush_left = true; + break; + + case '+': + fmt.print_sign = true; + break; + + case ' ': + fmt.blank_space = true; + break; + + case '.': + fmt.width = number; + fmt.precision = 0; + have_precision = true; + number = 0; + end_number = false; + break; + + case '0': + if (number == 0) { + fmt.fill_zero = true; + break; + } + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + number = number * 10 + (*p - '0'); + break; + + case '%': + assert("we shouldn't get here"); + break; + + default: + done = true; + break; + } + + if (end_number) { + if (have_precision) + fmt.precision = number; + else + fmt.width = number; + + end_number = false; + number = 0; + } + } + + if (iter != end) + { + ios::fmtflags saved_flags = stream->flags(); + char old_fill = stream->fill(); + int old_precision = stream->precision(); + + (*iter)->process(*stream, fmt); + + stream->flags(saved_flags); + stream->fill(old_fill); + stream->precision(old_precision); + + ++iter; + } else { + *stream << "<missing arg for format>"; + } + + ++p; + } + break; + + case '\n': + *stream << endl; + ++p; + break; + case '\r': + ++p; + if (*p != '\n') + *stream << endl; + break; + + default: { + size_t len = strcspn(p, "%\n\r\0"); + stream->write(p, len); + p += len; + } + break; + } + } + + while (iter != end) { + *stream << "<extra arg>"; + ++iter; + } +} + +string +ArgList::dumpToString(const string &format) +{ + stringstream ss; + + dump(ss, format); + + return ss.str(); +} + +} diff --git a/src/base/cprintf.hh b/src/base/cprintf.hh new file mode 100644 index 000000000..6b2a77f90 --- /dev/null +++ b/src/base/cprintf.hh @@ -0,0 +1,200 @@ +/* + * 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 + * Steve Reinhardt + */ + +#ifndef __CPRINTF_HH__ +#define __CPRINTF_HH__ + +#include <iostream> +#include <list> +#include <string> + +#include "base/cprintf_formats.hh" + +namespace cp { + +class ArgList +{ + private: + class Base + { + public: + virtual ~Base() {} + virtual void process(std::ostream &out, Format &fmt) = 0; + }; + + template <typename T> + class Node : public Base + { + public: + const T &data; + + public: + Node(const T &d) : data(d) {} + virtual void process(std::ostream &out, Format &fmt) { + switch (fmt.format) { + case Format::character: + format_char(out, data, fmt); + break; + + case Format::integer: + format_integer(out, data, fmt); + break; + + case Format::floating: + format_float(out, data, fmt); + break; + + case Format::string: + format_string(out, data, fmt); + break; + + default: + out << "<bad format>"; + break; + } + } + }; + + typedef std::list<Base *> list_t; + + protected: + list_t objects; + std::ostream *stream; + + public: + ArgList() : stream(&std::cout) {} + ~ArgList(); + + template<class T> + void append(const T &data) { + Base *obj = new ArgList::Node<T>(data); + objects.push_back(obj); + } + + template<class T> + void prepend(const T &data) { + Base *obj = new ArgList::Node<T>(data); + objects.push_front(obj); + } + + void dump(const std::string &format); + void dump(std::ostream &strm, const std::string &fmt) + { stream = &strm; dump(fmt); } + + std::string dumpToString(const std::string &format); + + friend ArgList &operator<<(std::ostream &str, ArgList &list); +}; + +template<class T> +inline ArgList & +operator,(ArgList &alist, const T &data) +{ + alist.append(data); + return alist; +} + +class ArgListNull { +}; + +inline ArgList & +operator,(ArgList &alist, ArgListNull) +{ return alist; } + +// +// cprintf(format, args, ...) prints to cout +// (analogous to printf()) +// +inline void +__cprintf(const std::string &format, ArgList &args) +{ args.dump(format); delete &args; } +#define __cprintf__(format, args...) \ + cp::__cprintf(format, (*(new cp::ArgList), args)) +#define cprintf(args...) \ + __cprintf__(args, cp::ArgListNull()) + +// +// ccprintf(stream, format, args, ...) prints to the specified stream +// (analogous to fprintf()) +// +inline void +__ccprintf(std::ostream &stream, const std::string &format, ArgList &args) +{ args.dump(stream, format); delete &args; } +#define __ccprintf__(stream, format, args...) \ + cp::__ccprintf(stream, format, (*(new cp::ArgList), args)) +#define ccprintf(stream, args...) \ + __ccprintf__(stream, args, cp::ArgListNull()) + +// +// csprintf(format, args, ...) returns a string +// (roughly analogous to sprintf()) +// +inline std::string +__csprintf(const std::string &format, ArgList &args) +{ std::string s = args.dumpToString(format); delete &args; return s; } +#define __csprintf__(format, args...) \ + cp::__csprintf(format, (*(new cp::ArgList), args)) +#define csprintf(args...) \ + __csprintf__(args, cp::ArgListNull()) + +template<class T> +inline ArgList & +operator<<(ArgList &list, const T &data) +{ + list.append(data); + return list; +} + +inline ArgList & +operator<<(std::ostream &str, ArgList &list) +{ + list.stream = &str; + return list; +} + +class ArgListTemp +{ + private: + std::string format; + ArgList *args; + + public: + ArgListTemp(const std::string &f) : format(f) { args = new ArgList; } + ~ArgListTemp() { args->dump(format); delete args; } + + operator ArgList *() { return args; } +}; + +#define cformat(format) \ + (*((cp::ArgList *)cp::ArgListTemp(format))) +} + +#endif // __CPRINTF_HH__ diff --git a/src/base/cprintf_formats.hh b/src/base/cprintf_formats.hh new file mode 100644 index 000000000..58ee7f795 --- /dev/null +++ b/src/base/cprintf_formats.hh @@ -0,0 +1,355 @@ +/* + * Copyright (c) 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: Nathan Binkert + */ + +#ifndef __CPRINTF_FORMATS_HH__ +#define __CPRINTF_FORMATS_HH__ + +#include <sstream> +#include <ostream> + +namespace cp { + +struct Format +{ + bool alternate_form; + bool flush_left; + bool print_sign; + bool blank_space; + bool fill_zero; + bool uppercase; + enum { dec, hex, oct } base; + enum { none, string, integer, character, floating } format; + enum { best, fixed, scientific } float_format; + int precision; + int width; + + Format() { clear(); } + + void clear() + { + alternate_form = false; + flush_left = false; + print_sign = false; + blank_space = false; + fill_zero = false; + uppercase = false; + base = dec; + format = none; + precision = -1; + width = 0; + } +}; + +template <typename T> +inline void +_format_char(std::ostream &out, const T &data, Format &fmt) +{ + using namespace std; + + out << data; +} + +template <typename T> +inline void +_format_integer(std::ostream &out, const T &data, Format &fmt) +{ + using namespace std; + + switch (fmt.base) { + case Format::hex: + out.setf(ios::hex, ios::basefield); + break; + + case Format::oct: + out.setf(ios::oct, ios::basefield); + break; + + case Format::dec: + out.setf(ios::dec, ios::basefield); + break; + } + + if (fmt.alternate_form) { + if (!fmt.fill_zero) + out.setf(ios::showbase); + else { + switch (fmt.base) { + case Format::hex: + out << "0x"; + fmt.width -= 2; + break; + case Format::oct: + out << "0"; + fmt.width -= 1; + break; + case Format::dec: + break; + } + } + } + + if (fmt.fill_zero) + out.fill('0'); + + if (fmt.width > 0) + out.width(fmt.width); + + if (fmt.flush_left && !fmt.fill_zero) + out.setf(ios::left); + + if (fmt.print_sign) + out.setf(ios::showpos); + + if (fmt.uppercase) + out.setf(ios::uppercase); + + out << data; +} + +template <typename T> +inline void +_format_float(std::ostream &out, const T &data, Format &fmt) +{ + using namespace std; + + switch (fmt.float_format) { + case Format::scientific: + if (fmt.precision != -1) { + if (fmt.width > 0) + out.width(fmt.width); + + if (fmt.precision == 0) + fmt.precision = 1; + else + out.setf(ios::scientific); + + out.precision(fmt.precision); + } else + if (fmt.width > 0) + out.width(fmt.width); + + if (fmt.uppercase) + out.setf(ios::uppercase); + break; + + case Format::fixed: + if (fmt.precision != -1) { + if (fmt.width > 0) + out.width(fmt.width); + + out.setf(ios::fixed); + out.precision(fmt.precision); + } else + if (fmt.width > 0) + out.width(fmt.width); + + break; + + default: + if (fmt.precision != -1) + out.precision(fmt.precision); + + if (fmt.width > 0) + out.width(fmt.width); + + break; + } + + out << data; +} + +template <typename T> +inline void +_format_string(std::ostream &out, const T &data, Format &fmt) +{ + using namespace std; + +#if defined(__GNUC__) && (__GNUC__ < 3) || 1 + if (fmt.width > 0) { + std::stringstream foo; + foo << data; + int flen = foo.str().size(); + + if (fmt.width > flen) { + char *spaces = new char[fmt.width - flen + 1]; + memset(spaces, ' ', fmt.width - flen); + spaces[fmt.width - flen] = 0; + + if (fmt.flush_left) + out << foo.str() << spaces; + else + out << spaces << foo.str(); + + delete [] spaces; + } else + out << data; + } else + out << data; +#else + if (fmt.width > 0) + out.width(fmt.width); + if (fmt.flush_left) + out.setf(ios::left); + + out << data; +#endif +} + +///////////////////////////////////////////////////////////////////////////// +// +// The code below controls the actual usage of formats for various types +// + +// +// character formats +// +template <typename T> +inline void +format_char(std::ostream &out, const T &data, Format &fmt) +{ out << "<bad arg type for char format>"; } + +inline void +format_char(std::ostream &out, char data, Format &fmt) +{ _format_char(out, data, fmt); } + +inline void +format_char(std::ostream &out, unsigned char data, Format &fmt) +{ _format_char(out, data, fmt); } + +inline void +format_char(std::ostream &out, signed char data, Format &fmt) +{ _format_char(out, data, fmt); } + +inline void +format_char(std::ostream &out, short data, Format &fmt) +{ _format_char(out, (char)data, fmt); } + +inline void +format_char(std::ostream &out, unsigned short data, Format &fmt) +{ _format_char(out, (char)data, fmt); } + +inline void +format_char(std::ostream &out, int data, Format &fmt) +{ _format_char(out, (char)data, fmt); } + +inline void +format_char(std::ostream &out, unsigned int data, Format &fmt) +{ _format_char(out, (char)data, fmt); } + +inline void +format_char(std::ostream &out, long data, Format &fmt) +{ _format_char(out, (char)data, fmt); } + +inline void +format_char(std::ostream &out, unsigned long data, Format &fmt) +{ _format_char(out, (char)data, fmt); } + +inline void +format_char(std::ostream &out, long long data, Format &fmt) +{ _format_char(out, (char)data, fmt); } + +inline void +format_char(std::ostream &out, unsigned long long data, Format &fmt) +{ _format_char(out, (char)data, fmt); } + +// +// integer formats +// +template <typename T> +inline void +format_integer(std::ostream &out, const T &data, Format &fmt) +{ _format_integer(out, data, fmt); } +inline void +format_integer(std::ostream &out, char data, Format &fmt) +{ _format_integer(out, data, fmt); } +inline void +format_integer(std::ostream &out, unsigned char data, Format &fmt) +{ _format_integer(out, data, fmt); } +inline void +format_integer(std::ostream &out, signed char data, Format &fmt) +{ _format_integer(out, data, fmt); } +#if 0 +inline void +format_integer(std::ostream &out, short data, Format &fmt) +{ _format_integer(out, data, fmt); } +inline void +format_integer(std::ostream &out, unsigned short data, Format &fmt) +{ _format_integer(out, data, fmt); } +inline void +format_integer(std::ostream &out, int data, Format &fmt) +{ _format_integer(out, data, fmt); } +inline void +format_integer(std::ostream &out, unsigned int data, Format &fmt) +{ _format_integer(out, data, fmt); } +inline void +format_integer(std::ostream &out, long data, Format &fmt) +{ _format_integer(out, data, fmt); } +inline void +format_integer(std::ostream &out, unsigned long data, Format &fmt) +{ _format_integer(out, data, fmt); } +inline void +format_integer(std::ostream &out, long long data, Format &fmt) +{ _format_integer(out, data, fmt); } +inline void +format_integer(std::ostream &out, unsigned long long data, Format &fmt) +{ _format_integer(out, data, fmt); } +#endif + +// +// floating point formats +// +template <typename T> +inline void +format_float(std::ostream &out, const T &data, Format &fmt) +{ out << "<bad arg type for float format>"; } + +inline void +format_float(std::ostream &out, float data, Format &fmt) +{ _format_float(out, data, fmt); } + +inline void +format_float(std::ostream &out, double data, Format &fmt) +{ _format_float(out, data, fmt); } + +// +// string formats +// +template <typename T> +inline void +format_string(std::ostream &out, const T &data, Format &fmt) +{ _format_string(out, data, fmt); } + +inline void +format_string(std::ostream &out, const std::stringstream &data, Format &fmt) +{ _format_string(out, data.str(), fmt); } + +} // namespace cp + +#endif // __CPRINTF_FORMATS_HH__ diff --git a/src/base/crc.cc b/src/base/crc.cc new file mode 100644 index 000000000..08f039577 --- /dev/null +++ b/src/base/crc.cc @@ -0,0 +1,114 @@ +/* + * Copyright (c) 1988, 1992, 1993 + * The 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: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <string> + +#include "sim/host.hh" +#include "base/crc.hh" + +#define ETHER_CRC_POLY_LE 0xedb88320 +#define ETHER_CRC_POLY_BE 0x04c11db6 + +#if 0 +/* + * This is for reference. We have a table-driven version + * of the little-endian crc32 generator, which is faster + * than the double-loop. + */ +uint32_t +crc32le(const uint8_t *buf, size_t len) +{ + uint32_t c, crc, carry; + size_t i, j; + + crc = 0xffffffffU; /* initial value */ + + for (i = 0; i < len; i++) { + c = buf[i]; + for (j = 0; j < 8; j++) { + carry = ((crc & 0x01) ? 1 : 0) ^ (c & 0x01); + crc >>= 1; + c >>= 1; + if (carry) + crc = (crc ^ ETHER_CRC_POLY_LE); + } + } + + return (crc); +} +#else +uint32_t +crc32le(const uint8_t *buf, size_t len) +{ + static const uint32_t crctab[] = { + 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, + 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, + 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, + 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c + }; + uint32_t crc; + int i; + + crc = 0xffffffffU; /* initial value */ + + for (i = 0; i < len; i++) { + crc ^= buf[i]; + crc = (crc >> 4) ^ crctab[crc & 0xf]; + crc = (crc >> 4) ^ crctab[crc & 0xf]; + } + + return (crc); +} +#endif + +uint32_t +crc32be(const uint8_t *buf, size_t len) +{ + uint32_t c, crc, carry; + size_t i, j; + + crc = 0xffffffffU; /* initial value */ + + for (i = 0; i < len; i++) { + c = buf[i]; + for (j = 0; j < 8; j++) { + carry = ((crc & 0x80000000U) ? 1 : 0) ^ (c & 0x01); + crc <<= 1; + c >>= 1; + if (carry) + crc = (crc ^ ETHER_CRC_POLY_BE) | carry; + } + } + + return (crc); +} diff --git a/src/base/crc.hh b/src/base/crc.hh new file mode 100644 index 000000000..16dce79aa --- /dev/null +++ b/src/base/crc.hh @@ -0,0 +1,39 @@ +/* + * 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: Nathan Binkert + */ + +#ifndef __BASE_CRC_HH__ +#define __BASE_CRC_HH__ + +#include "sim/host.hh" + +uint32_t crc32be(const uint8_t *buf, size_t len); +uint32_t crc32le(const uint8_t *buf, size_t len); + +#endif // __BASE_CRC_HH__ diff --git a/src/base/date.cc b/src/base/date.cc new file mode 100644 index 000000000..9ec8a0b33 --- /dev/null +++ b/src/base/date.cc @@ -0,0 +1,31 @@ +/* + * Copyright (c) 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: Nathan Binkert + */ + +const char *compileDate = __DATE__ " " __TIME__; diff --git a/src/base/dbl_list.hh b/src/base/dbl_list.hh new file mode 100644 index 000000000..8fca72998 --- /dev/null +++ b/src/base/dbl_list.hh @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2000-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 Reinhardt + */ + +#ifndef __DBL_LIST_HH__ +#define __DBL_LIST_HH__ + +class DblListEl { + DblListEl *next; + DblListEl *prev; + + // remove this from list + void remove() { + prev->next = next; + next->prev = prev; + } + + // insert this before old_el + void insertBefore(DblListEl *old_el) { + prev = old_el->prev; + next = old_el; + prev->next = this; + next->prev = this; + } + + // insert this after old_el + void insertAfter(DblListEl *old_el) { + next = old_el->next; + prev = old_el; + next->prev = this; + prev->next = this; + } + + friend class DblListBase; +}; + + +// +// doubly-linked list of DblListEl objects +// +class DblListBase { + // dummy list head element: dummy.next is head, dummy.prev is tail + DblListEl dummy; + + // length counter + unsigned length; + + DblListEl *valid_or_null(DblListEl *el) { + // make sure users never see the dummy element + return (el == &dummy) ? NULL : el; + } + + public: + + DblListEl *head() { + return valid_or_null(dummy.next); + } + + DblListEl *tail() { + return valid_or_null(dummy.prev); + } + + DblListEl *next(DblListEl *el) { + return valid_or_null(el->next); + } + + DblListEl *prev(DblListEl *el) { + return valid_or_null(el->prev); + } + + bool is_empty() { + return (dummy.next == &dummy); + } + + void remove(DblListEl *el) { + el->remove(); + --length; + } + + void insertBefore(DblListEl *new_el, DblListEl *old_el) { + new_el->insertBefore(old_el); + ++length; + } + + void insertAfter(DblListEl *new_el, DblListEl *old_el) { + new_el->insertAfter(old_el); + ++length; + } + + // append to end of list, i.e. as dummy.prev + void append(DblListEl *el) { + insertBefore(el, &dummy); + } + + // prepend to front of list (push), i.e. as dummy.next + void prepend(DblListEl *el) { + insertAfter(el, &dummy); + } + + DblListEl *pop() { + DblListEl *hd = head(); + if (hd != NULL) + remove(hd); + return hd; + } + + // constructor + DblListBase() { + dummy.next = dummy.prev = &dummy; + length = 0; + } +}; + + +// +// Template class serves solely to cast args & return values +// to appropriate type (T *) +// +template<class T> class DblList : private DblListBase { + + public: + + T *head() { return (T *)DblListBase::head(); } + T *tail() { return (T *)DblListBase::tail(); } + + T *next(T *el) { return (T *)DblListBase::next(el); } + T *prev(T *el) { return (T *)DblListBase::prev(el); } + + bool is_empty() { return DblListBase::is_empty(); } + + void remove(T *el) { DblListBase::remove(el); } + + void append(T *el) { DblListBase::append(el); } + void prepend(T *el) { DblListBase::prepend(el); } + + T *pop() { return (T *)DblListBase::pop(); } + + DblList<T>() { } +}; + +#endif // __DBL_LIST_HH__ diff --git a/src/base/endian.hh b/src/base/endian.hh new file mode 100644 index 000000000..d2b9dc65c --- /dev/null +++ b/src/base/endian.hh @@ -0,0 +1,43 @@ +/* + * Copyright (c) 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: Nathan Binkert + */ + +#ifndef __ENDIAN_HH__ +#define __ENDIAN_HH__ + +#include <arpa/inet.h> + +inline bool +HostBigEndian() +{ + int x = 0x11223344; + return x == htonl(x); +} + +#endif // __ENDIAN_HH__ diff --git a/src/base/fast_alloc.cc b/src/base/fast_alloc.cc new file mode 100644 index 000000000..455fb8ed7 --- /dev/null +++ b/src/base/fast_alloc.cc @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2000-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 + */ + +/* + * This code was originally written by Steve Reinhardt as part of + * the Wisconsin Wind Tunnel simulator. Relicensed as part of M5 + * by permission. + */ + +#ifndef NO_FAST_ALLOC + +#ifdef __GNUC__ +#pragma implementation +#endif + +#include <assert.h> +#include "base/fast_alloc.hh" + +void *FastAlloc::freeLists[Num_Buckets]; + +#ifdef FAST_ALLOC_STATS +unsigned FastAlloc::newCount[Num_Buckets]; +unsigned FastAlloc::deleteCount[Num_Buckets]; +unsigned FastAlloc::allocCount[Num_Buckets]; +#endif + +void *FastAlloc::moreStructs(int bucket) +{ + assert(bucket > 0 && bucket < Num_Buckets); + + int sz = bucket * Alloc_Quantum; + const int nstructs = Num_Structs_Per_New; // how many to allocate? + char *p = ::new char[nstructs * sz]; + +#ifdef FAST_ALLOC_STATS + ++allocCount[bucket]; +#endif + + freeLists[bucket] = p; + for (int i = 0; i < (nstructs-2); ++i, p += sz) + *(void **)p = p + sz; + *(void **)p = 0; + + return (p + sz); +} + + +#ifdef FAST_ALLOC_DEBUG + +#include <typeinfo> +#include <iostream> +#include <iomanip> +#include <map> +#include <string> + +using namespace std; + +// count of in-use FastAlloc objects +int FastAlloc::numInUse; + +// dummy head & tail object for doubly linked list of in-use FastAlloc +// objects +FastAlloc FastAlloc::inUseHead(&FastAlloc::inUseHead, &FastAlloc::inUseHead); + +// special constructor for dummy head: make inUsePrev & inUseNext +// point to self +FastAlloc::FastAlloc(FastAlloc *prev, FastAlloc *next) +{ + inUsePrev = prev; + inUseNext = next; +} + + +// constructor: marks as in use, add to in-use list +FastAlloc::FastAlloc() +{ + // mark this object in use + inUse = true; + + // update count + ++numInUse; + + // add to tail of list of in-use objects ("before" dummy head) + FastAlloc *myNext = &inUseHead; + FastAlloc *myPrev = inUseHead.inUsePrev; + + inUsePrev = myPrev; + inUseNext = myNext; + myPrev->inUseNext = this; + myNext->inUsePrev = this; +} + +// destructor: mark not in use, remove from in-use list +FastAlloc::~FastAlloc() +{ + assert(inUse); + inUse = false; + + --numInUse; + assert(numInUse >= 0); + + // remove me from in-use list + inUsePrev->inUseNext = inUseNext; + inUseNext->inUsePrev = inUsePrev; +} + + +// summarize in-use list +void +FastAlloc::dump_summary() +{ + map<string, int> typemap; + + for (FastAlloc *p = inUseHead.inUseNext; p != &inUseHead; p = p->inUseNext) + { + ++typemap[typeid(*p).name()]; + } + + map<string, int>::const_iterator mapiter; + + cout << " count type\n" + << " ----- ----\n"; + for (mapiter = typemap.begin(); mapiter != typemap.end(); ++mapiter) + { + cout << setw(6) << mapiter->second << " " << mapiter->first << endl; + } +} + + +// show oldest n items on in-use list +void +FastAlloc::dump_oldest(int n) +{ + // sanity check: don't want to crash the debugger if you forget to + // pass in a parameter + if (n < 0 || n > numInUse) + { + cout << "FastAlloc::dump_oldest: bad arg " << n + << " (" << numInUse << " objects in use" << endl; + return; + } + + for (FastAlloc *p = inUseHead.inUsePrev; + p != &inUseHead && n > 0; + p = p->inUsePrev, --n) + { + cout << p << " " << typeid(*p).name() << endl; + } +} + + +// +// C interfaces to FastAlloc::dump_summary() and FastAlloc::dump_oldest(). +// gdb seems to have trouble with calling C++ functions directly. +// +extern "C" void +fast_alloc_summary() +{ + FastAlloc::dump_summary(); +} + +extern "C" void +fast_alloc_oldest(int n) +{ + FastAlloc::dump_oldest(n); +} + +#endif + +#endif // NO_FAST_ALLOC diff --git a/src/base/fast_alloc.hh b/src/base/fast_alloc.hh new file mode 100644 index 000000000..3e22e59c1 --- /dev/null +++ b/src/base/fast_alloc.hh @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2000-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 Reinhardt + */ + +/* + * This code was originally written by Steve Reinhardt as part of + * the Wisconsin Wind Tunnel simulator. Relicensed as part of M5 + * by permission. + */ + +#ifndef __FAST_ALLOC_H__ +#define __FAST_ALLOC_H__ + +#include <stddef.h> + +// Fast structure allocator. Designed for small objects that are +// frequently allocated and deallocated. This code is derived from the +// 'alloc_struct' package used in WWT and Blizzard. C++ provides a +// much nicer framework for the same optimization. The package is +// implemented as a class, FastAlloc. Allocation and deletion are +// performed using FastAlloc's new and delete operators. Any object +// that derives from the FastAlloc class will transparently use this +// allocation package. + +// The static allocate() and deallocate() methods can also be called +// directly if desired. + +// In order for derived classes to call delete with the correct +// structure size even when they are deallocated via a base-type +// pointer, they must have a virtual destructor. It is sufficient for +// FastAlloc to declare a virtual destructor (as it does); it is not +// required for derived classes to declare their own destructor. The +// compiler will automatically generate a virtual destructor for each +// derived class. However, it is more efficient if each derived class +// defines an inline destructor, so that the compiler can statically +// collapse the destructor call chain back up the inheritance +// hierarchy. + +// Uncomment this #define to track in-use objects +// (for debugging memory leaks). +//#define FAST_ALLOC_DEBUG + +// Uncomment this #define to count news, deletes, and chunk allocations +// (by bucket). +// #define FAST_ALLOC_STATS + +#include "config/no_fast_alloc.hh" + +#if NO_FAST_ALLOC + +class FastAlloc { +}; + +#else + +class FastAlloc { + public: + + static void *allocate(size_t); + static void deallocate(void *, size_t); + + void *operator new(size_t); + void operator delete(void *, size_t); + +#ifdef FAST_ALLOC_DEBUG + FastAlloc(); + FastAlloc(FastAlloc*,FastAlloc*); // for inUseHead, see below + virtual ~FastAlloc(); +#else + virtual ~FastAlloc() {} +#endif + + private: + + // Max_Alloc_Size is the largest object that can be allocated with + // this class. There's no fundamental limit, but this limits the + // size of the freeLists array. Let's not make this really huge + // like in Blizzard. + static const int Max_Alloc_Size = 512; + + // Alloc_Quantum is the difference in size between adjacent + // buckets in the free list array. + static const int Log2_Alloc_Quantum = 3; + static const int Alloc_Quantum = (1 << Log2_Alloc_Quantum); + + // Num_Buckets = bucketFor(Max_Alloc_Size) + 1 + static const int Num_Buckets = + ((Max_Alloc_Size + Alloc_Quantum - 1) >> Log2_Alloc_Quantum) + 1; + + // when we call new() for more structures, how many should we get? + static const int Num_Structs_Per_New = 20; + + static int bucketFor(size_t); + static void *moreStructs(int bucket); + + static void *freeLists[Num_Buckets]; + +#ifdef FAST_ALLOC_STATS + static unsigned newCount[Num_Buckets]; + static unsigned deleteCount[Num_Buckets]; + static unsigned allocCount[Num_Buckets]; +#endif + +#ifdef FAST_ALLOC_DEBUG + // per-object debugging fields + bool inUse; // in-use flag + FastAlloc *inUsePrev; // ptrs to build list of in-use objects + FastAlloc *inUseNext; + + // static (global) debugging vars + static int numInUse; // count in-use objects + static FastAlloc inUseHead; // dummy head for list of in-use objects + + public: + // functions to dump debugging info (see fast_alloc.cc for C + // versions that might be more agreeable to call from gdb) + static void dump_summary(); + static void dump_oldest(int n); +#endif +}; + + +inline +int FastAlloc::bucketFor(size_t sz) +{ + return (sz + Alloc_Quantum - 1) >> Log2_Alloc_Quantum; +} + + +inline +void *FastAlloc::allocate(size_t sz) +{ + int b; + void *p; + + if (sz > Max_Alloc_Size) + return (void *)::new char[sz]; + + b = bucketFor(sz); + p = freeLists[b]; + + if (p) + freeLists[b] = *(void **)p; + else + p = moreStructs(b); + +#ifdef FAST_ALLOC_STATS + ++newCount[b]; +#endif + + return p; +} + + +inline +void FastAlloc::deallocate(void *p, size_t sz) +{ + int b; + + if (sz > Max_Alloc_Size) + { + ::delete [] (char *)p; + return; + } + + b = bucketFor(sz); + *(void **)p = freeLists[b]; + freeLists[b] = p; +#ifdef FAST_ALLOC_STATS + ++deleteCount[b]; +#endif +} + + +inline +void *FastAlloc::operator new(size_t sz) +{ + return allocate(sz); +} + + +inline +void FastAlloc::operator delete(void *p, size_t sz) +{ + deallocate(p, sz); +} + +#endif // NO_FAST_ALLOC + +#endif // __FAST_ALLOC_H__ diff --git a/src/base/fenv.hh b/src/base/fenv.hh new file mode 100644 index 000000000..013d2f09b --- /dev/null +++ b/src/base/fenv.hh @@ -0,0 +1,54 @@ +/* + * 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: Steve Reinhardt + */ + +#ifndef __BASE_FENV_HH__ +#define __BASE_FENV_HH__ + +#include "config/use_fenv.hh" + +#if USE_FENV + +#include <fenv.h> + +#else + +// Dummy definitions to allow code to compile w/o a real <fenv.h>. + +#define FE_TONEAREST 0 +#define FE_DOWNWARD 0 +#define FE_UPWARD 0 +#define FE_TOWARDZERO 0 + +inline int fesetround(int rounding_mode) { return 0; } + +#endif // USE_FENV + + +#endif // __BASE_FENV_HH__ diff --git a/src/base/fifo_buffer.cc b/src/base/fifo_buffer.cc new file mode 100644 index 000000000..4bafa88bd --- /dev/null +++ b/src/base/fifo_buffer.cc @@ -0,0 +1,43 @@ +/* + * 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: Steve Raasch + * Nathan Binkert + */ + +#include "base/fifo_buffer.hh" + +template<class T> +void +FifoBuffer<T>::dump() +{ + if (buffer->count() > 0) + for (iterator i=buffer->tail(); i.notnull(); i=i.prev()) + i->dump(); +} + + diff --git a/src/base/fifo_buffer.hh b/src/base/fifo_buffer.hh new file mode 100644 index 000000000..f6205330b --- /dev/null +++ b/src/base/fifo_buffer.hh @@ -0,0 +1,89 @@ +/* + * 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: Steve Raasch + * Nathan Binkert + */ + +#ifndef __FIFO_BUFFER_HH__ +#define __FIFO_BUFFER_HH__ + +#include "base/res_list.hh" + + +// +// The FifoBuffer requires only that the objects to be used have a default +// constructor and a dump() method +// +template<class T> +class FifoBuffer +{ + public: + typedef typename res_list<T>::iterator iterator; + + private: + res_list<T> *buffer; + + unsigned size; + + public: + FifoBuffer(unsigned sz) + { + buffer = new res_list<T>(sz, true, 0); + size = sz; + } + + void add(T &item) + { + assert(buffer->num_free() > 0); + buffer->add_head(item); + } + + iterator head() { return buffer->head(); } + iterator tail() { return buffer->tail(); } + + unsigned count() {return buffer->count();} + unsigned free_slots() {return buffer->num_free();} + + T *peek() { return (count() > 0) ? tail().data_ptr() : 0; } + + T remove() + { + assert(buffer->count() > 0); + T rval = *buffer->tail(); + buffer->remove_tail(); + return rval; + } + + void dump(); + + ~FifoBuffer() { delete buffer; } +}; + + +#endif + diff --git a/src/base/hashmap.hh b/src/base/hashmap.hh new file mode 100644 index 000000000..570cbc152 --- /dev/null +++ b/src/base/hashmap.hh @@ -0,0 +1,87 @@ +/* + * Copyright (c) 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: Nathan Binkert + */ + +#ifndef __HASHMAP_HH__ +#define __HASHMAP_HH__ + +#if defined(__GNUC__) && __GNUC__ >= 3 +#include <ext/hash_map> +#else +#include <hash_map> +#endif + +#include <string> + +#include "sim/host.hh" + +#if defined(__GNUC__) && __GNUC__ >= 3 + #define __hash_namespace __gnu_cxx +#else + #define __hash_namespace std +#endif + +namespace m5 { + using ::__hash_namespace::hash_multimap; + using ::__hash_namespace::hash_map; + using ::__hash_namespace::hash; +} + + +/////////////////////////////////// +// Some default Hashing Functions +// + +namespace __hash_namespace { +#if !defined(__LP64__) && !defined(__alpha__) + template<> + struct hash<uint64_t> { + size_t operator()(uint64_t r) const { + return r; + } + }; + + template<> + struct hash<int64_t> { + size_t operator()(int64_t r) const { + return r; + }; + }; +#endif + + template<> + struct hash<std::string> { + size_t operator()(const std::string &s) const { + return(__stl_hash_string(s.c_str())); + } + }; +} + + +#endif // __HASHMAP_HH__ diff --git a/src/base/hostinfo.cc b/src/base/hostinfo.cc new file mode 100644 index 000000000..a7c93e712 --- /dev/null +++ b/src/base/hostinfo.cc @@ -0,0 +1,87 @@ +/* + * Copyright (c) 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: Nathan Binkert + */ + +#include <ctype.h> +#include <errno.h> +#include <math.h> +#include <unistd.h> + +#include <cstdlib> +#include <cstring> +#include <string> + +#include "base/misc.hh" +#include "sim/host.hh" + +using namespace std; + +string +__get_hostname() +{ + char host[256]; + if (gethostname(host, sizeof host) == -1) + warn("could not get host name!"); + return host; +} + +string & +hostname() +{ + static string hostname = __get_hostname(); + return hostname; +} + +uint64_t +procInfo(char *filename, char *target) +{ + int done = 0; + char line[80]; + char format[80]; + long usage; + + FILE *fp = fopen(filename, "r"); + + while (fp && !feof(fp) && !done) { + if (fgets(line, 80, fp)) { + if (strncmp(line, target, strlen(target)) == 0) { + snprintf(format, sizeof(format), "%s %%ld", target); + sscanf(line, format, &usage); + + fclose(fp); + return usage ; + } + } + } + + if (fp) + fclose(fp); + + return 0; +} diff --git a/src/base/hostinfo.hh b/src/base/hostinfo.hh new file mode 100644 index 000000000..b6663ea69 --- /dev/null +++ b/src/base/hostinfo.hh @@ -0,0 +1,45 @@ +/* + * Copyright (c) 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: Nathan Binkert + */ + +#ifndef __HOSTINFO_HH__ +#define __HOSTINFO_HH__ + +#include <string> + +#include "sim/host.hh" + +std::string &hostname(); + +uint64_t procInfo(char *filename, char *target); + +inline uint64_t memUsage() +{ return procInfo("/proc/self/status", "VmSize:"); } + +#endif // __HOSTINFO_HH__ diff --git a/src/base/hybrid_pred.cc b/src/base/hybrid_pred.cc new file mode 100644 index 000000000..73216489e --- /dev/null +++ b/src/base/hybrid_pred.cc @@ -0,0 +1,276 @@ +/* + * Copyright (c) 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 Reinhardt + * Lisa Hsu + */ + +#include <string> +#include <sstream> + +#include "base/hybrid_pred.hh" +#include "base/statistics.hh" +#include "sim/stats.hh" + +using namespace std; + +HybridPredictor::HybridPredictor(const char *_p_name, const char *_z_name, + const char *_o_name, + unsigned _index_bits, unsigned _counter_bits, + unsigned _zero_change, unsigned _one_change, + unsigned _thresh, + unsigned _global_bits, + unsigned _global_thresh, + bool _reg_individual_stats) +{ + stringstream local_name, global_name; + + pred_name = _p_name; + one_name = _o_name; + zero_name = _z_name; + reg_individual_stats = _reg_individual_stats; + + local_name << pred_name.c_str() << ":L"; + local = new SaturatingCounterPred(local_name.str(), zero_name, one_name, + _index_bits, _counter_bits, + _zero_change, _one_change, _thresh); + + global_name << pred_name.c_str() << ":G"; + global = new SaturatingCounterPred(global_name.str(), zero_name, one_name, + 0, _global_bits, 1, 1, _global_thresh); +} + +void HybridPredictor::regStats() +{ + using namespace Stats; + + string p_name; + stringstream description; + + if (reg_individual_stats) + p_name = pred_name + ":A"; + else + p_name = pred_name; + + + // + // Number of predictions + // + stringstream num_zero_preds; + num_zero_preds << p_name << ":" << zero_name << ":preds"; + description << "number of predictions of " << zero_name; + pred_zero + .name(num_zero_preds.str()) + .desc(description.str()); + description.str(""); + + stringstream num_one_preds; + num_one_preds << p_name << ":" << one_name << ":preds"; + description << "number of predictions of " << one_name; + pred_one + .name(num_one_preds.str()) + .desc(description.str()) + ; + description.str(""); + + // + // Count the number of correct predictions + // + stringstream num_zero_correct; + num_zero_correct << p_name << ":" << zero_name << ":corr_preds"; + description << "number of correct " << zero_name << " preds" ; + correct_pred_zero + .name(num_zero_correct.str()) + .desc(description.str()) + ; + description.str(""); + + stringstream num_one_correct; + num_one_correct << p_name << ":" << one_name << ":corr_preds"; + description << "number of correct " << one_name << " preds" ; + correct_pred_one + .name(num_one_correct.str()) + .desc(description.str()) + ; + description.str(""); + + + // + // Number of predictor updates + // + stringstream num_zero_updates; + num_zero_updates << p_name << ":" << zero_name << ":updates" ; + description << "number of actual " << zero_name << "s" ; + record_zero + .name(num_zero_updates.str()) + .desc(description.str()) + ; + description.str(""); + + stringstream num_one_updates; + num_one_updates << p_name << ":" << one_name << ":updates" ; + description << "number of actual " << one_name << "s" ; + record_one + .name(num_one_updates.str()) + .desc(description.str()) + ; + description.str(""); + + // + // Local & Global predictor stats + // + if (reg_individual_stats) { + local->regStats(); + global->regStats(); + } +} + +void HybridPredictor::regFormulas() +{ + using namespace Stats; + + string p_name; + stringstream description; + stringstream name; + + if (reg_individual_stats) + p_name = pred_name + ":A"; + else + p_name = pred_name; + + // + // Number of predictions + // + name << p_name << ":predictions" ; + total_preds + .name(name.str()) + .desc("total number of predictions made") + ; + total_preds = pred_one + pred_zero; + name.str(""); + + // + // Fraction of all predictions that are one or zero + // + name << p_name << ":" << zero_name << ":pred_frac"; + description << "fraction of all preds that were " << zero_name ; + frac_preds_zero + .name(name.str()) + .desc(description.str()) + ; + frac_preds_zero = 100 * record_zero / total_preds; + description.str(""); + name.str(""); + + name << p_name << ":" << one_name << ":pred_frac"; + description << "fraction of all preds that were " << one_name ; + frac_preds_one + .name(name.str()) + .desc(description.str()) + ; + frac_preds_one = 100 * record_one / total_preds; + description.str(""); + name.str(""); + + // + // Count the number of correct predictions + // + name << p_name << ":correct_preds" ; + total_correct + .name(name.str()) + .desc("total number of correct predictions made") + ; + total_correct = correct_pred_one + correct_pred_zero; + name.str(""); + + + // + // Prediction accuracy rates + // + name << p_name << ":pred_rate"; + total_accuracy + .name(name.str()) + .desc("fraction of all preds that were correct") + ; + total_accuracy = 100 * total_correct / total_preds; + name.str(""); + + name << p_name << ":" << zero_name << ":pred_rate" ; + description << "fraction of "<< zero_name <<" preds that were correct"; + zero_accuracy + .name(name.str()) + .desc(description.str()) + ; + zero_accuracy = 100 * correct_pred_zero / pred_zero; + description.str(""); + name.str(""); + + name << p_name << ":" << one_name << ":pred_rate" ; + description << "fraction of "<< one_name <<" preds that were correct"; + one_accuracy + .name(name.str()) + .desc(description.str()) + ; + one_accuracy = 100 * correct_pred_one / pred_one; + description.str(""); + name.str(""); + + // + // Coverage + // + name << p_name << ":" << zero_name << ":coverage"; + description << "fraction of " << zero_name + << "s that were predicted correctly"; + zero_coverage + .name(name.str()) + .desc(description.str()) + ; + zero_coverage = 100 * correct_pred_zero / record_zero; + description.str(""); + name.str(""); + + name << p_name << ":" << one_name << ":coverage"; + description << "fraction of " << one_name + << "s that were predicted correctly"; + one_coverage + .name(name.str()) + .desc(description.str()) + ; + one_coverage = 100 * correct_pred_one / record_one; + description.str(""); + name.str(""); + + // + // Local & Global predictor stats + // + if (reg_individual_stats) { + local->regFormulas(); + global->regFormulas(); + } + +} + diff --git a/src/base/hybrid_pred.hh b/src/base/hybrid_pred.hh new file mode 100644 index 000000000..cb1d6003b --- /dev/null +++ b/src/base/hybrid_pred.hh @@ -0,0 +1,204 @@ +/* + * 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 Raasch + * Steve Reinhardt + */ + +//========================================================================== +// +// This predictor takes the AND of a "local" and a "global" predictor +// in order to determine its prediction. +// +// +// +// + +#ifndef __HYBRID_PRED_HH__ +#define __HYBRID_PRED_HH__ + +#include <string> + +#include "base/sat_counter.hh" +#include "base/statistics.hh" + +class HybridPredictor : public GenericPredictor +{ + private: + std::string pred_name; + std::string one_name; + std::string zero_name; + bool reg_individual_stats; + + SaturatingCounterPred *local; + SaturatingCounterPred *global; + + unsigned long max_index; + + // + // Stats + // + Stats::Scalar<> pred_one; //num_one_preds + Stats::Scalar<> pred_zero; //num_zero_preds + Stats::Scalar<> correct_pred_one; //num_one_correct + Stats::Scalar<> correct_pred_zero; //num_zero_correct + Stats::Scalar<> record_one; //num_one_updates + Stats::Scalar<> record_zero; //num_zero_updates + + Stats::Formula total_preds; + Stats::Formula frac_preds_zero; + Stats::Formula frac_preds_one; + Stats::Formula total_correct; + Stats::Formula total_accuracy; + Stats::Formula zero_accuracy; + Stats::Formula one_accuracy; + Stats::Formula zero_coverage; + Stats::Formula one_coverage; + + public: + HybridPredictor(const char *_p_name, const char *_z_name, + const char *_o_name, + unsigned _index_bits, unsigned _counter_bits, + unsigned _zero_change, unsigned _one_change, + unsigned _thresh, + unsigned _global_bits, unsigned _global_thresh, + bool _reg_individual_stats = false); + + void clear() { + global->clear(); + local->clear(); + } + + unsigned peek(unsigned long _index) { + unsigned l = local->peek(_index); + unsigned g = global->peek(_index); + + if (l && g) + return 1; + + return 0; + } + + unsigned value(unsigned long _index) { + unsigned l = local->peek(_index); + unsigned g = global->peek(_index); + + l = l & 0xFFFF; + g = g & 0xFFFF; + + return (l << 16) | g; + + } + + unsigned predict(unsigned long _index) { + unsigned l = local->predict(_index); + unsigned g = global->predict(_index); + + if (l && g) { + ++pred_one; + return 1; + } + + ++pred_zero; + return 0; + } + + + // + // This version need only be used if local/global statistics + // will be maintained + // + unsigned predict(unsigned long _index, unsigned &_pdata) { + unsigned l = local->predict(_index); + unsigned g = global->predict(_index); + + // + // bit 0 => local predictor result + // bit 1 => global predictor result + // + _pdata = 0; + if (l) + _pdata |= 1; + if (g) + _pdata |= 2; + if (l && g) { + ++pred_one; + return 1; + } + + ++pred_zero; + return 0; + } + + void record(unsigned long _index, unsigned _val, unsigned _predicted) { + + if (_val) { + local->record(_index, _val, 0); + global->record(_index, _val, 0); + ++record_one; + + if (_val == _predicted) { + ++correct_pred_one; + } + } else { + local->record(_index, _val, 0); + global->record(_index, _val, 0); + ++record_zero; + + if (_val == _predicted) + ++correct_pred_zero; + } + } + + void record(unsigned long _index, unsigned _val, unsigned _predicted, + unsigned _pdata) + { + + local->record(_index, _val, (_pdata & 1)); + global->record(_index, _val, ((_pdata & 2) ? 1 : 0)); + + + if (_val) { + ++record_one; + + if (_val == _predicted) + ++correct_pred_one; + } else { + ++record_zero; + + if (_val == _predicted) + ++correct_pred_zero; + } + } + + void regStats(); + void regFormulas(); +}; + + +#endif // _HYBRID_PRED_HH__ + diff --git a/src/base/inet.cc b/src/base/inet.cc new file mode 100644 index 000000000..b8da12a99 --- /dev/null +++ b/src/base/inet.cc @@ -0,0 +1,209 @@ +/* + * 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 + */ + +#include <sstream> +#include <string> + +#include "base/cprintf.hh" +#include "sim/host.hh" +#include "base/inet.hh" + +using namespace std; +namespace Net { + +EthAddr::EthAddr() +{ + memset(data, 0, ETH_ADDR_LEN); +} + +EthAddr::EthAddr(const uint8_t ea[ETH_ADDR_LEN]) +{ + *data = *ea; +} + +EthAddr::EthAddr(const eth_addr &ea) +{ + *data = *ea.data; +} + +EthAddr::EthAddr(const std::string &addr) +{ + parse(addr); +} + +const EthAddr & +EthAddr::operator=(const eth_addr &ea) +{ + *data = *ea.data; + return *this; +} + +const EthAddr & +EthAddr::operator=(const std::string &addr) +{ + parse(addr); + return *this; +} + +void +EthAddr::parse(const std::string &addr) +{ + // the hack below is to make sure that ETH_ADDR_LEN is 6 otherwise + // the sscanf function won't work. + int bytes[ETH_ADDR_LEN == 6 ? ETH_ADDR_LEN : -1]; + if (sscanf(addr.c_str(), "%x:%x:%x:%x:%x:%x", &bytes[0], &bytes[1], + &bytes[2], &bytes[3], &bytes[4], &bytes[5]) != ETH_ADDR_LEN) { + memset(data, 0xff, ETH_ADDR_LEN); + return; + } + + for (int i = 0; i < ETH_ADDR_LEN; ++i) { + if (bytes[i] & ~0xff) { + memset(data, 0xff, ETH_ADDR_LEN); + return; + } + + data[i] = bytes[i]; + } +} + +string +EthAddr::string() const +{ + stringstream stream; + stream << *this; + return stream.str(); +} + +bool +operator==(const EthAddr &left, const EthAddr &right) +{ + return memcmp(left.bytes(), right.bytes(), ETH_ADDR_LEN); +} + +ostream & +operator<<(ostream &stream, const EthAddr &ea) +{ + const uint8_t *a = ea.addr(); + ccprintf(stream, "%x:%x:%x:%x:%x:%x", a[0], a[1], a[2], a[3], a[4], a[5]); + return stream; +} + +uint16_t +cksum(const IpPtr &ptr) +{ + int sum = ip_cksum_add(ptr->bytes(), ptr->hlen(), 0); + return ip_cksum_carry(sum); +} + +uint16_t +__tu_cksum(const IpPtr &ip) +{ + int tcplen = ip->len() - ip->hlen(); + int sum = ip_cksum_add(ip->payload(), tcplen, 0); + sum = ip_cksum_add(&ip->ip_src, 8, sum); // source and destination + sum += htons(ip->ip_p + tcplen); + return ip_cksum_carry(sum); +} + +uint16_t +cksum(const TcpPtr &tcp) +{ return __tu_cksum(IpPtr(tcp.packet())); } + +uint16_t +cksum(const UdpPtr &udp) +{ return __tu_cksum(IpPtr(udp.packet())); } + +bool +IpHdr::options(vector<const IpOpt *> &vec) const +{ + vec.clear(); + + const uint8_t *data = bytes() + sizeof(struct ip_hdr); + int all = hlen() - sizeof(struct ip_hdr); + while (all > 0) { + const IpOpt *opt = (const IpOpt *)data; + int len = opt->len(); + if (all < len) + return false; + + vec.push_back(opt); + all -= len; + data += len; + } + + return true; +} + +bool +TcpHdr::options(vector<const TcpOpt *> &vec) const +{ + vec.clear(); + + const uint8_t *data = bytes() + sizeof(struct tcp_hdr); + int all = off() - sizeof(struct tcp_hdr); + while (all > 0) { + const TcpOpt *opt = (const TcpOpt *)data; + int len = opt->len(); + if (all < len) + return false; + + vec.push_back(opt); + all -= len; + data += len; + } + + return true; +} + +bool +TcpOpt::sack(vector<SackRange> &vec) const +{ + vec.clear(); + + const uint8_t *data = bytes() + sizeof(struct tcp_hdr); + int all = len() - offsetof(tcp_opt, opt_data.sack); + while (all > 0) { + const uint16_t *sack = (const uint16_t *)data; + int len = sizeof(uint16_t) * 2; + if (all < len) { + vec.clear(); + return false; + } + + vec.push_back(RangeIn(ntohs(sack[0]), ntohs(sack[1]))); + all -= len; + data += len; + } + + return false; +} + +/* namespace Net */ } diff --git a/src/base/inet.hh b/src/base/inet.hh new file mode 100644 index 000000000..1bf7c585f --- /dev/null +++ b/src/base/inet.hh @@ -0,0 +1,410 @@ +/* + * 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 + * Steve Reinhardt + */ + +#ifndef __BASE_INET_HH__ +#define __BASE_INET_HH__ + +#include <iosfwd> +#include <string> +#include <utility> +#include <vector> + +#include "base/range.hh" +#include "dev/etherpkt.hh" +#include "sim/host.hh" + +#include "dnet/os.h" +#include "dnet/eth.h" +#include "dnet/ip.h" +#include "dnet/ip6.h" +#include "dnet/addr.h" +#include "dnet/arp.h" +#include "dnet/icmp.h" +#include "dnet/tcp.h" +#include "dnet/udp.h" +#include "dnet/intf.h" +#include "dnet/route.h" +#include "dnet/fw.h" +#include "dnet/blob.h" +#include "dnet/rand.h" + +namespace Net { + +/* + * Ethernet Stuff + */ +struct EthAddr : protected eth_addr +{ + protected: + void parse(const std::string &addr); + + public: + EthAddr(); + EthAddr(const uint8_t ea[ETH_ADDR_LEN]); + EthAddr(const eth_addr &ea); + EthAddr(const std::string &addr); + const EthAddr &operator=(const eth_addr &ea); + const EthAddr &operator=(const std::string &addr); + + int size() const { return sizeof(eth_addr); } + + const uint8_t *bytes() const { return &data[0]; } + uint8_t *bytes() { return &data[0]; } + + const uint8_t *addr() const { return &data[0]; } + bool unicast() const { return data[0] == 0x00; } + bool multicast() const { return data[0] == 0x01; } + bool broadcast() const { return data[0] == 0xff; } + std::string string() const; + + operator uint64_t() const + { + uint64_t reg = 0; + reg |= ((uint64_t)data[0]) << 40; + reg |= ((uint64_t)data[1]) << 32; + reg |= ((uint64_t)data[2]) << 24; + reg |= ((uint64_t)data[3]) << 16; + reg |= ((uint64_t)data[4]) << 8; + reg |= ((uint64_t)data[5]) << 0; + return reg; + } + +}; + +std::ostream &operator<<(std::ostream &stream, const EthAddr &ea); +bool operator==(const EthAddr &left, const EthAddr &right); + +struct EthHdr : public eth_hdr +{ + uint16_t type() const { return ntohs(eth_type); } + const EthAddr &src() const { return *(EthAddr *)ð_src; } + const EthAddr &dst() const { return *(EthAddr *)ð_dst; } + + int size() const { return sizeof(eth_hdr); } + + const uint8_t *bytes() const { return (const uint8_t *)this; } + const uint8_t *payload() const { return bytes() + size(); } + uint8_t *bytes() { return (uint8_t *)this; } + uint8_t *payload() { return bytes() + size(); } +}; + +class EthPtr +{ + protected: + friend class IpPtr; + EthPacketPtr p; + + public: + EthPtr() {} + EthPtr(const EthPacketPtr &ptr) : p(ptr) { } + + EthHdr *operator->() { return (EthHdr *)p->data; } + EthHdr &operator*() { return *(EthHdr *)p->data; } + operator EthHdr *() { return (EthHdr *)p->data; } + + const EthHdr *operator->() const { return (const EthHdr *)p->data; } + const EthHdr &operator*() const { return *(const EthHdr *)p->data; } + operator const EthHdr *() const { return (const EthHdr *)p->data; } + + const EthPtr &operator=(const EthPacketPtr &ptr) { p = ptr; return *this; } + + const EthPacketPtr packet() const { return p; } + EthPacketPtr packet() { return p; } + bool operator!() const { return !p; } + operator bool() const { return p; } +}; + +/* + * IP Stuff + */ +struct IpOpt; +struct IpHdr : public ip_hdr +{ + uint8_t version() const { return ip_v; } + uint8_t hlen() const { return ip_hl * 4; } + uint8_t tos() const { return ip_tos; } + uint16_t len() const { return ntohs(ip_len); } + uint16_t id() const { return ntohs(ip_id); } + uint16_t frag_flags() const { return ntohs(ip_off) >> 13; } + uint16_t frag_off() const { return ntohs(ip_off) & 0x1fff; } + uint8_t ttl() const { return ip_ttl; } + uint8_t proto() const { return ip_p; } + uint16_t sum() const { return ip_sum; } + uint32_t src() const { return ntohl(ip_src); } + uint32_t dst() const { return ntohl(ip_dst); } + + void sum(uint16_t sum) { ip_sum = sum; } + + bool options(std::vector<const IpOpt *> &vec) const; + + int size() const { return hlen(); } + const uint8_t *bytes() const { return (const uint8_t *)this; } + const uint8_t *payload() const { return bytes() + size(); } + uint8_t *bytes() { return (uint8_t *)this; } + uint8_t *payload() { return bytes() + size(); } +}; + +class IpPtr +{ + protected: + friend class TcpPtr; + friend class UdpPtr; + EthPacketPtr p; + + const IpHdr *h() const + { return (const IpHdr *)(p->data + sizeof(eth_hdr)); } + IpHdr *h() { return (IpHdr *)(p->data + sizeof(eth_hdr)); } + + void set(const EthPacketPtr &ptr) + { + EthHdr *eth = (EthHdr *)ptr->data; + if (eth->type() == ETH_TYPE_IP) + p = ptr; + else + p = 0; + } + + public: + IpPtr() {} + IpPtr(const EthPacketPtr &ptr) { set(ptr); } + IpPtr(const EthPtr &ptr) { set(ptr.p); } + IpPtr(const IpPtr &ptr) : p(ptr.p) { } + + IpHdr *operator->() { return h(); } + IpHdr &operator*() { return *h(); } + operator IpHdr *() { return h(); } + + const IpHdr *operator->() const { return h(); } + const IpHdr &operator*() const { return *h(); } + operator const IpHdr *() const { return h(); } + + const IpPtr &operator=(const EthPacketPtr &ptr) { set(ptr); return *this; } + const IpPtr &operator=(const EthPtr &ptr) { set(ptr.p); return *this; } + const IpPtr &operator=(const IpPtr &ptr) { p = ptr.p; return *this; } + + const EthPacketPtr packet() const { return p; } + EthPacketPtr packet() { return p; } + bool operator!() const { return !p; } + operator bool() const { return p; } + operator bool() { return p; } +}; + +uint16_t cksum(const IpPtr &ptr); + +struct IpOpt : public ip_opt +{ + uint8_t type() const { return opt_type; } + uint8_t typeNumber() const { return IP_OPT_NUMBER(opt_type); } + uint8_t typeClass() const { return IP_OPT_CLASS(opt_type); } + uint8_t typeCopied() const { return IP_OPT_COPIED(opt_type); } + uint8_t len() const { return IP_OPT_TYPEONLY(type()) ? 1 : opt_len; } + + bool isNumber(int num) const { return typeNumber() == IP_OPT_NUMBER(num); } + bool isClass(int cls) const { return typeClass() == IP_OPT_CLASS(cls); } + bool isCopied(int cpy) const { return typeCopied() == IP_OPT_COPIED(cpy); } + + const uint8_t *data() const { return opt_data.data8; } + void sec(ip_opt_data_sec &sec) const; + void lsrr(ip_opt_data_rr &rr) const; + void ssrr(ip_opt_data_rr &rr) const; + void ts(ip_opt_data_ts &ts) const; + uint16_t satid() const { return ntohs(opt_data.satid); } + uint16_t mtup() const { return ntohs(opt_data.mtu); } + uint16_t mtur() const { return ntohs(opt_data.mtu); } + void tr(ip_opt_data_tr &tr) const; + const uint32_t *addext() const { return &opt_data.addext[0]; } + uint16_t rtralt() const { return ntohs(opt_data.rtralt); } + void sdb(std::vector<uint32_t> &vec) const; +}; + +/* + * TCP Stuff + */ +struct TcpOpt; +struct TcpHdr : public tcp_hdr +{ + uint16_t sport() const { return ntohs(th_sport); } + uint16_t dport() const { return ntohs(th_dport); } + uint32_t seq() const { return ntohl(th_seq); } + uint32_t ack() const { return ntohl(th_ack); } + uint8_t off() const { return th_off; } + uint8_t flags() const { return th_flags & 0x3f; } + uint16_t win() const { return ntohs(th_win); } + uint16_t sum() const { return th_sum; } + uint16_t urp() const { return ntohs(th_urp); } + + void sum(uint16_t sum) { th_sum = sum; } + + bool options(std::vector<const TcpOpt *> &vec) const; + + int size() const { return off(); } + const uint8_t *bytes() const { return (const uint8_t *)this; } + const uint8_t *payload() const { return bytes() + size(); } + uint8_t *bytes() { return (uint8_t *)this; } + uint8_t *payload() { return bytes() + size(); } +}; + +class TcpPtr +{ + protected: + EthPacketPtr p; + int off; + + const TcpHdr *h() const { return (const TcpHdr *)(p->data + off); } + TcpHdr *h() { return (TcpHdr *)(p->data + off); } + + void set(const EthPacketPtr &ptr, int offset) { p = ptr; off = offset; } + void set(const IpPtr &ptr) + { + if (ptr->proto() == IP_PROTO_TCP) + set(ptr.p, sizeof(eth_hdr) + ptr->hlen()); + else + set(0, 0); + } + + public: + TcpPtr() {} + TcpPtr(const IpPtr &ptr) { set(ptr); } + TcpPtr(const TcpPtr &ptr) : p(ptr.p), off(ptr.off) {} + + TcpHdr *operator->() { return h(); } + TcpHdr &operator*() { return *h(); } + operator TcpHdr *() { return h(); } + + const TcpHdr *operator->() const { return h(); } + const TcpHdr &operator*() const { return *h(); } + operator const TcpHdr *() const { return h(); } + + const TcpPtr &operator=(const IpPtr &i) { set(i); return *this; } + const TcpPtr &operator=(const TcpPtr &t) { set(t.p, t.off); return *this; } + + const EthPacketPtr packet() const { return p; } + EthPacketPtr packet() { return p; } + bool operator!() const { return !p; } + operator bool() const { return p; } + operator bool() { return p; } +}; + +uint16_t cksum(const TcpPtr &ptr); + +typedef Range<uint16_t> SackRange; + +struct TcpOpt : public tcp_opt +{ + uint8_t type() const { return opt_type; } + uint8_t len() const { return TCP_OPT_TYPEONLY(type()) ? 1 : opt_len; } + + bool isopt(int opt) const { return type() == opt; } + + const uint8_t *data() const { return opt_data.data8; } + + uint16_t mss() const { return ntohs(opt_data.mss); } + uint8_t wscale() const { return opt_data.wscale; } + bool sack(std::vector<SackRange> &vec) const; + uint32_t echo() const { return ntohl(opt_data.echo); } + uint32_t tsval() const { return ntohl(opt_data.timestamp[0]); } + uint32_t tsecr() const { return ntohl(opt_data.timestamp[1]); } + uint32_t cc() const { return ntohl(opt_data.cc); } + uint8_t cksum() const{ return opt_data.cksum; } + const uint8_t *md5() const { return opt_data.md5; } + + int size() const { return len(); } + const uint8_t *bytes() const { return (const uint8_t *)this; } + const uint8_t *payload() const { return bytes() + size(); } + uint8_t *bytes() { return (uint8_t *)this; } + uint8_t *payload() { return bytes() + size(); } +}; + +/* + * UDP Stuff + */ +struct UdpHdr : public udp_hdr +{ + uint16_t sport() const { return ntohs(uh_sport); } + uint16_t dport() const { return ntohs(uh_dport); } + uint16_t len() const { return ntohs(uh_ulen); } + uint16_t sum() const { return uh_sum; } + + void sum(uint16_t sum) { uh_sum = sum; } + + int size() const { return sizeof(udp_hdr); } + const uint8_t *bytes() const { return (const uint8_t *)this; } + const uint8_t *payload() const { return bytes() + size(); } + uint8_t *bytes() { return (uint8_t *)this; } + uint8_t *payload() { return bytes() + size(); } +}; + +class UdpPtr +{ + protected: + EthPacketPtr p; + int off; + + const UdpHdr *h() const { return (const UdpHdr *)(p->data + off); } + UdpHdr *h() { return (UdpHdr *)(p->data + off); } + + void set(const EthPacketPtr &ptr, int offset) { p = ptr; off = offset; } + void set(const IpPtr &ptr) + { + if (ptr->proto() == IP_PROTO_UDP) + set(ptr.p, sizeof(eth_hdr) + ptr->hlen()); + else + set(0, 0); + } + + public: + UdpPtr() {} + UdpPtr(const IpPtr &ptr) { set(ptr); } + UdpPtr(const UdpPtr &ptr) : p(ptr.p), off(ptr.off) {} + + UdpHdr *operator->() { return h(); } + UdpHdr &operator*() { return *h(); } + operator UdpHdr *() { return h(); } + + const UdpHdr *operator->() const { return h(); } + const UdpHdr &operator*() const { return *h(); } + operator const UdpHdr *() const { return h(); } + + const UdpPtr &operator=(const IpPtr &i) { set(i); return *this; } + const UdpPtr &operator=(const UdpPtr &t) { set(t.p, t.off); return *this; } + + const EthPacketPtr packet() const { return p; } + EthPacketPtr packet() { return p; } + bool operator!() const { return !p; } + operator bool() const { return p; } + operator bool() { return p; } +}; + +uint16_t cksum(const UdpPtr &ptr); + +/* namespace Net */ } + +#endif // __BASE_INET_HH__ diff --git a/src/base/inifile.cc b/src/base/inifile.cc new file mode 100644 index 000000000..4d504d04f --- /dev/null +++ b/src/base/inifile.cc @@ -0,0 +1,436 @@ +/* + * 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 + * Steve Reinhardt + */ + +#define USE_CPP + +#ifdef USE_CPP +#include <sys/signal.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include <libgen.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#endif + +#include <fstream> +#include <iostream> + +#include <vector> +#include <string> + +#include "base/inifile.hh" +#include "base/str.hh" + +using namespace std; + +IniFile::IniFile() +{} + +IniFile::~IniFile() +{ + SectionTable::iterator i = table.begin(); + SectionTable::iterator end = table.end(); + + while (i != end) { + delete (*i).second; + ++i; + } +} + + +#ifdef USE_CPP +bool +IniFile::loadCPP(const string &file, vector<char *> &cppArgs) +{ + // Open the file just to verify that we can. Otherwise if the + // file doesn't exist or has bad permissions the user will get + // confusing errors from cpp/g++. + ifstream tmpf(file.c_str()); + + if (!tmpf.is_open()) + return false; + + tmpf.close(); + + char *cfile = strncpy(new char[file.size() + 1], file.c_str(), + file.size()); + char *dir = dirname(cfile); + char *dir_arg = NULL; + if (*dir != '.') { + string arg = "-I"; + arg += dir; + + dir_arg = new char[arg.size() + 1]; + strncpy(dir_arg, arg.c_str(), arg.size()); + } + + delete [] cfile; + + char tempfile[] = "/tmp/configXXXXXX"; + int tmp_fd = mkstemp(tempfile); + + int pid = fork(); + + if (pid == -1) + return false; + + if (pid == 0) { + char filename[FILENAME_MAX]; + string::size_type i = file.copy(filename, sizeof(filename) - 1); + filename[i] = '\0'; + + int arg_count = cppArgs.size(); + + char **args = new char *[arg_count + 20]; + + int nextArg = 0; + args[nextArg++] = "g++"; + args[nextArg++] = "-E"; + args[nextArg++] = "-P"; + args[nextArg++] = "-nostdinc"; + args[nextArg++] = "-nostdinc++"; + args[nextArg++] = "-x"; + args[nextArg++] = "c++"; + args[nextArg++] = "-undef"; + + for (int i = 0; i < arg_count; i++) + args[nextArg++] = cppArgs[i]; + + if (dir_arg) + args[nextArg++] = dir_arg; + + args[nextArg++] = filename; + args[nextArg++] = NULL; + + close(STDOUT_FILENO); + if (dup2(tmp_fd, STDOUT_FILENO) == -1) + exit(1); + + execvp("g++", args); + + exit(0); + } + + int retval; + waitpid(pid, &retval, 0); + + delete [] dir_arg; + + // check for normal completion of CPP + if (!WIFEXITED(retval) || WEXITSTATUS(retval) != 0) + return false; + + close(tmp_fd); + + bool status = false; + + status = load(tempfile); + + unlink(tempfile); + + return status; +} +#endif + +bool +IniFile::load(const string &file) +{ + ifstream f(file.c_str()); + + if (!f.is_open()) + return false; + + return load(f); +} + + +const string & +IniFile::Entry::getValue() const +{ + referenced = true; + return value; +} + + +void +IniFile::Section::addEntry(const std::string &entryName, + const std::string &value, + bool append) +{ + EntryTable::iterator ei = table.find(entryName); + + if (ei == table.end()) { + // new entry + table[entryName] = new Entry(value); + } + else if (append) { + // append new reult to old entry + ei->second->appendValue(value); + } + else { + // override old entry + ei->second->setValue(value); + } +} + + +bool +IniFile::Section::add(const std::string &assignment) +{ + string::size_type offset = assignment.find('='); + if (offset == string::npos) { + // no '=' found + cerr << "Can't parse .ini line " << assignment << endl; + return false; + } + + // if "+=" rather than just "=" then append value + bool append = (assignment[offset-1] == '+'); + + string entryName = assignment.substr(0, append ? offset-1 : offset); + string value = assignment.substr(offset + 1); + + eat_white(entryName); + eat_white(value); + + addEntry(entryName, value, append); + return true; +} + + +IniFile::Entry * +IniFile::Section::findEntry(const std::string &entryName) const +{ + referenced = true; + + EntryTable::const_iterator ei = table.find(entryName); + + return (ei == table.end()) ? NULL : ei->second; +} + + +IniFile::Section * +IniFile::addSection(const string §ionName) +{ + SectionTable::iterator i = table.find(sectionName); + + if (i != table.end()) { + return i->second; + } + else { + // new entry + Section *sec = new Section(); + table[sectionName] = sec; + return sec; + } +} + + +IniFile::Section * +IniFile::findSection(const string §ionName) const +{ + SectionTable::const_iterator i = table.find(sectionName); + + return (i == table.end()) ? NULL : i->second; +} + + +// Take string of the form "<section>:<parameter>=<value>" and add to +// database. Return true if successful, false if parse error. +bool +IniFile::add(const string &str) +{ + // find ':' + string::size_type offset = str.find(':'); + if (offset == string::npos) // no ':' found + return false; + + string sectionName = str.substr(0, offset); + string rest = str.substr(offset + 1); + + eat_white(sectionName); + Section *s = addSection(sectionName); + + return s->add(rest); +} + +bool +IniFile::load(istream &f) +{ + Section *section = NULL; + + while (!f.eof()) { + f >> ws; // Eat whitespace + if (f.eof()) { + break; + } + + string line; + getline(f, line); + if (line.size() == 0) + continue; + + eat_end_white(line); + int last = line.size() - 1; + + if (line[0] == '[' && line[last] == ']') { + string sectionName = line.substr(1, last - 1); + eat_white(sectionName); + section = addSection(sectionName); + continue; + } + + if (section == NULL) + continue; + + if (!section->add(line)) + return false; + } + + return true; +} + +bool +IniFile::find(const string §ionName, const string &entryName, + string &value) const +{ + Section *section = findSection(sectionName); + if (section == NULL) + return false; + + Entry *entry = section->findEntry(entryName); + if (entry == NULL) + return false; + + value = entry->getValue(); + + return true; +} + +bool +IniFile::sectionExists(const string §ionName) const +{ + return findSection(sectionName) != NULL; +} + + +bool +IniFile::Section::printUnreferenced(const string §ionName) +{ + bool unref = false; + bool search_unref_entries = false; + vector<string> unref_ok_entries; + + Entry *entry = findEntry("unref_entries_ok"); + if (entry != NULL) { + tokenize(unref_ok_entries, entry->getValue(), ' '); + if (unref_ok_entries.size()) { + search_unref_entries = true; + } + } + + for (EntryTable::iterator ei = table.begin(); + ei != table.end(); ++ei) { + const string &entryName = ei->first; + Entry *entry = ei->second; + + if (entryName == "unref_section_ok" || + entryName == "unref_entries_ok") + { + continue; + } + + if (!entry->isReferenced()) { + if (search_unref_entries && + (std::find(unref_ok_entries.begin(), unref_ok_entries.end(), + entryName) != unref_ok_entries.end())) + { + continue; + } + + cerr << "Parameter " << sectionName << ":" << entryName + << " not referenced." << endl; + unref = true; + } + } + + return unref; +} + + +bool +IniFile::printUnreferenced() +{ + bool unref = false; + + for (SectionTable::iterator i = table.begin(); + i != table.end(); ++i) { + const string §ionName = i->first; + Section *section = i->second; + + if (!section->isReferenced()) { + if (section->findEntry("unref_section_ok") == NULL) { + cerr << "Section " << sectionName << " not referenced." + << endl; + unref = true; + } + } + else { + if (section->printUnreferenced(sectionName)) { + unref = true; + } + } + } + + return unref; +} + + +void +IniFile::Section::dump(const string §ionName) +{ + for (EntryTable::iterator ei = table.begin(); + ei != table.end(); ++ei) { + cout << sectionName << ": " << (*ei).first << " => " + << (*ei).second->getValue() << "\n"; + } +} + +void +IniFile::dump() +{ + for (SectionTable::iterator i = table.begin(); + i != table.end(); ++i) { + i->second->dump(i->first); + } +} diff --git a/src/base/inifile.hh b/src/base/inifile.hh new file mode 100644 index 000000000..631b29b87 --- /dev/null +++ b/src/base/inifile.hh @@ -0,0 +1,211 @@ +/* + * 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 + * Steve Reinhardt + */ + +#ifndef __INIFILE_HH__ +#define __INIFILE_HH__ + +#include <fstream> +#include <list> +#include <string> +#include <vector> + +#include "base/hashmap.hh" + +/** + * @file + * Declaration of IniFile object. + * @todo Change comments to match documentation style. + */ + +/// +/// This class represents the contents of a ".ini" file. +/// +/// It's basically a two level lookup table: a set of named sections, +/// where each section is a set of key/value pairs. Section names, +/// keys, and values are all uninterpreted strings. +/// +class IniFile +{ + protected: + + /// + /// A single key/value pair. + /// + class Entry + { + std::string value; ///< The entry value. + mutable bool referenced; ///< Has this entry been used? + + public: + /// Constructor. + Entry(const std::string &v) + : value(v), referenced(false) + { + } + + /// Has this entry been used? + bool isReferenced() { return referenced; } + + /// Fetch the value. + const std::string &getValue() const; + + /// Set the value. + void setValue(const std::string &v) { value = v; } + + /// Append the given string to the value. A space is inserted + /// between the existing value and the new value. Since this + /// operation is typically used with values that are + /// space-separated lists of tokens, this keeps the tokens + /// separate. + void appendValue(const std::string &v) { value += " "; value += v; } + }; + + /// + /// A section. + /// + class Section + { + /// EntryTable type. Map of strings to Entry object pointers. + typedef m5::hash_map<std::string, Entry *> EntryTable; + + EntryTable table; ///< Table of entries. + mutable bool referenced; ///< Has this section been used? + + public: + /// Constructor. + Section() + : table(), referenced(false) + { + } + + /// Has this section been used? + bool isReferenced() { return referenced; } + + /// Add an entry to the table. If an entry with the same name + /// already exists, the 'append' parameter is checked If true, + /// the new value will be appended to the existing entry. If + /// false, the new value will replace the existing entry. + void addEntry(const std::string &entryName, const std::string &value, + bool append); + + /// Add an entry to the table given a string assigment. + /// Assignment should be of the form "param=value" or + /// "param+=value" (for append). This funciton parses the + /// assignment statment and calls addEntry(). + /// @retval True for success, false if parse error. + bool add(const std::string &assignment); + + /// Find the entry with the given name. + /// @retval Pointer to the entry object, or NULL if none. + Entry *findEntry(const std::string &entryName) const; + + /// Print the unreferenced entries in this section to cerr. + /// Messages can be suppressed using "unref_section_ok" and + /// "unref_entries_ok". + /// @param sectionName Name of this section, for use in output message. + /// @retval True if any entries were printed. + bool printUnreferenced(const std::string §ionName); + + /// Print the contents of this section to cout (for debugging). + void dump(const std::string §ionName); + }; + + /// SectionTable type. Map of strings to Section object pointers. + typedef m5::hash_map<std::string, Section *> SectionTable; + + protected: + /// Hash of section names to Section object pointers. + SectionTable table; + + /// Look up section with the given name, creating a new section if + /// not found. + /// @retval Pointer to section object. + Section *addSection(const std::string §ionName); + + /// Look up section with the given name. + /// @retval Pointer to section object, or NULL if not found. + Section *findSection(const std::string §ionName) const; + + public: + /// Constructor. + IniFile(); + + /// Destructor. + ~IniFile(); + + /// Load parameter settings from given istream. This is a helper + /// function for load(string) and loadCPP(), which open a file + /// and then pass it here. + /// @retval True if successful, false if errors were encountered. + bool load(std::istream &f); + + /// Load the specified file, passing it through the C preprocessor. + /// Parameter settings found in the file will be merged with any + /// already defined in this object. + /// @param file The path of the file to load. + /// @param cppFlags Vector of extra flags to pass to cpp. + /// @retval True if successful, false if errors were encountered. + bool loadCPP(const std::string &file, std::vector<char *> &cppFlags); + + /// Load the specified file. + /// Parameter settings found in the file will be merged with any + /// already defined in this object. + /// @param file The path of the file to load. + /// @retval True if successful, false if errors were encountered. + bool load(const std::string &file); + + /// Take string of the form "<section>:<parameter>=<value>" or + /// "<section>:<parameter>+=<value>" and add to database. + /// @retval True if successful, false if parse error. + bool add(const std::string &s); + + /// Find value corresponding to given section and entry names. + /// Value is returned by reference in 'value' param. + /// @retval True if found, false if not. + bool find(const std::string §ion, const std::string &entry, + std::string &value) const; + + /// Determine whether the named section exists in the .ini file. + /// Note that the 'Section' class is (intentionally) not public, + /// so all clients can do is get a bool that says whether there + /// are any values in that section or not. + /// @return True if the section exists. + bool sectionExists(const std::string §ion) const; + + /// Print unreferenced entries in object. Iteratively calls + /// printUnreferend() on all the constituent sections. + bool printUnreferenced(); + + /// Dump contents to cout. For debugging. + void dump(); +}; + +#endif // __INIFILE_HH__ diff --git a/src/base/intmath.cc b/src/base/intmath.cc new file mode 100644 index 000000000..22414ea4b --- /dev/null +++ b/src/base/intmath.cc @@ -0,0 +1,61 @@ +/* + * 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: Nathan Binkert + * Steve Reinhardt + */ + +#include "base/intmath.hh" + +int +prevPrime(int n) +{ + int decr; + + // If the number is even, let's start with the previous odd number. + if (!(n & 1)) + --n; + + // Lets test for divisibility by 3. Then we will be able to easily + // avoid numbers that are divisible by 3 in the future. + decr = n % 3; + if (decr == 0) { + n -= 2; + decr = 2; + } + else if (decr == 1) + decr = 4; + + for (;;) { + if (isPrime(n)) + return n; + n -= decr; + // Toggle between 2 and 4 to prevent trying numbers that are known + // to be divisible by 3. + decr = 6 - decr; + } +} diff --git a/src/base/intmath.hh b/src/base/intmath.hh new file mode 100644 index 000000000..227012e30 --- /dev/null +++ b/src/base/intmath.hh @@ -0,0 +1,232 @@ +/* + * 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: Nathan Binkert + */ + +#ifndef __INTMATH_HH__ +#define __INTMATH_HH__ + +#include <assert.h> + +#include "sim/host.hh" + +// Returns the prime number one less than n. +int prevPrime(int n); + +// Determine if a number is prime +template <class T> +inline bool +isPrime(T n) +{ + T i; + + if (n == 2 || n == 3) + return true; + + // Don't try every odd number to prove if it is a prime. + // Toggle between every 2nd and 4th number. + // (This is because every 6th odd number is divisible by 3.) + for (i = 5; i*i <= n; i += 6) { + if (((n % i) == 0 ) || ((n % (i + 2)) == 0) ) { + return false; + } + } + + return true; +} + +template <class T> +inline T +leastSigBit(T n) +{ + return n & ~(n - 1); +} + +template <class T> +inline bool +isPowerOf2(T n) +{ + return n != 0 && leastSigBit(n) == n; +} + +inline int +floorLog2(unsigned x) +{ + assert(x > 0); + + int y = 0; + + if (x & 0xffff0000) { y += 16; x >>= 16; } + if (x & 0x0000ff00) { y += 8; x >>= 8; } + if (x & 0x000000f0) { y += 4; x >>= 4; } + if (x & 0x0000000c) { y += 2; x >>= 2; } + if (x & 0x00000002) { y += 1; } + + return y; +} + +inline int +floorLog2(unsigned long x) +{ + assert(x > 0); + + int y = 0; + +#if defined(__LP64__) + if (x & ULL(0xffffffff00000000)) { y += 32; x >>= 32; } +#endif + if (x & 0xffff0000) { y += 16; x >>= 16; } + if (x & 0x0000ff00) { y += 8; x >>= 8; } + if (x & 0x000000f0) { y += 4; x >>= 4; } + if (x & 0x0000000c) { y += 2; x >>= 2; } + if (x & 0x00000002) { y += 1; } + + return y; +} + +inline int +floorLog2(unsigned long long x) +{ + assert(x > 0); + + int y = 0; + + if (x & ULL(0xffffffff00000000)) { y += 32; x >>= 32; } + if (x & ULL(0x00000000ffff0000)) { y += 16; x >>= 16; } + if (x & ULL(0x000000000000ff00)) { y += 8; x >>= 8; } + if (x & ULL(0x00000000000000f0)) { y += 4; x >>= 4; } + if (x & ULL(0x000000000000000c)) { y += 2; x >>= 2; } + if (x & ULL(0x0000000000000002)) { y += 1; } + + return y; +} + +inline int +floorLog2(int x) +{ + assert(x > 0); + return floorLog2((unsigned)x); +} + +inline int +floorLog2(long x) +{ + assert(x > 0); + return floorLog2((unsigned long)x); +} + +inline int +floorLog2(long long x) +{ + assert(x > 0); + return floorLog2((unsigned long long)x); +} + +template <class T> +inline int +ceilLog2(T n) +{ + if (n == 1) + return 0; + + return floorLog2(n - (T)1) + 1; +} + +template <class T> +inline T +floorPow2(T n) +{ + return (T)1 << floorLog2(n); +} + +template <class T> +inline T +ceilPow2(T n) +{ + return (T)1 << ceilLog2(n); +} + +template <class T> +inline T +divCeil(T a, T b) +{ + return (a + b - 1) / b; +} + +template <class T> +inline T +roundUp(T val, int align) +{ + T mask = (T)align - 1; + return (val + mask) & ~mask; +} + +template <class T> +inline T +roundDown(T val, int align) +{ + T mask = (T)align - 1; + return val & ~mask; +} + +inline bool +isHex(char c) +{ + return c >= '0' && c <= '9' || + c >= 'A' && c <= 'F' || + c >= 'a' && c <= 'f'; +} + +inline bool +isOct(char c) +{ + return c >= '0' && c <= '7'; +} + +inline bool +isDec(char c) +{ + return c >= '0' && c <= '9'; +} + +inline int +hex2Int(char c) +{ + if (c >= '0' && c <= '9') + return (c - '0'); + + if (c >= 'A' && c <= 'F') + return (c - 'A') + 10; + + if (c >= 'a' && c <= 'f') + return (c - 'a') + 10; + + return 0; +} + +#endif // __INTMATH_HH__ diff --git a/base/kgdb.h b/src/base/kgdb.h index 104244d0b..104244d0b 100644 --- a/base/kgdb.h +++ b/src/base/kgdb.h diff --git a/src/base/loader/aout_object.cc b/src/base/loader/aout_object.cc new file mode 100644 index 000000000..6691bd4ae --- /dev/null +++ b/src/base/loader/aout_object.cc @@ -0,0 +1,96 @@ +/* + * Copyright (c) 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 Reinhardt + */ + +#include <string> + +#include "base/loader/aout_object.hh" + +#include "base/loader/symtab.hh" + +#include "base/trace.hh" // for DPRINTF + +#include "base/loader/exec_aout.h" + +using namespace std; + +ObjectFile * +AoutObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data) +{ + if (!N_BADMAG(*(aout_exechdr *)data)) { + // right now this is only used for Alpha PAL code + return new AoutObject(fname, fd, len, data, + ObjectFile::Alpha, ObjectFile::UnknownOpSys); + } + else { + return NULL; + } +} + + +AoutObject::AoutObject(const string &_filename, int _fd, + size_t _len, uint8_t *_data, + Arch _arch, OpSys _opSys) + : ObjectFile(_filename, _fd, _len, _data, _arch, _opSys) +{ + execHdr = (aout_exechdr *)fileData; + + entry = execHdr->entry; + + text.baseAddr = N_TXTADDR(*execHdr); + text.size = execHdr->tsize; + text.fileImage = fileData + N_TXTOFF(*execHdr); + + data.baseAddr = N_DATADDR(*execHdr); + data.size = execHdr->dsize; + data.fileImage = fileData + N_DATOFF(*execHdr); + + bss.baseAddr = N_BSSADDR(*execHdr); + bss.size = execHdr->bsize; + bss.fileImage = NULL; + + DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n", + text.baseAddr, text.size, data.baseAddr, data.size, + bss.baseAddr, bss.size); +} + + +bool +AoutObject::loadGlobalSymbols(SymbolTable *symtab) +{ + // a.out symbols not supported yet + return false; +} + +bool +AoutObject::loadLocalSymbols(SymbolTable *symtab) +{ + // a.out symbols not supported yet + return false; +} diff --git a/src/base/loader/aout_object.hh b/src/base/loader/aout_object.hh new file mode 100644 index 000000000..d180d69f3 --- /dev/null +++ b/src/base/loader/aout_object.hh @@ -0,0 +1,58 @@ +/* + * Copyright (c) 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 Reinhardt + */ + +#ifndef __AOUT_OBJECT_HH__ +#define __AOUT_OBJECT_HH__ + +#include "base/loader/object_file.hh" + +// forward decls: avoid including exec_aout.h here +struct aout_exechdr; + +class AoutObject : public ObjectFile +{ + protected: + aout_exechdr *execHdr; + + AoutObject(const std::string &_filename, int _fd, + size_t _len, uint8_t *_data, + Arch _arch, OpSys _opSys); + + public: + virtual ~AoutObject() {} + + virtual bool loadGlobalSymbols(SymbolTable *symtab); + virtual bool loadLocalSymbols(SymbolTable *symtab); + + static ObjectFile *tryFile(const std::string &fname, int fd, + size_t len, uint8_t *data); +}; + +#endif // __AOUT_OBJECT_HH__ diff --git a/src/base/loader/coff_sym.h b/src/base/loader/coff_sym.h new file mode 100644 index 000000000..4c6540395 --- /dev/null +++ b/src/base/loader/coff_sym.h @@ -0,0 +1,519 @@ +/* + * Copyright (c) 2003, 2005-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 + */ + +/* + * Taken from binutils-2.14.90.0.5 include/coff/sym.h + */ + +/* Declarations of internal format of MIPS ECOFF symbols. + Originally contributed by MIPS Computer Systems and Third Eye Software. + Changes contributed by Cygnus Support are in the public domain. + + This file is just aggregated with the files that make up the GNU + release; it is not considered part of GAS, GDB, or other GNU + programs. */ + +/* + * |-----------------------------------------------------------| + * | Copyright (c) 1992, 1991, 1990 MIPS Computer Systems, Inc.| + * | MIPS Computer Systems, Inc. grants reproduction and use | + * | rights to all parties, PROVIDED that this comment is | + * | maintained in the copy. | + * |-----------------------------------------------------------| + */ +#ifndef _SYM_H +#define _SYM_H + +/* (C) Copyright 1984 by Third Eye Software, Inc. + * + * Third Eye Software, Inc. grants reproduction and use rights to + * all parties, PROVIDED that this comment is maintained in the copy. + * + * Third Eye makes no claims about the applicability of this + * symbol table to a particular use. + */ + +/* + * This file contains the definition of the Third Eye Symbol Table. + * + * Symbols are assumed to be in 'encounter order' - i.e. the order that + * the things they represent were encountered by the compiler/assembler/loader. + * EXCEPT for globals! These are assumed to be bunched together, + * probably right after the last 'normal' symbol. Globals ARE sorted + * in ascending order. + * + * ----------------------------------------------------------------------- + * A brief word about Third Eye naming/use conventions: + * + * All arrays and index's are 0 based. + * All "ifooMax" values are the highest legal value PLUS ONE. This makes + * them good for allocating arrays, etc. All checks are "ifoo < ifooMax". + * + * "isym" Index into the SYMbol table. + * "ipd" Index into the Procedure Descriptor array. + * "ifd" Index into the File Descriptor array. + * "iss" Index into String Space. + * "cb" Count of Bytes. + * "rgPd" array whose domain is "0..ipdMax-1" and RanGe is PDR. + * "rgFd" array whose domain is "0..ifdMax-1" and RanGe is FDR. + */ + + +/* + * Symbolic Header (HDR) structure. + * As long as all the pointers are set correctly, + * we don't care WHAT order the various sections come out in! + * + * A file produced solely for the use of CDB will probably NOT have + * any instructions or data areas in it, as these are available + * in the original. + */ + +typedef struct ecoff_symhdr { + coff_short magic; /* to verify validity of the table */ + coff_short vstamp; /* version stamp */ + coff_int ilineMax; /* number of line number entries */ + coff_int idnMax; /* max index into dense number table */ + coff_int ipdMax; /* number of procedures */ + coff_int isymMax; /* number of local symbols */ + coff_int ioptMax; /* max index into optimization symbol entries */ + coff_int iauxMax; /* number of auxillary symbol entries */ + coff_int issMax; /* max index into local strings */ + coff_int issExtMax; /* max index into external strings */ + coff_int ifdMax; /* number of file descriptor entries */ + coff_int crfd; /* number of relative file descriptor entries */ + coff_int iextMax; /* max index into external symbols */ + coff_addr cbLine; /* number of bytes for line number entries */ + coff_addr cbLineOffset; /* offset to start of line number entries*/ + coff_addr cbDnOffset; /* offset to start dense number table */ + coff_addr cbPdOffset; /* offset to procedure descriptor table */ + coff_addr cbSymOffset; /* offset to start of local symbols*/ + coff_addr cbOptOffset; /* offset to optimization symbol entries */ + coff_addr cbAuxOffset; /* offset to start of auxillary symbol entries*/ + coff_addr cbSsOffset; /* offset to start of local strings */ + coff_addr cbSsExtOffset; /* offset to start of external strings */ + coff_addr cbFdOffset; /* offset to file descriptor table */ + coff_addr cbRfdOffset; /* offset to relative file descriptor table */ + coff_addr cbExtOffset; /* offset to start of external symbol entries*/ + /* If you add machine dependent fields, add them here */ +} HDRR, *pHDRR; +#define cbHDRR sizeof(HDRR) +#define hdrNil ((pHDRR)0) + +/* + * The FDR and PDR structures speed mapping of address <-> name. + * They are sorted in ascending memory order and are kept in + * memory by CDB at runtime. + */ + +/* + * File Descriptor + * + * There is one of these for EVERY FILE, whether compiled with + * full debugging symbols or not. The name of a file should be + * the path name given to the compiler. This allows the user + * to simply specify the names of the directories where the COMPILES + * were done, and we will be able to find their files. + * A field whose comment starts with "R - " indicates that it will be + * setup at runtime. + */ +typedef struct ecoff_fdr { + coff_addr adr; /* memory address of beginning of file */ + coff_addr cbLineOffset; /* byte offset from header for this file ln's */ + coff_addr cbLine; /* size of lines for this file */ + coff_addr cbSs; /* number of bytes in the ss */ + coff_int rss; /* file name (of source, if known) */ + coff_int issBase; /* file's string space */ + coff_int isymBase; /* beginning of symbols */ + coff_int csym; /* count file's of symbols */ + coff_int ilineBase; /* file's line symbols */ + coff_int cline; /* count of file's line symbols */ + coff_int ioptBase; /* file's optimization entries */ + coff_int copt; /* count of file's optimization entries */ + coff_int ipdFirst; /* start of procedures for this file */ + coff_int cpd; /* count of procedures for this file */ + coff_int iauxBase; /* file's auxiliary entries */ + coff_int caux; /* count of file's auxiliary entries */ + coff_int rfdBase; /* index into the file indirect table */ + coff_int crfd; /* count file indirect entries */ + unsigned lang: 5; /* language for this file */ + unsigned fMerge : 1; /* whether this file can be merged */ + unsigned fReadin : 1; /* true if it was read in (not just created) */ + unsigned fBigendian : 1;/* if set, was compiled on big endian machine */ + /* aux's will be in compile host's sex */ + unsigned glevel : 2; /* level this file was compiled with */ + unsigned reserved : 22; /* reserved for future use */ + coff_uint reserved2; +} FDR, *pFDR; +#define cbFDR sizeof(FDR) +#define fdNil ((pFDR)0) +#define ifdNil -1 +#define ifdTemp 0 +#define ilnNil -1 + + +/* + * Procedure Descriptor + * + * There is one of these for EVERY TEXT LABEL. + * If a procedure is in a file with full symbols, then isym + * will point to the PROC symbols, else it will point to the + * global symbol for the label. + */ + +typedef struct pdr { + coff_addr adr; /* memory address of start of procedure */ + coff_addr cbLineOffset; /* byte offset for this procedure from the fd base */ + coff_int isym; /* start of local symbol entries */ + coff_int iline; /* start of line number entries*/ + coff_uint regmask; /* save register mask */ + coff_int regoffset; /* save register offset */ + coff_int iopt; /* start of optimization symbol entries*/ + coff_uint fregmask; /* save floating point register mask */ + coff_int fregoffset; /* save floating point register offset */ + coff_int frameoffset; /* frame size */ + coff_int lnLow; /* lowest line in the procedure */ + coff_int lnHigh; /* highest line in the procedure */ + /* These fields are new for 64 bit ECOFF. */ + unsigned gp_prologue : 8; /* byte size of GP prologue */ + unsigned gp_used : 1; /* true if the procedure uses GP */ + unsigned reg_frame : 1; /* true if register frame procedure */ + unsigned prof : 1; /* true if compiled with -pg */ + unsigned reserved : 13; /* reserved: must be zero */ + unsigned localoff : 8; /* offset of local variables from vfp */ + coff_short framereg; /* frame pointer register */ + coff_short pcreg; /* offset or reg of return pc */ +} PDR, *pPDR; +#define cbPDR sizeof(PDR) +#define pdNil ((pPDR) 0) +#define ipdNil -1 + +/* + * The structure of the runtime procedure descriptor created by the loader + * for use by the static exception system. + */ +/* + * If 0'd out because exception_info chokes Visual C++ and because there + * don't seem to be any references to this structure elsewhere in gdb. + */ +#if 0 +typedef struct runtime_pdr { + coff_addr adr; /* memory address of start of procedure */ + coff_uint regmask; /* save register mask */ + coff_int regoffset; /* save register offset */ + coff_uint fregmask; /* save floating point register mask */ + coff_int fregoffset; /* save floating point register offset */ + coff_int frameoffset; /* frame size */ + coff_ushort framereg; /* frame pointer register */ + coff_ushort pcreg; /* offset or reg of return pc */ + coff_int irpss; /* index into the runtime string table */ + coff_uint reserved; + struct exception_info *exception_info;/* pointer to exception array */ +} RPDR, *pRPDR; +#define cbRPDR sizeof(RPDR) +#define rpdNil ((pRPDR) 0) +#endif + +/* + * Line Numbers + * + * Line Numbers are segregated from the normal symbols because they + * are [1] smaller , [2] are of no interest to your + * average loader, and [3] are never needed in the middle of normal + * scanning and therefore slow things down. + * + * By definition, the first LINER for any given procedure will have + * the first line of a procedure and represent the first address. + */ + +typedef coff_int LINER, *pLINER; +#define lineNil ((pLINER)0) +#define cbLINER sizeof(LINER) +#define ilineNil -1 + + + +/* + * The Symbol Structure (GFW, to those who Know!) + */ + +typedef struct ecoff_sym { + coff_long value; /* value of symbol */ + coff_int iss; /* index into String Space of name */ + unsigned st : 6; /* symbol type */ + unsigned sc : 5; /* storage class - text, data, etc */ + unsigned reserved : 1; /* reserved */ + unsigned index : 20; /* index into sym/aux table */ +} SYMR, *pSYMR; +#define symNil ((pSYMR)0) +#define cbSYMR sizeof(SYMR) +#define isymNil -1 +#define indexNil 0xfffff +#define issNil -1 +#define issNull 0 + + +/* The following converts a memory resident string to an iss. + * This hack is recognized in SbFIss, in sym.c of the debugger. + */ +#define IssFSb(sb) (0x80000000 | ((coff_ulong)(sb))) + +/* E X T E R N A L S Y M B O L R E C O R D + * + * Same as the SYMR except it contains file context to determine where + * the index is. + */ +typedef struct ecoff_extsym { + SYMR asym; /* symbol for the external */ + unsigned jmptbl:1; /* symbol is a jump table entry for shlibs */ + unsigned cobol_main:1; /* symbol is a cobol main procedure */ + unsigned weakext:1; /* symbol is weak external */ + unsigned reserved:29; /* reserved for future use */ + coff_int ifd; /* where the iss and index fields point into */ +} EXTR, *pEXTR; +#define extNil ((pEXTR)0) +#define cbEXTR sizeof(EXTR) + + +/* A U X I L L A R Y T Y P E I N F O R M A T I O N */ + +/* + * Type Information Record + */ +typedef struct { + unsigned fBitfield : 1; /* set if bit width is specified */ + unsigned continued : 1; /* indicates additional TQ info in next AUX */ + unsigned bt : 6; /* basic type */ + unsigned tq4 : 4; + unsigned tq5 : 4; + /* ---- 16 bit boundary ---- */ + unsigned tq0 : 4; + unsigned tq1 : 4; /* 6 type qualifiers - tqPtr, etc. */ + unsigned tq2 : 4; + unsigned tq3 : 4; +} TIR, *pTIR; +#define cbTIR sizeof(TIR) +#define tiNil ((pTIR)0) +#define itqMax 6 + +/* + * Relative symbol record + * + * If the rfd field is 4095, the index field indexes into the global symbol + * table. + */ + +typedef struct { + unsigned rfd : 12; /* index into the file indirect table */ + unsigned index : 20; /* index int sym/aux/iss tables */ +} RNDXR, *pRNDXR; +#define cbRNDXR sizeof(RNDXR) +#define rndxNil ((pRNDXR)0) + +/* dense numbers or sometimes called block numbers are stored in this type, + * a rfd of 0xffffffff is an index into the global table. + */ +typedef struct { + coff_uint rfd; /* index into the file table */ + coff_uint index; /* index int sym/aux/iss tables */ +} DNR, *pDNR; +#define cbDNR sizeof(DNR) +#define dnNil ((pDNR)0) + + + +/* + * Auxillary information occurs only if needed. + * It ALWAYS occurs in this order when present. + + isymMac used by stProc only + TIR type info + TIR additional TQ info (if first TIR was not enough) + rndx if (bt == btStruct,btUnion,btEnum,btSet,btRange, + btTypedef): + rsym.index == iaux for btSet or btRange + else rsym.index == isym + dimLow btRange, btSet + dimMac btRange, btSet + rndx0 As many as there are tq arrays + dimLow0 + dimHigh0 + ... + rndxMax-1 + dimLowMax-1 + dimHighMax-1 + width in bits if (bit field), width in bits. + */ +#define cAuxMax (6 + (idimMax*3)) + +/* a union of all possible info in the AUX universe */ +typedef union { + TIR ti; /* type information record */ + RNDXR rndx; /* relative index into symbol table */ + coff_int dnLow; /* low dimension */ + coff_int dnHigh; /* high dimension */ + coff_int isym; /* symbol table index (end of proc) */ + coff_int iss; /* index into string space (not used) */ + coff_int width; /* width for non-default sized struc fields */ + coff_int count; /* count of ranges for variant arm */ +} AUXU, *pAUXU; +#define cbAUXU sizeof(AUXU) +#define auxNil ((pAUXU)0) +#define iauxNil -1 + + +/* + * Optimization symbols + * + * Optimization symbols contain some overlap information with the normal + * symbol table. In particular, the proc information + * is somewhat redundant but necessary to easily find the other information + * present. + * + * All of the offsets are relative to the beginning of the last otProc + */ + +typedef struct { + unsigned ot: 8; /* optimization type */ + unsigned value: 24; /* address where we are moving it to */ + RNDXR rndx; /* points to a symbol or opt entry */ + coff_ulong offset; /* relative offset this occured */ +} OPTR, *pOPTR; +#define optNil ((pOPTR) 0) +#define cbOPTR sizeof(OPTR) +#define ioptNil -1 + +/* + * File Indirect + * + * When a symbol is referenced across files the following procedure is used: + * 1) use the file index to get the File indirect entry. + * 2) use the file indirect entry to get the File descriptor. + * 3) add the sym index to the base of that file's sym table + * + */ + +typedef coff_long RFDT, *pRFDT; +#define cbRFDT sizeof(RFDT) +#define rfdNil -1 + +/* + * The file indirect table in the mips loader is known as an array of FITs. + * This is done to keep the code in the loader readable in the area where + * these tables are merged. Note this is only a name change. + */ +typedef coff_int FIT, *pFIT; +#define cbFIT sizeof(FIT) +#define ifiNil -1 +#define fiNil ((pFIT) 0) + +#ifdef _LANGUAGE_PASCAL +#define ifdNil -1 +#define ilnNil -1 +#define ipdNil -1 +#define ilineNil -1 +#define isymNil -1 +#define indexNil 16#fffff +#define issNil -1 +#define issNull 0 +#define itqMax 6 +#define iauxNil -1 +#define ioptNil -1 +#define rfdNil -1 +#define ifiNil -1 +#endif /* _LANGUAGE_PASCAL */ + + +/* Dense numbers + * + * Rather than use file index, symbol index pairs to represent symbols + * and globals, we use dense number so that they can be easily embeded + * in intermediate code and the programs that process them can + * use direct access tabls instead of hash table (which would be + * necesary otherwise because of the sparse name space caused by + * file index, symbol index pairs. Dense number are represented + * by RNDXRs. + */ + +/* + * The following table defines the meaning of each SYM field as + * a function of the "st". (scD/B == scData OR scBss) + * + * Note: the value "isymMac" is used by symbols that have the concept + * of enclosing a block of related information. This value is the + * isym of the first symbol AFTER the end associated with the primary + * symbol. For example if a procedure was at isym==90 and had an + * isymMac==155, the associated end would be at isym==154, and the + * symbol at 155 would probably (although not necessarily) be the + * symbol for the next procedure. This allows rapid skipping over + * internal information of various sorts. "stEnd"s ALWAYS have the + * isym of the primary symbol that started the block. + * + +ST SC VALUE INDEX +-------- ------ -------- ------ +stFile scText address isymMac +stLabel scText address --- +stGlobal scD/B address iaux +stStatic scD/B address iaux +stParam scAbs offset iaux +stLocal scAbs offset iaux +stProc scText address iaux (isymMac is first AUX) +stStaticProc scText address iaux (isymMac is first AUX) + +stMember scNil ordinal --- (if member of enum) + (mipsread thinks the case below has a bit, not byte, offset.) +stMember scNil byte offset iaux (if member of struct/union) +stMember scBits bit offset iaux (bit field spec) + +stBlock scText address isymMac (text block) + (the code seems to think that rather than scNil, we see scInfo for + the two cases below.) +stBlock scNil cb isymMac (struct/union member define) +stBlock scNil cMembers isymMac (enum member define) + + (New types added by SGI to simplify things:) +stStruct scInfo cb isymMac (struct type define) +stUnion scInfo cb isymMac (union type define) +stEnum scInfo cMembers isymMac (enum type define) + +stEnd scText address isymStart +stEnd scNil ------- isymStart (struct/union/enum) + +stTypedef scNil ------- iaux +stRegReloc sc??? value old register number +stForward sc??? new address isym to original symbol + +stConstant scInfo value --- (scalar) +stConstant scInfo iss --- (complex, e.g. string) + + * + */ +#endif diff --git a/src/base/loader/coff_symconst.h b/src/base/loader/coff_symconst.h new file mode 100644 index 000000000..f383c19e6 --- /dev/null +++ b/src/base/loader/coff_symconst.h @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2003, 2005-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 + */ + +/* + * Taken from binutils-2.14.90.0.5 include/coff/symconst.h + */ + +/* Declarations of constants for internal format of MIPS ECOFF symbols. + Originally contributed by MIPS Computer Systems and Third Eye Software. + Changes contributed by Cygnus Support are in the public domain. + + This file is just aggregated with the files that make up the GNU + release; it is not considered part of GAS, GDB, or other GNU + programs. */ + +/* + * |-----------------------------------------------------------| + * | Copyright (c) 1992, 1991, 1990 MIPS Computer Systems, Inc.| + * | MIPS Computer Systems, Inc. grants reproduction and use | + * | rights to all parties, PROVIDED that this comment is | + * | maintained in the copy. | + * |-----------------------------------------------------------| + */ + +/* (C) Copyright 1984 by Third Eye Software, Inc. + * + * Third Eye Software, Inc. grants reproduction and use rights to + * all parties, PROVIDED that this comment is maintained in the copy. + * + * Third Eye makes no claims about the applicability of this + * symbol table to a particular use. + */ + +/* glevels for field in FDR */ +#define GLEVEL_0 2 +#define GLEVEL_1 1 +#define GLEVEL_2 0 /* for upward compat reasons. */ +#define GLEVEL_3 3 + +/* magic number fo symheader */ +#define magicSym 0x7009 +/* The Alpha uses this value instead, for some reason. */ +#define magicSym2 0x1992 + +/* Language codes */ +#define langC 0 +#define langPascal 1 +#define langFortran 2 +#define langAssembler 3 /* one Assembley inst might map to many mach */ +#define langMachine 4 +#define langNil 5 +#define langAda 6 +#define langPl1 7 +#define langCobol 8 +#define langStdc 9 /* FIXME: Collides with SGI langCplusplus */ +#define langCplusplus 9 /* FIXME: Collides with langStdc */ +#define langCplusplusV2 10 /* SGI addition */ +#define langMax 11 /* maximun allowed 32 -- 5 bits */ + +/* The following are value definitions for the fields in the SYMR */ + +/* + * Storage Classes + */ + +#define scNil 0 +#define scText 1 /* text symbol */ +#define scData 2 /* initialized data symbol */ +#define scBss 3 /* un-initialized data symbol */ +#define scRegister 4 /* value of symbol is register number */ +#define scAbs 5 /* value of symbol is absolute */ +#define scUndefined 6 /* who knows? */ +#define scCdbLocal 7 /* variable's value is IN se->va.?? */ +#define scBits 8 /* this is a bit field */ +#define scCdbSystem 9 /* variable's value is IN CDB's address space */ +#define scDbx 9 /* overlap dbx internal use */ +#define scRegImage 10 /* register value saved on stack */ +#define scInfo 11 /* symbol contains debugger information */ +#define scUserStruct 12 /* address in struct user for current process */ +#define scSData 13 /* load time only small data */ +#define scSBss 14 /* load time only small common */ +#define scRData 15 /* load time only read only data */ +#define scVar 16 /* Var parameter (fortran,pascal) */ +#define scCommon 17 /* common variable */ +#define scSCommon 18 /* small common */ +#define scVarRegister 19 /* Var parameter in a register */ +#define scVariant 20 /* Variant record */ +#define scSUndefined 21 /* small undefined(external) data */ +#define scInit 22 /* .init section symbol */ +#define scBasedVar 23 /* Fortran or PL/1 ptr based var */ +#define scXData 24 /* exception handling data */ +#define scPData 25 /* Procedure section */ +#define scFini 26 /* .fini section */ +#define scRConst 27 /* .rconst section */ +#define scMax 32 + + +/* + * Symbol Types + */ + +#define stNil 0 /* Nuthin' special */ +#define stGlobal 1 /* external symbol */ +#define stStatic 2 /* static */ +#define stParam 3 /* procedure argument */ +#define stLocal 4 /* local variable */ +#define stLabel 5 /* label */ +#define stProc 6 /* " " Procedure */ +#define stBlock 7 /* beginnning of block */ +#define stEnd 8 /* end (of anything) */ +#define stMember 9 /* member (of anything - struct/union/enum */ +#define stTypedef 10 /* type definition */ +#define stFile 11 /* file name */ +#define stRegReloc 12 /* register relocation */ +#define stForward 13 /* forwarding address */ +#define stStaticProc 14 /* load time only static procs */ +#define stConstant 15 /* const */ +#define stStaParam 16 /* Fortran static parameters */ + /* These new symbol types have been recently added to SGI machines. */ +#define stStruct 26 /* Beginning of block defining a struct type */ +#define stUnion 27 /* Beginning of block defining a union type */ +#define stEnum 28 /* Beginning of block defining an enum type */ +#define stIndirect 34 /* Indirect type specification */ + /* Pseudo-symbols - internal to debugger */ +#define stStr 60 /* string */ +#define stNumber 61 /* pure number (ie. 4 NOR 2+2) */ +#define stExpr 62 /* 2+2 vs. 4 */ +#define stType 63 /* post-coersion SER */ +#define stMax 64 + +/* definitions for fields in TIR */ + +/* type qualifiers for ti.tq0 -> ti.(itqMax-1) */ +#define tqNil 0 /* bt is what you see */ +#define tqPtr 1 /* pointer */ +#define tqProc 2 /* procedure */ +#define tqArray 3 /* duh */ +#define tqFar 4 /* longer addressing - 8086/8 land */ +#define tqVol 5 /* volatile */ +#define tqConst 6 /* const */ +#define tqMax 8 + +/* basic types as seen in ti.bt */ +#define btNil 0 /* undefined (also, enum members) */ +#define btAdr 1 /* address - integer same size as pointer */ +#define btChar 2 /* character */ +#define btUChar 3 /* unsigned character */ +#define btShort 4 /* short */ +#define btUShort 5 /* unsigned short */ +#define btInt 6 /* int */ +#define btUInt 7 /* unsigned int */ +#define btLong 8 /* long */ +#define btULong 9 /* unsigned long */ +#define btFloat 10 /* float (real) */ +#define btDouble 11 /* Double (real) */ +#define btStruct 12 /* Structure (Record) */ +#define btUnion 13 /* Union (variant) */ +#define btEnum 14 /* Enumerated */ +#define btTypedef 15 /* defined via a typedef, isymRef points */ +#define btRange 16 /* subrange of int */ +#define btSet 17 /* pascal sets */ +#define btComplex 18 /* fortran complex */ +#define btDComplex 19 /* fortran double complex */ +#define btIndirect 20 /* forward or unnamed typedef */ +#define btFixedDec 21 /* Fixed Decimal */ +#define btFloatDec 22 /* Float Decimal */ +#define btString 23 /* Varying Length Character String */ +#define btBit 24 /* Aligned Bit String */ +#define btPicture 25 /* Picture */ +#define btVoid 26 /* void */ +#define btLongLong 27 /* long long */ +#define btULongLong 28 /* unsigned long long */ +#define btMax 64 diff --git a/src/base/loader/ecoff_object.cc b/src/base/loader/ecoff_object.cc new file mode 100644 index 000000000..134f2d98d --- /dev/null +++ b/src/base/loader/ecoff_object.cc @@ -0,0 +1,155 @@ +/* + * Copyright (c) 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 Reinhardt + */ + +#include <string> + +#include "base/loader/ecoff_object.hh" +#include "base/misc.hh" +#include "base/loader/symtab.hh" + +#include "base/trace.hh" // for DPRINTF + +#include "base/loader/exec_ecoff.h" +#include "base/loader/coff_sym.h" +#include "base/loader/coff_symconst.h" + +using namespace std; + +ObjectFile * +EcoffObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data) +{ + if (((ecoff_filehdr *)data)->f_magic == ECOFF_MAGIC_ALPHA) { + // it's Alpha ECOFF + return new EcoffObject(fname, fd, len, data, + ObjectFile::Alpha, ObjectFile::Tru64); + } + else { + return NULL; + } +} + + +EcoffObject::EcoffObject(const string &_filename, int _fd, + size_t _len, uint8_t *_data, + Arch _arch, OpSys _opSys) + : ObjectFile(_filename, _fd, _len, _data, _arch, _opSys) +{ + execHdr = (ecoff_exechdr *)fileData; + fileHdr = &(execHdr->f); + aoutHdr = &(execHdr->a); + + entry = aoutHdr->entry; + + text.baseAddr = aoutHdr->text_start; + text.size = aoutHdr->tsize; + text.fileImage = fileData + ECOFF_TXTOFF(execHdr); + + data.baseAddr = aoutHdr->data_start; + data.size = aoutHdr->dsize; + data.fileImage = fileData + ECOFF_DATOFF(execHdr); + + bss.baseAddr = aoutHdr->bss_start; + bss.size = aoutHdr->bsize; + bss.fileImage = NULL; + + DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n", + text.baseAddr, text.size, data.baseAddr, data.size, + bss.baseAddr, bss.size); +} + + +bool +EcoffObject::loadGlobalSymbols(SymbolTable *symtab) +{ + if (!symtab) + return false; + + if (fileHdr->f_magic != ECOFF_MAGIC_ALPHA) { + warn("loadGlobalSymbols: wrong magic on %s\n", filename); + return false; + } + + ecoff_symhdr *syms = (ecoff_symhdr *)(fileData + fileHdr->f_symptr); + if (syms->magic != magicSym2) { + warn("loadGlobalSymbols: bad symbol header magic on %s\n", filename); + return false; + } + + ecoff_extsym *ext_syms = (ecoff_extsym *)(fileData + syms->cbExtOffset); + + char *ext_strings = (char *)(fileData + syms->cbSsExtOffset); + for (int i = 0; i < syms->iextMax; i++) { + ecoff_sym *entry = &(ext_syms[i].asym); + if (entry->iss != -1) + symtab->insert(entry->value, ext_strings + entry->iss); + } + + return true; +} + +bool +EcoffObject::loadLocalSymbols(SymbolTable *symtab) +{ + if (!symtab) + return false; + + if (fileHdr->f_magic != ECOFF_MAGIC_ALPHA) { + warn("loadGlobalSymbols: wrong magic on %s\n", filename); + return false; + } + + ecoff_symhdr *syms = (ecoff_symhdr *)(fileData + fileHdr->f_symptr); + if (syms->magic != magicSym2) { + warn("loadGlobalSymbols: bad symbol header magic on %s\n", filename); + return false; + } + + ecoff_sym *local_syms = (ecoff_sym *)(fileData + syms->cbSymOffset); + char *local_strings = (char *)(fileData + syms->cbSsOffset); + ecoff_fdr *fdesc = (ecoff_fdr *)(fileData + syms->cbFdOffset); + + for (int i = 0; i < syms->ifdMax; i++) { + ecoff_sym *entry = (ecoff_sym *)(local_syms + fdesc[i].isymBase); + char *strings = (char *)(local_strings + fdesc[i].issBase); + for (int j = 0; j < fdesc[i].csym; j++) { + if (entry[j].st == stGlobal || entry[j].st == stProc) + if (entry[j].iss != -1) + symtab->insert(entry[j].value, strings + entry[j].iss); + } + } + + for (int i = 0; i < syms->isymMax; i++) { + ecoff_sym *entry = &(local_syms[i]); + if (entry->st == stProc) + symtab->insert(entry->value, local_strings + entry->iss); + } + + return true; +} diff --git a/src/base/loader/ecoff_object.hh b/src/base/loader/ecoff_object.hh new file mode 100644 index 000000000..05c604b2b --- /dev/null +++ b/src/base/loader/ecoff_object.hh @@ -0,0 +1,62 @@ +/* + * Copyright (c) 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 Reinhardt + */ + +#ifndef __ECOFF_OBJECT_HH__ +#define __ECOFF_OBJECT_HH__ + +#include "base/loader/object_file.hh" + +// forward decls: avoid including exec_ecoff.h here +struct ecoff_exechdr; +struct ecoff_filehdr; +struct ecoff_aouthdr; + +class EcoffObject : public ObjectFile +{ + protected: + ecoff_exechdr *execHdr; + ecoff_filehdr *fileHdr; + ecoff_aouthdr *aoutHdr; + + EcoffObject(const std::string &_filename, int _fd, + size_t _len, uint8_t *_data, + Arch _arch, OpSys _opSys); + + public: + virtual ~EcoffObject() {} + + virtual bool loadGlobalSymbols(SymbolTable *symtab); + virtual bool loadLocalSymbols(SymbolTable *symtab); + + static ObjectFile *tryFile(const std::string &fname, int fd, + size_t len, uint8_t *data); +}; + +#endif // __ECOFF_OBJECT_HH__ diff --git a/src/base/loader/elf_object.cc b/src/base/loader/elf_object.cc new file mode 100644 index 000000000..00d218b76 --- /dev/null +++ b/src/base/loader/elf_object.cc @@ -0,0 +1,312 @@ +/* + * Copyright (c) 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 Reinhardt + * Ali Saidi + */ + +#include <string> + +// Because of the -Wundef flag we have to do this +#define __LIBELF_INTERNAL__ 0 +#define __LIBELF_NEED_LINK_H 0 +#define __LIBELF_SYMBOL_VERSIONS 0 + +#include "gelf.h" + +#include "base/loader/elf_object.hh" +#include "base/misc.hh" + +#include "base/loader/symtab.hh" + +#include "base/trace.hh" // for DPRINTF + +#include "sim/byteswap.hh" + + +using namespace std; + +ObjectFile * +ElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data) +{ + Elf *elf; + GElf_Ehdr ehdr; + Arch arch = UnknownArch; + OpSys opSys = UnknownOpSys; + + // check that header matches library version + if (elf_version(EV_CURRENT) == EV_NONE) + panic("wrong elf version number!"); + + // get a pointer to elf structure + elf = elf_memory((char*)data,len); + // will only fail if fd is invalid + assert(elf != NULL); + + // Check that we actually have a elf file + if (gelf_getehdr(elf, &ehdr) ==0) { + DPRINTFR(Loader, "Not ELF\n"); + elf_end(elf); + return NULL; + } else { + //Detect the architecture + //Since we don't know how to check for alpha right now, we'll + //just assume if it wasn't something else and it's 64 bit, that's + //what it must be. + if (ehdr.e_machine == EM_SPARC64 || + ehdr.e_machine == EM_SPARC || + ehdr.e_machine == EM_SPARCV9) { + arch = ObjectFile::SPARC; + } else if (ehdr.e_machine == EM_MIPS + && ehdr.e_ident[EI_CLASS] == ELFCLASS32) { + arch = ObjectFile::Mips; + } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) { + arch = ObjectFile::Alpha; + } else { + warn("Unknown architecture: %d\n", ehdr.e_machine); + arch = ObjectFile::UnknownArch; + } + + //Detect the operating system + switch (ehdr.e_ident[EI_OSABI]) + { + + case ELFOSABI_LINUX: + opSys = ObjectFile::Linux; + break; + case ELFOSABI_SOLARIS: + opSys = ObjectFile::Solaris; + break; + case ELFOSABI_TRU64: + opSys = ObjectFile::Tru64; + break; + default: + opSys = ObjectFile::UnknownOpSys; + } + + //take a look at the .note.ABI section + //It can let us know what's what. + if (opSys == ObjectFile::UnknownOpSys) { + Elf_Scn *section; + GElf_Shdr shdr; + Elf_Data *data; + uint32_t osAbi;; + int secIdx = 1; + + // Get the first section + section = elf_getscn(elf, secIdx); + + // While there are no more sections + while (section != NULL && opSys == ObjectFile::UnknownOpSys) { + gelf_getshdr(section, &shdr); + if (shdr.sh_type == SHT_NOTE && !strcmp(".note.ABI-tag", + elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) { + // we have found a ABI note section + // Check the 5th 32bit word for OS 0 == linux, 1 == hurd, + // 2 == solaris, 3 == freebsd + data = elf_rawdata(section, NULL); + assert(data->d_buf); + if(ehdr.e_ident[EI_DATA] == ELFDATA2LSB) + osAbi = htole(((uint32_t*)data->d_buf)[4]); + else + osAbi = htobe(((uint32_t*)data->d_buf)[4]); + + switch(osAbi) { + case 0: + opSys = ObjectFile::Linux; + break; + case 2: + opSys = ObjectFile::Solaris; + break; + } + } // if section found + if (!strcmp(".SUNW_version", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) + opSys = ObjectFile::Solaris; + if (!strcmp(".stab.index", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) + opSys = ObjectFile::Solaris; + + section = elf_getscn(elf, ++secIdx); + } // while sections + } + + elf_end(elf); + return new ElfObject(fname, fd, len, data, arch, opSys); + } +} + + +ElfObject::ElfObject(const string &_filename, int _fd, + size_t _len, uint8_t *_data, + Arch _arch, OpSys _opSys) + : ObjectFile(_filename, _fd, _len, _data, _arch, _opSys) + +{ + Elf *elf; + GElf_Ehdr ehdr; + + // check that header matches library version + if (elf_version(EV_CURRENT) == EV_NONE) + panic("wrong elf version number!"); + + // get a pointer to elf structure + elf = elf_memory((char*)fileData,len); + // will only fail if fd is invalid + assert(elf != NULL); + + // Check that we actually have a elf file + if (gelf_getehdr(elf, &ehdr) ==0) { + panic("Not ELF, shouldn't be here"); + } + + entry = ehdr.e_entry; + + + // initialize segment sizes to 0 in case they're not present + text.size = data.size = bss.size = 0; + + for (int i = 0; i < ehdr.e_phnum; ++i) { + GElf_Phdr phdr; + if (gelf_getphdr(elf, i, &phdr) == 0) { + panic("gelf_getphdr failed for section %d", i); + } + + // for now we don't care about non-loadable segments + if (!(phdr.p_type & PT_LOAD)) + continue; + + // the headers don't explicitly distinguish text from data, + // but empirically the text segment comes first. + if (text.size == 0) { // haven't seen text segment yet + text.baseAddr = phdr.p_vaddr; + text.size = phdr.p_filesz; + text.fileImage = fileData + phdr.p_offset; + // if there's any padding at the end that's not in the + // file, call it the bss. This happens in the "text" + // segment if there's only one loadable segment (as for + // kernel images). + bss.size = phdr.p_memsz - phdr.p_filesz; + bss.baseAddr = phdr.p_vaddr + phdr.p_filesz; + bss.fileImage = NULL; + } else if (data.size == 0) { // have text, this must be data + data.baseAddr = phdr.p_vaddr; + data.size = phdr.p_filesz; + data.fileImage = fileData + phdr.p_offset; + // if there's any padding at the end that's not in the + // file, call it the bss. Warn if this happens for both + // the text & data segments (should only have one bss). + if (phdr.p_memsz - phdr.p_filesz > 0 && bss.size != 0) { + warn("Two implied bss segments in file!\n"); + } + bss.size = phdr.p_memsz - phdr.p_filesz; + bss.baseAddr = phdr.p_vaddr + phdr.p_filesz; + bss.fileImage = NULL; + } else { + warn("More than two loadable segments in ELF object."); + warn("Ignoring segment @ 0x%x length 0x%x.", + phdr.p_vaddr, phdr.p_filesz); + } + } + + // should have found at least one loadable segment + assert(text.size != 0); + + DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n", + text.baseAddr, text.size, data.baseAddr, data.size, + bss.baseAddr, bss.size); + + elf_end(elf); + + // We will actually read the sections when we need to load them +} + + +bool +ElfObject::loadSomeSymbols(SymbolTable *symtab, int binding) +{ + Elf *elf; + int sec_idx = 1; // there is a 0 but it is nothing, go figure + Elf_Scn *section; + GElf_Shdr shdr; + Elf_Data *data; + int count, ii; + bool found = false; + GElf_Sym sym; + + if (!symtab) + return false; + + // check that header matches library version + if (elf_version(EV_CURRENT) == EV_NONE) + panic("wrong elf version number!"); + + // get a pointer to elf structure + elf = elf_memory((char*)fileData,len); + + assert(elf != NULL); + + // Get the first section + section = elf_getscn(elf, sec_idx); + + // While there are no more sections + while (section != NULL) { + gelf_getshdr(section, &shdr); + + if (shdr.sh_type == SHT_SYMTAB) { + found = true; + data = elf_getdata(section, NULL); + count = shdr.sh_size / shdr.sh_entsize; + DPRINTF(Loader, "Found Symbol Table, %d symbols present\n", count); + + // loop through all the symbols, only loading global ones + for (ii = 0; ii < count; ++ii) { + gelf_getsym(data, ii, &sym); + if (GELF_ST_BIND(sym.st_info) == binding) { + symtab->insert(sym.st_value, + elf_strptr(elf, shdr.sh_link, sym.st_name)); + } + } + } + ++sec_idx; + section = elf_getscn(elf, sec_idx); + } + + elf_end(elf); + + return found; +} + +bool +ElfObject::loadGlobalSymbols(SymbolTable *symtab) +{ + return loadSomeSymbols(symtab, STB_GLOBAL); +} + +bool +ElfObject::loadLocalSymbols(SymbolTable *symtab) +{ + return loadSomeSymbols(symtab, STB_LOCAL); +} diff --git a/src/base/loader/elf_object.hh b/src/base/loader/elf_object.hh new file mode 100644 index 000000000..46dbfe37b --- /dev/null +++ b/src/base/loader/elf_object.hh @@ -0,0 +1,57 @@ +/* + * Copyright (c) 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 Reinhardt + */ + +#ifndef __ELF_OBJECT_HH__ +#define __ELF_OBJECT_HH__ + +#include "base/loader/object_file.hh" + +class ElfObject : public ObjectFile +{ + protected: + + /// Helper functions for loadGlobalSymbols() and loadLocalSymbols(). + bool loadSomeSymbols(SymbolTable *symtab, int binding); + + ElfObject(const std::string &_filename, int _fd, + size_t _len, uint8_t *_data, + Arch _arch, OpSys _opSys); + + public: + virtual ~ElfObject() {} + + virtual bool loadGlobalSymbols(SymbolTable *symtab); + virtual bool loadLocalSymbols(SymbolTable *symtab); + + static ObjectFile *tryFile(const std::string &fname, int fd, + size_t len, uint8_t *data); +}; + +#endif // __ELF_OBJECT_HH__ diff --git a/base/loader/exec_aout.h b/src/base/loader/exec_aout.h index eed44baee..eed44baee 100644 --- a/base/loader/exec_aout.h +++ b/src/base/loader/exec_aout.h diff --git a/base/loader/exec_ecoff.h b/src/base/loader/exec_ecoff.h index 555589806..555589806 100644 --- a/base/loader/exec_ecoff.h +++ b/src/base/loader/exec_ecoff.h diff --git a/src/base/loader/object_file.cc b/src/base/loader/object_file.cc new file mode 100644 index 000000000..42c74d418 --- /dev/null +++ b/src/base/loader/object_file.cc @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2002-2004 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 + * Steve Reinhardt + */ + +#include <list> +#include <string> + +#include <sys/types.h> +#include <sys/mman.h> +#include <fcntl.h> +#include <stdio.h> +#include <unistd.h> + +#include "base/cprintf.hh" +#include "base/loader/object_file.hh" +#include "base/loader/symtab.hh" + +#include "base/loader/ecoff_object.hh" +#include "base/loader/aout_object.hh" +#include "base/loader/elf_object.hh" + +#include "mem/translating_port.hh" + +using namespace std; + +ObjectFile::ObjectFile(const string &_filename, int _fd, + size_t _len, uint8_t *_data, + Arch _arch, OpSys _opSys) + : filename(_filename), descriptor(_fd), fileData(_data), len(_len), + arch(_arch), opSys(_opSys) +{ +} + + +ObjectFile::~ObjectFile() +{ + close(); +} + + +bool +ObjectFile::loadSection(Section *sec, Port *memPort, Addr addrMask) +{ + if (sec->size != 0) { + Addr addr = sec->baseAddr & addrMask; + if (sec->fileImage) { + memPort->writeBlob(addr, sec->fileImage, sec->size); + } + else { + // no image: must be bss + memPort->memsetBlob(addr, 0, sec->size); + } + } + return true; +} + + +bool +ObjectFile::loadSections(Port *memPort, Addr addrMask) +{ + return (loadSection(&text, memPort, addrMask) + && loadSection(&data, memPort, addrMask) + && loadSection(&bss, memPort, addrMask)); +} + + +void +ObjectFile::close() +{ + if (descriptor >= 0) { + ::close(descriptor); + descriptor = -1; + } + + if (fileData) { + ::munmap(fileData, len); + fileData = NULL; + } +} + + +ObjectFile * +createObjectFile(const string &fname) +{ + // open the file + int fd = open(fname.c_str(), O_RDONLY); + if (fd < 0) { + return NULL; + } + + // find the length of the file by seeking to the end + size_t len = (size_t)lseek(fd, 0, SEEK_END); + + // mmap the whole shebang + uint8_t *fileData = + (uint8_t *)mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0); + if (fileData == MAP_FAILED) { + close(fd); + return NULL; + } + + ObjectFile *fileObj = NULL; + + // figure out what we have here + if ((fileObj = EcoffObject::tryFile(fname, fd, len, fileData)) != NULL) { + return fileObj; + } + + if ((fileObj = AoutObject::tryFile(fname, fd, len, fileData)) != NULL) { + return fileObj; + } + + if ((fileObj = ElfObject::tryFile(fname, fd, len, fileData)) != NULL) { + return fileObj; + } + + // don't know what it is + close(fd); + munmap(fileData, len); + return NULL; +} diff --git a/src/base/loader/object_file.hh b/src/base/loader/object_file.hh new file mode 100644 index 000000000..79fa394c6 --- /dev/null +++ b/src/base/loader/object_file.hh @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2002-2004 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 + * Steve Reinhardt + */ + +#ifndef __OBJECT_FILE_HH__ +#define __OBJECT_FILE_HH__ + +#include <limits> +#include <string> + +#include "sim/host.hh" // for Addr + +class Port; +class SymbolTable; + +class ObjectFile +{ + public: + + enum Arch { + UnknownArch, + Alpha, + SPARC, + Mips + }; + + enum OpSys { + UnknownOpSys, + Tru64, + Linux, + Solaris + }; + + protected: + const std::string filename; + int descriptor; + uint8_t *fileData; + size_t len; + + Arch arch; + OpSys opSys; + + ObjectFile(const std::string &_filename, int _fd, + size_t _len, uint8_t *_data, + Arch _arch, OpSys _opSys); + + public: + virtual ~ObjectFile(); + + void close(); + + virtual bool loadSections(Port *memPort, Addr addrMask = + std::numeric_limits<Addr>::max()); + virtual bool loadGlobalSymbols(SymbolTable *symtab) = 0; + virtual bool loadLocalSymbols(SymbolTable *symtab) = 0; + + Arch getArch() const { return arch; } + OpSys getOpSys() const { return opSys; } + + protected: + + struct Section { + Addr baseAddr; + uint8_t *fileImage; + size_t size; + }; + + Addr entry; + Addr globalPtr; + + Section text; + Section data; + Section bss; + + bool loadSection(Section *sec, Port *memPort, Addr addrMask); + void setGlobalPointer(Addr global_ptr) { globalPtr = global_ptr; } + + public: + Addr entryPoint() const { return entry; } + + Addr globalPointer() const { return globalPtr; } + + Addr textBase() const { return text.baseAddr; } + Addr dataBase() const { return data.baseAddr; } + Addr bssBase() const { return bss.baseAddr; } + + size_t textSize() const { return text.size; } + size_t dataSize() const { return data.size; } + size_t bssSize() const { return bss.size; } +}; + +ObjectFile *createObjectFile(const std::string &fname); + + +#endif // __OBJECT_FILE_HH__ diff --git a/src/base/loader/symtab.cc b/src/base/loader/symtab.cc new file mode 100644 index 000000000..3e73eb7a3 --- /dev/null +++ b/src/base/loader/symtab.cc @@ -0,0 +1,139 @@ +/* + * 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 + */ + +#include <iostream> +#include <fstream> +#include <string> +#include <vector> + +#include "base/loader/symtab.hh" +#include "base/misc.hh" +#include "base/str.hh" +#include "sim/host.hh" +#include "sim/serialize.hh" + +using namespace std; + +SymbolTable *debugSymbolTable = NULL; + +void +SymbolTable::clear() +{ + addrTable.clear(); + symbolTable.clear(); +} + +bool +SymbolTable::insert(Addr address, string symbol) +{ + if (symbol.empty()) + return false; + + if (!addrTable.insert(make_pair(address, symbol)).second) + return false; + + if (!symbolTable.insert(make_pair(symbol, address)).second) + return false; + + return true; +} + + +bool +SymbolTable::load(const string &filename) +{ + string buffer; + ifstream file(filename.c_str()); + + if (!file) + fatal("file error: Can't open symbol table file %s\n", filename); + + while (!file.eof()) { + getline(file, buffer); + if (buffer.empty()) + continue; + + int idx = buffer.find(','); + if (idx == string::npos) + return false; + + string address = buffer.substr(0, idx); + eat_white(address); + if (address.empty()) + return false; + + string symbol = buffer.substr(idx + 1); + eat_white(symbol); + if (symbol.empty()) + return false; + + Addr addr; + if (!to_number(address, addr)) + return false; + + if (!insert(addr, symbol)) + return false; + } + + file.close(); + + return true; +} + +void +SymbolTable::serialize(const string &base, ostream &os) +{ + paramOut(os, base + ".size", addrTable.size()); + + int i = 0; + ATable::const_iterator p, end = addrTable.end(); + for (p = addrTable.begin(); p != end; ++p) { + paramOut(os, csprintf("%s.addr_%d", base, i), p->first); + paramOut(os, csprintf("%s.symbol_%d", base, i), p->second); + ++i; + } +} + +void +SymbolTable::unserialize(const string &base, Checkpoint *cp, + const string §ion) +{ + clear(); + int size; + paramIn(cp, section, base + ".size", size); + for (int i = 0; i < size; ++i) { + Addr addr; + std::string symbol; + + paramIn(cp, section, csprintf("%s.addr_%d", base, i), addr); + paramIn(cp, section, csprintf("%s.symbol_%d", base, i), symbol); + insert(addr, symbol); + } +} diff --git a/src/base/loader/symtab.hh b/src/base/loader/symtab.hh new file mode 100644 index 000000000..55ff0c86f --- /dev/null +++ b/src/base/loader/symtab.hh @@ -0,0 +1,176 @@ +/* + * 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 + * Steve Reinhardt + */ + +#ifndef __SYMTAB_HH__ +#define __SYMTAB_HH__ + +#include <iosfwd> +#include <map> + +#include "sim/host.hh" // for Addr + +class Checkpoint; +class SymbolTable +{ + public: + typedef std::map<Addr, std::string> ATable; + typedef std::map<std::string, Addr> STable; + + private: + ATable addrTable; + STable symbolTable; + + private: + bool + upperBound(Addr addr, ATable::const_iterator &iter) const + { + // find first key *larger* than desired address + iter = addrTable.upper_bound(addr); + + // if very first key is larger, we're out of luck + if (iter == addrTable.begin()) + return false; + + return true; + } + + public: + SymbolTable() {} + SymbolTable(const std::string &file) { load(file); } + ~SymbolTable() {} + + void clear(); + bool insert(Addr address, std::string symbol); + bool load(const std::string &file); + + const ATable &getAddrTable() const { return addrTable; } + const STable &getSymbolTable() const { return symbolTable; } + + public: + void serialize(const std::string &base, std::ostream &os); + void unserialize(const std::string &base, Checkpoint *cp, + const std::string §ion); + + public: + bool + findSymbol(Addr address, std::string &symbol) const + { + ATable::const_iterator i = addrTable.find(address); + if (i == addrTable.end()) + return false; + + symbol = (*i).second; + return true; + } + + bool + findAddress(const std::string &symbol, Addr &address) const + { + STable::const_iterator i = symbolTable.find(symbol); + if (i == symbolTable.end()) + return false; + + address = (*i).second; + return true; + } + + /// Find the nearest symbol equal to or less than the supplied + /// address (e.g., the label for the enclosing function). + /// @param address The address to look up. + /// @param symbol Return reference for symbol string. + /// @param sym_address Return reference for symbol address. + /// @param next_sym_address Address of following symbol (for + /// determining valid range of symbol). + /// @retval True if a symbol was found. + bool + findNearestSymbol(Addr addr, std::string &symbol, Addr &symaddr, + Addr &nextaddr) const + { + ATable::const_iterator i; + if (!upperBound(addr, i)) + return false; + + nextaddr = i->first; + --i; + symaddr = i->first; + symbol = i->second; + return true; + } + + /// Overload for findNearestSymbol() for callers who don't care + /// about next_sym_address. + bool + findNearestSymbol(Addr addr, std::string &symbol, Addr &symaddr) const + { + ATable::const_iterator i; + if (!upperBound(addr, i)) + return false; + + --i; + symaddr = i->first; + symbol = i->second; + return true; + } + + + bool + findNearestAddr(Addr addr, Addr &symaddr, Addr &nextaddr) const + { + ATable::const_iterator i; + if (!upperBound(addr, i)) + return false; + + nextaddr = i->first; + --i; + symaddr = i->first; + return true; + } + + bool + findNearestAddr(Addr addr, Addr &symaddr) const + { + ATable::const_iterator i; + if (!upperBound(addr, i)) + return false; + + --i; + symaddr = i->first; + return true; + } +}; + +/// Global unified debugging symbol table (for target). Conceptually +/// there should be one of these per System object for full system, +/// and per Process object for non-full-system, but so far one big +/// global one has worked well enough. +extern SymbolTable *debugSymbolTable; + +#endif // __SYMTAB_HH__ diff --git a/src/base/match.cc b/src/base/match.cc new file mode 100644 index 000000000..994209864 --- /dev/null +++ b/src/base/match.cc @@ -0,0 +1,98 @@ +/* + * 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: Nathan Binkert + */ + +#include "base/match.hh" +#include "base/str.hh" + +using namespace std; + +ObjectMatch::ObjectMatch() +{ +} + +ObjectMatch::ObjectMatch(const string &expr) +{ + setExpression(expr); +} + +void +ObjectMatch::setExpression(const string &expr) +{ + tokens.resize(1); + tokenize(tokens[0], expr, '.'); +} + +void +ObjectMatch::setExpression(const vector<string> &expr) +{ + if (expr.empty()) { + tokens.resize(0); + } else { + tokens.resize(expr.size()); + for (int i = 0; i < expr.size(); ++i) + tokenize(tokens[i], expr[i], '.'); + } +} + +/** + * @todo this should probably be changed to just use regular + * expression code + */ +bool +ObjectMatch::domatch(const string &name) const +{ + vector<string> name_tokens; + tokenize(name_tokens, name, '.'); + int ntsize = name_tokens.size(); + + int num_expr = tokens.size(); + for (int i = 0; i < num_expr; ++i) { + const vector<string> &token = tokens[i]; + int jstop = token.size(); + + bool match = true; + for (int j = 0; j < jstop; ++j) { + if (j >= ntsize) + break; + + const string &var = token[j]; + if (var != "*" && var != name_tokens[j]) { + match = false; + break; + } + } + + if (match == true) + return true; + } + + return false; +} + diff --git a/src/base/match.hh b/src/base/match.hh new file mode 100644 index 000000000..6e1f03b80 --- /dev/null +++ b/src/base/match.hh @@ -0,0 +1,59 @@ +/* + * 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: Nathan Binkert + */ + +/* @file + * User Console Definitions + */ + +#ifndef __BASE_MATCH_HH__ +#define __BASE_MATCH_HH__ + +#include <string> +#include <vector> + +class ObjectMatch +{ + protected: + std::vector<std::vector<std::string> > tokens; + bool domatch(const std::string &name) const; + + public: + ObjectMatch(); + ObjectMatch(const std::string &expression); + void setExpression(const std::string &expression); + void setExpression(const std::vector<std::string> &expression); + bool match(const std::string &name) const + { + return tokens.empty() ? false : domatch(name); + } +}; + +#endif // __BASE_MATCH_HH__ + diff --git a/src/base/misc.cc b/src/base/misc.cc new file mode 100644 index 000000000..991a33736 --- /dev/null +++ b/src/base/misc.cc @@ -0,0 +1,126 @@ +/* + * 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 + */ + +#include <iostream> +#include <string> + +#include "base/cprintf.hh" +#include "base/hostinfo.hh" +#include "base/misc.hh" +#include "base/output.hh" +#include "base/trace.hh" +#include "sim/host.hh" +#include "sim/root.hh" + +using namespace std; + +void +__panic(const string &format, cp::ArgList &args, const char *func, + const char *file, int line) +{ + string fmt = "panic: " + format; + switch (fmt[fmt.size() - 1]) { + case '\n': + case '\r': + break; + default: + fmt += "\n"; + } + + fmt += " @ cycle %d\n[%s:%s, line %d]\n"; + + args.append(curTick); + args.append(func); + args.append(file); + args.append(line); + args.dump(cerr, fmt); + + delete &args; + + abort(); +} + +void +__fatal(const string &format, cp::ArgList &args, const char *func, + const char *file, int line) +{ + string fmt = "fatal: " + format; + + switch (fmt[fmt.size() - 1]) { + case '\n': + case '\r': + break; + default: + fmt += "\n"; + } + + fmt += " @ cycle %d\n[%s:%s, line %d]\n"; + fmt += "Memory Usage: %ld KBytes\n"; + + args.append(curTick); + args.append(func); + args.append(file); + args.append(line); + args.append(memUsage()); + args.dump(cerr, fmt); + + delete &args; + + exit(1); +} + +void +__warn(const string &format, cp::ArgList &args, const char *func, + const char *file, int line) +{ + string fmt = "warn: " + format; + + switch (fmt[fmt.size() - 1]) { + case '\n': + case '\r': + break; + default: + fmt += "\n"; + } + +#ifdef VERBOSE_WARN + fmt += " @ cycle %d\n[%s:%s, line %d]\n"; + args.append(curTick); + args.append(func); + args.append(file); + args.append(line); +#endif + + args.dump(cerr, fmt); + if (simout.isFile(*outputStream)) + args.dump(*outputStream, fmt); + + delete &args; +} diff --git a/src/base/misc.hh b/src/base/misc.hh new file mode 100644 index 000000000..87faf20e6 --- /dev/null +++ b/src/base/misc.hh @@ -0,0 +1,88 @@ +/* + * 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 + * Dave Greene + */ + +#ifndef __MISC_HH__ +#define __MISC_HH__ + +#include <assert.h> +#include "base/cprintf.hh" + +// +// This implements a cprintf based panic() function. panic() should +// be called when something happens that should never ever happen +// regardless of what the user does (i.e., an acutal m5 bug). panic() +// calls abort which can dump core or enter the debugger. +// +// +void __panic(const std::string&, cp::ArgList &, const char*, const char*, int) + __attribute__((noreturn)); +#define __panic__(format, args...) \ + __panic(format, (*(new cp::ArgList), args), \ + __FUNCTION__, __FILE__, __LINE__) +#define panic(args...) \ + __panic__(args, cp::ArgListNull()) + +// +// This implements a cprintf based fatal() function. fatal() should +// be called when the simulation cannot continue due to some condition +// that is the user's fault (bad configuration, invalid arguments, +// etc.) and not a simulator bug. fatal() calls exit(1), i.e., a +// "normal" exit with an error code, as opposed to abort() like +// panic() does. +// +void __fatal(const std::string&, cp::ArgList &, const char*, const char*, int) + __attribute__((noreturn)); +#define __fatal__(format, args...) \ + __fatal(format, (*(new cp::ArgList), args), \ + __FUNCTION__, __FILE__, __LINE__) +#define fatal(args...) \ + __fatal__(args, cp::ArgListNull()) + +// +// This implements a cprintf based warn +// +void __warn(const std::string&, cp::ArgList &, const char*, const char*, int); +#define __warn__(format, args...) \ + __warn(format, (*(new cp::ArgList), args), \ + __FUNCTION__, __FILE__, __LINE__) +#define warn(args...) \ + __warn__(args, cp::ArgListNull()) + +// +// assert() that prints out the current cycle +// +#define m5_assert(TEST) \ + if (!(TEST)) { \ + std::cerr << "Assertion failure, curTick = " << curTick << std::endl; \ + } \ + assert(TEST); + +#endif // __MISC_HH__ diff --git a/src/base/mod_num.hh b/src/base/mod_num.hh new file mode 100644 index 000000000..6962dc0fd --- /dev/null +++ b/src/base/mod_num.hh @@ -0,0 +1,203 @@ +/* + * 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: Steve Raasch + */ + +template<class T, T MV> +class ModNum { + private: + T value; + + // Compiler should optimize this + void setValue(T n) { value = n % MV; } + + public: + ModNum() {} + ModNum(T n) { setValue(n); } + ModNum(const ModNum<T, MV> &n) : value(n.value) {} + + ModNum operator=(T n) { + setValue(n); + return *this; + } + + const ModNum operator=(ModNum n) { + value = n.value; + return *this; + } + + // Return the value if object used as RHS + operator T() const { return value; } + + // + // Operator "+=" + // + const ModNum<T, MV> operator+=(ModNum<T, MV> r) { + setValue(value + r.value); + return *this; + } + + const ModNum<T, MV> operator+=(T r) { + setValue(value + r); + return *this; + } + + // + // Operator "-=" + // + const ModNum<T, MV> operator-=(ModNum<T, MV> r) { + setValue(value - r.value); + return *this; + } + + const ModNum<T, MV> operator-=(T r) { + setValue(value - r); + return *this; + } + + // + // Operator "++" + // + // PREFIX (like ++a) + const ModNum<T, MV> operator++() { + *this += 1; + return *this; + } + + // POSTFIX (like a++) + const ModNum<T, MV> operator++(int) { + ModNum<T, MV> rv = *this; + + *this += 1; + + return rv; + } + + // + // Operator "--" + // + // PREFIX (like --a) + const ModNum<T, MV> operator--() { + *this -= 1; + return *this; + } + + // POSTFIX (like a--) + const ModNum<T, MV> operator--(int) { + ModNum<T, MV> rv = *this; + *this -= 1; + return rv; + } +}; + + +// +// Define operator "+" like this to avoid creating a temporary +// +template<class T, T MV> +inline ModNum<T, MV> +operator+(ModNum<T, MV> l, ModNum<T, MV> r) { + l += r; + return l; +} + +template<class T, T MV> +inline ModNum<T, MV> +operator+(ModNum<T, MV> l, T r) { + l += r; + return l; +} + +template<class T, T MV> +inline ModNum<T, MV> +operator+(T l, ModNum<T, MV> r) { + r += l; + return r; +} + + +// +// Define operator "-" like this to avoid creating a temporary +// +template<class T, T MV> +inline ModNum<T, MV> +operator-(ModNum<T, MV> l, ModNum<T, MV> r) { + l -= r; + return l; +} + +template<class T, T MV> +inline ModNum<T, MV> +operator-(ModNum<T, MV> l, T r) { + l -= r; + return l; +} + +template<class T, T MV> +inline ModNum<T, MV> +operator-(T l, ModNum<T, MV> r) { + r -= l; + return r; +} + + +// +// Comparison operators +// (all other cases are handled with conversons) +// +template<class T, T MV> +inline bool +operator<(ModNum<T, MV> l, ModNum<T, MV> r) { + return l.value < r.value; +} + +template<class T, T MV> +inline bool +operator>(ModNum<T, MV> l, ModNum<T, MV> r) { + return l.value > r.value; +} + +template<class T, T MV> +inline bool +operator==(ModNum<T, MV> l, ModNum<T, MV> r) { + return l.value == r.value; +} + +template<class T, T MV> +inline bool +operator<=(ModNum<T, MV> l, ModNum<T, MV> r) { + return l.value <= r.value; +} + +template<class T, T MV> +inline bool +operator>=(ModNum<T, MV> l, ModNum<T, MV> r) { + return l.value >= r.value; +} + + diff --git a/src/base/mysql.cc b/src/base/mysql.cc new file mode 100644 index 000000000..2416c766a --- /dev/null +++ b/src/base/mysql.cc @@ -0,0 +1,112 @@ +/* + * 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: Nathan Binkert + */ + +#include <iostream> + +#include "base/mysql.hh" +#include "base/trace.hh" + +using namespace std; + +namespace MySQL { + +inline const char * +charstar(const string &string) +{ + return string.empty() ? NULL : string.c_str(); +} + +ostream & +operator<<(ostream &stream, const Error &error) +{ + stream << error.string(); + return stream; +} + +/* + * The connection class + */ +Connection::Connection() + : valid(false) +{ +} + +Connection::~Connection() +{ + if (valid) + close(); +} + + +bool +Connection::connect(const string &xhost, const string &xuser, + const string &xpasswd, const string &xdatabase) +{ + if (connected()) + return error.set("Already Connected"); + + _host = xhost; + _user = xuser; + _passwd = xpasswd; + _database = xdatabase; + + error.clear(); + + mysql_init(&mysql); + mysql_options(&mysql, MYSQL_OPT_COMPRESS, 0); // might want to be 1 + mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "odbc"); + if (!mysql_real_connect(&mysql, charstar(_host), charstar(_user), + charstar(_passwd), charstar(_database), + 0, NULL, 0)) + return error.set(mysql_error(&mysql)); + + valid = true; + return false; +} + +void +Connection::close() +{ + mysql_close(&mysql); +} + +bool +Connection::query(const string &sql) +{ + DPRINTF(SQL, "Sending SQL query to server:\n%s", sql); + error.clear(); + if (mysql_real_query(&mysql, sql.c_str(), sql.size())) + error.set(mysql_error(&mysql)); + + return error; +} + + +/* namespace MySQL */ } diff --git a/src/base/mysql.hh b/src/base/mysql.hh new file mode 100644 index 000000000..272a0f07c --- /dev/null +++ b/src/base/mysql.hh @@ -0,0 +1,425 @@ +/* + * 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: Nathan Binkert + */ + +#ifndef __BASE_MYSQL_HH__ +#define __BASE_MYSQL_HH__ + +#define TO_BE_INCLUDED_LATER 0 + +#include <cassert> +#include <iosfwd> +#include <mysql_version.h> +#include <mysql.h> +#include <string> +#include <sstream> + +namespace MySQL { + +class Error +{ + protected: + const char *error; + + public: + Error() : error(NULL) {} + + Error &clear() { error = NULL; return *this; } + Error &set(const char *err) { error = err; return *this; } + + const char *string() const { return error; } + + operator bool() const { return error != NULL; } + bool operator!() const { return error == NULL; } +}; + +std::ostream &operator<<(std::ostream &stream, const Error &error); + +class Result +{ + private: + MYSQL_RES *result; + int *refcount; + + void + decref() + { + if (!refcount) + return; + + *refcount -= 1; + if (*refcount == 0) { + mysql_free_result(result); + delete refcount; + } + + refcount = NULL; + } + + public: + Result() + : result(0), refcount(NULL) + { } + + Result(MYSQL_RES *res) + : result(res) + { + if (result) + refcount = new int(1); + else + refcount = NULL; + } + + Result(const Result &result) + : result(result.result), refcount(result.refcount) + { + if (result) + *refcount += 1; + } + + ~Result() + { + decref(); + } + + const Result & + operator=(MYSQL_RES *res) + { + decref(); + result = res; + if (result) + refcount = new int(1); + + return *this; + } + + const Result & + operator=(const Result &res) + { + decref(); + result = res.result; + refcount = res.refcount; + if (result) + *refcount += 1; + + return *this; + } + + operator bool() const { return result != NULL; } + bool operator!() const { return result == NULL; } + + unsigned + num_fields() + { + assert(result); + return mysql_num_fields(result); + } + + MYSQL_ROW + fetch_row() + { + return mysql_fetch_row(result); + } + + unsigned long * + fetch_lengths() + { + return mysql_fetch_lengths(result); + } +}; + +typedef MYSQL_ROW Row; + +class Connection +{ + protected: + MYSQL mysql; + bool valid; + + protected: + std::string _host; + std::string _user; + std::string _passwd; + std::string _database; + + public: + Connection(); + virtual ~Connection(); + + bool connected() const { return valid; } + bool connect(const std::string &host, const std::string &user, + const std::string &passwd, const std::string &database); + void close(); + + public: + Error error; + operator MYSQL *() { return &mysql; } + + public: + bool query(const std::string &sql); + + bool + query(const std::stringstream &sql) + { + return query(sql.str()); + } + + bool + autocommit(bool mode) + { + return mysql_autocommit(&mysql, mode); + } + + bool + commit() + { + return mysql_commit(&mysql); + } + + bool + rollback() + { + return mysql_rollback(&mysql); + } + + unsigned + field_count() + { + return mysql_field_count(&mysql); + } + + unsigned + affected_rows() + { + return mysql_affected_rows(&mysql); + } + + unsigned + insert_id() + { + return mysql_insert_id(&mysql); + } + + + Result + store_result() + { + error.clear(); + Result result = mysql_store_result(&mysql); + if (!result) + error.set(mysql_error(&mysql)); + + return result; + } +}; + +#if 0 +class BindProxy +{ + MYSQL_BIND *bind; + BindProxy(MYSQL_BIND *b) : bind(b) {} + + void operator=(bool &buffer) + { + bind->buffer_type = MYSQL_TYPE_TINY; + bind->buffer = (char *)&buffer; + } + + void operator=(int8_t &buffer) + { + bind->buffer_type = MYSQL_TYPE_TINY; + bind->buffer = (char *)&buffer; + } + + void operator=(int16_t &buffer) + { + bind->buffer_type = MYSQL_TYPE_SHORT; + bind->buffer = (char *)&buffer; + } + + void operator=(int32_t &buffer) + { + bind->buffer_type = MYSQL_TYPE_LONG; + bind->buffer = (char *)&buffer; + } + + void operator=(int64_t &buffer) + { + bind->buffer_type = MYSQL_TYPE_LONGLONG; + bind->buffer = (char *)&buffer; + } + + void operator=(uint8_t &buffer) + { + bind->buffer_type = MYSQL_TYPE_TINY; + bind->buffer = (char *)&buffer; + } + + void operator=(uint16_t &buffer) + { + bind->buffer_type = MYSQL_TYPE_SHORT; + bind->buffer = (char *)&buffer; + } + + void operator=(uint32_t &buffer) + { + bind->buffer_type = MYSQL_TYPE_LONG; + bind->buffer = (char *)&buffer; + } + + void operator=(uint64_t &buffer) + { + bind->buffer_type = MYSQL_TYPE_LONGLONG; + bind->buffer = (char *)&buffer; + } + + void operator=(float &buffer) + { + bind->buffer_type = MYSQL_TYPE_FLOAT; + bind->buffer = (char *)&buffer; + } + + void operator=(double &buffer) + { + bind->buffer_type = MYSQL_TYPE_DOUBLE; + bind->buffer = (char *)&buffer; + } + + void operator=(Time &buffer) + { + bind->buffer_type = MYSQL_TYPE_DATE; + bind->buffer = (char *)&buffer; + } + + void operator=(const char *buffer) + { + bind->buffer_type = MYSQL_TYPE_VAR_STRING; + bind->buffer = buffer; + } + + void operator=(const std::string &buffer) + { + bind->buffer_type = MYSQL_TYPE_VAR_STRING; + bind->buffer = (char *)&buffer; + bind->length = buffer.length; + } + + bool + set_null(bool null) + { + bind->is_null = null; + } +}; + +class Statement +{ + protected: + Error &error; + MYSQL_STMT *stmt; + MYSQL_BIND *bind; + int size; + + public: + Statement(Connection &mysql) + : error(mysql.error), bind(NULL), size(0) + { + stmt = mysql_stmt_init(mysql); + assert(valid() && "mysql_stmt_init(), out of memory\n"); + } + + ~Statement() + { + assert(valid()); + error.clear(); + if (mysql_stmt_close(stmt)) + error.set(mysql_stmt_error(stmt)); + + if (bind) + delete [] bind; + } + + bool valid() + { + return stmt != NULL; + } + + void prepare(const std::string &query) + { + assert(valid()); + mysql.error.clear(); + if (mysql_stmt_prepare(mysql, query, strlen(query))) + mysql.error.set(mysql_stmt_error(stmt)); + + int size = count(); + bind = new MYSQL_BIND[size]; + } + + unsigned count() + { + assert(valid()); + return mysql_stmt_param_count(stmt); + } + + unsigned affected() + { + assert(valid()); + return mysql_stmt_affected_rows(stmt); + } + + void bind(MYSQL_BIND *bind) + { + mysql.error.clear(); + if (mysql_stmt_bind_param(stmt, bind)) + mysql.error.set(mysql_stmt_error(stmt)); + } + + BindProxy operator[](int index) + { + assert(index > 0 && index < N); + return &bind[N]; + } + + operator MYSQL_BIND *() + { + return bind; + } + + void operator()() + { + assert(valid()); + error.clear(); + if (mysql_stmt_execute(stmt)) + error.set(mysql_stmt_error(stmt)); + } +} +#endif + +/* namespace MySQL */ } + +#endif // __BASE_MYSQL_HH__ diff --git a/src/base/output.cc b/src/base/output.cc new file mode 100644 index 000000000..afcac03a5 --- /dev/null +++ b/src/base/output.cc @@ -0,0 +1,131 @@ +/* + * Copyright (c) 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 + */ + +#include <errno.h> +#include <limits.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include <fstream> + +#include "base/misc.hh" +#include "base/output.hh" + +using namespace std; + +OutputDirectory simout; + +/** + * + */ +OutputDirectory::OutputDirectory() +{} + +OutputDirectory::~OutputDirectory() +{} + +void +OutputDirectory::setDirectory(const string &d) +{ + if (!dir.empty()) + panic("Output directory already set!\n"); + + dir = d; + + if (dir != ".") { + if (mkdir(dir.c_str(), 0777) < 0 && errno != EEXIST) + panic("couldn't make output dir %s: %s\n", + dir, strerror(errno)); + } + + // guarantee that directory ends with a '/' + if (dir[dir.size() - 1] != '/') + dir += "/"; +} + +const string & +OutputDirectory::directory() +{ + if (dir.empty()) + panic("Output directory not set!"); + + return dir; +} + +string +OutputDirectory::resolve(const string &name) +{ + return (name[0] != '/') ? dir + name : name; +} + +ostream * +OutputDirectory::create(const string &name) +{ + if (name == "cerr" || name == "stderr") + return &cerr; + + if (name == "cout" || name == "stdout") + return &cout; + + ofstream *file = new ofstream(resolve(name).c_str(), ios::trunc); + if (!file->is_open()) + panic("Cannot open file %s", name); + + return file; +} + +ostream * +OutputDirectory::find(const string &name) +{ + if (name == "cerr" || name == "stderr") + return &cerr; + + if (name == "cout" || name == "stdout") + return &cout; + + string filename = resolve(name); + map_t::iterator i = files.find(filename); + if (i != files.end()) + return (*i).second; + + ofstream *file = new ofstream(filename.c_str(), ios::trunc); + if (!file->is_open()) + panic("Cannot open file %s", filename); + + files[filename] = file; + return file; +} + +bool +OutputDirectory::isFile(const std::ostream *os) +{ + return os && os != &cerr && os != &cout; +} diff --git a/src/base/output.hh b/src/base/output.hh new file mode 100644 index 000000000..0aae4ae81 --- /dev/null +++ b/src/base/output.hh @@ -0,0 +1,63 @@ +/* + * Copyright (c) 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 + */ + +#ifndef __BASE_OUTPUT_HH__ +#define __BASE_OUTPUT_HH__ + +#include <iosfwd> +#include <map> +#include <string> + +class OutputDirectory +{ + private: + typedef std::map<std::string, std::ostream *> map_t; + + map_t files; + std::string dir; + + public: + OutputDirectory(); + ~OutputDirectory(); + + void setDirectory(const std::string &dir); + const std::string &directory(); + + std::string resolve(const std::string &name); + std::ostream *create(const std::string &name); + std::ostream *find(const std::string &name); + + static bool isFile(const std::ostream *os); + static inline bool isFile(const std::ostream &os) { return isFile(&os); } +}; + +extern OutputDirectory simout; + +#endif // __BASE_OUTPUT_HH__ diff --git a/src/base/pollevent.cc b/src/base/pollevent.cc new file mode 100644 index 000000000..2743cd95d --- /dev/null +++ b/src/base/pollevent.cc @@ -0,0 +1,275 @@ +/* + * 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 + */ + +#include <sys/ioctl.h> +#include <sys/types.h> + +#include <fcntl.h> +#include <signal.h> +#include <unistd.h> + +#include "sim/async.hh" +#include "sim/host.hh" +#include "base/misc.hh" +#include "base/pollevent.hh" +#include "sim/root.hh" +#include "sim/serialize.hh" + +using namespace std; + +PollQueue pollQueue; + +///////////////////////////////////////////////////// +// +PollEvent::PollEvent(int _fd, int _events) + : queue(NULL), enabled(true) +{ + pfd.fd = _fd; + pfd.events = _events; +} + +PollEvent::~PollEvent() +{ + if (queue) + queue->remove(this); +} + +void +PollEvent::disable() +{ + if (!enabled) return; + enabled = false; + + if (queue) + queue->copy(); +} + +void +PollEvent::enable() +{ + if (enabled) return; + enabled = true; + + if (queue) + queue->copy(); +} + +void +PollEvent::serialize(ostream &os) +{ + SERIALIZE_SCALAR(pfd.fd); + SERIALIZE_SCALAR(pfd.events); + SERIALIZE_SCALAR(enabled); +} + +void +PollEvent::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_SCALAR(pfd.fd); + UNSERIALIZE_SCALAR(pfd.events); + UNSERIALIZE_SCALAR(enabled); +} + +///////////////////////////////////////////////////// +// +PollQueue::PollQueue() + : poll_fds(NULL), max_size(0), num_fds(0) +{ } + +PollQueue::~PollQueue() +{ + removeHandler(); + for (int i = 0; i < num_fds; i++) + setupAsyncIO(poll_fds[0].fd, false); + + delete [] poll_fds; +} + +void +PollQueue::copy() +{ + eventvec_t::iterator i = events.begin(); + eventvec_t::iterator end = events.end(); + + num_fds = 0; + + while (i < end) { + if ((*i)->enabled) + poll_fds[num_fds++] = (*i)->pfd; + ++i; + } +} + +void +PollQueue::remove(PollEvent *event) +{ + eventvec_t::iterator i = events.begin(); + eventvec_t::iterator end = events.end(); + + while (i < end) { + if (*i == event) { + events.erase(i); + copy(); + event->queue = NULL; + return; + } + + ++i; + } + + panic("Event does not exist. Cannot remove."); +} + +void +PollQueue::schedule(PollEvent *event) +{ + if (event->queue) + panic("Event already scheduled!"); + + event->queue = this; + events.push_back(event); + setupAsyncIO(event->pfd.fd, true); + + // if we ran out of space in the fd array, double the capacity + // if this is the first time that we've scheduled an event, create + // the array with an initial size of 16 + if (++num_fds > max_size) { + if (max_size > 0) { + delete [] poll_fds; + max_size *= 2; + } else { + max_size = 16; + setupHandler(); + } + + poll_fds = new pollfd[max_size]; + } + + copy(); +} + +void +PollQueue::service() +{ + int ret = poll(poll_fds, num_fds, 0); + + if (ret <= 0) + return; + + for (int i = 0; i < num_fds; i++) { + int revents = poll_fds[i].revents; + if (revents) { + events[i]->process(revents); + if (--ret <= 0) + break; + } + } +} + +struct sigaction PollQueue::oldio; +struct sigaction PollQueue::oldalrm; +bool PollQueue::handler = false; + +void +PollQueue::setupAsyncIO(int fd, bool set) +{ + int flags = fcntl(fd, F_GETFL); + if (flags == -1) + panic("Could not set up async IO"); + + if (set) + flags |= FASYNC; + else + flags &= ~(FASYNC); + + if (fcntl(fd, F_SETFL, flags) == -1) + panic("Could not set up async IO"); + + if (set) { + if (fcntl(fd, F_SETOWN, getpid()) == -1) + panic("Could not set up async IO"); + } +} + +void +PollQueue::setupHandler() +{ + struct sigaction act; + + act.sa_handler = handleIO; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_RESTART; + + if (sigaction(SIGIO, &act, &oldio) == -1) + panic("could not do sigaction"); + + act.sa_handler = handleALRM; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_RESTART; + + if (sigaction(SIGALRM, &act, &oldalrm) == -1) + panic("could not do sigaction"); + + alarm(1); + + handler = true; +} + +void +PollQueue::removeHandler() +{ + if (sigaction(SIGIO, &oldio, NULL) == -1) + panic("could not remove handler"); + + if (sigaction(SIGIO, &oldalrm, NULL) == -1) + panic("could not remove handler"); +} + +void +PollQueue::handleIO(int sig) +{ + if (sig != SIGIO) + panic("Wrong Handler"); + + async_event = true; + async_io = true; +} + +void +PollQueue::handleALRM(int sig) +{ + if (sig != SIGALRM) + panic("Wrong Handler"); + + async_event = true; + async_alarm = true; + alarm(1); +} + diff --git a/src/base/pollevent.hh b/src/base/pollevent.hh new file mode 100644 index 000000000..5b84650cb --- /dev/null +++ b/src/base/pollevent.hh @@ -0,0 +1,99 @@ +/* + * 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 + */ + +#ifndef __POLLEVENT_H__ +#define __POLLEVENT_H__ + +#include <vector> +#include <poll.h> +#include "sim/root.hh" + +class Checkpoint; +class PollQueue; + +class PollEvent +{ + private: + friend class PollQueue; + + protected: + pollfd pfd; + PollQueue *queue; + bool enabled; + + public: + PollEvent(int fd, int event); + virtual ~PollEvent(); + + void disable(); + void enable(); + virtual void process(int revent) = 0; + + bool queued() { return queue != 0; } + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); +}; + +class PollQueue +{ + private: + typedef std::vector<PollEvent *> eventvec_t; + eventvec_t events; + + pollfd *poll_fds; + int max_size; + int num_fds; + + public: + PollQueue(); + ~PollQueue(); + + void copy(); + void remove(PollEvent *event); + void schedule(PollEvent *event); + void service(); + + protected: + static bool handler; + static struct sigaction oldio; + static struct sigaction oldalrm; + + public: + static void setupAsyncIO(int fd, bool set); + static void handleIO(int); + static void handleALRM(int); + static void removeHandler(); + static void setupHandler(); +}; + +extern PollQueue pollQueue; + +#endif // __POLLEVENT_H__ diff --git a/src/base/predictor.hh b/src/base/predictor.hh new file mode 100644 index 000000000..94f19ca28 --- /dev/null +++ b/src/base/predictor.hh @@ -0,0 +1,63 @@ +/* + * 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 Raasch + * Nathan Binkert + */ + +// +// Abstract base class for a generic predictor +// +// + +#ifndef __PREDICTOR_HH__ +#define __PREDICTOR_HH__ + +class GenericPredictor { + + public: + virtual void clear() = 0; + + virtual unsigned predict(unsigned long _index) = 0; + virtual unsigned predict(unsigned long _index, unsigned &pdata) = 0; + + virtual unsigned peek(unsigned long _index) = 0; + + virtual void record(unsigned long _index, unsigned _actual_value, + unsigned _pred_value) = 0; + virtual void record(unsigned long _index, unsigned _actual_value, + unsigned _pred_value, unsigned _pdata) = 0; + + virtual unsigned value(unsigned long _index) = 0; + + virtual void regStats() = 0; + virtual void regFormulas() = 0; + + virtual ~GenericPredictor() {}; +}; + +#endif // __PREDICTOR_HH__ diff --git a/src/base/random.cc b/src/base/random.cc new file mode 100644 index 000000000..e135b55f5 --- /dev/null +++ b/src/base/random.cc @@ -0,0 +1,100 @@ +/* + * Copyright (c) 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: Nathan Binkert + * Ali Saidi + */ + +#include <cstdlib> +#include <cmath> + +#include "sim/param.hh" +#include "base/random.hh" +#include "base/trace.hh" + +using namespace std; + +class RandomContext : public ParamContext +{ + public: + RandomContext(const string &_iniSection) + : ::ParamContext(_iniSection) {} + ~RandomContext() {} + + void checkParams(); +}; + +RandomContext paramContext("random"); + +Param<unsigned> +seed(¶mContext, "seed", "seed to random number generator", 1); + +void +RandomContext::checkParams() +{ + ::srand48(seed); +} + +long +getLong() +{ + return mrand48(); +} + +int64_t +getUniform(int64_t min, int64_t max) +{ + double r; + r = drand48() * (max-min) + min; + return (int64_t)round(r); +} + +uint64_t +getUniformPos(uint64_t min, uint64_t max) +{ + double r; + r = drand48() * (max-min) + min; + return (uint64_t)round(r); +} + + +// idea for generating a double from erand48 +double +getDouble() +{ + union { + uint32_t _long[2]; + uint16_t _short[4]; + }; + + _long[0] = mrand48(); + _long[1] = mrand48(); + + return ldexp((double) _short[0], -48) + + ldexp((double) _short[1], -32) + + ldexp((double) _short[2], -16); +} diff --git a/src/base/random.hh b/src/base/random.hh new file mode 100644 index 000000000..b5eb39f94 --- /dev/null +++ b/src/base/random.hh @@ -0,0 +1,129 @@ +/* + * Copyright (c) 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: Nathan Binkert + * Ali Saidi + */ + +#ifndef __BASE_RANDOM_HH__ +#define __BASE_RANDOM_HH__ + +#include "sim/host.hh" + +long getLong(); +double getDouble(); +uint64_t getUniformPos(uint64_t min, uint64_t max); +int64_t getUniform(int64_t min, int64_t max); + +template <typename T> +struct Random; + +template<> struct Random<int8_t> +{ + static int8_t get() + { return getLong() & (int8_t)-1; } + + static int8_t uniform(int8_t min, int8_t max) + { return getUniform(min, max); } +}; + +template<> struct Random<uint8_t> +{ + static uint8_t get() + { return getLong() & (uint8_t)-1; } + + static uint8_t uniform(uint8_t min, uint8_t max) + { return getUniformPos(min, max); } +}; + +template<> struct Random<int16_t> +{ + static int16_t get() + { return getLong() & (int16_t)-1; } + + static int16_t uniform(int16_t min, int16_t max) + { return getUniform(min, max); } +}; + +template<> struct Random<uint16_t> +{ + static uint16_t get() + { return getLong() & (uint16_t)-1; } + + static uint16_t uniform(uint16_t min, uint16_t max) + { return getUniformPos(min, max); } +}; + +template<> struct Random<int32_t> +{ + static int32_t get() + { return (int32_t)getLong(); } + + static int32_t uniform(int32_t min, int32_t max) + { return getUniform(min, max); } +}; + +template<> struct Random<uint32_t> +{ + static uint32_t get() + { return (uint32_t)getLong(); } + + static uint32_t uniform(uint32_t min, uint32_t max) + { return getUniformPos(min, max); } +}; + +template<> struct Random<int64_t> +{ + static int64_t get() + { return (int64_t)getLong() << 32 || (uint64_t)getLong(); } + + static int64_t uniform(int64_t min, int64_t max) + { return getUniform(min, max); } +}; + +template<> struct Random<uint64_t> +{ + static uint64_t get() + { return (uint64_t)getLong() << 32 || (uint64_t)getLong(); } + + static uint64_t uniform(uint64_t min, uint64_t max) + { return getUniformPos(min, max); } +}; + +template<> struct Random<float> +{ + static float get() + { return getDouble(); } +}; + +template<> struct Random<double> +{ + static double get() + { return getDouble(); } +}; + +#endif // __BASE_RANDOM_HH__ diff --git a/src/base/range.cc b/src/base/range.cc new file mode 100644 index 000000000..442e5fdf8 --- /dev/null +++ b/src/base/range.cc @@ -0,0 +1,85 @@ +/* + * 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: Nathan Binkert + */ + +#include "base/intmath.hh" +#include "base/range.hh" +#include "base/str.hh" + +using namespace std; + +template <class T> +bool +__x_parse_range(const std::string &str, T &first, T &last) +{ + std::vector<std::string> values; + tokenize(values, str, ':'); + + T thefirst, thelast; + + if (values.size() != 2) + return false; + + std::string s = values[0]; + std::string e = values[1]; + + if (!to_number(s, thefirst)) + return false; + + bool increment = (e[0] == '+'); + if (increment) + e = e.substr(1); + + if (!to_number(e, thelast)) + return false; + + if (increment) + thelast += thefirst - 1; + + first = thefirst; + last = thelast; + + return true; +} + +#define RANGE_PARSE(type) \ +template<> bool \ +__parse_range(const std::string &s, type &first, type &last) \ +{ return __x_parse_range(s, first, last); } + +RANGE_PARSE(unsigned long long); +RANGE_PARSE(signed long long); +RANGE_PARSE(unsigned long); +RANGE_PARSE(signed long); +RANGE_PARSE(unsigned int); +RANGE_PARSE(signed int); +RANGE_PARSE(unsigned short); +RANGE_PARSE(signed short); +RANGE_PARSE(unsigned char); +RANGE_PARSE(signed char); diff --git a/src/base/range.hh b/src/base/range.hh new file mode 100644 index 000000000..d9542c0ca --- /dev/null +++ b/src/base/range.hh @@ -0,0 +1,358 @@ +/* + * 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 + * Steve Reinhardt + */ + +#ifndef __BASE_RANGE_HH__ +#define __BASE_RANGE_HH__ + +#include <cassert> +#include <iostream> +#include <string> + +/** + * @param s range string + * EndExclusive Ranges are in the following format: + * @verbatim + * <range> := {<start_val>}:{<end>} + * <start> := <end_val> | +<delta> + * @endverbatim + */ +template <class T> +bool __parse_range(const std::string &s, T &start, T &end); + +template <class T> +struct Range +{ + T start; + T end; + + Range() { invalidate(); } + + template <class U> + Range(const std::pair<U, U> &r) + : start(r.first), end(r.second) + {} + + template <class U> + Range(const Range<U> &r) + : start(r.start), end(r.end) + {} + + Range(const std::string &s) + { + if (!__parse_range(s, start, end)) + invalidate(); + } + + template <class U> + const Range<T> &operator=(const Range<U> &r) + { + start = r.start; + end = r.end; + return *this; + } + + template <class U> + const Range<T> &operator=(const std::pair<U, U> &r) + { + start = r.first; + end = r.second; + return *this; + } + + const Range &operator=(const std::string &s) + { + if (!__parse_range(s, start, end)) + invalidate(); + return *this; + } + + void invalidate() { start = 1; end = 0; } + T size() const { return end - start + 1; } + bool valid() const { return start < end; } +}; + +template <class T> +inline std::ostream & +operator<<(std::ostream &o, const Range<T> &r) +{ + o << '[' << r.start << "," << r.end << ']'; + return o; +} + +template <class T> +inline Range<T> +RangeEx(T start, T end) +{ return std::make_pair(start, end - 1); } + +template <class T> +inline Range<T> +RangeIn(T start, T end) +{ return std::make_pair(start, end); } + +template <class T, class U> +inline Range<T> +RangeSize(T start, U size) +{ return std::make_pair(start, start + size - 1); } + +//////////////////////////////////////////////////////////////////////// +// +// Range to Range Comparisons +// + +/** + * @param range1 is a range. + * @param range2 is a range. + * @return if range1 and range2 are identical. + */ +template <class T, class U> +inline bool +operator==(const Range<T> &range1, const Range<U> &range2) +{ + return range1.start == range2.start && range1.end == range2.end; +} + +/** + * @param range1 is a range. + * @param range2 is a range. + * @return if range1 and range2 are not identical. + */ +template <class T, class U> +inline bool +operator!=(const Range<T> &range1, const Range<U> &range2) +{ + return range1.start != range2.start || range1.end != range2.end; +} + +/** + * @param range1 is a range. + * @param range2 is a range. + * @return if range1 is less than range2 and does not overlap range1. + */ +template <class T, class U> +inline bool +operator<(const Range<T> &range1, const Range<U> &range2) +{ + return range1.start < range2.start; +} + +/** + * @param range1 is a range. + * @param range2 is a range. + * @return if range1 is less than range2. range1 may overlap range2, + * but not extend beyond the end of range2. + */ +template <class T, class U> +inline bool +operator<=(const Range<T> &range1, const Range<U> &range2) +{ + return range1.start <= range2.start; +} + +/** + * @param range1 is a range. + * @param range2 is a range. + * @return if range1 is greater than range2 and does not overlap range2. + */ +template <class T, class U> +inline bool +operator>(const Range<T> &range1, const Range<U> &range2) +{ + return range1.start > range2.start; +} + +/** + * @param range1 is a range. + * @param range2 is a range. + * @return if range1 is greater than range2. range1 may overlap range2, + * but not extend beyond the beginning of range2. + */ +template <class T, class U> +inline bool +operator>=(const Range<T> &range1, const Range<U> &range2) +{ + return range1.start >= range2.start; +} + +//////////////////////////////////////////////////////////////////////// +// +// Position to Range Comparisons +// + +/** + * @param pos position compared to the range. + * @param range range compared against. + * @return indicates that position pos is within the range. + */ +template <class T, class U> +inline bool +operator==(const T &pos, const Range<U> &range) +{ + return pos >= range.start && pos <= range.end; +} + +/** + * @param pos position compared to the range. + * @param range range compared against. + * @return indicates that position pos is not within the range. + */ +template <class T, class U> +inline bool +operator!=(const T &pos, const Range<U> &range) +{ + return pos < range.start || pos > range.end; +} + +/** + * @param pos position compared to the range. + * @param range range compared against. + * @return indicates that position pos is below the range. + */ +template <class T, class U> +inline bool +operator<(const T &pos, const Range<U> &range) +{ + return pos < range.start; +} + +/** + * @param pos position compared to the range. + * @param range range compared against. + * @return indicates that position pos is below or in the range. + */ +template <class T, class U> +inline bool +operator<=(const T &pos, const Range<U> &range) +{ + return pos <= range.end; +} + +/** + * @param pos position compared to the range. + * @param range range compared against. + * @return indicates that position pos is above the range. + */ +template <class T, class U> +inline bool +operator>(const T &pos, const Range<U> &range) +{ + return pos > range.end; +} + +/** + * @param pos position compared to the range. + * @param range range compared against. + * @return indicates that position pos is above or in the range. + */ +template <class T, class U> +inline bool +operator>=(const T &pos, const Range<U> &range) +{ + return pos >= range.start; +} + +//////////////////////////////////////////////////////////////////////// +// +// Range to Position Comparisons (for symmetry) +// + +/** + * @param range range compared against. + * @param pos position compared to the range. + * @return indicates that position pos is within the range. + */ +template <class T, class U> +inline bool +operator==(const Range<T> &range, const U &pos) +{ + return pos >= range.start && pos <= range.end; +} + +/** + * @param range range compared against. + * @param pos position compared to the range. + * @return indicates that position pos is not within the range. + */ +template <class T, class U> +inline bool +operator!=(const Range<T> &range, const U &pos) +{ + return pos < range.start || pos > range.end; +} + +/** + * @param range range compared against. + * @param pos position compared to the range. + * @return indicates that position pos is above the range. + */ +template <class T, class U> +inline bool +operator<(const Range<T> &range, const U &pos) +{ + return range.end < pos; +} + +/** + * @param range range compared against. + * @param pos position compared to the range. + * @return indicates that position pos is above or in the range. + */ +template <class T, class U> +inline bool +operator<=(const Range<T> &range, const U &pos) +{ + return range.start <= pos; +} + +/** + * @param range range compared against. + * @param pos position compared to the range. + * 'range > pos' indicates that position pos is below the range. + */ +template <class T, class U> +inline bool +operator>(const Range<T> &range, const U &pos) +{ + return range.start > pos; +} + +/** + * @param range range compared against. + * @param pos position compared to the range. + * 'range >= pos' indicates that position pos is below or in the range. + */ +template <class T, class U> +inline bool +operator>=(const Range<T> &range, const U &pos) +{ + return range.end >= pos; +} + +#endif // __BASE_RANGE_HH__ diff --git a/src/base/refcnt.hh b/src/base/refcnt.hh new file mode 100644 index 000000000..6672d4a5f --- /dev/null +++ b/src/base/refcnt.hh @@ -0,0 +1,125 @@ +/* + * 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 + */ + +#ifndef __REFCNT_HH__ +#define __REFCNT_HH__ + +#include <stddef.h> //For the NULL macro definition + +class RefCounted +{ + private: + int count; + + private: + RefCounted(const RefCounted &); + + public: + RefCounted() : count(0) {} + virtual ~RefCounted() {} + + void incref() { ++count; } + void decref() { if (--count <= 0) delete this; } +}; + +template <class T> +class RefCountingPtr +{ + protected: + T *data; + + void copy(T *d) + { + data = d; + if (data) + data->incref(); + } + void del() + { + if (data) + data->decref(); + } + void set(T *d) + { + if (data == d) + return; + + del(); + copy(d); + } + + + public: + RefCountingPtr() : data(NULL) {} + RefCountingPtr(T *data) { copy(data); } + RefCountingPtr(const RefCountingPtr &r) { copy(r.data); } + ~RefCountingPtr() { del(); } + + T *operator->() { return data; } + T &operator*() { return *data; } + T *get() { return data; } + + const T *operator->() const { return data; } + const T &operator*() const { return *data; } + const T *get() const { return data; } + + RefCountingPtr &operator=(T *p) { set(p); return *this; } + RefCountingPtr &operator=(const RefCountingPtr &r) + { return operator=(r.data); } + + bool operator!() const { return data == 0; } + operator bool() const { return data != 0; } +}; + +template<class T> +bool operator==(const RefCountingPtr<T> &l, const RefCountingPtr<T> &r) +{ return l.get() == r.get(); } + +template<class T> +bool operator==(const RefCountingPtr<T> &l, const T *r) +{ return l.get() == r; } + +template<class T> +bool operator==(const T &l, const RefCountingPtr<T> &r) +{ return l == r.get(); } + +template<class T> +bool operator!=(const RefCountingPtr<T> &l, const RefCountingPtr<T> &r) +{ return l.get() != r.get(); } + +template<class T> +bool operator!=(const RefCountingPtr<T> &l, const T *r) +{ return l.get() != r; } + +template<class T> +bool operator!=(const T &l, const RefCountingPtr<T> &r) +{ return l != r.get(); } + +#endif // __REFCNT_HH__ diff --git a/src/base/remote_gdb.cc b/src/base/remote_gdb.cc new file mode 100644 index 000000000..0d3b73b1e --- /dev/null +++ b/src/base/remote_gdb.cc @@ -0,0 +1,1180 @@ +/* + * 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 + */ + +/* + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratories. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)kgdb_stub.c 8.4 (Berkeley) 1/12/94 + */ + +/*- + * Copyright (c) 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * $NetBSD: kgdb_stub.c,v 1.8 2001/07/07 22:58:00 wdk Exp $ + * + * Taken from NetBSD + * + * "Stub" to allow remote cpu to debug over a serial line using gdb. + */ + +#include <sys/signal.h> + +#include <string> +#include <unistd.h> + +#include "arch/vtophys.hh" +#include "base/intmath.hh" +#include "base/kgdb.h" +#include "base/remote_gdb.hh" +#include "base/socket.hh" +#include "base/trace.hh" +#include "config/full_system.hh" +#include "cpu/thread_context.hh" +#include "cpu/static_inst.hh" +#include "mem/physical.hh" +#include "mem/port.hh" +#include "sim/system.hh" + +using namespace std; +using namespace TheISA; + +#ifndef NDEBUG +vector<RemoteGDB *> debuggers; +int current_debugger = -1; + +void +debugger() +{ + if (current_debugger >= 0 && current_debugger < debuggers.size()) { + RemoteGDB *gdb = debuggers[current_debugger]; + if (!gdb->isattached()) + gdb->listener->accept(); + if (gdb->isattached()) + gdb->trap(ALPHA_KENTRY_IF); + } +} +#endif + +/////////////////////////////////////////////////////////// +// +// +// + +GDBListener::Event::Event(GDBListener *l, int fd, int e) + : PollEvent(fd, e), listener(l) +{} + +void +GDBListener::Event::process(int revent) +{ + listener->accept(); +} + +GDBListener::GDBListener(RemoteGDB *g, int p) + : event(NULL), gdb(g), port(p) +{ + assert(!gdb->listener); + gdb->listener = this; +} + +GDBListener::~GDBListener() +{ + if (event) + delete event; +} + +string +GDBListener::name() +{ + return gdb->name() + ".listener"; +} + +void +GDBListener::listen() +{ + while (!listener.listen(port, true)) { + DPRINTF(GDBMisc, "Can't bind port %d\n", port); + port++; + } + + event = new Event(this, listener.getfd(), POLLIN); + pollQueue.schedule(event); + +#ifndef NDEBUG + gdb->number = debuggers.size(); + debuggers.push_back(gdb); +#endif + +#ifndef NDEBUG + ccprintf(cerr, "%d: %s: listening for remote gdb #%d on port %d\n", + curTick, name(), gdb->number, port); +#else + ccprintf(cerr, "%d: %s: listening for remote gdb on port %d\n", + curTick, name(), port); +#endif +} + +void +GDBListener::accept() +{ + if (!listener.islistening()) + panic("GDBListener::accept(): cannot accept if we're not listening!"); + + int sfd = listener.accept(true); + + if (sfd != -1) { + if (gdb->isattached()) + close(sfd); + else + gdb->attach(sfd); + } +} + +/////////////////////////////////////////////////////////// +// +// +// +int digit2i(char); +char i2digit(int); +void mem2hex(void *, const void *, int); +const char *hex2mem(void *, const char *, int); +Addr hex2i(const char **); + +RemoteGDB::Event::Event(RemoteGDB *g, int fd, int e) + : PollEvent(fd, e), gdb(g) +{} + +void +RemoteGDB::Event::process(int revent) +{ + if (revent & POLLIN) + gdb->trap(ALPHA_KENTRY_IF); + else if (revent & POLLNVAL) + gdb->detach(); +} + +RemoteGDB::RemoteGDB(System *_system, ThreadContext *c) + : event(NULL), listener(NULL), number(-1), fd(-1), + active(false), attached(false), + system(_system), pmem(_system->physmem), context(c) +{ + memset(gdbregs, 0, sizeof(gdbregs)); +} + +RemoteGDB::~RemoteGDB() +{ + if (event) + delete event; +} + +string +RemoteGDB::name() +{ + return system->name() + ".remote_gdb"; +} + +bool +RemoteGDB::isattached() +{ return attached; } + +void +RemoteGDB::attach(int f) +{ + fd = f; + + event = new Event(this, fd, POLLIN); + pollQueue.schedule(event); + + attached = true; + DPRINTFN("remote gdb attached\n"); +} + +void +RemoteGDB::detach() +{ + attached = false; + close(fd); + fd = -1; + + pollQueue.remove(event); + DPRINTFN("remote gdb detached\n"); +} + +const char * +gdb_command(char cmd) +{ + switch (cmd) { + case KGDB_SIGNAL: return "KGDB_SIGNAL"; + case KGDB_SET_BAUD: return "KGDB_SET_BAUD"; + case KGDB_SET_BREAK: return "KGDB_SET_BREAK"; + case KGDB_CONT: return "KGDB_CONT"; + case KGDB_ASYNC_CONT: return "KGDB_ASYNC_CONT"; + case KGDB_DEBUG: return "KGDB_DEBUG"; + case KGDB_DETACH: return "KGDB_DETACH"; + case KGDB_REG_R: return "KGDB_REG_R"; + case KGDB_REG_W: return "KGDB_REG_W"; + case KGDB_SET_THREAD: return "KGDB_SET_THREAD"; + case KGDB_CYCLE_STEP: return "KGDB_CYCLE_STEP"; + case KGDB_SIG_CYCLE_STEP: return "KGDB_SIG_CYCLE_STEP"; + case KGDB_KILL: return "KGDB_KILL"; + case KGDB_MEM_W: return "KGDB_MEM_W"; + case KGDB_MEM_R: return "KGDB_MEM_R"; + case KGDB_SET_REG: return "KGDB_SET_REG"; + case KGDB_READ_REG: return "KGDB_READ_REG"; + case KGDB_QUERY_VAR: return "KGDB_QUERY_VAR"; + case KGDB_SET_VAR: return "KGDB_SET_VAR"; + case KGDB_RESET: return "KGDB_RESET"; + case KGDB_STEP: return "KGDB_STEP"; + case KGDB_ASYNC_STEP: return "KGDB_ASYNC_STEP"; + case KGDB_THREAD_ALIVE: return "KGDB_THREAD_ALIVE"; + case KGDB_TARGET_EXIT: return "KGDB_TARGET_EXIT"; + case KGDB_BINARY_DLOAD: return "KGDB_BINARY_DLOAD"; + case KGDB_CLR_HW_BKPT: return "KGDB_CLR_HW_BKPT"; + case KGDB_SET_HW_BKPT: return "KGDB_SET_HW_BKPT"; + case KGDB_START: return "KGDB_START"; + case KGDB_END: return "KGDB_END"; + case KGDB_GOODP: return "KGDB_GOODP"; + case KGDB_BADP: return "KGDB_BADP"; + default: return "KGDB_UNKNOWN"; + } +} + +/////////////////////////////////////////////////////////// +// RemoteGDB::acc +// +// Determine if the mapping at va..(va+len) is valid. +// +bool +RemoteGDB::acc(Addr va, size_t len) +{ + Addr last_va; + + va = TheISA::TruncPage(va); + last_va = TheISA::RoundPage(va + len); + + do { + if (TheISA::IsK0Seg(va)) { + if (va < (TheISA::K0SegBase + pmem->size())) { + DPRINTF(GDBAcc, "acc: Mapping is valid K0SEG <= " + "%#x < K0SEG + size\n", va); + return true; + } else { + DPRINTF(GDBAcc, "acc: Mapping invalid %#x > K0SEG + size\n", + va); + return false; + } + } + + /** + * This code says that all accesses to palcode (instruction and data) + * are valid since there isn't a va->pa mapping because palcode is + * accessed physically. At some point this should probably be cleaned up + * but there is no easy way to do it. + */ + + if (AlphaISA::PcPAL(va) || va < 0x10000) + return true; + + Addr ptbr = context->readMiscReg(AlphaISA::IPR_PALtemp20); + TheISA::PageTableEntry pte = TheISA::kernel_pte_lookup(context->getPhysPort(), ptbr, va); + if (!pte.valid()) { + DPRINTF(GDBAcc, "acc: %#x pte is invalid\n", va); + return false; + } + va += TheISA::PageBytes; + } while (va < last_va); + + DPRINTF(GDBAcc, "acc: %#x mapping is valid\n", va); + return true; +} + +/////////////////////////////////////////////////////////// +// RemoteGDB::signal +// +// Translate a trap number into a Unix-compatible signal number. +// (GDB only understands Unix signal numbers.) +// +int +RemoteGDB::signal(int type) +{ + switch (type) { + case ALPHA_KENTRY_INT: + return (SIGTRAP); + + case ALPHA_KENTRY_UNA: + return (SIGBUS); + + case ALPHA_KENTRY_ARITH: + return (SIGFPE); + + case ALPHA_KENTRY_IF: + return (SIGILL); + + case ALPHA_KENTRY_MM: + return (SIGSEGV); + + default: + panic("unknown signal type"); + return 0; + } +} + +/////////////////////////////////////////////////////////// +// RemoteGDB::getregs +// +// Translate the kernel debugger register format into +// the GDB register format. +void +RemoteGDB::getregs() +{ + memset(gdbregs, 0, sizeof(gdbregs)); + + gdbregs[KGDB_REG_PC] = context->readPC(); + + // @todo: Currently this is very Alpha specific. + if (AlphaISA::PcPAL(gdbregs[KGDB_REG_PC])) { + for (int i = 0; i < TheISA::NumIntArchRegs; ++i) { + gdbregs[i] = context->readIntReg(AlphaISA::reg_redir[i]); + } + } else { + for (int i = 0; i < TheISA::NumIntArchRegs; ++i) { + gdbregs[i] = context->readIntReg(i); + } + } + +#ifdef KGDB_FP_REGS + for (int i = 0; i < TheISA::NumFloatArchRegs; ++i) { + gdbregs[i + KGDB_REG_F0] = context->readFloatRegBits(i); + } +#endif +} + +/////////////////////////////////////////////////////////// +// RemoteGDB::setregs +// +// Translate the GDB register format into the kernel +// debugger register format. +// +void +RemoteGDB::setregs() +{ + // @todo: Currently this is very Alpha specific. + if (AlphaISA::PcPAL(gdbregs[KGDB_REG_PC])) { + for (int i = 0; i < TheISA::NumIntArchRegs; ++i) { + context->setIntReg(AlphaISA::reg_redir[i], gdbregs[i]); + } + } else { + for (int i = 0; i < TheISA::NumIntArchRegs; ++i) { + context->setIntReg(i, gdbregs[i]); + } + } + +#ifdef KGDB_FP_REGS + for (int i = 0; i < TheISA::NumFloatArchRegs; ++i) { + context->setFloatRegBits(i, gdbregs[i + KGDB_REG_F0]); + } +#endif + context->setPC(gdbregs[KGDB_REG_PC]); +} + +void +RemoteGDB::setTempBreakpoint(TempBreakpoint &bkpt, Addr addr) +{ + DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", addr); + + bkpt.address = addr; + insertHardBreak(addr, 4); +} + +void +RemoteGDB::clearTempBreakpoint(TempBreakpoint &bkpt) +{ + DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", + bkpt.address); + + + removeHardBreak(bkpt.address, 4); + bkpt.address = 0; +} + +void +RemoteGDB::clearSingleStep() +{ + DPRINTF(GDBMisc, "clearSingleStep bt_addr=%#x nt_addr=%#x\n", + takenBkpt.address, notTakenBkpt.address); + + if (takenBkpt.address != 0) + clearTempBreakpoint(takenBkpt); + + if (notTakenBkpt.address != 0) + clearTempBreakpoint(notTakenBkpt); +} + +void +RemoteGDB::setSingleStep() +{ + Addr pc = context->readPC(); + Addr npc, bpc; + bool set_bt = false; + + npc = pc + sizeof(MachInst); + + // User was stopped at pc, e.g. the instruction at pc was not + // executed. + MachInst inst = read<MachInst>(pc); + StaticInstPtr si(inst); + if (si->hasBranchTarget(pc, context, bpc)) { + // Don't bother setting a breakpoint on the taken branch if it + // is the same as the next pc + if (bpc != npc) + set_bt = true; + } + + DPRINTF(GDBMisc, "setSingleStep bt_addr=%#x nt_addr=%#x\n", + takenBkpt.address, notTakenBkpt.address); + + setTempBreakpoint(notTakenBkpt, npc); + + if (set_bt) + setTempBreakpoint(takenBkpt, bpc); +} + +///////////////////////// +// +// + +uint8_t +RemoteGDB::getbyte() +{ + uint8_t b; + ::read(fd, &b, 1); + return b; +} + +void +RemoteGDB::putbyte(uint8_t b) +{ + ::write(fd, &b, 1); +} + +// Send a packet to gdb +void +RemoteGDB::send(const char *bp) +{ + const char *p; + uint8_t csum, c; + + DPRINTF(GDBSend, "send: %s\n", bp); + + do { + p = bp; + putbyte(KGDB_START); + for (csum = 0; (c = *p); p++) { + putbyte(c); + csum += c; + } + putbyte(KGDB_END); + putbyte(i2digit(csum >> 4)); + putbyte(i2digit(csum)); + } while ((c = getbyte() & 0x7f) == KGDB_BADP); +} + +// Receive a packet from gdb +int +RemoteGDB::recv(char *bp, int maxlen) +{ + char *p; + int c, csum; + int len; + + do { + p = bp; + csum = len = 0; + while ((c = getbyte()) != KGDB_START) + ; + + while ((c = getbyte()) != KGDB_END && len < maxlen) { + c &= 0x7f; + csum += c; + *p++ = c; + len++; + } + csum &= 0xff; + *p = '\0'; + + if (len >= maxlen) { + putbyte(KGDB_BADP); + continue; + } + + csum -= digit2i(getbyte()) * 16; + csum -= digit2i(getbyte()); + + if (csum == 0) { + putbyte(KGDB_GOODP); + // Sequence present? + if (bp[2] == ':') { + putbyte(bp[0]); + putbyte(bp[1]); + len -= 3; + bcopy(bp + 3, bp, len); + } + break; + } + putbyte(KGDB_BADP); + } while (1); + + DPRINTF(GDBRecv, "recv: %s: %s\n", gdb_command(*bp), bp); + + return (len); +} + +// Read bytes from kernel address space for debugger. +bool +RemoteGDB::read(Addr vaddr, size_t size, char *data) +{ + static Addr lastaddr = 0; + static size_t lastsize = 0; + + if (vaddr < 10) { + DPRINTF(GDBRead, "read: reading memory location zero!\n"); + vaddr = lastaddr + lastsize; + } + + DPRINTF(GDBRead, "read: addr=%#x, size=%d", vaddr, size); + + VirtualPort *vp = context->getVirtPort(context); + vp->readBlob(vaddr, (uint8_t*)data, size); + context->delVirtPort(vp); + +#if TRACING_ON + if (DTRACE(GDBRead)) { + if (DTRACE(GDBExtra)) { + char buf[1024]; + mem2hex(buf, data, size); + DPRINTFNR(": %s\n", buf); + } else + DPRINTFNR("\n"); + } +#endif + + return true; +} + +// Write bytes to kernel address space for debugger. +bool +RemoteGDB::write(Addr vaddr, size_t size, const char *data) +{ + static Addr lastaddr = 0; + static size_t lastsize = 0; + + if (vaddr < 10) { + DPRINTF(GDBWrite, "write: writing memory location zero!\n"); + vaddr = lastaddr + lastsize; + } + + if (DTRACE(GDBWrite)) { + DPRINTFN("write: addr=%#x, size=%d", vaddr, size); + if (DTRACE(GDBExtra)) { + char buf[1024]; + mem2hex(buf, data, size); + DPRINTFNR(": %s\n", buf); + } else + DPRINTFNR("\n"); + } + VirtualPort *vp = context->getVirtPort(context); + vp->writeBlob(vaddr, (uint8_t*)data, size); + context->delVirtPort(vp); + +#ifdef IMB + alpha_pal_imb(); +#endif + + return true; +} + + +PCEventQueue *RemoteGDB::getPcEventQueue() +{ + return &system->pcEventQueue; +} + + +RemoteGDB::HardBreakpoint::HardBreakpoint(RemoteGDB *_gdb, Addr pc) + : PCEvent(_gdb->getPcEventQueue(), "HardBreakpoint Event", pc), + gdb(_gdb), refcount(0) +{ + DPRINTF(GDBMisc, "creating hardware breakpoint at %#x\n", evpc); +} + +void +RemoteGDB::HardBreakpoint::process(ThreadContext *tc) +{ + DPRINTF(GDBMisc, "handling hardware breakpoint at %#x\n", pc()); + + if (tc == gdb->context) + gdb->trap(ALPHA_KENTRY_INT); +} + +bool +RemoteGDB::insertSoftBreak(Addr addr, size_t len) +{ + if (len != sizeof(MachInst)) + panic("invalid length\n"); + + return insertHardBreak(addr, len); +} + +bool +RemoteGDB::removeSoftBreak(Addr addr, size_t len) +{ + if (len != sizeof(MachInst)) + panic("invalid length\n"); + + return removeHardBreak(addr, len); +} + +bool +RemoteGDB::insertHardBreak(Addr addr, size_t len) +{ + if (len != sizeof(MachInst)) + panic("invalid length\n"); + + DPRINTF(GDBMisc, "inserting hardware breakpoint at %#x\n", addr); + + HardBreakpoint *&bkpt = hardBreakMap[addr]; + if (bkpt == 0) + bkpt = new HardBreakpoint(this, addr); + + bkpt->refcount++; + + return true; +} + +bool +RemoteGDB::removeHardBreak(Addr addr, size_t len) +{ + if (len != sizeof(MachInst)) + panic("invalid length\n"); + + DPRINTF(GDBMisc, "removing hardware breakpoint at %#x\n", addr); + + break_iter_t i = hardBreakMap.find(addr); + if (i == hardBreakMap.end()) + return false; + + HardBreakpoint *hbp = (*i).second; + if (--hbp->refcount == 0) { + delete hbp; + hardBreakMap.erase(i); + } + + return true; +} + +const char * +break_type(char c) +{ + switch(c) { + case '0': return "software breakpoint"; + case '1': return "hardware breakpoint"; + case '2': return "write watchpoint"; + case '3': return "read watchpoint"; + case '4': return "access watchpoint"; + default: return "unknown breakpoint/watchpoint"; + } +} + +// This function does all command processing for interfacing to a +// remote gdb. Note that the error codes are ignored by gdb at +// present, but might eventually become meaningful. (XXX) It might +// makes sense to use POSIX errno values, because that is what the +// gdb/remote.c functions want to return. +bool +RemoteGDB::trap(int type) +{ + uint64_t val; + size_t datalen, len; + char data[KGDB_BUFLEN + 1]; + char buffer[sizeof(gdbregs) * 2 + 256]; + char temp[KGDB_BUFLEN]; + const char *p; + char command, subcmd; + string var; + bool ret; + + if (!attached) + return false; + + DPRINTF(GDBMisc, "trap: PC=%#x NPC=%#x\n", + context->readPC(), context->readNextPC()); + + clearSingleStep(); + + /* + * The first entry to this function is normally through + * a breakpoint trap in kgdb_connect(), in which case we + * must advance past the breakpoint because gdb will not. + * + * On the first entry here, we expect that gdb is not yet + * listening to us, so just enter the interaction loop. + * After the debugger is "active" (connected) it will be + * waiting for a "signaled" message from us. + */ + if (!active) + active = true; + else + // Tell remote host that an exception has occurred. + snprintf((char *)buffer, sizeof(buffer), "S%02x", signal(type)); + send(buffer); + + // Stick frame regs into our reg cache. + getregs(); + + for (;;) { + datalen = recv(data, sizeof(data)); + data[sizeof(data) - 1] = 0; // Sentinel + command = data[0]; + subcmd = 0; + p = data + 1; + switch (command) { + + case KGDB_SIGNAL: + // if this command came from a running gdb, answer it -- + // the other guy has no way of knowing if we're in or out + // of this loop when he issues a "remote-signal". + snprintf((char *)buffer, sizeof(buffer), "S%02x", signal(type)); + send(buffer); + continue; + + case KGDB_REG_R: + if (2 * sizeof(gdbregs) > sizeof(buffer)) + panic("buffer too small"); + + mem2hex(buffer, gdbregs, sizeof(gdbregs)); + send(buffer); + continue; + + case KGDB_REG_W: + p = hex2mem(gdbregs, p, sizeof(gdbregs)); + if (p == NULL || *p != '\0') + send("E01"); + else { + setregs(); + send("OK"); + } + continue; + +#if 0 + case KGDB_SET_REG: + val = hex2i(&p); + if (*p++ != '=') { + send("E01"); + continue; + } + if (val < 0 && val >= KGDB_NUMREGS) { + send("E01"); + continue; + } + + gdbregs[val] = hex2i(&p); + setregs(); + send("OK"); + + continue; +#endif + + case KGDB_MEM_R: + val = hex2i(&p); + if (*p++ != ',') { + send("E02"); + continue; + } + len = hex2i(&p); + if (*p != '\0') { + send("E03"); + continue; + } + if (len > sizeof(buffer)) { + send("E04"); + continue; + } + if (!acc(val, len)) { + send("E05"); + continue; + } + + if (read(val, (size_t)len, (char *)buffer)) { + mem2hex(temp, buffer, len); + send(temp); + } else { + send("E05"); + } + continue; + + case KGDB_MEM_W: + val = hex2i(&p); + if (*p++ != ',') { + send("E06"); + continue; + } + len = hex2i(&p); + if (*p++ != ':') { + send("E07"); + continue; + } + if (len > datalen - (p - data)) { + send("E08"); + continue; + } + p = hex2mem(buffer, p, sizeof(buffer)); + if (p == NULL) { + send("E09"); + continue; + } + if (!acc(val, len)) { + send("E0A"); + continue; + } + if (write(val, (size_t)len, (char *)buffer)) + send("OK"); + else + send("E0B"); + continue; + + case KGDB_SET_THREAD: + subcmd = *p++; + val = hex2i(&p); + if (val == 0) + send("OK"); + else + send("E01"); + continue; + + case KGDB_DETACH: + case KGDB_KILL: + active = false; + clearSingleStep(); + detach(); + goto out; + + case KGDB_ASYNC_CONT: + subcmd = hex2i(&p); + if (*p++ == ';') { + val = hex2i(&p); + context->setPC(val); + context->setNextPC(val + sizeof(MachInst)); + } + clearSingleStep(); + goto out; + + case KGDB_CONT: + if (p - data < datalen) { + val = hex2i(&p); + context->setPC(val); + context->setNextPC(val + sizeof(MachInst)); + } + clearSingleStep(); + goto out; + + case KGDB_ASYNC_STEP: + subcmd = hex2i(&p); + if (*p++ == ';') { + val = hex2i(&p); + context->setPC(val); + context->setNextPC(val + sizeof(MachInst)); + } + setSingleStep(); + goto out; + + case KGDB_STEP: + if (p - data < datalen) { + val = hex2i(&p); + context->setPC(val); + context->setNextPC(val + sizeof(MachInst)); + } + setSingleStep(); + goto out; + + case KGDB_CLR_HW_BKPT: + subcmd = *p++; + if (*p++ != ',') send("E0D"); + val = hex2i(&p); + if (*p++ != ',') send("E0D"); + len = hex2i(&p); + + DPRINTF(GDBMisc, "clear %s, addr=%#x, len=%d\n", + break_type(subcmd), val, len); + + ret = false; + + switch (subcmd) { + case '0': // software breakpoint + ret = removeSoftBreak(val, len); + break; + + case '1': // hardware breakpoint + ret = removeHardBreak(val, len); + break; + + case '2': // write watchpoint + case '3': // read watchpoint + case '4': // access watchpoint + default: // unknown + send(""); + break; + } + + send(ret ? "OK" : "E0C"); + continue; + + case KGDB_SET_HW_BKPT: + subcmd = *p++; + if (*p++ != ',') send("E0D"); + val = hex2i(&p); + if (*p++ != ',') send("E0D"); + len = hex2i(&p); + + DPRINTF(GDBMisc, "set %s, addr=%#x, len=%d\n", + break_type(subcmd), val, len); + + ret = false; + + switch (subcmd) { + case '0': // software breakpoint + ret = insertSoftBreak(val, len); + break; + + case '1': // hardware breakpoint + ret = insertHardBreak(val, len); + break; + + case '2': // write watchpoint + case '3': // read watchpoint + case '4': // access watchpoint + default: // unknown + send(""); + break; + } + + send(ret ? "OK" : "E0C"); + continue; + + case KGDB_QUERY_VAR: + var = string(p, datalen - 1); + if (var == "C") + send("QC0"); + else + send(""); + continue; + + case KGDB_SET_BAUD: + case KGDB_SET_BREAK: + case KGDB_DEBUG: + case KGDB_CYCLE_STEP: + case KGDB_SIG_CYCLE_STEP: + case KGDB_READ_REG: + case KGDB_SET_VAR: + case KGDB_RESET: + case KGDB_THREAD_ALIVE: + case KGDB_TARGET_EXIT: + case KGDB_BINARY_DLOAD: + // Unsupported command + DPRINTF(GDBMisc, "Unsupported command: %s\n", + gdb_command(command)); + DDUMP(GDBMisc, (uint8_t *)data, datalen); + send(""); + continue; + + default: + // Unknown command. + DPRINTF(GDBMisc, "Unknown command: %c(%#x)\n", + command, command); + send(""); + continue; + + + } + } + + out: + return true; +} + +// Convert a hex digit into an integer. +// This returns -1 if the argument passed is no valid hex digit. +int +digit2i(char c) +{ + if (c >= '0' && c <= '9') + return (c - '0'); + else if (c >= 'a' && c <= 'f') + return (c - 'a' + 10); + else if (c >= 'A' && c <= 'F') + + return (c - 'A' + 10); + else + return (-1); +} + +// Convert the low 4 bits of an integer into an hex digit. +char +i2digit(int n) +{ + return ("0123456789abcdef"[n & 0x0f]); +} + +// Convert a byte array into an hex string. +void +mem2hex(void *vdst, const void *vsrc, int len) +{ + char *dst = (char *)vdst; + const char *src = (const char *)vsrc; + + while (len--) { + *dst++ = i2digit(*src >> 4); + *dst++ = i2digit(*src++); + } + *dst = '\0'; +} + +// Convert an hex string into a byte array. +// This returns a pointer to the character following the last valid +// hex digit. If the string ends in the middle of a byte, NULL is +// returned. +const char * +hex2mem(void *vdst, const char *src, int maxlen) +{ + char *dst = (char *)vdst; + int msb, lsb; + + while (*src && maxlen--) { + msb = digit2i(*src++); + if (msb < 0) + return (src - 1); + lsb = digit2i(*src++); + if (lsb < 0) + return (NULL); + *dst++ = (msb << 4) | lsb; + } + return (src); +} + +// Convert an hex string into an integer. +// This returns a pointer to the character following the last valid +// hex digit. +Addr +hex2i(const char **srcp) +{ + const char *src = *srcp; + Addr r = 0; + int nibble; + + while ((nibble = digit2i(*src)) >= 0) { + r *= 16; + r += nibble; + src++; + } + *srcp = src; + return (r); +} + diff --git a/src/base/remote_gdb.hh b/src/base/remote_gdb.hh new file mode 100644 index 000000000..90b53e53f --- /dev/null +++ b/src/base/remote_gdb.hh @@ -0,0 +1,211 @@ +/* + * 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 + */ + +#ifndef __REMOTE_GDB_HH__ +#define __REMOTE_GDB_HH__ + +#include <map> + +#include "base/kgdb.h" +#include "cpu/pc_event.hh" +#include "base/pollevent.hh" +#include "base/socket.hh" + +class System; +class ThreadContext; +class PhysicalMemory; + +class GDBListener; +class RemoteGDB +{ + protected: + typedef TheISA::MachInst MachInst; + private: + friend void debugger(); + friend class GDBListener; + + protected: + class Event : public PollEvent + { + protected: + RemoteGDB *gdb; + + public: + Event(RemoteGDB *g, int fd, int e); + void process(int revent); + }; + + friend class Event; + Event *event; + GDBListener *listener; + int number; + + protected: + int fd; + uint64_t gdbregs[KGDB_NUMREGS]; + + protected: +#ifdef notyet + label_t recover; +#endif + bool active; + bool attached; + + System *system; + PhysicalMemory *pmem; + ThreadContext *context; + + protected: + uint8_t getbyte(); + void putbyte(uint8_t b); + + int recv(char *data, int len); + void send(const char *data); + + protected: + // Machine memory + bool read(Addr addr, size_t size, char *data); + bool write(Addr addr, size_t size, const char *data); + + template <class T> T read(Addr addr); + template <class T> void write(Addr addr, T data); + + public: + RemoteGDB(System *system, ThreadContext *context); + ~RemoteGDB(); + + void replaceThreadContext(ThreadContext *tc) { context = tc; } + + void attach(int fd); + void detach(); + bool isattached(); + + bool acc(Addr addr, size_t len); + static int signal(int type); + bool trap(int type); + + protected: + void getregs(); + void setregs(); + + void clearSingleStep(); + void setSingleStep(); + + PCEventQueue *getPcEventQueue(); + + protected: + class HardBreakpoint : public PCEvent + { + private: + RemoteGDB *gdb; + + public: + int refcount; + + public: + HardBreakpoint(RemoteGDB *_gdb, Addr addr); + std::string name() { return gdb->name() + ".hwbkpt"; } + + virtual void process(ThreadContext *tc); + }; + friend class HardBreakpoint; + + typedef std::map<Addr, HardBreakpoint *> break_map_t; + typedef break_map_t::iterator break_iter_t; + break_map_t hardBreakMap; + + bool insertSoftBreak(Addr addr, size_t len); + bool removeSoftBreak(Addr addr, size_t len); + bool insertHardBreak(Addr addr, size_t len); + bool removeHardBreak(Addr addr, size_t len); + + protected: + struct TempBreakpoint { + Addr address; // set here + MachInst bkpt_inst; // saved instruction at bkpt + int init_count; // number of times to skip bkpt + int count; // current count + }; + + TempBreakpoint notTakenBkpt; + TempBreakpoint takenBkpt; + + void clearTempBreakpoint(TempBreakpoint &bkpt); + void setTempBreakpoint(TempBreakpoint &bkpt, Addr addr); + + public: + std::string name(); +}; + +template <class T> +inline T +RemoteGDB::read(Addr addr) +{ + T temp; + read(addr, sizeof(T), (char *)&temp); + return temp; +} + +template <class T> +inline void +RemoteGDB::write(Addr addr, T data) +{ write(addr, sizeof(T), (const char *)&data); } + +class GDBListener +{ + protected: + class Event : public PollEvent + { + protected: + GDBListener *listener; + + public: + Event(GDBListener *l, int fd, int e); + void process(int revent); + }; + + friend class Event; + Event *event; + + protected: + ListenSocket listener; + RemoteGDB *gdb; + int port; + + public: + GDBListener(RemoteGDB *g, int p); + ~GDBListener(); + + void accept(); + void listen(); + std::string name(); +}; + +#endif /* __REMOTE_GDB_H__ */ diff --git a/src/base/res_list.hh b/src/base/res_list.hh new file mode 100644 index 000000000..442280e15 --- /dev/null +++ b/src/base/res_list.hh @@ -0,0 +1,758 @@ +/* + * 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 Raasch + * Nathan Binkert + */ + +#ifndef __RES_LIST_HH__ +#define __RES_LIST_HH__ + +#include "base/cprintf.hh" +#include <assert.h> + +#define DEBUG_REMOVE 0 + +#define DEBUG_MEMORY 0 +//#define DEBUG_MEMORY DEBUG + +class res_list_base +{ +#if DEBUG_MEMORY + protected: + static long long allocated_elements; + static long long allocated_lists; + + public: + long long get_elements(void) { + return allocated_elements; + } + long long get_lists(void) { + return allocated_lists; + } + +#endif +}; + +#if DEBUG_MEMORY +extern void what_the(void); +#endif + +template<class T> +class res_list : public res_list_base +{ + public: + class iterator; + + class res_element + { + res_element *next; + res_element *prev; + T *data; + bool allocate_data; + + public: + // always adds to the END of the list + res_element(res_element *_prev, bool allocate); + ~res_element(); + void dump(void); + + friend class res_list<T>; + friend class res_list<T>::iterator; + }; + + class iterator + { + private: + res_element *p; + + friend class res_list<T>; + + public: + // Constructors + iterator(res_element *q) : p(q) {} + iterator(void) { p=0; }; + + void dump(void); + T* data_ptr(void); + res_element *res_el_ptr(void) { return p;} + void point_to(T &d) { p->data = &d; } + + iterator next(void) { return iterator(p->next); } + iterator prev(void) { return iterator(p->prev); } + bool operator== (iterator x) { return (x.p == this->p); } + bool operator != (iterator x) { return (x.p != this->p); } + T &operator * (void) { return *(p->data); } + T* operator -> (void) { return p->data; } + bool isnull(void) { return (p==0); } + bool notnull(void) { return (p!=0); } + }; + + private: + iterator unused_elements; + iterator head_ptr; + iterator tail_ptr; + + unsigned base_elements; + unsigned extra_elements; + unsigned active_elements; + bool allocate_storage; + unsigned build_size; + + int remove_count; + + // + // Allocate new elements, and assign them to the unused_elements + // list. + // + unsigned allocate_elements(unsigned num, bool allocate_storage); + + public: + // + // List Constructor + // + res_list(unsigned size, bool alloc_storage = false, + unsigned build_sz = 5); + + // + // List Destructor + // + ~res_list(); + + iterator head(void) {return head_ptr;}; + iterator tail(void) {return tail_ptr;}; + + unsigned num_free(void) { return size() - count(); } + unsigned size(void) { return base_elements + extra_elements; } + unsigned count(void) { return active_elements; } + bool empty(void) { return count() == 0; } + bool full(void); + + // + // Insert with data copy + // + iterator insert_after(iterator prev, T *d); + iterator insert_after(iterator prev, T &d); + iterator insert_before(iterator prev, T *d); + iterator insert_before(iterator prev, T &d); + + // + // Insert new list element (no data copy) + // + iterator insert_after(iterator prev); + iterator insert_before(iterator prev); + + iterator add_tail(T *d) { return insert_after(tail_ptr, d); } + iterator add_tail(T &d) { return insert_after(tail_ptr, d); } + iterator add_tail(void) { return insert_after(tail_ptr); } + iterator add_head(T *d) { return insert_before(head_ptr, d); } + iterator add_head(T &d) { return insert_before(head_ptr, d); } + iterator add_head(void) { return insert_before(head_ptr); } + + iterator remove(iterator q); + iterator remove_head(void) {return remove(head_ptr);} + iterator remove_tail(void) {return remove(tail_ptr);} + + bool in_list(iterator j); + void free_extras(void); + void clear(void); + void dump(void); + void raw_dump(void); +}; + +template <class T> +inline +res_list<T>::res_element::res_element(res_element *_prev, bool allocate) +{ + allocate_data = allocate; + prev = _prev; + next = 0; + + if (prev) + prev->next = this; + + if (allocate) + data = new T; + else + data = 0; + +#if DEBUG_MEMORY + ++allocated_elements; +#endif +} + +template <class T> +inline +res_list<T>::res_element::~res_element(void) +{ + if (prev) + prev->next = next; + + if (next) + next->prev = prev; + + if (allocate_data) + delete data; + +#if DEBUG_MEMORY + --allocated_elements; +#endif +} + +template <class T> +inline void +res_list<T>::res_element::dump(void) +{ + cprintf(" prev = %#x\n", prev); + cprintf(" next = %#x\n", next); + cprintf(" data = %#x\n", data); +} + +template <class T> +inline void +res_list<T>::iterator::dump(void) +{ + if (p && p->data) + p->data->dump(); + else { + if (!p) + cprintf(" Null Pointer\n"); + else + cprintf(" Null 'data' Pointer\n"); + } +} + +template <class T> +inline T * +res_list<T>::iterator::data_ptr(void) +{ + if (p) + return p->data; + else + return 0; +} + + +// +// Allocate new elements, and assign them to the unused_elements +// list. +// +template <class T> +inline unsigned +res_list<T>::allocate_elements(unsigned num, bool allocate_storage) +{ + res_element *pnew, *plast = 0, *pfirst=0; + + for (int i=0; i<num; ++i) { + pnew = new res_element(plast, allocate_storage); + if (i==0) + pfirst = pnew; + plast = pnew; + } + + if (unused_elements.notnull()) { + // Add these new elements to the front of the list + plast->next = unused_elements.res_el_ptr(); + unused_elements.res_el_ptr()->prev = plast; + } + + unused_elements = iterator(pfirst); + + return num; +} + +template <class T> +inline +res_list<T>::res_list(unsigned size, bool alloc_storage, unsigned build_sz) +{ +#if DEBUG_MEMORY + ++allocated_lists; +#endif + extra_elements = 0; + active_elements = 0; + build_size = build_sz; + allocate_storage = alloc_storage; + remove_count = 0; + + // Create the new elements + base_elements = allocate_elements(size, alloc_storage); + + // The list of active elements + head_ptr = iterator(0); + tail_ptr = iterator(0); +} + +// +// List Destructor +// +template <class T> +inline +res_list<T>::~res_list(void) +{ + iterator n; + +#if DEBUG_MEMORY + --allocated_lists; +#endif + + // put everything into the unused list + clear(); + + // rudely delete all the res_elements + for (iterator p = unused_elements; + p.notnull(); + p = n) { + + n = p.next(); + + // delete the res_element + // (it will take care of deleting the data) + delete p.res_el_ptr(); + } +} + +template <class T> +inline bool +res_list<T>::full(void) +{ + if (build_size) + return false; + else + return unused_elements.isnull(); +} + +// +// Insert with data copy +// +template <class T> +inline typename res_list<T>::iterator +res_list<T>::insert_after(iterator prev, T *d) +{ + iterator p; + + if (!allocate_storage) + this->panic("Can't copy data... not allocating storage"); + + p = insert_after(prev); + if (p.notnull()) + *p = *d; + + return p; +} + + +template <class T> +inline typename res_list<T>::iterator +res_list<T>::insert_after(iterator prev, T &d) +{ + iterator p; + + p = insert_after(prev); + if (p.notnull()) { + + if (allocate_storage) { + // if we allocate storage, then copy the contents of the + // specified object to our object + *p = d; + } + else { + // if we don't allocate storage, then we just want to + // point to the specified object + p.point_to(d); + } + } + + return p; +} + + +template <class T> +inline typename res_list<T>::iterator +res_list<T>::insert_after(iterator prev) +{ + +#if DEBUG_MEMORY + if (active_elements > 2*base_elements) { + what_the(); + } +#endif + + // If we have no unused elements, make some more + if (unused_elements.isnull()) { + + if (build_size == 0) { + return 0; // No space left, and can't allocate more.... + } + + extra_elements += allocate_elements(build_size, allocate_storage); + } + + // grab the first unused element + res_element *p = unused_elements.res_el_ptr(); + + unused_elements = unused_elements.next(); + + ++active_elements; + + // Insert the new element + if (head_ptr.isnull()) { + // + // Special case #1: Empty List + // + head_ptr = p; + tail_ptr = p; + p->prev = 0; + p->next = 0; + } + else if (prev.isnull()) { + // + // Special case #2: Insert at head + // + + // our next ptr points to old head element + p->next = head_ptr.res_el_ptr(); + + // our element becomes the new head element + head_ptr = p; + + // no previous element for the head + p->prev = 0; + + // old head element points back to this element + p->next->prev = p; + } + else if (prev.next().isnull()) { + // + // Special case #3 Insert at tail + // + + // our prev pointer points to old tail element + p->prev = tail_ptr.res_el_ptr(); + + // our element becomes the new tail + tail_ptr = p; + + // no next element for the tail + p->next = 0; + + // old tail element point to this element + p->prev->next = p; + } + else { + // + // Normal insertion (after prev) + // + p->prev = prev.res_el_ptr(); + p->next = prev.next().res_el_ptr(); + + prev.res_el_ptr()->next = p; + p->next->prev = p; + } + + return iterator(p); +} + +template <class T> +inline typename res_list<T>::iterator +res_list<T>::insert_before(iterator next, T &d) +{ + iterator p; + + p = insert_before(next); + if (p.notnull()) { + + if (allocate_storage) { + // if we allocate storage, then copy the contents of the + // specified object to our object + *p = d; + } + else { + // if we don't allocate storage, then we just want to + // point to the specified object + p.point_to(d); + } + } + + return p; +} + + +template <class T> +inline typename res_list<T>::iterator +res_list<T>::insert_before(iterator next) +{ + +#if DEBUG_MEMORY + if (active_elements > 2*base_elements) { + what_the(); + } +#endif + + // If we have no unused elements, make some more + if (unused_elements.isnull()) { + + if (build_size == 0) { + return 0; // No space left, and can't allocate more.... + } + + extra_elements += allocate_elements(build_size, allocate_storage); + } + + // grab the first unused element + res_element *p = unused_elements.res_el_ptr(); + + unused_elements = unused_elements.next(); + + ++active_elements; + + // Insert the new element + if (head_ptr.isnull()) { + // + // Special case #1: Empty List + // + head_ptr = p; + tail_ptr = p; + p->prev = 0; + p->next = 0; + } + else if (next.isnull()) { + // + // Special case #2 Insert at tail + // + + // our prev pointer points to old tail element + p->prev = tail_ptr.res_el_ptr(); + + // our element becomes the new tail + tail_ptr = p; + + // no next element for the tail + p->next = 0; + + // old tail element point to this element + p->prev->next = p; + } + else if (next.prev().isnull()) { + // + // Special case #3: Insert at head + // + + // our next ptr points to old head element + p->next = head_ptr.res_el_ptr(); + + // our element becomes the new head element + head_ptr = p; + + // no previous element for the head + p->prev = 0; + + // old head element points back to this element + p->next->prev = p; + } + else { + // + // Normal insertion (before next) + // + p->next = next.res_el_ptr(); + p->prev = next.prev().res_el_ptr(); + + next.res_el_ptr()->prev = p; + p->prev->next = p; + } + + return iterator(p); +} + + +template <class T> +inline typename res_list<T>::iterator +res_list<T>::remove(iterator q) +{ + res_element *p = q.res_el_ptr(); + iterator n = 0; + + // Handle the special cases + if (active_elements == 1) { // This is the only element + head_ptr = 0; + tail_ptr = 0; + } + else if (q == head_ptr) { // This is the head element + head_ptr = q.next(); + head_ptr.res_el_ptr()->prev = 0; + + n = head_ptr; + } + else if (q == tail_ptr) { // This is the tail element + tail_ptr = q.prev(); + tail_ptr.res_el_ptr()->next = 0; + } + else { // This is between two elements + p->prev->next = p->next; + p->next->prev = p->prev; + + // Get the "next" element for return + n = p->next; + } + + --active_elements; + + // Put this element back onto the unused list + p->next = unused_elements.res_el_ptr(); + p->prev = 0; + if (p->next) { // NULL if unused list is empty + p->next->prev = p; + } + + if (!allocate_storage) { + p->data = 0; + } + + unused_elements = q; + + // A little "garbage collection" + if (++remove_count > 10) { + // free_extras(); + remove_count = 0; + } + +#if DEBUG_REMOVE + unsigned unused_count = 0; + for (iterator i=unused_elements; + i.notnull(); + i = i.next()) { + + ++unused_count; + } + + assert((active_elements+unused_count) == (base_elements+extra_elements)); +#endif + + return iterator(n); +} + + +template <class T> +inline bool +res_list<T>::in_list(iterator j) +{ + iterator i; + + for (i=head(); i.notnull(); i=i.next()) { + if (j.res_el_ptr() == i.res_el_ptr()) { + return true; + } + } + + return false; +} + +template <class T> +inline void +res_list<T>::free_extras(void) +{ + unsigned num_unused = base_elements + extra_elements - active_elements; + unsigned to_free = extra_elements; + res_element *p; + + + if (extra_elements != 0) { + // + // Free min(extra_elements, # unused elements) + // + if (extra_elements > num_unused) { + to_free = num_unused; + } + + p = unused_elements.res_el_ptr(); + for (int i=0; i<to_free; ++i) { + res_element *q = p->next; + + delete p; + + p = q; + } + + // update the unused element pointer to point to the first + // element that wasn't deleted. + unused_elements = iterator(p); + + // Update the number of extra elements + extra_elements -= to_free; + } + + return; +} + + +template <class T> +inline void +res_list<T>::clear(void) +{ + iterator i,n; + + for (i=head_ptr; i.notnull(); i=n) { + n = i.next(); + remove(i); + } + + free_extras(); +} + +template <class T> +inline void +res_list<T>::dump(void) +{ + for (iterator i=head(); !i.isnull(); i=i.next()) + i->dump(); +} + +template <class T> +inline void +res_list<T>::raw_dump(void) +{ + int j = 0; + res_element *p; + for (iterator i=head(); !i.isnull(); i=i.next()) { + cprintf("Element %d:\n", j); + + if (i.notnull()) { + p = i.res_el_ptr(); + cprintf(" points to res_element @ %#x\n", p); + p->dump(); + cprintf(" Data Element:\n"); + i->dump(); + } + else { + cprintf(" NULL iterator!\n"); + } + + ++j; + } + +} + +#endif // __RES_LIST_HH__ diff --git a/src/base/sat_counter.cc b/src/base/sat_counter.cc new file mode 100644 index 000000000..8980275eb --- /dev/null +++ b/src/base/sat_counter.cc @@ -0,0 +1,271 @@ +/* + * Copyright (c) 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 Reinhardt + * Lisa Hsu + */ + +#include <sstream> + +#include "base/sat_counter.hh" +#include "base/statistics.hh" +#include "sim/stats.hh" + + +using namespace std; + + +SaturatingCounterPred::SaturatingCounterPred(string p_name, + string z_name, + string o_name, + unsigned _index_bits, + unsigned _counter_bits, + unsigned _zero_change, + unsigned _one_change, + unsigned _thresh, + unsigned _init_value) +{ + pred_name = p_name; + zero_name = z_name; + one_name = o_name; + + index_bits = _index_bits; + counter_bits = _counter_bits; + zero_change = _zero_change; + one_change = _one_change; + thresh = _thresh; + init_value = _init_value; + + max_index = (1 << index_bits) - 1; + max_value = (1 << counter_bits) - 1; + + table = new unsigned[max_index + 1]; + + // Initialize with the right parameters & clear the counter + for (int i = 0; i <= max_index; ++i) + table[i] = init_value; +} + +void SaturatingCounterPred::regStats() +{ + using namespace Stats; + stringstream name, description; + + // + // Number of predictions + // + name << pred_name << ":" << zero_name << ":preds"; + description << "number of predictions of " << zero_name; + predicted_zero + .name(name.str()) + .desc(description.str()) + ; + description.str(""); + name.str(""); + + name << pred_name << ":" << one_name << ":preds"; + description << "number of predictions of " << one_name; + predicted_one + .name(name.str()) + .desc(description.str()) + ; + description.str(""); + name.str(""); + + // + // Count the number of correct predictions + // + name << pred_name << ":" << zero_name << ":corr_preds"; + description << "number of correct " << zero_name << " preds"; + correct_pred_zero + .name(name.str()) + .desc(description.str()) + ; + description.str(""); + name.str(""); + + name << pred_name << ":" << one_name << ":corr_preds"; + description << "number of correct " << one_name << " preds"; + correct_pred_one + .name(name.str()) + .desc(description.str()) + ; + description.str(""); + name.str(""); + + // + // Number of predictor updates + // + name << pred_name << ":" << zero_name << ":updates"; + description << "number of actual " << zero_name << "s"; + record_zero + .name(name.str()) + .desc(description.str()) + ; + description.str(""); + name.str(""); + + name << pred_name << ":" << one_name << ":updates"; + description << "number of actual " << one_name << "s"; + record_one + .name(name.str()) + .desc(description.str()) + ; + description.str(""); + name.str(""); +} + +void SaturatingCounterPred::regFormulas() +{ + using namespace Stats; + stringstream name, description; + + // + // Number of predictions + // + name << pred_name << ":predictions"; + preds_total + .name(name.str()) + .desc("total number of predictions made") + ; + preds_total = predicted_zero + predicted_one; + name.str(""); + + // + // Fraction of all predictions that are one or zero + // + name << pred_name << ":" << zero_name << ":pred_frac"; + description << "fraction of all preds that were " << zero_name; + pred_frac_zero + .name(name.str()) + .desc(description.str()) + ; + pred_frac_zero = 100 * predicted_zero / preds_total; + description.str(""); + name.str(""); + + name << pred_name << ":" << one_name << ":pred_frac"; + description << "fraction of all preds that were " << one_name; + pred_frac_one + .name(name.str()) + .desc(description.str()) + ; + pred_frac_one = 100 * predicted_one / preds_total; + description.str(""); + name.str(""); + + + // + // Count the number of correct predictions + // + name << pred_name << ":correct_preds"; + correct_total + .name(name.str()) + .desc("total correct predictions made") + ; + correct_total = correct_pred_one + correct_pred_zero; + name.str(""); + + // + // Number of predictor updates + // + name << pred_name << ":updates"; + updates_total + .name(name.str()) + .desc("total number of updates") + ; + updates_total = record_zero + record_one; + name.str(""); + + // + // Prediction accuracy rates + // + name << pred_name << ":pred_rate"; + pred_rate + .name(name.str()) + .desc("correct fraction of all preds") + ; + pred_rate = correct_total / updates_total; + name.str(""); + + name << pred_name << ":" << zero_name << ":pred_rate"; + description << "fraction of " << zero_name << " preds that were correct"; + frac_correct_zero + .name(name.str()) + .desc(description.str()) + ; + frac_correct_zero = 100 * correct_pred_zero / + (correct_pred_zero + record_one - correct_pred_one); + description.str(""); + name.str(""); + + name << pred_name << ":" << one_name << ":pred_rate"; + description << "fraction of " << one_name << " preds that were correct"; + frac_correct_one + .name(name.str()) + .desc(description.str()) + ; + frac_correct_one = 100 * correct_pred_one / + (correct_pred_one + record_zero - correct_pred_zero); + description.str(""); + name.str(""); + + // + // Coverage + // + name << pred_name << ":" << zero_name << ":coverage"; + description << "fraction of " << zero_name + << "s that were predicted correctly"; + coverage_zero + .name(name.str()) + .desc(description.str()) + ; + coverage_zero = 100 * correct_pred_zero / record_zero; + description.str(""); + name.str(""); + + name << pred_name << ":" << one_name << ":coverage"; + description << "fraction of " << one_name + << "s that were predicted correctly"; + coverage_one + .name(name.str()) + .desc(description.str()) + ; + coverage_one = 100 * correct_pred_one / record_one; + description.str(""); + name.str(""); +} + + + + + + + + + + diff --git a/src/base/sat_counter.hh b/src/base/sat_counter.hh new file mode 100644 index 000000000..79de11156 --- /dev/null +++ b/src/base/sat_counter.hh @@ -0,0 +1,193 @@ +/* + * 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 Raasch + * Steve Reinhardt + */ + +#ifndef __SAT_COUNTER_HH__ +#define __SAT_COUNTER_HH__ + +#include <string> + +#include "base/predictor.hh" + +#include "base/statistics.hh" +#include "sim/stats.hh" + +// +// +// A simple saturating counter predictor +// +// +class SaturatingCounterPred : public GenericPredictor +{ + private: + std::string pred_name; + std::string zero_name; + std::string one_name; + + unsigned index_bits; + unsigned counter_bits; + unsigned zero_change; + unsigned one_change; + unsigned thresh; + unsigned init_value; + + unsigned max_value; // maximum counter value + + unsigned long max_index; // also the index mask value + unsigned *table; + + // Statistics + Stats::Scalar<> predicted_one; // Total predictions of one, preds_one + Stats::Scalar<> predicted_zero; // Total predictions of zero, preds_zero + Stats::Scalar<> correct_pred_one; // Total correct predictions of one, correct_one + Stats::Scalar<> correct_pred_zero; // Total correct predictions of zero, correct_zero + + Stats::Scalar<> record_zero; //updates_zero + Stats::Scalar<> record_one; //updates_one + + Stats::Formula preds_total; + Stats::Formula pred_frac_zero; + Stats::Formula pred_frac_one; + Stats::Formula correct_total; + Stats::Formula updates_total; + Stats::Formula pred_rate; + Stats::Formula frac_correct_zero; + Stats::Formula frac_correct_one; + Stats::Formula coverage_zero; + Stats::Formula coverage_one; + + private: + bool pred_one(unsigned &counter) { return counter > thresh; } + bool pred_zero(unsigned &counter) { return counter <= thresh; } + + void update_one(unsigned &counter) { + + if (one_change) + counter += one_change; + else + counter = 0; + + // check for wrap + if (counter > max_value) + counter = max_value; + } + + void update_zero(unsigned &counter) { + if (zero_change) { + // check for wrap + if (counter < zero_change) + counter = 0; + else + counter -= zero_change; + } else + counter = 0; + } + + + public: + + SaturatingCounterPred(std::string p_name, + std::string z_name, std::string o_name, + unsigned _index_bits, unsigned _counter_bits = 2, + unsigned _zero_change = 1, unsigned _one_change = 1, + unsigned _thresh = 1, unsigned _init_value = 0); + + void clear() { + for (int i = 0; i <= max_index; ++i) + table[i] = init_value; + } + + // Record the ACTUAL result... and indicate whether the prediction + // corresponding to this event was correct + void record(unsigned long _index, unsigned _val, unsigned _predicted, + unsigned _pdata) + { + record(_index, _val, _predicted); + } + + void record(unsigned long _index, unsigned _val, unsigned _predicted) { + unsigned long index = _index & max_index; + + if (_val) { + update_one(table[index]); + ++record_one; + + if (_predicted) + ++correct_pred_one; + } else { + update_zero(table[index]); + ++record_zero; + + if (!_predicted) + ++correct_pred_zero; + } + } + + unsigned value(unsigned long _index) { + unsigned long index = _index & max_index; + + return table[index]; + } + + + unsigned predict(unsigned long _index, unsigned &pdata) { + return predict(_index); + } + + unsigned predict(unsigned long _index) { + unsigned long index = _index & max_index; + + if (pred_one(table[index])) { + ++predicted_one; + return 1; + } + + ++predicted_zero; + return 0; + } + + // No internal state is changed here + unsigned peek(unsigned long _index) { + unsigned long index = _index & max_index; + + if (pred_one(table[index])) + return 1; + + return 0; + } + + + //======================================================= + void regStats(); + void regFormulas(); +}; + + +#endif // __SAT_COUNTER_HH__ diff --git a/src/base/sched_list.hh b/src/base/sched_list.hh new file mode 100644 index 000000000..56ee2f8ec --- /dev/null +++ b/src/base/sched_list.hh @@ -0,0 +1,180 @@ +/* + * 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: Steve Raasch + */ + +#ifndef SCHED_LIST_HH +#define SCHED_LIST_HH + +#include <list> +#include "base/intmath.hh" +#include "base/misc.hh" + + +// Any types you use this class for must be covered here... +namespace { + void ClearEntry(int &i) { i = 0; }; + void ClearEntry(unsigned &i) { i = 0; }; + void ClearEntry(double &i) { i = 0; }; + template <class T> void ClearEntry(std::list<T> &l) { l.clear(); }; +}; + + +// +// this is a special list type that allows the user to insert elements at a +// specified positive offset from the "current" element, but only allow them +// be extracted from the "current" element +// + + +template <class T> +class SchedList +{ + T *data_array; + unsigned position; + unsigned size; + unsigned mask; + + public: + SchedList(unsigned size); + SchedList(void); + + void init(unsigned size); + + T &operator[](unsigned offset); + + void advance(void); + + void clear(void); +}; + + + +// +// Constructor +// +template<class T> +SchedList<T>::SchedList(unsigned _size) +{ + size = _size; + + // size must be a power of two + if (!isPowerOf2(size)) { + panic("SchedList: size must be a power of two"); + } + + if (size < 2) { + panic("SchedList: you don't want a list that small"); + } + + // calculate the bit mask for the modulo operation + mask = size - 1; + + data_array = new T[size]; + + if (!data_array) { + panic("SchedList: could not allocate memory"); + } + + clear(); +} + +template<class T> +SchedList<T>::SchedList(void) +{ + data_array = 0; + size = 0; +} + + +template<class T> void +SchedList<T>::init(unsigned _size) +{ + size = _size; + + if (!data_array) { + // size must be a power of two + if (size & (size-1)) { + panic("SchedList: size must be a power of two"); + } + + if (size < 2) { + panic("SchedList: you don't want a list that small"); + } + + // calculate the bit mask for the modulo operation + mask = size - 1; + + data_array = new T[size]; + + if (!data_array) { + panic("SchedList: could not allocate memory"); + } + + clear(); + } +} + + +template<class T> void +SchedList<T>::advance(void) +{ + ClearEntry(data_array[position]); + + // position = (++position % size); + position = ++position & mask; +} + + +template<class T> void +SchedList<T>::clear(void) +{ + for (unsigned i=0; i<size; ++i) { + ClearEntry(data_array[i]); + } + + position = 0; +} + + +template<class T> T& +SchedList<T>::operator[](unsigned offset) +{ + if (offset >= size) { + panic("SchedList: can't access element beyond current pointer"); + } + + // unsigned p = (position + offset) % size; + unsigned p = (position + offset) & mask; + + return data_array[p]; +} + + + +#endif diff --git a/src/base/socket.cc b/src/base/socket.cc new file mode 100644 index 000000000..adcc48735 --- /dev/null +++ b/src/base/socket.cc @@ -0,0 +1,113 @@ +/* + * 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 + */ + +#include <sys/types.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <netinet/tcp.h> + +#include <errno.h> +#include <unistd.h> + +#include "sim/host.hh" +#include "base/misc.hh" +#include "base/socket.hh" + +using namespace std; + +//////////////////////////////////////////////////////////////////////// +// +// + +ListenSocket::ListenSocket() + : listening(false), fd(-1) +{} + +ListenSocket::~ListenSocket() +{ + if (fd != -1) + close(fd); +} + +// Create a socket and configure it for listening +bool +ListenSocket::listen(int port, bool reuse) +{ + if (listening) + panic("Socket already listening!"); + + fd = ::socket(PF_INET, SOCK_STREAM, 0); + if (fd < 0) + panic("Can't create socket:%s !", strerror(errno)); + + if (reuse) { + int i = 1; + if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&i, + sizeof(i)) < 0) + panic("ListenSocket(listen): setsockopt() SO_REUSEADDR failed!"); + } + + struct sockaddr_in sockaddr; + sockaddr.sin_family = PF_INET; + sockaddr.sin_addr.s_addr = INADDR_ANY; + + sockaddr.sin_port = htons(port); + int ret = ::bind(fd, (struct sockaddr *)&sockaddr, sizeof (sockaddr)); + if (ret != 0) { + if (ret == -1 && errno != EADDRINUSE) + panic("ListenSocket(listen): bind() failed!"); + return false; + } + + if (::listen(fd, 1) == -1) + panic("ListenSocket(listen): listen() failed!"); + + listening = true; + + return true; +} + + +// Open a connection. Accept will block, so if you don't want it to, +// make sure a connection is ready before you call accept. +int +ListenSocket::accept(bool nodelay) +{ + struct sockaddr_in sockaddr; + socklen_t slen = sizeof (sockaddr); + int sfd = ::accept(fd, (struct sockaddr *)&sockaddr, &slen); + if (sfd != -1 && nodelay) { + int i = 1; + ::setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (char *)&i, sizeof(i)); + } + + return sfd; +} diff --git a/src/base/socket.hh b/src/base/socket.hh new file mode 100644 index 000000000..8e55eae72 --- /dev/null +++ b/src/base/socket.hh @@ -0,0 +1,51 @@ +/* + * 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 + */ + +#ifndef __SOCKET_HH__ +#define __SOCKET_HH__ + +class ListenSocket +{ + protected: + bool listening; + int fd; + + public: + ListenSocket(); + virtual ~ListenSocket(); + + virtual int accept(bool nodelay = false); + virtual bool listen(int port, bool reuse = true); + + int getfd() const { return fd; } + bool islistening() const { return listening; } +}; + +#endif //__SOCKET_HH__ diff --git a/src/base/statistics.cc b/src/base/statistics.cc new file mode 100644 index 000000000..2acef83c5 --- /dev/null +++ b/src/base/statistics.cc @@ -0,0 +1,292 @@ +/* + * Copyright (c) 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: Nathan Binkert + */ + +#include <iomanip> +#include <fstream> +#include <list> +#include <map> +#include <string> + +#include "base/callback.hh" +#include "base/cprintf.hh" +#include "base/hostinfo.hh" +#include "base/misc.hh" +#include "base/statistics.hh" +#include "base/str.hh" +#include "base/time.hh" +#include "base/trace.hh" +#include "base/stats/statdb.hh" + +using namespace std; + +namespace Stats { + +StatData * +DataAccess::find() const +{ + return Database::find(const_cast<void *>((const void *)this)); +} + +const StatData * +getStatData(const void *stat) +{ + return Database::find(const_cast<void *>(stat)); +} + +void +DataAccess::map(StatData *data) +{ + Database::regStat(this, data); +} + +StatData * +DataAccess::statData() +{ + StatData *ptr = find(); + assert(ptr); + return ptr; +} + +const StatData * +DataAccess::statData() const +{ + const StatData *ptr = find(); + assert(ptr); + return ptr; +} + +void +DataAccess::setInit() +{ + statData()->flags |= init; +} + +void +DataAccess::setPrint() +{ + Database::regPrint(this); +} + +StatData::StatData() + : flags(none), precision(-1), prereq(0) +{ + static int count = 0; + id = count++; +} + +StatData::~StatData() +{ +} + +bool +StatData::less(StatData *stat1, StatData *stat2) +{ + const string &name1 = stat1->name; + const string &name2 = stat2->name; + + vector<string> v1; + vector<string> v2; + + tokenize(v1, name1, '.'); + tokenize(v2, name2, '.'); + + int last = min(v1.size(), v2.size()) - 1; + for (int i = 0; i < last; ++i) + if (v1[i] != v2[i]) + return v1[i] < v2[i]; + + // Special compare for last element. + if (v1[last] == v2[last]) + return v1.size() < v2.size(); + else + return v1[last] < v2[last]; + + return false; +} + +bool +StatData::baseCheck() const +{ + if (!(flags & init)) { +#ifdef DEBUG + cprintf("this is stat number %d\n", id); +#endif + panic("Not all stats have been initialized"); + return false; + } + + if ((flags & print) && name.empty()) { + panic("all printable stats must be named"); + return false; + } + + return true; +} + + +void +FormulaBase::result(VResult &vec) const +{ + if (root) + vec = root->result(); +} + +Result +FormulaBase::total() const +{ + return root ? root->total() : 0.0; +} + +size_t +FormulaBase::size() const +{ + if (!root) + return 0; + else + return root->size(); +} + +void +FormulaBase::reset() +{ +} + +bool +FormulaBase::zero() const +{ + VResult vec; + result(vec); + for (int i = 0; i < vec.size(); ++i) + if (vec[i] != 0.0) + return false; + return true; +} + +void +FormulaBase::update(StatData *) +{ +} + +string +FormulaBase::str() const +{ + return root ? root->str() : ""; +} + +Formula::Formula() +{ + setInit(); +} + +Formula::Formula(Temp r) +{ + root = r; + assert(size()); +} + +const Formula & +Formula::operator=(Temp r) +{ + assert(!root && "Can't change formulas"); + root = r; + assert(size()); + return *this; +} + +const Formula & +Formula::operator+=(Temp r) +{ + if (root) + root = NodePtr(new BinaryNode<std::plus<Result> >(root, r)); + else + root = r; + assert(size()); + return *this; +} + +void +check() +{ + typedef Database::stat_list_t::iterator iter_t; + + iter_t i, end = Database::stats().end(); + for (i = Database::stats().begin(); i != end; ++i) { + StatData *data = *i; + assert(data); + if (!data->check() || !data->baseCheck()) + panic("stat check failed for %s\n", data->name); + } + + int j = 0; + for (i = Database::stats().begin(); i != end; ++i) { + StatData *data = *i; + if (!(data->flags & print)) + data->name = "__Stat" + to_string(j++); + } + + Database::stats().sort(StatData::less); + + if (i == end) + return; + + iter_t last = i; + ++i; + + for (i = Database::stats().begin(); i != end; ++i) { + if ((*i)->name == (*last)->name) + panic("same name used twice! name=%s\n", (*i)->name); + + last = i; + } +} + +CallbackQueue resetQueue; + +void +reset() +{ + Database::stat_list_t::iterator i = Database::stats().begin(); + Database::stat_list_t::iterator end = Database::stats().end(); + while (i != end) { + StatData *data = *i; + data->reset(); + ++i; + } + + resetQueue.process(); +} + +void +registerResetCallback(Callback *cb) +{ + resetQueue.add(cb); +} + +/* namespace Stats */ } diff --git a/src/base/statistics.hh b/src/base/statistics.hh new file mode 100644 index 000000000..59f219c07 --- /dev/null +++ b/src/base/statistics.hh @@ -0,0 +1,2887 @@ +/* + * Copyright (c) 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: Nathan Binkert + * Erik Hallnor + */ + +/** @file + * Declaration of Statistics objects. + */ + +/** +* @todo +* +* Generalized N-dimensinal vector +* documentation +* key stats +* interval stats +* -- these both can use the same function that prints out a +* specific set of stats +* VectorStandardDeviation totals +* Document Namespaces +*/ +#ifndef __BASE_STATISTICS_HH__ +#define __BASE_STATISTICS_HH__ + +#include <algorithm> +#include <cassert> +#include <cmath> +#include <functional> +#include <iosfwd> +#include <string> +#include <vector> + +#include "base/cprintf.hh" +#include "base/intmath.hh" +#include "base/refcnt.hh" +#include "base/str.hh" +#include "base/stats/flags.hh" +#include "base/stats/visit.hh" +#include "base/stats/types.hh" +#include "sim/host.hh" + +class Callback; + +/** The current simulated cycle. */ +extern Tick curTick; + +/* A namespace for all of the Statistics */ +namespace Stats { + +/* Contains the statistic implementation details */ +////////////////////////////////////////////////////////////////////// +// +// Statistics Framework Base classes +// +////////////////////////////////////////////////////////////////////// +struct StatData +{ + /** The name of the stat. */ + std::string name; + /** The description of the stat. */ + std::string desc; + /** The formatting flags. */ + StatFlags flags; + /** The display precision. */ + int precision; + /** A pointer to a prerequisite Stat. */ + const StatData *prereq; + /** + * A unique stat ID for each stat in the simulator. + * Can be used externally for lookups as well as for debugging. + */ + int id; + + StatData(); + virtual ~StatData(); + + /** + * Reset the corresponding stat to the default state. + */ + virtual void reset() = 0; + + /** + * @return true if this stat has a value and satisfies its + * requirement as a prereq + */ + virtual bool zero() const = 0; + + /** + * Check that this stat has been set up properly and is ready for + * use + * @return true for success + */ + virtual bool check() const = 0; + bool baseCheck() const; + + /** + * Visitor entry for outputing statistics data + */ + virtual void visit(Visit &visitor) = 0; + + /** + * Checks if the first stat's name is alphabetically less than the second. + * This function breaks names up at periods and considers each subname + * separately. + * @param stat1 The first stat. + * @param stat2 The second stat. + * @return stat1's name is alphabetically before stat2's + */ + static bool less(StatData *stat1, StatData *stat2); +}; + +class ScalarData : public StatData +{ + public: + virtual Counter value() const = 0; + virtual Result result() const = 0; + virtual Result total() const = 0; + virtual void visit(Visit &visitor) { visitor.visit(*this); } +}; + +template <class Stat> +class ScalarStatData : public ScalarData +{ + protected: + Stat &s; + + public: + ScalarStatData(Stat &stat) : s(stat) {} + + virtual bool check() const { return s.check(); } + virtual Counter value() const { return s.value(); } + virtual Result result() const { return s.result(); } + virtual Result total() const { return s.total(); } + virtual void reset() { s.reset(); } + virtual bool zero() const { return s.zero(); } +}; + +struct VectorData : public StatData +{ + /** Names and descriptions of subfields. */ + mutable std::vector<std::string> subnames; + mutable std::vector<std::string> subdescs; + + virtual size_t size() const = 0; + virtual const VCounter &value() const = 0; + virtual const VResult &result() const = 0; + virtual Result total() const = 0; + void update() + { + if (!subnames.empty()) { + int s = size(); + if (subnames.size() < s) + subnames.resize(s); + + if (subdescs.size() < s) + subdescs.resize(s); + } + } +}; + +template <class Stat> +class VectorStatData : public VectorData +{ + protected: + Stat &s; + mutable VCounter cvec; + mutable VResult rvec; + + public: + VectorStatData(Stat &stat) : s(stat) {} + + virtual bool check() const { return s.check(); } + virtual bool zero() const { return s.zero(); } + virtual void reset() { s.reset(); } + + virtual size_t size() const { return s.size(); } + virtual VCounter &value() const + { + s.value(cvec); + return cvec; + } + virtual const VResult &result() const + { + s.result(rvec); + return rvec; + } + virtual Result total() const { return s.total(); } + virtual void visit(Visit &visitor) + { + update(); + s.update(this); + visitor.visit(*this); + } +}; + +struct DistDataData +{ + Counter min_val; + Counter max_val; + Counter underflow; + Counter overflow; + VCounter cvec; + Counter sum; + Counter squares; + Counter samples; + + Counter min; + Counter max; + Counter bucket_size; + int size; + bool fancy; +}; + +struct DistData : public StatData +{ + /** Local storage for the entry values, used for printing. */ + DistDataData data; +}; + +template <class Stat> +class DistStatData : public DistData +{ + protected: + Stat &s; + + public: + DistStatData(Stat &stat) : s(stat) {} + + virtual bool check() const { return s.check(); } + virtual void reset() { s.reset(); } + virtual bool zero() const { return s.zero(); } + virtual void visit(Visit &visitor) + { + s.update(this); + visitor.visit(*this); + } +}; + +struct VectorDistData : public StatData +{ + std::vector<DistDataData> data; + + /** Names and descriptions of subfields. */ + mutable std::vector<std::string> subnames; + mutable std::vector<std::string> subdescs; + + /** Local storage for the entry values, used for printing. */ + mutable VResult rvec; + + virtual size_t size() const = 0; + void update() + { + int s = size(); + if (subnames.size() < s) + subnames.resize(s); + + if (subdescs.size() < s) + subdescs.resize(s); + } +}; + +template <class Stat> +class VectorDistStatData : public VectorDistData +{ + protected: + Stat &s; + + public: + VectorDistStatData(Stat &stat) : s(stat) {} + + virtual bool check() const { return s.check(); } + virtual void reset() { s.reset(); } + virtual size_t size() const { return s.size(); } + virtual bool zero() const { return s.zero(); } + virtual void visit(Visit &visitor) + { + update(); + s.update(this); + visitor.visit(*this); + } +}; + +struct Vector2dData : public StatData +{ + /** Names and descriptions of subfields. */ + std::vector<std::string> subnames; + std::vector<std::string> subdescs; + std::vector<std::string> y_subnames; + + /** Local storage for the entry values, used for printing. */ + mutable VCounter cvec; + mutable int x; + mutable int y; + + void update() + { + if (subnames.size() < x) + subnames.resize(x); + } +}; + +template <class Stat> +class Vector2dStatData : public Vector2dData +{ + protected: + Stat &s; + + public: + Vector2dStatData(Stat &stat) : s(stat) {} + + virtual bool check() const { return s.check(); } + virtual void reset() { s.reset(); } + virtual bool zero() const { return s.zero(); } + virtual void visit(Visit &visitor) + { + update(); + s.update(this); + visitor.visit(*this); + } +}; + +class DataAccess +{ + protected: + StatData *find() const; + void map(StatData *data); + + StatData *statData(); + const StatData *statData() const; + + void setInit(); + void setPrint(); +}; + +template <class Parent, class Child, template <class> class Data> +class Wrap : public Child +{ + protected: + Parent &self() { return *reinterpret_cast<Parent *>(this); } + + protected: + Data<Child> *statData() + { + StatData *__data = DataAccess::statData(); + Data<Child> *ptr = dynamic_cast<Data<Child> *>(__data); + assert(ptr); + return ptr; + } + + public: + const Data<Child> *statData() const + { + const StatData *__data = DataAccess::statData(); + const Data<Child> *ptr = dynamic_cast<const Data<Child> *>(__data); + assert(ptr); + return ptr; + } + + protected: + /** + * Copy constructor, copies are not allowed. + */ + Wrap(const Wrap &stat); + /** + * Can't copy stats. + */ + void operator=(const Wrap &); + + public: + Wrap() + { + map(new Data<Child>(*this)); + } + + /** + * Set the name and marks this stat to print at the end of simulation. + * @param name The new name. + * @return A reference to this stat. + */ + Parent &name(const std::string &_name) + { + Data<Child> *data = this->statData(); + data->name = _name; + this->setPrint(); + return this->self(); + } + + /** + * Set the description and marks this stat to print at the end of + * simulation. + * @param desc The new description. + * @return A reference to this stat. + */ + Parent &desc(const std::string &_desc) + { + this->statData()->desc = _desc; + return this->self(); + } + + /** + * Set the precision and marks this stat to print at the end of simulation. + * @param p The new precision + * @return A reference to this stat. + */ + Parent &precision(int _precision) + { + this->statData()->precision = _precision; + return this->self(); + } + + /** + * Set the flags and marks this stat to print at the end of simulation. + * @param f The new flags. + * @return A reference to this stat. + */ + Parent &flags(StatFlags _flags) + { + this->statData()->flags |= _flags; + return this->self(); + } + + /** + * Set the prerequisite stat and marks this stat to print at the end of + * simulation. + * @param prereq The prerequisite stat. + * @return A reference to this stat. + */ + template <class Stat> + Parent &prereq(const Stat &prereq) + { + this->statData()->prereq = prereq.statData(); + return this->self(); + } +}; + +template <class Parent, class Child, template <class Child> class Data> +class WrapVec : public Wrap<Parent, Child, Data> +{ + public: + // The following functions are specific to vectors. If you use them + // in a non vector context, you will get a nice compiler error! + + /** + * Set the subfield name for the given index, and marks this stat to print + * at the end of simulation. + * @param index The subfield index. + * @param name The new name of the subfield. + * @return A reference to this stat. + */ + Parent &subname(int index, const std::string &name) + { + std::vector<std::string> &subn = this->statData()->subnames; + if (subn.size() <= index) + subn.resize(index + 1); + subn[index] = name; + return this->self(); + } + + /** + * Set the subfield description for the given index and marks this stat to + * print at the end of simulation. + * @param index The subfield index. + * @param desc The new description of the subfield + * @return A reference to this stat. + */ + Parent &subdesc(int index, const std::string &desc) + { + std::vector<std::string> &subd = this->statData()->subdescs; + if (subd.size() <= index) + subd.resize(index + 1); + subd[index] = desc; + + return this->self(); + } + +}; + +template <class Parent, class Child, template <class Child> class Data> +class WrapVec2d : public WrapVec<Parent, Child, Data> +{ + public: + /** + * @warning This makes the assumption that if you're gonna subnames a 2d + * vector, you're subnaming across all y + */ + Parent &ysubnames(const char **names) + { + Data<Child> *data = this->statData(); + data->y_subnames.resize(this->y); + for (int i = 0; i < this->y; ++i) + data->y_subnames[i] = names[i]; + return this->self(); + } + Parent &ysubname(int index, const std::string subname) + { + Data<Child> *data = this->statData(); + assert(index < this->y); + data->y_subnames.resize(this->y); + data->y_subnames[index] = subname.c_str(); + return this->self(); + } +}; + +////////////////////////////////////////////////////////////////////// +// +// Simple Statistics +// +////////////////////////////////////////////////////////////////////// + +/** + * Templatized storage and interface for a simple scalar stat. + */ +struct StatStor +{ + public: + /** The paramaters for this storage type, none for a scalar. */ + struct Params { }; + + private: + /** The statistic value. */ + Counter data; + + public: + /** + * Builds this storage element and calls the base constructor of the + * datatype. + */ + StatStor(const Params &) : data(Counter()) {} + + /** + * The the stat to the given value. + * @param val The new value. + * @param p The paramters of this storage type. + */ + void set(Counter val, const Params &p) { data = val; } + /** + * Increment the stat by the given value. + * @param val The new value. + * @param p The paramters of this storage type. + */ + void inc(Counter val, const Params &p) { data += val; } + /** + * Decrement the stat by the given value. + * @param val The new value. + * @param p The paramters of this storage type. + */ + void dec(Counter val, const Params &p) { data -= val; } + /** + * Return the value of this stat as its base type. + * @param p The params of this storage type. + * @return The value of this stat. + */ + Counter value(const Params &p) const { return data; } + /** + * Return the value of this stat as a result type. + * @param p The parameters of this storage type. + * @return The value of this stat. + */ + Result result(const Params &p) const { return (Result)data; } + /** + * Reset stat value to default + */ + void reset() { data = Counter(); } + + /** + * @return true if zero value + */ + bool zero() const { return data == Counter(); } +}; + +/** + * Templatized storage and interface to a per-cycle average stat. This keeps + * a current count and updates a total (count * cycles) when this count + * changes. This allows the quick calculation of a per cycle count of the item + * being watched. This is good for keeping track of residencies in structures + * among other things. + */ +struct AvgStor +{ + public: + /** The paramaters for this storage type */ + struct Params { }; + + private: + /** The current count. */ + Counter current; + /** The total count for all cycles. */ + mutable Result total; + /** The cycle that current last changed. */ + mutable Tick last; + + public: + /** + * Build and initializes this stat storage. + */ + AvgStor(Params &p) : current(0), total(0), last(0) { } + + /** + * Set the current count to the one provided, update the total and last + * set values. + * @param val The new count. + * @param p The parameters for this storage. + */ + void set(Counter val, Params &p) { + total += current * (curTick - last); + last = curTick; + current = val; + } + + /** + * Increment the current count by the provided value, calls set. + * @param val The amount to increment. + * @param p The parameters for this storage. + */ + void inc(Counter val, Params &p) { set(current + val, p); } + + /** + * Deccrement the current count by the provided value, calls set. + * @param val The amount to decrement. + * @param p The parameters for this storage. + */ + void dec(Counter val, Params &p) { set(current - val, p); } + + /** + * Return the current count. + * @param p The parameters for this storage. + * @return The current count. + */ + Counter value(const Params &p) const { return current; } + + /** + * Return the current average. + * @param p The parameters for this storage. + * @return The current average. + */ + Result result(const Params &p) const + { + total += current * (curTick - last); + last = curTick; + return (Result)(total + current) / (Result)(curTick + 1); + } + + /** + * Reset stat value to default + */ + void reset() + { + total = 0; + last = curTick; + } + + /** + * @return true if zero value + */ + bool zero() const { return total == 0.0; } +}; + +/** + * Implementation of a scalar stat. The type of stat is determined by the + * Storage template. + */ +template <class Stor> +class ScalarBase : public DataAccess +{ + public: + typedef Stor Storage; + + /** Define the params of the storage class. */ + typedef typename Storage::Params Params; + + protected: + /** The storage of this stat. */ + char storage[sizeof(Storage)]; + + /** The parameters for this stat. */ + Params params; + + protected: + /** + * Retrieve the storage. + * @param index The vector index to access. + * @return The storage object at the given index. + */ + Storage * + data() + { + return reinterpret_cast<Storage *>(storage); + } + + /** + * Retrieve a const pointer to the storage. + * for the given index. + * @param index The vector index to access. + * @return A const pointer to the storage object at the given index. + */ + const Storage * + data() const + { + return reinterpret_cast<const Storage *>(storage); + } + + void + doInit() + { + new (storage) Storage(params); + setInit(); + } + + public: + /** + * Return the current value of this stat as its base type. + * @return The current value. + */ + Counter value() const { return data()->value(params); } + + public: + /** + * Create and initialize this stat, register it with the database. + */ + ScalarBase() + { } + + public: + // Common operators for stats + /** + * Increment the stat by 1. This calls the associated storage object inc + * function. + */ + void operator++() { data()->inc(1, params); } + /** + * Decrement the stat by 1. This calls the associated storage object dec + * function. + */ + void operator--() { data()->dec(1, params); } + + /** Increment the stat by 1. */ + void operator++(int) { ++*this; } + /** Decrement the stat by 1. */ + void operator--(int) { --*this; } + + /** + * Set the data value to the given value. This calls the associated storage + * object set function. + * @param v The new value. + */ + template <typename U> + void operator=(const U &v) { data()->set(v, params); } + + /** + * Increment the stat by the given value. This calls the associated + * storage object inc function. + * @param v The value to add. + */ + template <typename U> + void operator+=(const U &v) { data()->inc(v, params); } + + /** + * Decrement the stat by the given value. This calls the associated + * storage object dec function. + * @param v The value to substract. + */ + template <typename U> + void operator-=(const U &v) { data()->dec(v, params); } + + /** + * Return the number of elements, always 1 for a scalar. + * @return 1. + */ + size_t size() const { return 1; } + + bool check() const { return true; } + + /** + * Reset stat value to default + */ + void reset() { data()->reset(); } + + Counter value() { return data()->value(params); } + + Result result() { return data()->result(params); } + + Result total() { return result(); } + + bool zero() { return result() == 0.0; } + +}; + +class ProxyData : public ScalarData +{ + public: + virtual void visit(Visit &visitor) { visitor.visit(*this); } + virtual std::string str() const { return to_string(value()); } + virtual size_t size() const { return 1; } + virtual bool zero() const { return value() == 0; } + virtual bool check() const { return true; } + virtual void reset() { } +}; + +template <class T> +class ValueProxy : public ProxyData +{ + private: + T *scalar; + + public: + ValueProxy(T &val) : scalar(&val) {} + virtual Counter value() const { return *scalar; } + virtual Result result() const { return *scalar; } + virtual Result total() const { return *scalar; } +}; + +template <class T> +class FunctorProxy : public ProxyData +{ + private: + T *functor; + + public: + FunctorProxy(T &func) : functor(&func) {} + virtual Counter value() const { return (*functor)(); } + virtual Result result() const { return (*functor)(); } + virtual Result total() const { return (*functor)(); } +}; + +class ValueBase : public DataAccess +{ + private: + ProxyData *proxy; + + public: + ValueBase() : proxy(NULL) { } + ~ValueBase() { if (proxy) delete proxy; } + + template <class T> + void scalar(T &value) + { + proxy = new ValueProxy<T>(value); + setInit(); + } + + template <class T> + void functor(T &func) + { + proxy = new FunctorProxy<T>(func); + setInit(); + } + + Counter value() { return proxy->value(); } + Result result() const { return proxy->result(); } + Result total() const { return proxy->total(); }; + size_t size() const { return proxy->size(); } + + std::string str() const { return proxy->str(); } + bool zero() const { return proxy->zero(); } + bool check() const { return proxy != NULL; } + void reset() { } +}; + +////////////////////////////////////////////////////////////////////// +// +// Vector Statistics +// +////////////////////////////////////////////////////////////////////// + +/** + * A proxy class to access the stat at a given index in a VectorBase stat. + * Behaves like a ScalarBase. + */ +template <class Stat> +class ScalarProxy +{ + private: + /** Pointer to the parent Vector. */ + Stat *stat; + + /** The index to access in the parent VectorBase. */ + int index; + + public: + /** + * Return the current value of this stat as its base type. + * @return The current value. + */ + Counter value() const { return stat->data(index)->value(stat->params); } + + /** + * Return the current value of this statas a result type. + * @return The current value. + */ + Result result() const { return stat->data(index)->result(stat->params); } + + public: + /** + * Create and initialize this proxy, do not register it with the database. + * @param p The params to use. + * @param i The index to access. + */ + ScalarProxy(Stat *s, int i) + : stat(s), index(i) + { + assert(stat); + } + + /** + * Create a copy of the provided ScalarProxy. + * @param sp The proxy to copy. + */ + ScalarProxy(const ScalarProxy &sp) + : stat(sp.stat), index(sp.index) + {} + + /** + * Set this proxy equal to the provided one. + * @param sp The proxy to copy. + * @return A reference to this proxy. + */ + const ScalarProxy &operator=(const ScalarProxy &sp) { + stat = sp.stat; + index = sp.index; + return *this; + } + + public: + // Common operators for stats + /** + * Increment the stat by 1. This calls the associated storage object inc + * function. + */ + void operator++() { stat->data(index)->inc(1, stat->params); } + /** + * Decrement the stat by 1. This calls the associated storage object dec + * function. + */ + void operator--() { stat->data(index)->dec(1, stat->params); } + + /** Increment the stat by 1. */ + void operator++(int) { ++*this; } + /** Decrement the stat by 1. */ + void operator--(int) { --*this; } + + /** + * Set the data value to the given value. This calls the associated storage + * object set function. + * @param v The new value. + */ + template <typename U> + void operator=(const U &v) { stat->data(index)->set(v, stat->params); } + + /** + * Increment the stat by the given value. This calls the associated + * storage object inc function. + * @param v The value to add. + */ + template <typename U> + void operator+=(const U &v) { stat->data(index)->inc(v, stat->params); } + + /** + * Decrement the stat by the given value. This calls the associated + * storage object dec function. + * @param v The value to substract. + */ + template <typename U> + void operator-=(const U &v) { stat->data(index)->dec(v, stat->params); } + + /** + * Return the number of elements, always 1 for a scalar. + * @return 1. + */ + size_t size() const { return 1; } + + /** + * This stat has no state. Nothing to reset + */ + void reset() { } + + public: + std::string + str() const + { + return csprintf("%s[%d]", stat->str(), index); + + } +}; + +/** + * Implementation of a vector of stats. The type of stat is determined by the + * Storage class. @sa ScalarBase + */ +template <class Stor> +class VectorBase : public DataAccess +{ + public: + typedef Stor Storage; + + /** Define the params of the storage class. */ + typedef typename Storage::Params Params; + + /** Proxy type */ + typedef ScalarProxy<VectorBase<Storage> > Proxy; + + friend class ScalarProxy<VectorBase<Storage> >; + + protected: + /** The storage of this stat. */ + Storage *storage; + size_t _size; + + /** The parameters for this stat. */ + Params params; + + protected: + /** + * Retrieve the storage. + * @param index The vector index to access. + * @return The storage object at the given index. + */ + Storage *data(int index) { return &storage[index]; } + + /** + * Retrieve a const pointer to the storage. + * @param index The vector index to access. + * @return A const pointer to the storage object at the given index. + */ + const Storage *data(int index) const { return &storage[index]; } + + void + doInit(int s) + { + assert(s > 0 && "size must be positive!"); + assert(!storage && "already initialized"); + _size = s; + + char *ptr = new char[_size * sizeof(Storage)]; + storage = reinterpret_cast<Storage *>(ptr); + + for (int i = 0; i < _size; ++i) + new (&storage[i]) Storage(params); + + setInit(); + } + + public: + void value(VCounter &vec) const + { + vec.resize(size()); + for (int i = 0; i < size(); ++i) + vec[i] = data(i)->value(params); + } + + /** + * Copy the values to a local vector and return a reference to it. + * @return A reference to a vector of the stat values. + */ + void result(VResult &vec) const + { + vec.resize(size()); + for (int i = 0; i < size(); ++i) + vec[i] = data(i)->result(params); + } + + /** + * Return a total of all entries in this vector. + * @return The total of all vector entries. + */ + Result total() const { + Result total = 0.0; + for (int i = 0; i < size(); ++i) + total += data(i)->result(params); + return total; + } + + /** + * @return the number of elements in this vector. + */ + size_t size() const { return _size; } + + bool + zero() const + { + for (int i = 0; i < size(); ++i) + if (data(i)->zero()) + return false; + return true; + } + + bool + check() const + { + return storage != NULL; + } + + void + reset() + { + for (int i = 0; i < size(); ++i) + data(i)->reset(); + } + + public: + VectorBase() + : storage(NULL) + {} + + ~VectorBase() + { + if (!storage) + return; + + for (int i = 0; i < _size; ++i) + data(i)->~Storage(); + delete [] reinterpret_cast<char *>(storage); + } + + /** + * Return a reference (ScalarProxy) to the stat at the given index. + * @param index The vector index to access. + * @return A reference of the stat. + */ + Proxy + operator[](int index) + { + assert (index >= 0 && index < size()); + return Proxy(this, index); + } + + void update(StatData *data) {} +}; + +template <class Stat> +class VectorProxy +{ + private: + Stat *stat; + int offset; + int len; + + private: + mutable VResult vec; + + typename Stat::Storage * + data(int index) + { + assert(index < len); + return stat->data(offset + index); + } + + const typename Stat::Storage * + data(int index) const + { + assert(index < len); + return const_cast<Stat *>(stat)->data(offset + index); + } + + public: + const VResult & + result() const + { + vec.resize(size()); + + for (int i = 0; i < size(); ++i) + vec[i] = data(i)->result(stat->params); + + return vec; + } + + Result + total() const + { + Result total = 0; + for (int i = 0; i < size(); ++i) + total += data(i)->result(stat->params); + return total; + } + + public: + VectorProxy(Stat *s, int o, int l) + : stat(s), offset(o), len(l) + { + } + + VectorProxy(const VectorProxy &sp) + : stat(sp.stat), offset(sp.offset), len(sp.len) + { + } + + const VectorProxy & + operator=(const VectorProxy &sp) + { + stat = sp.stat; + offset = sp.offset; + len = sp.len; + return *this; + } + + ScalarProxy<Stat> operator[](int index) + { + assert (index >= 0 && index < size()); + return ScalarProxy<Stat>(stat, offset + index); + } + + size_t size() const { return len; } + + /** + * This stat has no state. Nothing to reset. + */ + void reset() { } +}; + +template <class Stor> +class Vector2dBase : public DataAccess +{ + public: + typedef Stor Storage; + typedef typename Storage::Params Params; + typedef VectorProxy<Vector2dBase<Storage> > Proxy; + friend class ScalarProxy<Vector2dBase<Storage> >; + friend class VectorProxy<Vector2dBase<Storage> >; + + protected: + size_t x; + size_t y; + size_t _size; + Storage *storage; + Params params; + + protected: + Storage *data(int index) { return &storage[index]; } + const Storage *data(int index) const { return &storage[index]; } + + void + doInit(int _x, int _y) + { + assert(_x > 0 && _y > 0 && "sizes must be positive!"); + assert(!storage && "already initialized"); + + Vector2dData *statdata = dynamic_cast<Vector2dData *>(find()); + + x = _x; + y = _y; + statdata->x = _x; + statdata->y = _y; + _size = x * y; + + char *ptr = new char[_size * sizeof(Storage)]; + storage = reinterpret_cast<Storage *>(ptr); + + for (int i = 0; i < _size; ++i) + new (&storage[i]) Storage(params); + + setInit(); + } + + public: + Vector2dBase() + : storage(NULL) + {} + + ~Vector2dBase() + { + if (!storage) + return; + + for (int i = 0; i < _size; ++i) + data(i)->~Storage(); + delete [] reinterpret_cast<char *>(storage); + } + + void + update(Vector2dData *newdata) + { + int size = this->size(); + newdata->cvec.resize(size); + for (int i = 0; i < size; ++i) + newdata->cvec[i] = data(i)->value(params); + } + + std::string ysubname(int i) const { return (*this->y_subnames)[i]; } + + Proxy + operator[](int index) + { + int offset = index * y; + assert (index >= 0 && offset + index < size()); + return Proxy(this, offset, y); + } + + + size_t + size() const + { + return _size; + } + + bool + zero() const + { + return data(0)->zero(); +#if 0 + for (int i = 0; i < size(); ++i) + if (!data(i)->zero()) + return false; + return true; +#endif + } + + /** + * Reset stat value to default + */ + void + reset() + { + for (int i = 0; i < size(); ++i) + data(i)->reset(); + } + + bool + check() + { + return storage != NULL; + } +}; + +////////////////////////////////////////////////////////////////////// +// +// Non formula statistics +// +////////////////////////////////////////////////////////////////////// + +/** + * Templatized storage and interface for a distrbution stat. + */ +struct DistStor +{ + public: + /** The parameters for a distribution stat. */ + struct Params + { + /** The minimum value to track. */ + Counter min; + /** The maximum value to track. */ + Counter max; + /** The number of entries in each bucket. */ + Counter bucket_size; + /** The number of buckets. Equal to (max-min)/bucket_size. */ + int size; + }; + enum { fancy = false }; + + private: + /** The smallest value sampled. */ + Counter min_val; + /** The largest value sampled. */ + Counter max_val; + /** The number of values sampled less than min. */ + Counter underflow; + /** The number of values sampled more than max. */ + Counter overflow; + /** The current sum. */ + Counter sum; + /** The sum of squares. */ + Counter squares; + /** The number of samples. */ + Counter samples; + /** Counter for each bucket. */ + VCounter cvec; + + public: + DistStor(const Params ¶ms) + : cvec(params.size) + { + reset(); + } + + /** + * Add a value to the distribution for the given number of times. + * @param val The value to add. + * @param number The number of times to add the value. + * @param params The paramters of the distribution. + */ + void sample(Counter val, int number, const Params ¶ms) + { + if (val < params.min) + underflow += number; + else if (val > params.max) + overflow += number; + else { + int index = (int)floor((val - params.min) / params.bucket_size); + assert(index < size(params)); + cvec[index] += number; + } + + if (val < min_val) + min_val = val; + + if (val > max_val) + max_val = val; + + Counter sample = val * number; + sum += sample; + squares += sample * sample; + samples += number; + } + + /** + * Return the number of buckets in this distribution. + * @return the number of buckets. + * @todo Is it faster to return the size from the parameters? + */ + size_t size(const Params &) const { return cvec.size(); } + + /** + * Returns true if any calls to sample have been made. + * @param params The paramters of the distribution. + * @return True if any values have been sampled. + */ + bool zero(const Params ¶ms) const + { + return samples == Counter(); + } + + void update(DistDataData *data, const Params ¶ms) + { + data->min = params.min; + data->max = params.max; + data->bucket_size = params.bucket_size; + data->size = params.size; + + data->min_val = (min_val == INT_MAX) ? 0 : min_val; + data->max_val = (max_val == INT_MIN) ? 0 : max_val; + data->underflow = underflow; + data->overflow = overflow; + data->cvec.resize(params.size); + for (int i = 0; i < params.size; ++i) + data->cvec[i] = cvec[i]; + + data->sum = sum; + data->squares = squares; + data->samples = samples; + } + + /** + * Reset stat value to default + */ + void reset() + { + min_val = INT_MAX; + max_val = INT_MIN; + underflow = 0; + overflow = 0; + + int size = cvec.size(); + for (int i = 0; i < size; ++i) + cvec[i] = Counter(); + + sum = Counter(); + squares = Counter(); + samples = Counter(); + } +}; + +/** + * Templatized storage and interface for a distribution that calculates mean + * and variance. + */ +struct FancyStor +{ + public: + /** + * No paramters for this storage. + */ + struct Params {}; + enum { fancy = true }; + + private: + /** The current sum. */ + Counter sum; + /** The sum of squares. */ + Counter squares; + /** The number of samples. */ + Counter samples; + + public: + /** + * Create and initialize this storage. + */ + FancyStor(const Params &) + : sum(Counter()), squares(Counter()), samples(Counter()) + { } + + /** + * Add a value the given number of times to this running average. + * Update the running sum and sum of squares, increment the number of + * values seen by the given number. + * @param val The value to add. + * @param number The number of times to add the value. + * @param p The parameters of this stat. + */ + void sample(Counter val, int number, const Params &p) + { + Counter value = val * number; + sum += value; + squares += value * value; + samples += number; + } + + void update(DistDataData *data, const Params ¶ms) + { + data->sum = sum; + data->squares = squares; + data->samples = samples; + } + + /** + * Return the number of entries in this stat, 1 + * @return 1. + */ + size_t size(const Params &) const { return 1; } + + /** + * Return true if no samples have been added. + * @return True if no samples have been added. + */ + bool zero(const Params &) const { return samples == Counter(); } + + /** + * Reset stat value to default + */ + void reset() + { + sum = Counter(); + squares = Counter(); + samples = Counter(); + } +}; + +/** + * Templatized storage for distribution that calculates per cycle mean and + * variance. + */ +struct AvgFancy +{ + public: + /** No parameters for this storage. */ + struct Params {}; + enum { fancy = true }; + + private: + /** Current total. */ + Counter sum; + /** Current sum of squares. */ + Counter squares; + + public: + /** + * Create and initialize this storage. + */ + AvgFancy(const Params &) : sum(Counter()), squares(Counter()) {} + + /** + * Add a value to the distribution for the given number of times. + * Update the running sum and sum of squares. + * @param val The value to add. + * @param number The number of times to add the value. + * @param p The paramters of the distribution. + */ + void sample(Counter val, int number, const Params &p) + { + Counter value = val * number; + sum += value; + squares += value * value; + } + + void update(DistDataData *data, const Params ¶ms) + { + data->sum = sum; + data->squares = squares; + data->samples = curTick; + } + + /** + * Return the number of entries, in this case 1. + * @return 1. + */ + size_t size(const Params ¶ms) const { return 1; } + /** + * Return true if no samples have been added. + * @return True if the sum is zero. + */ + bool zero(const Params ¶ms) const { return sum == Counter(); } + /** + * Reset stat value to default + */ + void reset() + { + sum = Counter(); + squares = Counter(); + } +}; + +/** + * Implementation of a distribution stat. The type of distribution is + * determined by the Storage template. @sa ScalarBase + */ +template <class Stor> +class DistBase : public DataAccess +{ + public: + typedef Stor Storage; + /** Define the params of the storage class. */ + typedef typename Storage::Params Params; + + protected: + /** The storage for this stat. */ + char storage[sizeof(Storage)]; + + /** The parameters for this stat. */ + Params params; + + protected: + /** + * Retrieve the storage. + * @return The storage object for this stat. + */ + Storage *data() + { + return reinterpret_cast<Storage *>(storage); + } + + /** + * Retrieve a const pointer to the storage. + * @return A const pointer to the storage object for this stat. + */ + const Storage * + data() const + { + return reinterpret_cast<const Storage *>(storage); + } + + void + doInit() + { + new (storage) Storage(params); + setInit(); + } + + public: + DistBase() { } + + /** + * Add a value to the distribtion n times. Calls sample on the storage + * class. + * @param v The value to add. + * @param n The number of times to add it, defaults to 1. + */ + template <typename U> + void sample(const U &v, int n = 1) { data()->sample(v, n, params); } + + /** + * Return the number of entries in this stat. + * @return The number of entries. + */ + size_t size() const { return data()->size(params); } + /** + * Return true if no samples have been added. + * @return True if there haven't been any samples. + */ + bool zero() const { return data()->zero(params); } + + void update(DistData *base) + { + base->data.fancy = Storage::fancy; + data()->update(&(base->data), params); + } + + /** + * Reset stat value to default + */ + void + reset() + { + data()->reset(); + } + + bool + check() + { + return true; + } +}; + +template <class Stat> +class DistProxy; + +template <class Stor> +class VectorDistBase : public DataAccess +{ + public: + typedef Stor Storage; + typedef typename Storage::Params Params; + typedef DistProxy<VectorDistBase<Storage> > Proxy; + friend class DistProxy<VectorDistBase<Storage> >; + + protected: + Storage *storage; + size_t _size; + Params params; + + protected: + Storage * + data(int index) + { + return &storage[index]; + } + + const Storage * + data(int index) const + { + return &storage[index]; + } + + void + doInit(int s) + { + assert(s > 0 && "size must be positive!"); + assert(!storage && "already initialized"); + _size = s; + + char *ptr = new char[_size * sizeof(Storage)]; + storage = reinterpret_cast<Storage *>(ptr); + + for (int i = 0; i < _size; ++i) + new (&storage[i]) Storage(params); + + setInit(); + } + + public: + VectorDistBase() + : storage(NULL) + {} + + ~VectorDistBase() + { + if (!storage) + return ; + + for (int i = 0; i < _size; ++i) + data(i)->~Storage(); + delete [] reinterpret_cast<char *>(storage); + } + + Proxy operator[](int index); + + size_t + size() const + { + return _size; + } + + bool + zero() const + { + return false; +#if 0 + for (int i = 0; i < size(); ++i) + if (!data(i)->zero(params)) + return false; + return true; +#endif + } + + /** + * Reset stat value to default + */ + void + reset() + { + for (int i = 0; i < size(); ++i) + data(i)->reset(); + } + + bool + check() + { + return storage != NULL; + } + + void + update(VectorDistData *base) + { + int size = this->size(); + base->data.resize(size); + for (int i = 0; i < size; ++i) { + base->data[i].fancy = Storage::fancy; + data(i)->update(&(base->data[i]), params); + } + } +}; + +template <class Stat> +class DistProxy +{ + private: + Stat *stat; + int index; + + protected: + typename Stat::Storage *data() { return stat->data(index); } + const typename Stat::Storage *data() const { return stat->data(index); } + + public: + DistProxy(Stat *s, int i) + : stat(s), index(i) + {} + + DistProxy(const DistProxy &sp) + : stat(sp.stat), index(sp.index) + {} + + const DistProxy &operator=(const DistProxy &sp) + { + stat = sp.stat; + index = sp.index; + return *this; + } + + public: + template <typename U> + void + sample(const U &v, int n = 1) + { + data()->sample(v, n, stat->params); + } + + size_t + size() const + { + return 1; + } + + bool + zero() const + { + return data()->zero(stat->params); + } + + /** + * Proxy has no state. Nothing to reset. + */ + void reset() { } +}; + +template <class Storage> +inline typename VectorDistBase<Storage>::Proxy +VectorDistBase<Storage>::operator[](int index) +{ + assert (index >= 0 && index < size()); + return typename VectorDistBase<Storage>::Proxy(this, index); +} + +#if 0 +template <class Storage> +Result +VectorDistBase<Storage>::total(int index) const +{ + int total = 0; + for (int i = 0; i < x_size(); ++i) { + total += data(i)->result(stat->params); + } +} +#endif + +////////////////////////////////////////////////////////////////////// +// +// Formula Details +// +////////////////////////////////////////////////////////////////////// + +/** + * Base class for formula statistic node. These nodes are used to build a tree + * that represents the formula. + */ +class Node : public RefCounted +{ + public: + /** + * Return the number of nodes in the subtree starting at this node. + * @return the number of nodes in this subtree. + */ + virtual size_t size() const = 0; + /** + * Return the result vector of this subtree. + * @return The result vector of this subtree. + */ + virtual const VResult &result() const = 0; + /** + * Return the total of the result vector. + * @return The total of the result vector. + */ + virtual Result total() const = 0; + + /** + * + */ + virtual std::string str() const = 0; +}; + +/** Reference counting pointer to a function Node. */ +typedef RefCountingPtr<Node> NodePtr; + +class ScalarStatNode : public Node +{ + private: + const ScalarData *data; + mutable VResult vresult; + + public: + ScalarStatNode(const ScalarData *d) : data(d), vresult(1) {} + virtual const VResult &result() const + { + vresult[0] = data->result(); + return vresult; + } + virtual Result total() const { return data->result(); }; + + virtual size_t size() const { return 1; } + + /** + * + */ + virtual std::string str() const { return data->name; } +}; + +template <class Stat> +class ScalarProxyNode : public Node +{ + private: + const ScalarProxy<Stat> proxy; + mutable VResult vresult; + + public: + ScalarProxyNode(const ScalarProxy<Stat> &p) + : proxy(p), vresult(1) + { } + + virtual const VResult & + result() const + { + vresult[0] = proxy.result(); + return vresult; + } + + virtual Result + total() const + { + return proxy.result(); + } + + virtual size_t + size() const + { + return 1; + } + + /** + * + */ + virtual std::string + str() const + { + return proxy.str(); + } +}; + +class VectorStatNode : public Node +{ + private: + const VectorData *data; + + public: + VectorStatNode(const VectorData *d) : data(d) { } + virtual const VResult &result() const { return data->result(); } + virtual Result total() const { return data->total(); }; + + virtual size_t size() const { return data->size(); } + + virtual std::string str() const { return data->name; } +}; + +template <class T> +class ConstNode : public Node +{ + private: + VResult vresult; + + public: + ConstNode(T s) : vresult(1, (Result)s) {} + const VResult &result() const { return vresult; } + virtual Result total() const { return vresult[0]; }; + virtual size_t size() const { return 1; } + virtual std::string str() const { return to_string(vresult[0]); } +}; + +template <class Op> +struct OpString; + +template<> +struct OpString<std::plus<Result> > +{ + static std::string str() { return "+"; } +}; + +template<> +struct OpString<std::minus<Result> > +{ + static std::string str() { return "-"; } +}; + +template<> +struct OpString<std::multiplies<Result> > +{ + static std::string str() { return "*"; } +}; + +template<> +struct OpString<std::divides<Result> > +{ + static std::string str() { return "/"; } +}; + +template<> +struct OpString<std::modulus<Result> > +{ + static std::string str() { return "%"; } +}; + +template<> +struct OpString<std::negate<Result> > +{ + static std::string str() { return "-"; } +}; + +template <class Op> +class UnaryNode : public Node +{ + public: + NodePtr l; + mutable VResult vresult; + + public: + UnaryNode(NodePtr &p) : l(p) {} + + const VResult &result() const + { + const VResult &lvec = l->result(); + int size = lvec.size(); + + assert(size > 0); + + vresult.resize(size); + Op op; + for (int i = 0; i < size; ++i) + vresult[i] = op(lvec[i]); + + return vresult; + } + + Result total() const { + Op op; + return op(l->total()); + } + + virtual size_t size() const { return l->size(); } + + virtual std::string str() const + { + return OpString<Op>::str() + l->str(); + } +}; + +template <class Op> +class BinaryNode : public Node +{ + public: + NodePtr l; + NodePtr r; + mutable VResult vresult; + + public: + BinaryNode(NodePtr &a, NodePtr &b) : l(a), r(b) {} + + const VResult &result() const + { + Op op; + const VResult &lvec = l->result(); + const VResult &rvec = r->result(); + + assert(lvec.size() > 0 && rvec.size() > 0); + + if (lvec.size() == 1 && rvec.size() == 1) { + vresult.resize(1); + vresult[0] = op(lvec[0], rvec[0]); + } else if (lvec.size() == 1) { + int size = rvec.size(); + vresult.resize(size); + for (int i = 0; i < size; ++i) + vresult[i] = op(lvec[0], rvec[i]); + } else if (rvec.size() == 1) { + int size = lvec.size(); + vresult.resize(size); + for (int i = 0; i < size; ++i) + vresult[i] = op(lvec[i], rvec[0]); + } else if (rvec.size() == lvec.size()) { + int size = rvec.size(); + vresult.resize(size); + for (int i = 0; i < size; ++i) + vresult[i] = op(lvec[i], rvec[i]); + } + + return vresult; + } + + Result total() const { + Op op; + return op(l->total(), r->total()); + } + + virtual size_t size() const { + int ls = l->size(); + int rs = r->size(); + if (ls == 1) + return rs; + else if (rs == 1) + return ls; + else { + assert(ls == rs && "Node vector sizes are not equal"); + return ls; + } + } + + virtual std::string str() const + { + return csprintf("(%s %s %s)", l->str(), OpString<Op>::str(), r->str()); + } +}; + +template <class Op> +class SumNode : public Node +{ + public: + NodePtr l; + mutable VResult vresult; + + public: + SumNode(NodePtr &p) : l(p), vresult(1) {} + + const VResult &result() const + { + const VResult &lvec = l->result(); + int size = lvec.size(); + assert(size > 0); + + vresult[0] = 0.0; + + Op op; + for (int i = 0; i < size; ++i) + vresult[0] = op(vresult[0], lvec[i]); + + return vresult; + } + + Result total() const + { + const VResult &lvec = l->result(); + int size = lvec.size(); + assert(size > 0); + + Result vresult = 0.0; + + Op op; + for (int i = 0; i < size; ++i) + vresult = op(vresult, lvec[i]); + + return vresult; + } + + virtual size_t size() const { return 1; } + + virtual std::string str() const + { + return csprintf("total(%s)", l->str()); + } +}; + + +////////////////////////////////////////////////////////////////////// +// +// Visible Statistics Types +// +////////////////////////////////////////////////////////////////////// +/** + * @defgroup VisibleStats "Statistic Types" + * These are the statistics that are used in the simulator. + * @{ + */ + +/** + * This is a simple scalar statistic, like a counter. + * @sa Stat, ScalarBase, StatStor + */ +template<int N = 0> +class Scalar : public Wrap<Scalar<N>, ScalarBase<StatStor>, ScalarStatData> +{ + public: + /** The base implementation. */ + typedef ScalarBase<StatStor> Base; + + Scalar() + { + this->doInit(); + } + + /** + * Sets the stat equal to the given value. Calls the base implementation + * of operator= + * @param v The new value. + */ + template <typename U> + void operator=(const U &v) { Base::operator=(v); } +}; + +class Value : public Wrap<Value, ValueBase, ScalarStatData> +{ + public: + /** The base implementation. */ + typedef ValueBase Base; + + template <class T> + Value &scalar(T &value) + { + Base::scalar(value); + return *this; + } + + template <class T> + Value &functor(T &func) + { + Base::functor(func); + return *this; + } +}; + +/** + * A stat that calculates the per cycle average of a value. + * @sa Stat, ScalarBase, AvgStor + */ +template<int N = 0> +class Average : public Wrap<Average<N>, ScalarBase<AvgStor>, ScalarStatData> +{ + public: + /** The base implementation. */ + typedef ScalarBase<AvgStor> Base; + + Average() + { + this->doInit(); + } + + /** + * Sets the stat equal to the given value. Calls the base implementation + * of operator= + * @param v The new value. + */ + template <typename U> + void operator=(const U &v) { Base::operator=(v); } +}; + +/** + * A vector of scalar stats. + * @sa Stat, VectorBase, StatStor + */ +template<int N = 0> +class Vector : public WrapVec<Vector<N>, VectorBase<StatStor>, VectorStatData> +{ + public: + /** The base implementation. */ + typedef ScalarBase<StatStor> Base; + + /** + * Set this vector to have the given size. + * @param size The new size. + * @return A reference to this stat. + */ + Vector &init(size_t size) { + this->doInit(size); + return *this; + } +}; + +/** + * A vector of Average stats. + * @sa Stat, VectorBase, AvgStor + */ +template<int N = 0> +class AverageVector + : public WrapVec<AverageVector<N>, VectorBase<AvgStor>, VectorStatData> +{ + public: + /** + * Set this vector to have the given size. + * @param size The new size. + * @return A reference to this stat. + */ + AverageVector &init(size_t size) { + this->doInit(size); + return *this; + } +}; + +/** + * A 2-Dimensional vecto of scalar stats. + * @sa Stat, Vector2dBase, StatStor + */ +template<int N = 0> +class Vector2d + : public WrapVec2d<Vector2d<N>, Vector2dBase<StatStor>, Vector2dStatData> +{ + public: + Vector2d &init(size_t x, size_t y) { + this->doInit(x, y); + return *this; + } +}; + +/** + * A simple distribution stat. + * @sa Stat, DistBase, DistStor + */ +template<int N = 0> +class Distribution + : public Wrap<Distribution<N>, DistBase<DistStor>, DistStatData> +{ + public: + /** Base implementation. */ + typedef DistBase<DistStor> Base; + /** The Parameter type. */ + typedef DistStor::Params Params; + + public: + /** + * Set the parameters of this distribution. @sa DistStor::Params + * @param min The minimum value of the distribution. + * @param max The maximum value of the distribution. + * @param bkt The number of values in each bucket. + * @return A reference to this distribution. + */ + Distribution &init(Counter min, Counter max, Counter bkt) { + this->params.min = min; + this->params.max = max; + this->params.bucket_size = bkt; + this->params.size = (int)rint((max - min) / bkt + 1.0); + this->doInit(); + return *this; + } +}; + +/** + * Calculates the mean and variance of all the samples. + * @sa Stat, DistBase, FancyStor + */ +template<int N = 0> +class StandardDeviation + : public Wrap<StandardDeviation<N>, DistBase<FancyStor>, DistStatData> +{ + public: + /** The base implementation */ + typedef DistBase<DistStor> Base; + /** The parameter type. */ + typedef DistStor::Params Params; + + public: + /** + * Construct and initialize this distribution. + */ + StandardDeviation() { + this->doInit(); + } +}; + +/** + * Calculates the per cycle mean and variance of the samples. + * @sa Stat, DistBase, AvgFancy + */ +template<int N = 0> +class AverageDeviation + : public Wrap<AverageDeviation<N>, DistBase<AvgFancy>, DistStatData> +{ + public: + /** The base implementation */ + typedef DistBase<DistStor> Base; + /** The parameter type. */ + typedef DistStor::Params Params; + + public: + /** + * Construct and initialize this distribution. + */ + AverageDeviation() + { + this->doInit(); + } +}; + +/** + * A vector of distributions. + * @sa Stat, VectorDistBase, DistStor + */ +template<int N = 0> +class VectorDistribution + : public WrapVec<VectorDistribution<N>, + VectorDistBase<DistStor>, + VectorDistStatData> +{ + public: + /** The base implementation */ + typedef VectorDistBase<DistStor> Base; + /** The parameter type. */ + typedef DistStor::Params Params; + + public: + /** + * Initialize storage and parameters for this distribution. + * @param size The size of the vector (the number of distributions). + * @param min The minimum value of the distribution. + * @param max The maximum value of the distribution. + * @param bkt The number of values in each bucket. + * @return A reference to this distribution. + */ + VectorDistribution &init(int size, Counter min, Counter max, Counter bkt) { + this->params.min = min; + this->params.max = max; + this->params.bucket_size = bkt; + this->params.size = (int)rint((max - min) / bkt + 1.0); + this->doInit(size); + return *this; + } +}; + +/** + * This is a vector of StandardDeviation stats. + * @sa Stat, VectorDistBase, FancyStor + */ +template<int N = 0> +class VectorStandardDeviation + : public WrapVec<VectorStandardDeviation<N>, + VectorDistBase<FancyStor>, + VectorDistStatData> +{ + public: + /** The base implementation */ + typedef VectorDistBase<FancyStor> Base; + /** The parameter type. */ + typedef DistStor::Params Params; + + public: + /** + * Initialize storage for this distribution. + * @param size The size of the vector. + * @return A reference to this distribution. + */ + VectorStandardDeviation &init(int size) { + this->doInit(size); + return *this; + } +}; + +/** + * This is a vector of AverageDeviation stats. + * @sa Stat, VectorDistBase, AvgFancy + */ +template<int N = 0> +class VectorAverageDeviation + : public WrapVec<VectorAverageDeviation<N>, + VectorDistBase<AvgFancy>, + VectorDistStatData> +{ + public: + /** The base implementation */ + typedef VectorDistBase<AvgFancy> Base; + /** The parameter type. */ + typedef DistStor::Params Params; + + public: + /** + * Initialize storage for this distribution. + * @param size The size of the vector. + * @return A reference to this distribution. + */ + VectorAverageDeviation &init(int size) { + this->doInit(size); + return *this; + } +}; + +/** + * A formula for statistics that is calculated when printed. A formula is + * stored as a tree of Nodes that represent the equation to calculate. + * @sa Stat, ScalarStat, VectorStat, Node, Temp + */ +class FormulaBase : public DataAccess +{ + protected: + /** The root of the tree which represents the Formula */ + NodePtr root; + friend class Temp; + + public: + /** + * Return the result of the Fomula in a vector. If there were no Vector + * components to the Formula, then the vector is size 1. If there were, + * like x/y with x being a vector of size 3, then the result returned will + * be x[0]/y, x[1]/y, x[2]/y, respectively. + * @return The result vector. + */ + void result(VResult &vec) const; + + /** + * Return the total Formula result. If there is a Vector + * component to this Formula, then this is the result of the + * Formula if the formula is applied after summing all the + * components of the Vector. For example, if Formula is x/y where + * x is size 3, then total() will return (x[1]+x[2]+x[3])/y. If + * there is no Vector component, total() returns the same value as + * the first entry in the VResult val() returns. + * @return The total of the result vector. + */ + Result total() const; + + /** + * Return the number of elements in the tree. + */ + size_t size() const; + + bool check() const { return true; } + + /** + * Formulas don't need to be reset + */ + void reset(); + + /** + * + */ + bool zero() const; + + /** + * + */ + void update(StatData *); + + std::string str() const; +}; + +class FormulaData : public VectorData +{ + public: + virtual std::string str() const = 0; + virtual bool check() const { return true; } +}; + +template <class Stat> +class FormulaStatData : public FormulaData +{ + protected: + Stat &s; + mutable VResult vec; + mutable VCounter cvec; + + public: + FormulaStatData(Stat &stat) : s(stat) {} + + virtual bool zero() const { return s.zero(); } + virtual void reset() { s.reset(); } + + virtual size_t size() const { return s.size(); } + virtual const VResult &result() const + { + s.result(vec); + return vec; + } + virtual Result total() const { return s.total(); } + virtual VCounter &value() const { return cvec; } + virtual void visit(Visit &visitor) + { + update(); + s.update(this); + visitor.visit(*this); + } + virtual std::string str() const { return s.str(); } +}; + +class Temp; +class Formula + : public WrapVec<Formula, + FormulaBase, + FormulaStatData> +{ + public: + /** + * Create and initialize thie formula, and register it with the database. + */ + Formula(); + + /** + * Create a formula with the given root node, register it with the + * database. + * @param r The root of the expression tree. + */ + Formula(Temp r); + + /** + * Set an unitialized Formula to the given root. + * @param r The root of the expression tree. + * @return a reference to this formula. + */ + const Formula &operator=(Temp r); + + /** + * Add the given tree to the existing one. + * @param r The root of the expression tree. + * @return a reference to this formula. + */ + const Formula &operator+=(Temp r); +}; + +class FormulaNode : public Node +{ + private: + const Formula &formula; + mutable VResult vec; + + public: + FormulaNode(const Formula &f) : formula(f) {} + + virtual size_t size() const { return formula.size(); } + virtual const VResult &result() const { formula.result(vec); return vec; } + virtual Result total() const { return formula.total(); } + + virtual std::string str() const { return formula.str(); } +}; + +/** + * Helper class to construct formula node trees. + */ +class Temp +{ + protected: + /** + * Pointer to a Node object. + */ + NodePtr node; + + public: + /** + * Copy the given pointer to this class. + * @param n A pointer to a Node object to copy. + */ + Temp(NodePtr n) : node(n) { } + + /** + * Return the node pointer. + * @return the node pointer. + */ + operator NodePtr&() { return node;} + + public: + /** + * Create a new ScalarStatNode. + * @param s The ScalarStat to place in a node. + */ + template <int N> + Temp(const Scalar<N> &s) + : node(new ScalarStatNode(s.statData())) { } + + /** + * Create a new ScalarStatNode. + * @param s The ScalarStat to place in a node. + */ + Temp(const Value &s) + : node(new ScalarStatNode(s.statData())) { } + + /** + * Create a new ScalarStatNode. + * @param s The ScalarStat to place in a node. + */ + template <int N> + Temp(const Average<N> &s) + : node(new ScalarStatNode(s.statData())) { } + + /** + * Create a new VectorStatNode. + * @param s The VectorStat to place in a node. + */ + template <int N> + Temp(const Vector<N> &s) + : node(new VectorStatNode(s.statData())) { } + + /** + * + */ + Temp(const Formula &f) + : node(new FormulaNode(f)) { } + + /** + * Create a new ScalarProxyNode. + * @param p The ScalarProxy to place in a node. + */ + template <class Stat> + Temp(const ScalarProxy<Stat> &p) + : node(new ScalarProxyNode<Stat>(p)) { } + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(signed char value) + : node(new ConstNode<signed char>(value)) {} + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(unsigned char value) + : node(new ConstNode<unsigned char>(value)) {} + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(signed short value) + : node(new ConstNode<signed short>(value)) {} + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(unsigned short value) + : node(new ConstNode<unsigned short>(value)) {} + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(signed int value) + : node(new ConstNode<signed int>(value)) {} + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(unsigned int value) + : node(new ConstNode<unsigned int>(value)) {} + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(signed long value) + : node(new ConstNode<signed long>(value)) {} + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(unsigned long value) + : node(new ConstNode<unsigned long>(value)) {} + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(signed long long value) + : node(new ConstNode<signed long long>(value)) {} + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(unsigned long long value) + : node(new ConstNode<unsigned long long>(value)) {} + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(float value) + : node(new ConstNode<float>(value)) {} + + /** + * Create a ConstNode + * @param value The value of the const node. + */ + Temp(double value) + : node(new ConstNode<double>(value)) {} +}; + + +/** + * @} + */ + +void check(); +void reset(); +void registerResetCallback(Callback *cb); + +inline Temp +operator+(Temp l, Temp r) +{ + return NodePtr(new BinaryNode<std::plus<Result> >(l, r)); +} + +inline Temp +operator-(Temp l, Temp r) +{ + return NodePtr(new BinaryNode<std::minus<Result> >(l, r)); +} + +inline Temp +operator*(Temp l, Temp r) +{ + return NodePtr(new BinaryNode<std::multiplies<Result> >(l, r)); +} + +inline Temp +operator/(Temp l, Temp r) +{ + return NodePtr(new BinaryNode<std::divides<Result> >(l, r)); +} + +inline Temp +operator-(Temp l) +{ + return NodePtr(new UnaryNode<std::negate<Result> >(l)); +} + +template <typename T> +inline Temp +constant(T val) +{ + return NodePtr(new ConstNode<T>(val)); +} + +inline Temp +sum(Temp val) +{ + return NodePtr(new SumNode<std::plus<Result> >(val)); +} + +/* namespace Stats */ } + +#endif // __BASE_STATISTICS_HH__ diff --git a/src/base/stats/events.cc b/src/base/stats/events.cc new file mode 100644 index 000000000..6ecc5434c --- /dev/null +++ b/src/base/stats/events.cc @@ -0,0 +1,171 @@ +/* + * 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: Nathan Binkert + */ + +#include <vector> + +#include "base/stats/events.hh" + +#if USE_MYSQL +#include "base/cprintf.hh" +#include "base/misc.hh" +#include "base/mysql.hh" +#include "base/stats/mysql.hh" +#include "base/stats/mysql_run.hh" +#include "base/str.hh" +#endif + +#include "base/match.hh" +#include "sim/host.hh" +#include "sim/sim_object.hh" +#include "sim/root.hh" + +using namespace std; + +namespace Stats { + +Tick EventStart = ULL(0x7fffffffffffffff); + +ObjectMatch event_ignore; + +#if USE_MYSQL +class InsertEvent +{ + private: + char *query; + int size; + bool first; + static const int maxsize = 1024*1024; + + typedef map<string, uint32_t> event_map_t; + event_map_t events; + + MySQL::Connection &mysql; + uint16_t run; + + public: + InsertEvent() + : mysql(MySqlDB.conn()), run(MySqlDB.run()) + { + query = new char[maxsize + 1]; + size = 0; + first = true; + flush(); + } + ~InsertEvent() + { + flush(); + } + + void flush(); + void insert(const string &stat); +}; + +void +InsertEvent::insert(const string &stat) +{ + assert(mysql.connected()); + + event_map_t::iterator i = events.find(stat); + uint32_t event; + if (i == events.end()) { + mysql.query( + csprintf("SELECT en_id " + "from event_names " + "where en_name=\"%s\"", + stat)); + + MySQL::Result result = mysql.store_result(); + if (!result) + panic("could not get a run\n%s\n", mysql.error); + + assert(result.num_fields() == 1); + MySQL::Row row = result.fetch_row(); + if (row) { + if (!to_number(row[0], event)) + panic("invalid event id: %s\n", row[0]); + } else { + mysql.query( + csprintf("INSERT INTO " + "event_names(en_name)" + "values(\"%s\")", + stat)); + + if (mysql.error) + panic("could not get a run\n%s\n", mysql.error); + + event = mysql.insert_id(); + } + } else { + event = (*i).second; + } + + if (size + 1024 > maxsize) + flush(); + + if (!first) { + query[size++] = ','; + query[size] = '\0'; + } + + first = false; + + size += sprintf(query + size, "(%u,%u,%llu)", + event, run, (unsigned long long)curTick); +} + +void +InsertEvent::flush() +{ + static const char query_header[] = "INSERT INTO " + "events(ev_event, ev_run, ev_tick)" + "values"; + + if (size) { + MySQL::Connection &mysql = MySqlDB.conn(); + assert(mysql.connected()); + mysql.query(query); + } + + query[0] = '\0'; + size = sizeof(query_header); + first = true; + memcpy(query, query_header, size); +} + +void +__event(const string &stat) +{ + static InsertEvent event; + event.insert(stat); +} + +#endif + +/* namespace Stats */ } diff --git a/src/base/stats/events.hh b/src/base/stats/events.hh new file mode 100644 index 000000000..b09b91c7c --- /dev/null +++ b/src/base/stats/events.hh @@ -0,0 +1,68 @@ +/* + * 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: Nathan Binkert + */ + +#ifndef __BASE_STATS_EVENTS_HH__ +#define __BASE_STATS_EVENTS_HH__ + +#include <string> + +#include "base/trace.hh" +#include "config/use_mysql.hh" + +namespace Stats { + +extern Tick EventStart; + +#if USE_MYSQL +void __event(const std::string &stat); +bool MySqlConnected(); +#endif + +bool ignoreEvent(const std::string &name); + +inline void +recordEvent(const std::string &stat) +{ + if (EventStart > curTick) + return; + + DPRINTF(StatEvents, "Statistics Event: %s\n", stat); + +#if USE_MYSQL + if (!MySqlConnected()) + return; + + __event(stat); +#endif +} + +/* namespace Stats */ } + +#endif // __BASE_STATS_EVENTS_HH__ diff --git a/src/base/stats/flags.hh b/src/base/stats/flags.hh new file mode 100644 index 000000000..ada1a4a87 --- /dev/null +++ b/src/base/stats/flags.hh @@ -0,0 +1,75 @@ +/* + * 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: Nathan Binkert + */ + +#ifndef __BASE_STATS_FLAGS_HH__ +#define __BASE_STATS_FLAGS_HH__ +namespace Stats { + +/** + * Define the storage for format flags. + * @todo Can probably shrink this. + */ +typedef u_int32_t StatFlags; + +/** Nothing extra to print. */ +const StatFlags none = 0x00000000; +/** This Stat is Initialized */ +const StatFlags init = 0x00000001; +/** Print this stat. */ +const StatFlags print = 0x00000002; +/** Print the total. */ +const StatFlags total = 0x00000010; +/** Print the percent of the total that this entry represents. */ +const StatFlags pdf = 0x00000020; +/** Print the cumulative percentage of total upto this entry. */ +const StatFlags cdf = 0x00000040; +/** Print the distribution. */ +const StatFlags dist = 0x00000080; +/** Don't print if this is zero. */ +const StatFlags nozero = 0x00000100; +/** Don't print if this is NAN */ +const StatFlags nonan = 0x00000200; +/** Used for SS compatability. */ +const StatFlags __substat = 0x80000000; + +/** Mask of flags that can't be set directly */ +const StatFlags __reserved = init | print | __substat; + +enum DisplayMode +{ + mode_m5, + mode_simplescalar +}; + +extern DisplayMode DefaultMode; + +/* namespace Stats */ } + +#endif // __BASE_STATS_FLAGS_HH__ diff --git a/src/base/stats/mysql.cc b/src/base/stats/mysql.cc new file mode 100644 index 000000000..0fb31f4ce --- /dev/null +++ b/src/base/stats/mysql.cc @@ -0,0 +1,828 @@ +/* + * 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: Nathan Binkert + */ + +#include <cassert> +#include <map> +#include <sstream> +#include <string> +#include <vector> + +#include "base/misc.hh" +#include "base/mysql.hh" +#include "base/statistics.hh" +#include "base/stats/flags.hh" +#include "base/stats/mysql.hh" +#include "base/stats/mysql_run.hh" +#include "base/stats/statdb.hh" +#include "base/stats/types.hh" +#include "base/str.hh" +#include "sim/host.hh" + +using namespace std; + +namespace Stats { + +MySqlRun MySqlDB; + +bool +MySqlConnected() +{ + return MySqlDB.connected(); +} + +void +MySqlRun::connect(const string &host, const string &user, const string &passwd, + const string &db, const string &name, const string &sample, + const string &project) +{ + if (connected()) + panic("can only get one database connection at this time!"); + + mysql.connect(host, user, passwd, db); + if (mysql.error) + panic("could not connect to database server\n%s\n", mysql.error); + + if (mysql.autocommit(false)) + panic("could not set autocommit\n%s\n", mysql.error); + + remove(name); + //cleanup(); + setup(name, sample, user, project); +} + +void +MySqlRun::setup(const string &name, const string &sample, const string &user, + const string &project) +{ + assert(mysql.connected()); + + stringstream insert; + ccprintf(insert, + "INSERT INTO " + "runs(rn_name,rn_sample,rn_user,rn_project,rn_date,rn_expire)" + "values(\"%s\", \"%s\", \"%s\", \"%s\", NOW()," + "DATE_ADD(CURDATE(), INTERVAL 31 DAY))", + name, sample, user, project); + + mysql.query(insert); + if (mysql.error) + panic("could not get a run\n%s\n", mysql.error); + + run_id = mysql.insert_id(); + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); +} + +void +MySqlRun::remove(const string &name) +{ + assert(mysql.connected()); + stringstream sql; + ccprintf(sql, "DELETE FROM runs WHERE rn_name=\"%s\"", name); + mysql.query(sql); + if (mysql.error) + panic("could not delete run\n%s\n", mysql.error); + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); +} + +void +MySqlRun::cleanup() +{ + assert(mysql.connected()); + + mysql.query("DELETE data " + "FROM data " + "LEFT JOIN runs ON dt_run=rn_id " + "WHERE rn_id IS NULL"); + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); + + mysql.query("DELETE formula_ref " + "FROM formula_ref " + "LEFT JOIN runs ON fr_run=rn_id " + "WHERE rn_id IS NULL"); + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); + + mysql.query("DELETE formulas " + "FROM formulas " + "LEFT JOIN formula_ref ON fm_stat=fr_stat " + "WHERE fr_stat IS NULL"); + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); + + mysql.query("DELETE stats " + "FROM stats " + "LEFT JOIN data ON st_id=dt_stat " + "WHERE dt_stat IS NULL"); + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); + + mysql.query("DELETE subdata " + "FROM subdata " + "LEFT JOIN data ON sd_stat=dt_stat " + "WHERE dt_stat IS NULL"); + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); + + mysql.query("DELETE events" + "FROM events" + "LEFT JOIN runs ON ev_run=rn_id" + "WHERE rn_id IS NULL"); + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); + + mysql.query("DELETE event_names" + "FROM event_names" + "LEFT JOIN events ON en_id=ev_event" + "WHERE ev_event IS NULL"); + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); +} + +void +SetupStat::init() +{ + name = ""; + descr = ""; + type = ""; + print = false; + prereq = 0; + prec = -1; + nozero = false; + nonan = false; + total = false; + pdf = false; + cdf = false; + min = 0; + max = 0; + bktsize = 0; + size = 0; +} + +unsigned +SetupStat::setup() +{ + MySQL::Connection &mysql = MySqlDB.conn(); + + stringstream insert; + ccprintf(insert, + "INSERT INTO " + "stats(st_name, st_descr, st_type, st_print, st_prereq, " + "st_prec, st_nozero, st_nonan, st_total, st_pdf, st_cdf, " + "st_min, st_max, st_bktsize, st_size)" + "values(\"%s\",\"%s\",\"%s\"," + " %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)", + name, descr, type, print, prereq, (int)prec, nozero, nonan, + total, pdf, cdf, + min, max, bktsize, size); + + mysql.query(insert); + if (!mysql.error) { + int id = mysql.insert_id(); + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); + return id; + } + + stringstream select; + ccprintf(select, "SELECT * FROM stats WHERE st_name=\"%s\"", name); + + mysql.query(select); + MySQL::Result result = mysql.store_result(); + if (!result) + panic("could not find stat\n%s\n", mysql.error); + + assert(result.num_fields() == 16); + MySQL::Row row = result.fetch_row(); + if (!row) + panic("could not get stat row\n%s\n", mysql.error); + + bool tb; + int8_t ti8; + uint16_t tu16; + int64_t ti64; + uint64_t tu64; + + if (name != (char *)row[1]) + panic("failed stat check on %s:name. %s != %s\n", + name, name, row[1]); + + if (descr != (char *)row[2]) + panic("failed stat check on %s:descr. %s != %s\n", + name, descr, row[2]); + + if (type != (char *)row[3]) + panic("failed stat check on %s:type. %s != %s\n", + name, type, row[3]); + + if (!to_number(row[4], tb) || print != tb) + panic("failed stat check on %s:print. %d != %d\n", + name, print, tb); + + if (!to_number(row[6], ti8) || prec != ti8) + panic("failed stat check on %s:prec. %d != %d\n", + name, prec, ti8); + + if (!to_number(row[7], tb) || nozero != tb) + panic("failed stat check on %s:nozero. %d != %d\n", + name, nozero, tb); + + if (!to_number(row[8], tb) || nonan != tb) + panic("failed stat check on %s:nonan. %d != %d\n", + name, nonan, tb); + + if (!to_number(row[9], tb) || total != tb) + panic("failed stat check on %s:total. %d != %d\n", + name, total, tb); + + if (!to_number(row[10], tb) || pdf != tb) + panic("failed stat check on %s:pdf. %d != %d\n", + name, pdf, tb); + + if (!to_number(row[11], tb) || cdf != tb) + panic("failed stat check on %s:cdf. %d != %d\n", + name, cdf, tb); + + if (!to_number(row[12], ti64) || min != ti64) + panic("failed stat check on %s:min. %d != %d\n", + name, min, ti64); + + if (!to_number(row[13], ti64) || max != ti64) + panic("failed stat check on %s:max. %d != %d\n", + name, max, ti64); + + if (!to_number(row[14], tu64) || bktsize != tu64) + panic("failed stat check on %s:bktsize. %d != %d\n", + name, bktsize, tu64); + + if (!to_number(row[15], tu16) || size != tu16) + panic("failed stat check on %s:size. %d != %d\n", + name, size, tu16); + + to_number(row[5], prereq); + uint16_t statid; + to_number(row[0], statid); + return statid; +} + +InsertData::InsertData() +{ + query = new char[maxsize + 1]; + size = 0; + flush(); +} + +InsertData::~InsertData() +{ + delete [] query; +} + +void +InsertData::flush() +{ + if (size) { + MySQL::Connection &mysql = MySqlDB.conn(); + assert(mysql.connected()); + mysql.query(query); + if (mysql.error) + panic("could not insert data\n%s\n", mysql.error); + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); + } + + query[0] = '\0'; + size = 0; + first = true; + strcpy(query, "INSERT INTO " + "data(dt_stat,dt_x,dt_y,dt_run,dt_tick,dt_data) " + "values"); + size = strlen(query); +} + +void +InsertData::insert() +{ + if (size + 1024 > maxsize) + flush(); + + if (!first) { + query[size++] = ','; + query[size] = '\0'; + } + + first = false; + + size += sprintf(query + size, "(%u,%d,%d,%u,%llu,\"%f\")", + stat, x, y, MySqlDB.run(), (unsigned long long)tick, + data); +} + +struct InsertSubData +{ + uint16_t stat; + int16_t x; + int16_t y; + string name; + string descr; + + void setup(); +}; + +void +InsertSubData::setup() +{ + MySQL::Connection &mysql = MySqlDB.conn(); + assert(mysql.connected()); + stringstream insert; + ccprintf(insert, + "INSERT INTO subdata(sd_stat,sd_x,sd_y,sd_name,sd_descr) " + "values(%d,%d,%d,\"%s\",\"%s\")", + stat, x, y, name, descr); + + mysql.query(insert); +// if (mysql.error) +// panic("could not insert subdata\n%s\n", mysql.error); + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); +} + +void +InsertFormula(uint16_t stat, const string &formula) +{ + MySQL::Connection &mysql = MySqlDB.conn(); + assert(mysql.connected()); + stringstream insert_formula; + ccprintf(insert_formula, + "INSERT INTO formulas(fm_stat,fm_formula) values(%d, \"%s\")", + stat, formula); + + mysql.query(insert_formula); +// if (mysql.error) +// panic("could not insert formula\n%s\n", mysql.error); + + stringstream insert_ref; + ccprintf(insert_ref, + "INSERT INTO formula_ref(fr_stat,fr_run) values(%d, %d)", + stat, MySqlDB.run()); + + mysql.query(insert_ref); +// if (mysql.error) +// panic("could not insert formula reference\n%s\n", mysql.error); + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); +} + +void +UpdatePrereq(uint16_t stat, uint16_t prereq) +{ + MySQL::Connection &mysql = MySqlDB.conn(); + assert(mysql.connected()); + stringstream update; + ccprintf(update, "UPDATE stats SET st_prereq=%d WHERE st_id=%d", + prereq, stat); + mysql.query(update); + if (mysql.error) + panic("could not update prereq\n%s\n", mysql.error); + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); +} + +void +MySql::configure() +{ + /* + * set up all stats! + */ + using namespace Database; + + MySQL::Connection &mysql = MySqlDB.conn(); + + stat_list_t::const_iterator i, end = stats().end(); + for (i = stats().begin(); i != end; ++i) { + (*i)->visit(*this); + } + + for (i = stats().begin(); i != end; ++i) { + StatData *data = *i; + if (data->prereq) { + uint16_t stat_id = find(data->id); + uint16_t prereq_id = find(data->prereq->id); + assert(stat_id && prereq_id); + + UpdatePrereq(stat_id, prereq_id); + } + } + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); + + configured = true; +} + + +bool +MySql::configure(const StatData &data, string type) +{ + stat.init(); + stat.name = data.name; + stat.descr = data.desc; + stat.type = type; + stat.print = data.flags & print; + stat.prec = data.precision; + stat.nozero = data.flags & nozero; + stat.nonan = data.flags & nonan; + stat.total = data.flags & total; + stat.pdf = data.flags & pdf; + stat.cdf = data.flags & cdf; + + return stat.print; +} + +void +MySql::configure(const ScalarData &data) +{ + if (!configure(data, "SCALAR")) + return; + + insert(data.id, stat.setup()); +} + +void +MySql::configure(const VectorData &data) +{ + if (!configure(data, "VECTOR")) + return; + + uint16_t statid = stat.setup(); + + if (!data.subnames.empty()) { + InsertSubData subdata; + subdata.stat = statid; + subdata.y = 0; + for (int i = 0; i < data.subnames.size(); ++i) { + subdata.x = i; + subdata.name = data.subnames[i]; + subdata.descr = data.subdescs.empty() ? "" : data.subdescs[i]; + + if (!subdata.name.empty() || !subdata.descr.empty()) + subdata.setup(); + } + } + + insert(data.id, statid); +} + +void +MySql::configure(const DistData &data) +{ + if (!configure(data, "DIST")) + return; + + if (!data.data.fancy) { + stat.size = data.data.size; + stat.min = data.data.min; + stat.max = data.data.max; + stat.bktsize = data.data.bucket_size; + } + insert(data.id, stat.setup()); +} + +void +MySql::configure(const VectorDistData &data) +{ + if (!configure(data, "VECTORDIST")) + return; + + if (!data.data[0].fancy) { + stat.size = data.data[0].size; + stat.min = data.data[0].min; + stat.max = data.data[0].max; + stat.bktsize = data.data[0].bucket_size; + } + + uint16_t statid = stat.setup(); + + if (!data.subnames.empty()) { + InsertSubData subdata; + subdata.stat = statid; + subdata.y = 0; + for (int i = 0; i < data.subnames.size(); ++i) { + subdata.x = i; + subdata.name = data.subnames[i]; + subdata.descr = data.subdescs.empty() ? "" : data.subdescs[i]; + if (!subdata.name.empty() || !subdata.descr.empty()) + subdata.setup(); + } + } + + insert(data.id, statid); +} + +void +MySql::configure(const Vector2dData &data) +{ + if (!configure(data, "VECTOR2D")) + return; + + uint16_t statid = stat.setup(); + + if (!data.subnames.empty()) { + InsertSubData subdata; + subdata.stat = statid; + subdata.y = -1; + for (int i = 0; i < data.subnames.size(); ++i) { + subdata.x = i; + subdata.name = data.subnames[i]; + subdata.descr = data.subdescs.empty() ? "" : data.subdescs[i]; + if (!subdata.name.empty() || !subdata.descr.empty()) + subdata.setup(); + } + } + + if (!data.y_subnames.empty()) { + InsertSubData subdata; + subdata.stat = statid; + subdata.x = -1; + subdata.descr = ""; + for (int i = 0; i < data.y_subnames.size(); ++i) { + subdata.y = i; + subdata.name = data.y_subnames[i]; + if (!subdata.name.empty()) + subdata.setup(); + } + } + + insert(data.id, statid); +} + +void +MySql::configure(const FormulaData &data) +{ + configure(data, "FORMULA"); + insert(data.id, stat.setup()); + InsertFormula(find(data.id), data.str()); +} + +bool +MySql::valid() const +{ + return MySqlDB.connected(); +} + +void +MySql::output() +{ + using namespace Database; + assert(valid()); + + if (!configured) + configure(); + + // store sample # + newdata.tick = curTick; + + MySQL::Connection &mysql = MySqlDB.conn(); + + Database::stat_list_t::const_iterator i, end = Database::stats().end(); + for (i = Database::stats().begin(); i != end; ++i) { + StatData *stat = *i; + stat->visit(*this); + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); + } + + newdata.flush(); +} + +void +MySql::output(const ScalarData &data) +{ + if (!(data.flags & print)) + return; + + newdata.stat = find(data.id); + newdata.x = 0; + newdata.y = 0; + newdata.data = data.value(); + + newdata.insert(); +} + +void +MySql::output(const VectorData &data) +{ + if (!(data.flags & print)) + return; + + newdata.stat = find(data.id); + newdata.y = 0; + + const VCounter &cvec = data.value(); + int size = data.size(); + for (int x = 0; x < size; x++) { + newdata.x = x; + newdata.data = cvec[x]; + newdata.insert(); + } +} + +void +MySql::output(const DistDataData &data) +{ + const int db_sum = -1; + const int db_squares = -2; + const int db_samples = -3; + const int db_min_val = -4; + const int db_max_val = -5; + const int db_underflow = -6; + const int db_overflow = -7; + + newdata.x = db_sum; + newdata.data = data.sum; + newdata.insert(); + + newdata.x = db_squares; + newdata.data = data.squares; + newdata.insert(); + + newdata.x = db_samples; + newdata.data = data.samples; + newdata.insert(); + + if (data.samples && !data.fancy) { + newdata.x = db_min_val; + newdata.data = data.min_val; + newdata.insert(); + + newdata.x = db_max_val; + newdata.data = data.max_val; + newdata.insert(); + + newdata.x = db_underflow; + newdata.data = data.underflow; + newdata.insert(); + + newdata.x = db_overflow; + newdata.data = data.overflow; + newdata.insert(); + + int size = data.cvec.size(); + for (int x = 0; x < size; x++) { + newdata.x = x; + newdata.data = data.cvec[x]; + newdata.insert(); + } + } +} + + +void +MySql::output(const DistData &data) +{ + if (!(data.flags & print)) + return; + + newdata.stat = find(data.id); + newdata.y = 0; + output(data.data); +} + +void +MySql::output(const VectorDistData &data) +{ + if (!(data.flags & print)) + return; + + newdata.stat = find(data.id); + + int size = data.data.size(); + for (int y = 0; y < size; ++y) { + newdata.y = y; + output(data.data[y]); + } +} + +void +MySql::output(const Vector2dData &data) +{ + if (!(data.flags & print)) + return; + + newdata.stat = find(data.id); + + int index = 0; + for (int x = 0; x < data.x; x++) { + newdata.x = x; + for (int y = 0; y < data.y; y++) { + newdata.y = y; + newdata.data = data.cvec[index++]; + newdata.insert(); + } + } +} + +void +MySql::output(const FormulaData &data) +{ +} + +/* + * Implement the visitor + */ +void +MySql::visit(const ScalarData &data) +{ + if (!configured) + configure(data); + else + output(data); +} + +void +MySql::visit(const VectorData &data) +{ + if (!configured) + configure(data); + else + output(data); +} + +void +MySql::visit(const DistData &data) +{ + return; + if (!configured) + configure(data); + else + output(data); +} + +void +MySql::visit(const VectorDistData &data) +{ + return; + if (!configured) + configure(data); + else + output(data); +} + +void +MySql::visit(const Vector2dData &data) +{ + return; + if (!configured) + configure(data); + else + output(data); +} + +void +MySql::visit(const FormulaData &data) +{ + if (!configured) + configure(data); + else + output(data); +} + +/* namespace Stats */ } diff --git a/src/base/stats/mysql.hh b/src/base/stats/mysql.hh new file mode 100644 index 000000000..50f7d9e97 --- /dev/null +++ b/src/base/stats/mysql.hh @@ -0,0 +1,154 @@ +/* + * 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: Nathan Binkert + */ + +#ifndef __BASE_STATS_MYSQL_HH__ +#define __BASE_STATS_MYSQL_HH__ + +#include <map> +#include <string> + +#include "base/stats/output.hh" + +namespace MySQL { class Connection; } +namespace Stats { + +class DistDataData; +class MySqlRun; +bool MySqlConnected(); +extern MySqlRun MySqlDB; + +struct SetupStat +{ + std::string name; + std::string descr; + std::string type; + bool print; + uint16_t prereq; + int8_t prec; + bool nozero; + bool nonan; + bool total; + bool pdf; + bool cdf; + double min; + double max; + double bktsize; + uint16_t size; + + void init(); + unsigned setup(); +}; + +class InsertData +{ + private: + char *query; + int size; + bool first; + static const int maxsize = 1024*1024; + + public: + MySqlRun *run; + + public: + uint64_t tick; + double data; + uint16_t stat; + int16_t x; + int16_t y; + + public: + InsertData(); + ~InsertData(); + + void flush(); + void insert(); +}; + +class MySql : public Output +{ + protected: + SetupStat stat; + InsertData newdata; + std::list<FormulaData *> formulas; + bool configured; + + protected: + std::map<int, int> idmap; + + void insert(int sim_id, int db_id) + { + using namespace std; + idmap.insert(make_pair(sim_id, db_id)); + } + + int find(int sim_id) + { + using namespace std; + map<int,int>::const_iterator i = idmap.find(sim_id); + assert(i != idmap.end()); + return (*i).second; + } + public: + // Implement Visit + virtual void visit(const ScalarData &data); + virtual void visit(const VectorData &data); + virtual void visit(const DistData &data); + virtual void visit(const VectorDistData &data); + virtual void visit(const Vector2dData &data); + virtual void visit(const FormulaData &data); + + // Implement Output + virtual bool valid() const; + virtual void output(); + + protected: + // Output helper + void output(const DistDataData &data); + void output(const ScalarData &data); + void output(const VectorData &data); + void output(const DistData &data); + void output(const VectorDistData &data); + void output(const Vector2dData &data); + void output(const FormulaData &data); + + void configure(); + bool configure(const StatData &data, std::string type); + void configure(const ScalarData &data); + void configure(const VectorData &data); + void configure(const DistData &data); + void configure(const VectorDistData &data); + void configure(const Vector2dData &data); + void configure(const FormulaData &data); +}; + +/* namespace Stats */ } + +#endif // __BASE_STATS_MYSQL_HH__ diff --git a/src/base/stats/mysql_run.hh b/src/base/stats/mysql_run.hh new file mode 100644 index 000000000..487224551 --- /dev/null +++ b/src/base/stats/mysql_run.hh @@ -0,0 +1,67 @@ +/* + * 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: Nathan Binkert + */ + +#ifndef __BASE_STATS_MYSQL_RUN_HH__ +#define __BASE_STATS_MYSQL_RUN_HH__ + +#include <string> + +#include "base/mysql.hh" +#include "sim/host.hh" + +namespace Stats { + +struct MySqlRun +{ + private: + MySQL::Connection mysql; + uint16_t run_id; + + protected: + void setup(const std::string &name, const std::string &sample, + const std::string &user, const std::string &project); + + void remove(const std::string &name); + void cleanup(); + + public: + bool connected() const { return mysql.connected(); } + void connect(const std::string &host, const std::string &user, + const std::string &passwd, const std::string &db, + const std::string &name, const std::string &sample, + const std::string &project); + + MySQL::Connection &conn() { return mysql; } + uint16_t run() const { return run_id; } +}; + +/* namespace Stats */ } + +#endif // __BASE_STATS_MYSQL_RUN_HH__ diff --git a/src/base/stats/output.hh b/src/base/stats/output.hh new file mode 100644 index 000000000..4fe93791f --- /dev/null +++ b/src/base/stats/output.hh @@ -0,0 +1,49 @@ +/* + * 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: Nathan Binkert + */ + +#ifndef __BASE_STATS_OUTPUT_HH__ +#define __BASE_STATS_OUTPUT_HH__ + +#include <string> + +#include "base/stats/visit.hh" + +namespace Stats { + +struct Output : public Visit +{ + inline void operator()() { output(); } + virtual void output() = 0; + virtual bool valid() const = 0; +}; + +/* namespace Stats */ } + +#endif // __BASE_STATS_OUTPUT_HH__ diff --git a/src/base/stats/statdb.cc b/src/base/stats/statdb.cc new file mode 100644 index 000000000..f9136807a --- /dev/null +++ b/src/base/stats/statdb.cc @@ -0,0 +1,83 @@ +/* + * 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: Nathan Binkert + */ + +#include "base/misc.hh" +#include "base/trace.hh" +#include "base/statistics.hh" +#include "base/stats/statdb.hh" + +using namespace std; + +namespace Stats { +namespace Database { + +StatData * +find(void *stat) +{ + stat_map_t::const_iterator i = map().find(stat); + + if (i == map().end()) + return NULL; + + return (*i).second; +} + +void +regStat(void *stat, StatData *data) +{ + if (map().find(stat) != map().end()) + panic("shouldn't register stat twice!"); + + stats().push_back(data); + +#ifndef NDEBUG + pair<stat_map_t::iterator, bool> result = +#endif + map().insert(make_pair(stat, data)); + assert(result.second && "this should never fail"); + assert(map().find(stat) != map().end()); +} + +void +regPrint(void *stat) +{ + StatData *data = find(stat); + assert(data); + data->flags |= print; +} + +TheDatabase &db() +{ + static TheDatabase db; + return db; +} + +/* namespace Database */ } +/* namespace Stats */ } diff --git a/src/base/stats/statdb.hh b/src/base/stats/statdb.hh new file mode 100644 index 000000000..a5b9be7eb --- /dev/null +++ b/src/base/stats/statdb.hh @@ -0,0 +1,70 @@ +/* + * 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: Nathan Binkert + */ + +#ifndef __BASE_STATS_STATDB_HH__ +#define __BASE_STATS_STATDB_HH__ + +#include <iosfwd> +#include <list> +#include <map> +#include <string> + +class Python; + +namespace Stats { + +class StatData; + +namespace Database { + +typedef std::map<void *, StatData *> stat_map_t; +typedef std::list<StatData *> stat_list_t; + +// We wrap the database in a struct to make sure it is built in time. +struct TheDatabase +{ + stat_map_t map; + stat_list_t stats; +}; + +TheDatabase &db(); +inline stat_map_t &map() { return db().map; } +inline stat_list_t &stats() { return db().stats; } + +StatData *find(void *stat); +void regStat(void *stat, StatData *data); +void regPrint(void *stat); + +inline std::string name() { return "Statistics Database"; } + +/* namespace Database */ } +/* namespace Stats */ } + +#endif // __BASE_STATS_STATDB_HH__ diff --git a/src/base/stats/text.cc b/src/base/stats/text.cc new file mode 100644 index 000000000..c4448efc9 --- /dev/null +++ b/src/base/stats/text.cc @@ -0,0 +1,724 @@ +/* + * 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: Nathan Binkert + */ + +#if defined(__APPLE__) +#define _GLIBCPP_USE_C99 1 +#endif + +#include <iostream> +#include <sstream> +#include <fstream> +#include <string> + +#include "base/misc.hh" +#include "base/statistics.hh" +#include "base/stats/statdb.hh" +#include "base/stats/text.hh" +#include "base/stats/visit.hh" + +using namespace std; + +#ifndef NAN +float __nan(); +/** Define Not a number. */ +#define NAN (__nan()) +/** Need to define __nan() */ +#define __M5_NAN +#endif + +#ifdef __M5_NAN +float +__nan() +{ + union { + uint32_t ui; + float f; + } nan; + + nan.ui = 0x7fc00000; + return nan.f; +} +#endif + +namespace Stats { + +Text::Text() + : mystream(false), stream(NULL), compat(false), descriptions(false) +{ +} + +Text::Text(std::ostream &stream) + : mystream(false), stream(NULL), compat(false), descriptions(false) +{ + open(stream); +} + +Text::Text(const std::string &file) + : mystream(false), stream(NULL), compat(false), descriptions(false) +{ + open(file); +} + + +Text::~Text() +{ + if (mystream) { + assert(stream); + delete stream; + } +} + +void +Text::open(std::ostream &_stream) +{ + if (stream) + panic("stream already set!"); + + mystream = false; + stream = &_stream; + assert(valid()); +} + +void +Text::open(const std::string &file) +{ + if (stream) + panic("stream already set!"); + + mystream = true; + stream = new ofstream(file.c_str(), ios::trunc); + assert(valid()); +} + +bool +Text::valid() const +{ + return stream != NULL; +} + +void +Text::output() +{ + using namespace Database; + + ccprintf(*stream, "\n---------- Begin Simulation Statistics ----------\n"); + stat_list_t::const_iterator i, end = stats().end(); + for (i = stats().begin(); i != end; ++i) + (*i)->visit(*this); + ccprintf(*stream, "\n---------- End Simulation Statistics ----------\n"); + stream->flush(); +} + +bool +Text::noOutput(const StatData &data) +{ + if (!(data.flags & print)) + return true; + + if (data.prereq && data.prereq->zero()) + return true; + + return false; +} + +string +ValueToString(Result value, int precision, bool compat) +{ + stringstream val; + + if (!isnan(value)) { + if (precision != -1) + val.precision(precision); + else if (value == rint(value)) + val.precision(0); + + val.unsetf(ios::showpoint); + val.setf(ios::fixed); + val << value; + } else { + val << (compat ? "<err: div-0>" : "no value"); + } + + return val.str(); +} + +struct ScalarPrint +{ + Result value; + string name; + string desc; + StatFlags flags; + bool compat; + bool descriptions; + int precision; + Result pdf; + Result cdf; + + void operator()(ostream &stream) const; +}; + +void +ScalarPrint::operator()(ostream &stream) const +{ + if (flags & nozero && value == 0.0 || + flags & nonan && isnan(value)) + return; + + stringstream pdfstr, cdfstr; + + if (!isnan(pdf)) + ccprintf(pdfstr, "%.2f%%", pdf * 100.0); + + if (!isnan(cdf)) + ccprintf(cdfstr, "%.2f%%", cdf * 100.0); + + if (compat && flags & __substat) { + ccprintf(stream, "%32s %12s %10s %10s", name, + ValueToString(value, precision, compat), pdfstr, cdfstr); + } else { + ccprintf(stream, "%-40s %12s %10s %10s", name, + ValueToString(value, precision, compat), pdfstr, cdfstr); + } + + if (descriptions) { + if (!desc.empty()) + ccprintf(stream, " # %s", desc); + } + stream << endl; +} + +struct VectorPrint +{ + string name; + string desc; + vector<string> subnames; + vector<string> subdescs; + StatFlags flags; + bool compat; + bool descriptions; + int precision; + VResult vec; + Result total; + + void operator()(ostream &stream) const; +}; + +void +VectorPrint::operator()(std::ostream &stream) const +{ + int _size = vec.size(); + Result _total = 0.0; + + if (flags & (pdf | cdf)) { + for (int i = 0; i < _size; ++i) { + _total += vec[i]; + } + } + + string base = name + (compat ? "_" : "::"); + + ScalarPrint print; + print.name = name; + print.desc = desc; + print.precision = precision; + print.descriptions = descriptions; + print.flags = flags; + print.pdf = NAN; + print.cdf = NAN; + + bool havesub = !subnames.empty(); + + if (_size == 1) { + print.value = vec[0]; + print(stream); + } else if (!compat) { + for (int i = 0; i < _size; ++i) { + if (havesub && (i >= subnames.size() || subnames[i].empty())) + continue; + + print.name = base + (havesub ? subnames[i] : to_string(i)); + print.desc = subdescs.empty() ? desc : subdescs[i]; + print.value = vec[i]; + + if (_total && (flags & pdf)) { + print.pdf = vec[i] / _total; + print.cdf += print.pdf; + } + + print(stream); + } + + if (flags & ::Stats::total) { + print.name = base + "total"; + print.desc = desc; + print.value = total; + print(stream); + } + } else { + if (flags & ::Stats::total) { + print.value = total; + print(stream); + } + + Result _pdf = 0.0; + Result _cdf = 0.0; + if (flags & dist) { + ccprintf(stream, "%s.start_dist\n", name); + for (int i = 0; i < _size; ++i) { + print.name = havesub ? subnames[i] : to_string(i); + print.desc = subdescs.empty() ? desc : subdescs[i]; + print.flags |= __substat; + print.value = vec[i]; + + if (_total) { + _pdf = vec[i] / _total; + _cdf += _pdf; + } + + if (flags & pdf) + print.pdf = _pdf; + if (flags & cdf) + print.cdf = _cdf; + + print(stream); + } + ccprintf(stream, "%s.end_dist\n", name); + } else { + for (int i = 0; i < _size; ++i) { + if (havesub && subnames[i].empty()) + continue; + + print.name = base; + print.name += havesub ? subnames[i] : to_string(i); + print.desc = subdescs.empty() ? desc : subdescs[i]; + print.value = vec[i]; + + if (_total) { + _pdf = vec[i] / _total; + _cdf += _pdf; + } else { + _pdf = _cdf = NAN; + } + + if (flags & pdf) { + print.pdf = _pdf; + print.cdf = _cdf; + } + + print(stream); + } + } + } +} + +struct DistPrint +{ + string name; + string desc; + StatFlags flags; + bool compat; + bool descriptions; + int precision; + + Result min_val; + Result max_val; + Result underflow; + Result overflow; + VResult vec; + Result sum; + Result squares; + Result samples; + + Counter min; + Counter max; + Counter bucket_size; + int size; + bool fancy; + + void operator()(ostream &stream) const; +}; + +void +DistPrint::operator()(ostream &stream) const +{ + if (fancy) { + ScalarPrint print; + string base = name + (compat ? "_" : "::"); + + print.precision = precision; + print.flags = flags; + print.compat = compat; + print.descriptions = descriptions; + print.desc = desc; + print.pdf = NAN; + print.cdf = NAN; + + print.name = base + "mean"; + print.value = samples ? sum / samples : NAN; + print(stream); + + print.name = base + "stdev"; + print.value = samples ? sqrt((samples * squares - sum * sum) / + (samples * (samples - 1.0))) : NAN; + print(stream); + + print.name = "**Ignore: " + base + "TOT"; + print.value = samples; + print(stream); + return; + } + + assert(size == vec.size()); + + Result total = 0.0; + + total += underflow; + for (int i = 0; i < size; ++i) + total += vec[i]; + total += overflow; + + string base = name + (compat ? "." : "::"); + + ScalarPrint print; + print.desc = compat ? "" : desc; + print.flags = flags; + print.compat = compat; + print.descriptions = descriptions; + print.precision = precision; + print.pdf = NAN; + print.cdf = NAN; + + if (compat) { + ccprintf(stream, "%-42s", base + "start_dist"); + if (descriptions && !desc.empty()) + ccprintf(stream, " # %s", desc); + stream << endl; + } + + print.name = base + "samples"; + print.value = samples; + print(stream); + + print.name = base + "min_value"; + print.value = min_val; + print(stream); + + if (!compat || underflow > 0.0) { + print.name = base + "underflows"; + print.value = underflow; + if (!compat && total) { + print.pdf = underflow / total; + print.cdf += print.pdf; + } + print(stream); + } + + + if (!compat) { + for (int i = 0; i < size; ++i) { + stringstream namestr; + namestr << name; + + Counter low = i * bucket_size + min; + Counter high = ::min(low + bucket_size, max); + namestr << low; + if (low < high) + namestr << "-" << high; + + print.name = namestr.str(); + print.value = vec[i]; + if (total) { + print.pdf = vec[i] / total; + print.cdf += print.pdf; + } + print(stream); + } + + } else { + Counter _min; + Result _pdf; + Result _cdf = 0.0; + + print.flags = flags | __substat; + + for (int i = 0; i < size; ++i) { + if (flags & nozero && vec[i] == 0.0 || + flags & nonan && isnan(vec[i])) + continue; + + _min = i * bucket_size + min; + _pdf = vec[i] / total * 100.0; + _cdf += _pdf; + + + print.name = ValueToString(_min, 0, compat); + print.value = vec[i]; + print.pdf = (flags & pdf) ? _pdf : NAN; + print.cdf = (flags & cdf) ? _cdf : NAN; + print(stream); + } + + print.flags = flags; + } + + if (!compat || overflow > 0.0) { + print.name = base + "overflows"; + print.value = overflow; + if (!compat && total) { + print.pdf = overflow / total; + print.cdf += print.pdf; + } else { + print.pdf = NAN; + print.cdf = NAN; + } + print(stream); + } + + print.pdf = NAN; + print.cdf = NAN; + + if (!compat) { + print.name = base + "total"; + print.value = total; + print(stream); + } + + print.name = base + "max_value"; + print.value = max_val; + print(stream); + + if (!compat && samples != 0) { + print.name = base + "mean"; + print.value = sum / samples; + print(stream); + + print.name = base + "stdev"; + print.value = sqrt((samples * squares - sum * sum) / + (samples * (samples - 1.0))); + print(stream); + } + + if (compat) + ccprintf(stream, "%send_dist\n\n", base); +} + +void +Text::visit(const ScalarData &data) +{ + if (noOutput(data)) + return; + + ScalarPrint print; + print.value = data.result(); + print.name = data.name; + print.desc = data.desc; + print.flags = data.flags; + print.compat = compat; + print.descriptions = descriptions; + print.precision = data.precision; + print.pdf = NAN; + print.cdf = NAN; + + print(*stream); +} + +void +Text::visit(const VectorData &data) +{ + if (noOutput(data)) + return; + + int size = data.size(); + VectorPrint print; + + print.name = data.name; + print.desc = data.desc; + print.flags = data.flags; + print.compat = compat; + print.descriptions = descriptions; + print.precision = data.precision; + print.vec = data.result(); + print.total = data.total(); + + if (!data.subnames.empty()) { + for (int i = 0; i < size; ++i) { + if (!data.subnames[i].empty()) { + print.subnames = data.subnames; + print.subnames.resize(size); + for (int i = 0; i < size; ++i) { + if (!data.subnames[i].empty() && + !data.subdescs[i].empty()) { + print.subdescs = data.subdescs; + print.subdescs.resize(size); + break; + } + } + break; + } + } + } + + print(*stream); +} + +void +Text::visit(const Vector2dData &data) +{ + if (noOutput(data)) + return; + + bool havesub = false; + VectorPrint print; + + print.subnames = data.y_subnames; + print.flags = data.flags; + print.compat = compat; + print.descriptions = descriptions; + print.precision = data.precision; + + if (!data.subnames.empty()) { + for (int i = 0; i < data.x; ++i) + if (!data.subnames[i].empty()) + havesub = true; + } + + VResult tot_vec(data.y); + Result super_total = 0.0; + for (int i = 0; i < data.x; ++i) { + if (havesub && (i >= data.subnames.size() || data.subnames[i].empty())) + continue; + + int iy = i * data.y; + VResult yvec(data.y); + + Result total = 0.0; + for (int j = 0; j < data.y; ++j) { + yvec[j] = data.cvec[iy + j]; + tot_vec[j] += yvec[j]; + total += yvec[j]; + super_total += yvec[j]; + } + + print.name = data.name + "_" + (havesub ? data.subnames[i] : to_string(i)); + print.desc = data.desc; + print.vec = yvec; + print.total = total; + print(*stream); + } + + if ((data.flags & ::Stats::total) && (data.x > 1)) { + print.name = data.name; + print.desc = data.desc; + print.vec = tot_vec; + print.total = super_total; + print(*stream); + } +} + +void +Text::visit(const DistData &data) +{ + if (noOutput(data)) + return; + + DistPrint print; + + print.name = data.name; + print.desc = data.desc; + print.flags = data.flags; + print.compat = compat; + print.descriptions = descriptions; + print.precision = data.precision; + + print.min_val = data.data.min_val; + print.max_val = data.data.max_val; + print.underflow = data.data.underflow; + print.overflow = data.data.overflow; + print.vec.resize(data.data.cvec.size()); + for (int i = 0; i < print.vec.size(); ++i) + print.vec[i] = (Result)data.data.cvec[i]; + print.sum = data.data.sum; + print.squares = data.data.squares; + print.samples = data.data.samples; + + print.min = data.data.min; + print.max = data.data.max; + print.bucket_size = data.data.bucket_size; + print.size = data.data.size; + print.fancy = data.data.fancy; + + print(*stream); +} + +void +Text::visit(const VectorDistData &data) +{ + if (noOutput(data)) + return; + + for (int i = 0; i < data.size(); ++i) { + DistPrint print; + + print.name = data.name + + (data.subnames[i].empty() ? ("_" + to_string(i)) : data.subnames[i]); + print.desc = data.subdescs[i].empty() ? data.desc : data.subdescs[i]; + print.flags = data.flags; + print.compat = compat; + print.descriptions = descriptions; + print.precision = data.precision; + + print.min_val = data.data[i].min_val; + print.max_val = data.data[i].max_val; + print.underflow = data.data[i].underflow; + print.overflow = data.data[i].overflow; + print.vec.resize(data.data[i].cvec.size()); + for (int j = 0; j < print.vec.size(); ++j) + print.vec[j] = (Result)data.data[i].cvec[j]; + print.sum = data.data[i].sum; + print.squares = data.data[i].squares; + print.samples = data.data[i].samples; + + print.min = data.data[i].min; + print.max = data.data[i].max; + print.bucket_size = data.data[i].bucket_size; + print.size = data.data[i].size; + print.fancy = data.data[i].fancy; + + print(*stream); + } +} + +void +Text::visit(const FormulaData &data) +{ + visit((const VectorData &)data); +} + +/* namespace Stats */ } diff --git a/src/base/stats/text.hh b/src/base/stats/text.hh new file mode 100644 index 000000000..b3faf5ad5 --- /dev/null +++ b/src/base/stats/text.hh @@ -0,0 +1,78 @@ +/* + * 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: Nathan Binkert + */ + +#ifndef __BASE_STATS_TEXT_HH__ +#define __BASE_STATS_TEXT_HH__ + +#include <iosfwd> +#include <string> + +#include "base/stats/output.hh" + +namespace Stats { + +class Text : public Output +{ + protected: + bool mystream; + std::ostream *stream; + + protected: + bool noOutput(const StatData &data); + + public: + bool compat; + bool descriptions; + + public: + Text(); + Text(std::ostream &stream); + Text(const std::string &file); + ~Text(); + + void open(std::ostream &stream); + void open(const std::string &file); + + // Implement Visit + virtual void visit(const ScalarData &data); + virtual void visit(const VectorData &data); + virtual void visit(const DistData &data); + virtual void visit(const VectorDistData &data); + virtual void visit(const Vector2dData &data); + virtual void visit(const FormulaData &data); + + // Implement Output + virtual bool valid() const; + virtual void output(); +}; + +/* namespace Stats */ } + +#endif // __BASE_STATS_TEXT_HH__ diff --git a/src/base/stats/types.hh b/src/base/stats/types.hh new file mode 100644 index 000000000..b64e8fb17 --- /dev/null +++ b/src/base/stats/types.hh @@ -0,0 +1,51 @@ +/* + * 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: Nathan Binkert + */ + +#ifndef __BASE_STATS_TYPES_HH__ +#define __BASE_STATS_TYPES_HH__ + +#include <vector> +#include "sim/host.hh" + +namespace Stats { + +/** All counters are of 64-bit values. */ +typedef double Counter; +/** vector of counters. */ +typedef std::vector<Counter> VCounter; + +/** All results are doubles. */ +typedef double Result; +/** vector of results. */ +typedef std::vector<Result> VResult; + +/* namespace Stats */ } + +#endif // __BASE_STATS_TYPES_HH__ diff --git a/src/base/stats/visit.cc b/src/base/stats/visit.cc new file mode 100644 index 000000000..870e4fb77 --- /dev/null +++ b/src/base/stats/visit.cc @@ -0,0 +1,43 @@ +/* + * 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: Nathan Binkert + */ + +#include "base/stats/visit.hh" + +namespace Stats { +namespace Detail { + +Visit::Visit() +{} + +Visit::~Visit() +{} + +/* namespace Detail */ } +/* namespace Stats */ } diff --git a/src/base/stats/visit.hh b/src/base/stats/visit.hh new file mode 100644 index 000000000..0087c227c --- /dev/null +++ b/src/base/stats/visit.hh @@ -0,0 +1,65 @@ +/* + * 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: Nathan Binkert + */ + +#ifndef __BASE_STATS_VISIT_HH__ +#define __BASE_STATS_VISIT_HH__ + +#include <string> + +#include "base/time.hh" +#include "sim/host.hh" + +namespace Stats { + +class StatData; +class ScalarData; +class VectorData; +class DistDataData; +class DistData; +class VectorDistData; +class Vector2dData; +class FormulaData; + +struct Visit +{ + Visit(); + virtual ~Visit(); + + virtual void visit(const ScalarData &data) = 0; + virtual void visit(const VectorData &data) = 0; + virtual void visit(const DistData &data) = 0; + virtual void visit(const VectorDistData &data) = 0; + virtual void visit(const Vector2dData &data) = 0; + virtual void visit(const FormulaData &data) = 0; +}; + +/* namespace Stats */ } + +#endif // __BASE_STATS_VISIT_HH__ diff --git a/src/base/str.cc b/src/base/str.cc new file mode 100644 index 000000000..0a517dff5 --- /dev/null +++ b/src/base/str.cc @@ -0,0 +1,375 @@ +/* + * 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 + */ + +#include <ctype.h> + +#include <cstring> +#include <iostream> +#include <string> +#include <vector> + +#include "base/intmath.hh" +#include "base/str.hh" + +using namespace std; + +bool +split_first(const string &s, string &lhs, string &rhs, char c) +{ + string::size_type offset = s.find(c); + if (offset == string::npos) { + lhs = s; + rhs = ""; + return false; + } + + lhs = s.substr(0, offset); + rhs = s.substr(offset + 1); + return true; +} + +bool +split_last(const string &s, string &lhs, string &rhs, char c) +{ + string::size_type offset = s.rfind(c); + if (offset == string::npos) { + lhs = s; + rhs = ""; + return false; + } + + lhs = s.substr(0, offset); + rhs = s.substr(offset + 1); + return true; +} + +void +tokenize(vector<string>& v, const string &s, char token, bool ignore) +{ + string::size_type first = 0; + string::size_type last = s.find_first_of(token); + + if (s.empty()) + return; + + if (ignore && last == first) { + while (last == first) + last = s.find_first_of(token, ++first); + + if (last == string::npos) { + if (first != s.size()) + v.push_back(s.substr(first)); + return; + } + } + + while (last != string::npos) { + v.push_back(s.substr(first, last - first)); + + if (ignore) { + first = s.find_first_not_of(token, last + 1); + + if (first == string::npos) + return; + } else + first = last + 1; + + last = s.find_first_of(token, first); + } + + v.push_back(s.substr(first)); +} + +/** + * @todo This function will not handle the smallest negative decimal + * value for a signed type + */ + +template <class T> +inline bool +__to_number(string value, T &retval) +{ + static const T maxnum = ((T)-1); + static const bool sign = maxnum < 0; + static const int bits = sizeof(T) * 8; + static const T hexmax = maxnum & (((T)1 << (bits - 4 - sign)) - 1); + static const T octmax = maxnum & (((T)1 << (bits - 3 - sign)) - 1); + static const T signmax = + (sign) ? maxnum & (((T)1 << (bits - 1)) - 1) : maxnum; + static const T decmax = signmax / 10; + +#if 0 + cout << "maxnum = 0x" << hex << (unsigned long long)maxnum << "\n" + << "sign = 0x" << hex << (unsigned long long)sign << "\n" + << "hexmax = 0x" << hex << (unsigned long long)hexmax << "\n" + << "octmax = 0x" << hex << (unsigned long long)octmax << "\n" + << "signmax = 0x" << hex << (unsigned long long)signmax << "\n" + << "decmax = 0x" << hex << (unsigned long long)decmax << "\n"; +#endif + + eat_white(value); + + bool negative = false; + bool hex = false; + bool oct = false; + int last = value.size() - 1; + retval = 0; + int i = 0; + + char c = value[i]; + if (!isDec(c)) { + if (c == '-' && sign) + negative = true; + else + return false; + } + else { + retval += c - '0'; + if (last == 0) return true; + } + + if (c == '0') + oct = true; + + c = value[++i]; + if (oct) { + if (sign && negative) + return false; + + if (!isOct(c)) { + if (c == 'X' || c == 'x') { + hex = true; + oct = false; + } else + return false; + } + else + retval += c - '0'; + } else if (!isDec(c)) + goto multiply; + else { + if (sign && negative && c == '0') + return false; + + retval *= 10; + retval += c - '0'; + if (last == 1) { + if (sign && negative) retval = -retval; + return true; + } + } + + if (hex) { + if (last == 1) + return false; + + for (i = 2; i <= last ; i++) { + c = value[i]; + if (!isHex(c)) + return false; + + if (retval > hexmax) return false; + retval *= 16; + retval += hex2Int(c); + } + return true; + } else if (oct) { + for (i = 2; i <= last ; i++) { + c = value[i]; + if (!isOct(c)) + return false; + + if (retval > octmax) return false; + retval *= 8; + retval += (c - '0'); + } + return true; + } + + for (i = 2; i < last ; i++) { + c = value[i]; + if (!isDec(c)) + goto multiply; + + if (retval > decmax) return false; + bool atmax = retval == decmax; + retval *= 10; + retval += c - '0'; + if (atmax && retval < decmax) return false; + if (sign && (retval & ((T)1 << (sizeof(T) * 8 - 1)))) + return false; + } + + c = value[last]; + if (isDec(c)) { + + if (retval > decmax) return false; + bool atmax = retval == decmax; + retval *= 10; + retval += c - '0'; + if (atmax && retval < decmax) return false; + if (sign && negative) { + if ((retval & ((T)1 << (sizeof(T) * 8 - 1))) && + retval >= (T)-signmax) + return false; + retval = -retval; + } + else + if (sign && (retval & ((T)1 << ((sizeof(T) * 8) - 1)))) + return false; + return true; + } + + multiply: + signed long long mult = 1; + T val; + switch (c) { + case 'k': + case 'K': + if (i != last) return false; + mult = 1024; + val = signmax / mult; + break; + case 'm': + case 'M': + if (i != last) return false; + mult = 1024 * 1024; + val = signmax / mult; + break; + case 'g': + case 'G': + if (i != last) return false; + mult = 1024 * 1024 * 1024; + val = signmax / mult; + break; + case 'e': + case 'E': + if (i >= last) return false; + + mult = 0; + for (i++; i <= last; i++) { + c = value[i]; + if (!isDec(c)) + return false; + + mult *= 10; + mult += c - '0'; + } + + for (i = 0; i < mult; i++) { + if (retval > signmax / 10) + return false; + retval *= 10; + if (sign && (retval & ((T)1 << (sizeof(T) * 8 - 1)))) + return false; + } + if (sign && negative) { + if ((retval & ((T)1 << (sizeof(T) * 8 - 1))) && + retval >= (T)-signmax) + return false; + retval = -retval; + } + else + if (sign && (retval & ((T)1 << ((sizeof(T) * 8) - 1)))) + return false; + + return true; + + default: + return false; + } + + if (sign && negative) + return false; + + if (mult > (unsigned long long)signmax) + return false; + + if (retval > val) + return false; + + retval *= mult; + + return true; +} + +#define STN(type) \ +template<> \ +bool to_number<type>(const string &value, type &retval) \ +{ return __to_number(value, retval); } + +STN(unsigned long long); +STN(signed long long); +STN(unsigned long); +STN(signed long); +STN(unsigned int); +STN(signed int); +STN(unsigned short); +STN(signed short); +STN(unsigned char); +STN(signed char); + +template<> +bool to_number<bool>(const string &value, bool &retval) +{ + string lowered = to_lower(value); + + if (value == "0") { + retval = false; + return true; + } + + if (value == "1"){ + retval = true; + return true; + } + + if (lowered == "false") { + retval = false; + return true; + } + + if (lowered == "true"){ + retval = true; + return true; + } + + if (lowered == "no") { + retval = false; + return true; + } + + if (lowered == "yes"){ + retval = true; + return true; + } + + return false; +} diff --git a/src/base/str.hh b/src/base/str.hh new file mode 100644 index 000000000..08953caf3 --- /dev/null +++ b/src/base/str.hh @@ -0,0 +1,144 @@ +/* + * 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 + * Steve Reinhardt + */ + +#ifndef __STR_HH__ +#define __STR_HH__ + +#include <sstream> +#include <string> +#include <vector> + +#include <ctype.h> + +template<class> class Hash; +template<> +class Hash<std::string> { +public: + unsigned operator()(const std::string &s) { + std::string::const_iterator i = s.begin(); + std::string::const_iterator end = s.end(); + unsigned hash = 5381; + + while (i < end) + hash = ((hash << 5) + hash) + *i++; + + return hash; + } +}; + +inline void +eat_lead_white(std::string &s) +{ + std::string::size_type off = s.find_first_not_of(' '); + if (off != std::string::npos) { + std::string::iterator begin = s.begin(); + s.erase(begin, begin + off); + } +} + +inline void +eat_end_white(std::string &s) +{ + std::string::size_type off = s.find_last_not_of(' '); + if (off != std::string::npos) + s.erase(s.begin() + off + 1, s.end()); +} + +inline void +eat_white(std::string &s) +{ + eat_lead_white(s); + eat_end_white(s); +} + +inline std::string +to_lower(const std::string &s) +{ + std::string lower; + int len = s.size(); + + lower.reserve(len); + + for (int i = 0; i < len; ++i) + lower.push_back(tolower(s[i])); + + return lower; +} + +// Split the string s into lhs and rhs on the first occurence of the +// character c. +bool +split_first(const std::string &s, std::string &lhs, std::string &rhs, char c); + +// Split the string s into lhs and rhs on the last occurence of the +// character c. +bool +split_last(const std::string &s, std::string &lhs, std::string &rhs, char c); + +// Tokenize the string <s> splitting on the character <token>, and +// place the result in the string vector <vector>. If <ign> is true, +// then empty result strings (due to trailing tokens, or consecutive +// tokens) are skipped. +void +tokenize(std::vector<std::string> &vector, const std::string &s, + char token, bool ign = true); + +template <class T> bool +to_number(const std::string &value, T &retval); + +template <class T> +inline std::string +to_string(const T &value) +{ + std::stringstream str; + str << value; + return str.str(); +} + +// Put quotes around string arg if it contains spaces. +inline std::string +quote(const std::string &s) +{ + std::string ret; + bool quote = s.find(' ') != std::string::npos; + + if (quote) + ret = '"'; + + ret += s; + + if (quote) + ret += '"'; + + return ret; +} + +#endif //__STR_HH__ diff --git a/src/base/time.cc b/src/base/time.cc new file mode 100644 index 000000000..cbc7256ee --- /dev/null +++ b/src/base/time.cc @@ -0,0 +1,133 @@ +/* + * Copyright (c) 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: Nathan Binkert + */ + +#include <sys/types.h> +#include <sys/time.h> +#include <time.h> +#include <iostream> +#include <string> + +#include "base/time.hh" + +using namespace std; + +struct _timeval +{ + timeval tv; +}; + +double +convert(const timeval &tv) +{ + return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0; +} + +Time::Time(bool set_now) +{ + time = new _timeval; + if (set_now) + set(); +} + +Time::Time(const timeval &val) +{ + time = new _timeval; + set(val); +} + +Time::Time(const Time &val) +{ + time = new _timeval; + set(val.get()); +} + +Time::~Time() +{ + delete time; +} + +const timeval & +Time::get() const +{ + return time->tv; +} + +void +Time::set() +{ + ::gettimeofday(&time->tv, NULL); +} + +void +Time::set(const timeval &tv) +{ + memcpy(&time->tv, &tv, sizeof(timeval)); +} + +double +Time::operator()() const +{ + return convert(get()); +} + +string +Time::date(string format) const +{ + const timeval &tv = get(); + time_t sec = tv.tv_sec; + char buf[256]; + + if (format.empty()) { + ctime_r(&sec, buf); + buf[24] = '\0'; + return buf; + } + + struct tm *tm = localtime(&sec); + strftime(buf, sizeof(buf), format.c_str(), tm); + return buf; +} + +ostream & +operator<<(ostream &out, const Time &start) +{ + out << start.date(); + return out; +} + +Time +operator-(const Time &l, const Time &r) +{ + timeval tv; + timersub(&l.get(), &r.get(), &tv); + return tv; +} + +const Time Time::start(true); diff --git a/src/base/time.hh b/src/base/time.hh new file mode 100644 index 000000000..24e8a8a53 --- /dev/null +++ b/src/base/time.hh @@ -0,0 +1,68 @@ +/* + * Copyright (c) 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 Reinhardt + * Nathan Binkert + */ + +#ifndef __SIM_TIME_HH__ +#define __SIM_TIME_HH__ + +#include <sys/time.h> + +#include <iosfwd> +#include <string> + +struct _timeval; + +class Time +{ + protected: + mutable _timeval *time; + + public: + explicit Time(bool set_now = false); + Time(const timeval &val); + Time(const Time &val); + ~Time(); + + void set(); + const timeval &get() const; + void set(const timeval &val); + + double operator()() const; + std::string date(std::string format = "") const; + + public: + static const Time start; +}; + +Time operator-(const Time &l, const Time &r); + +std::ostream &operator<<(std::ostream &out, const Time &time); + +#endif // __SIM_TIME_HH__ diff --git a/src/base/timebuf.hh b/src/base/timebuf.hh new file mode 100644 index 000000000..6a326d25a --- /dev/null +++ b/src/base/timebuf.hh @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#ifndef __BASE_TIMEBUF_HH__ +#define __BASE_TIMEBUF_HH__ + +#include <vector> + +template <class T> +class TimeBuffer +{ + protected: + int past; + int future; + int size; + + char *data; + std::vector<char *> index; + int base; + + void valid(int idx) + { + assert (idx >= -past && idx <= future); + } + + public: + friend class wire; + class wire + { + friend class TimeBuffer; + protected: + TimeBuffer<T> *buffer; + int index; + + void set(int idx) + { + buffer->valid(idx); + index = idx; + } + + wire(TimeBuffer<T> *buf, int i) + : buffer(buf), index(i) + { } + + public: + wire() + { } + + wire(const wire &i) + : buffer(i.buffer), index(i.index) + { } + + const wire &operator=(const wire &i) + { + buffer = i.buffer; + set(i.index); + return *this; + } + + const wire &operator=(int idx) + { + set(idx); + return *this; + } + + const wire &operator+=(int offset) + { + set(index + offset); + return *this; + } + + const wire &operator-=(int offset) + { + set(index - offset); + return *this; + } + + wire &operator++() + { + set(index + 1); + return *this; + } + + wire &operator++(int) + { + int i = index; + set(index + 1); + return wire(this, i); + } + + wire &operator--() + { + set(index - 1); + return *this; + } + + wire &operator--(int) + { + int i = index; + set(index - 1); + return wire(this, i); + } + T &operator*() const { return *buffer->access(index); } + T *operator->() const { return buffer->access(index); } + }; + + + public: + TimeBuffer(int p, int f) + : past(p), future(f), size(past + future + 1), + data(new char[size * sizeof(T)]), index(size), base(0) + { + assert(past >= 0 && future >= 0); + char *ptr = data; + for (int i = 0; i < size; i++) { + index[i] = ptr; + memset(ptr, 0, sizeof(T)); + new (ptr) T; + ptr += sizeof(T); + } + } + + TimeBuffer() + : data(NULL) + { + } + + ~TimeBuffer() + { + for (int i = 0; i < size; ++i) + (reinterpret_cast<T *>(index[i]))->~T(); + delete [] data; + } + + void + advance() + { + if (++base >= size) + base = 0; + + int ptr = base + future; + if (ptr >= size) + ptr -= size; + (reinterpret_cast<T *>(index[ptr]))->~T(); + memset(index[ptr], 0, sizeof(T)); + new (index[ptr]) T; + } + + T *access(int idx) + { + //Need more complex math here to calculate index. + valid(idx); + + int vector_index = idx + base; + if (vector_index >= size) { + vector_index -= size; + } else if (vector_index < 0) { + vector_index += size; + } + + return reinterpret_cast<T *>(index[vector_index]); + } + + T &operator[](int idx) + { + //Need more complex math here to calculate index. + valid(idx); + + int vector_index = idx + base; + if (vector_index >= size) { + vector_index -= size; + } else if (vector_index < 0) { + vector_index += size; + } + + return reinterpret_cast<T &>(*index[vector_index]); + } + + wire getWire(int idx) + { + valid(idx); + + return wire(this, idx); + } + + wire zero() + { + return wire(this, 0); + } +}; + +#endif // __BASE_TIMEBUF_HH__ + diff --git a/src/base/trace.cc b/src/base/trace.cc new file mode 100644 index 000000000..50426b992 --- /dev/null +++ b/src/base/trace.cc @@ -0,0 +1,353 @@ +/* + * 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 + * Steve Reinhardt + */ + +#include <ctype.h> +#include <fstream> +#include <iostream> +#include <list> +#include <string> +#include <vector> + +#include "base/misc.hh" +#include "base/trace.hh" +#include "base/str.hh" + +using namespace std; + +namespace Trace { +const string DefaultName("global"); +FlagVec flags(NumFlags, false); + +// +// This variable holds the output stream for debug information. Other +// than setting up/redirecting this stream, do *NOT* reference this +// directly; use DebugOut() (see below) to access this stream for +// output. +// +ostream *dprintf_stream = &cerr; + +ObjectMatch ignore; + +Log theLog; + +Log::Log() +{ + size = 0; + buffer = NULL; +} + + +void +Log::init(int _size) +{ + if (buffer != NULL) { + fatal("Trace::Log::init called twice!"); + } + + size = _size; + + buffer = new Record *[size]; + + for (int i = 0; i < size; ++i) { + buffer[i] = NULL; + } + + nextRecPtr = &buffer[0]; + wrapRecPtr = &buffer[size]; +} + + +Log::~Log() +{ + for (int i = 0; i < size; ++i) { + delete buffer[i]; + } + + delete [] buffer; +} + + +void +Log::append(Record *rec) +{ + // dump record to output stream if there's one open + if (dprintf_stream != NULL) { + rec->dump(*dprintf_stream); + } else { + rec->dump(cout); + } + + // no buffering: justget rid of it now + if (buffer == NULL) { + delete rec; + return; + } + + Record *oldRec = *nextRecPtr; + + if (oldRec != NULL) { + // log has wrapped: overwrite + delete oldRec; + } + + *nextRecPtr = rec; + + if (++nextRecPtr == wrapRecPtr) { + nextRecPtr = &buffer[0]; + } +} + + +void +Log::dump(ostream &os) +{ + if (buffer == NULL) { + return; + } + + Record **bufPtr = nextRecPtr; + + if (*bufPtr == NULL) { + // next record slot is empty: log must not be full yet. + // start dumping from beginning of buffer + bufPtr = buffer; + } + + do { + Record *rec = *bufPtr; + + rec->dump(os); + + if (++bufPtr == wrapRecPtr) { + bufPtr = &buffer[0]; + } + } while (bufPtr != nextRecPtr); +} + +PrintfRecord::~PrintfRecord() +{ + delete &args; +} + +void +PrintfRecord::dump(ostream &os) +{ + string fmt = ""; + + if (!name.empty()) { + fmt = "%s: " + fmt; + args.prepend(name); + } + + if (cycle != (Tick)-1) { + fmt = "%7d: " + fmt; + args.prepend(cycle); + } + + fmt += format; + + args.dump(os, fmt); + os.flush(); +} + +DataRecord::DataRecord(Tick _cycle, const string &_name, + const void *_data, int _len) + : Record(_cycle), name(_name), len(_len) +{ + data = new uint8_t[len]; + memcpy(data, _data, len); +} + +DataRecord::~DataRecord() +{ + delete [] data; +} + +void +DataRecord::dump(ostream &os) +{ + int c, i, j; + + for (i = 0; i < len; i += 16) { + ccprintf(os, "%d: %s: %08x ", cycle, name, i); + c = len - i; + if (c > 16) c = 16; + + for (j = 0; j < c; j++) { + ccprintf(os, "%02x ", data[i + j] & 0xff); + if ((j & 0xf) == 7 && j > 0) + ccprintf(os, " "); + } + + for (; j < 16; j++) + ccprintf(os, " "); + ccprintf(os, " "); + + for (j = 0; j < c; j++) { + int ch = data[i + j] & 0x7f; + ccprintf(os, + "%c", (char)(isprint(ch) ? ch : ' ')); + } + + ccprintf(os, "\n"); + + if (c < 16) + break; + } +} +} // namespace Trace + +// +// Returns the current output stream for debug information. As a +// wrapper around Trace::dprintf_stream, this handles cases where debug +// information is generated in the process of parsing .ini options, +// before we process the option that sets up the debug output stream +// itself. +// +std::ostream & +DebugOut() +{ + return *Trace::dprintf_stream; +} + +///////////////////////////////////////////// +// +// C-linkage functions for invoking from gdb +// +///////////////////////////////////////////// + +// +// Dump trace buffer to specified file (cout if NULL) +// +extern "C" +void +dumpTrace(const char *filename) +{ + if (filename != NULL) { + ofstream out(filename); + Trace::theLog.dump(out); + out.close(); + } + else { + Trace::theLog.dump(cout); + } +} + + +// +// Turn on/off trace output to cerr. Typically used when trace output +// is only going to circular buffer, but you want to see what's being +// sent there as you step through some code in gdb. This uses the +// same facility as the "trace to file" feature, and will print error +// messages rather than clobbering an existing ostream pointer. +// +extern "C" +void +echoTrace(bool on) +{ + if (on) { + if (Trace::dprintf_stream != NULL) { + cerr << "Already echoing trace to a file... go do a 'tail -f'" + << " on that file instead." << endl; + } else { + Trace::dprintf_stream = &cerr; + } + } else { + if (Trace::dprintf_stream != &cerr) { + cerr << "Not echoing trace to cerr." << endl; + } else { + Trace::dprintf_stream = NULL; + } + } +} + +extern "C" +void +printTraceFlags() +{ + using namespace Trace; + for (int i = 0; i < numFlagStrings; ++i) + if (flags[i]) + cprintf("%s\n", flagStrings[i]); +} + +void +tweakTraceFlag(const char *string, bool value) +{ + using namespace Trace; + std::string str(string); + + for (int i = 0; i < numFlagStrings; ++i) { + if (str != flagStrings[i]) + continue; + + int idx = i; + + if (idx < NumFlags) { + flags[idx] = value; + } else { + idx -= NumFlags; + if (idx >= NumCompoundFlags) { + ccprintf(cerr, "Invalid compound flag"); + return; + } + + const Flags *flagVec = compoundFlags[idx]; + + for (int j = 0; flagVec[j] != -1; ++j) { + if (flagVec[j] >= NumFlags) { + ccprintf(cerr, "Invalid compound flag"); + return; + } + flags[flagVec[j]] = value; + } + } + + cprintf("flag %s was %s\n", string, value ? "set" : "cleared"); + return; + } + + cprintf("could not find flag %s\n", string); +} + +extern "C" +void +setTraceFlag(const char *string) +{ + tweakTraceFlag(string, true); +} + +extern "C" +void +clearTraceFlag(const char *string) +{ + tweakTraceFlag(string, false); +} diff --git a/src/base/trace.hh b/src/base/trace.hh new file mode 100644 index 000000000..8df5dd893 --- /dev/null +++ b/src/base/trace.hh @@ -0,0 +1,234 @@ +/* + * 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 + * Steve Reinhardt + */ + +#ifndef __BASE_TRACE_HH__ +#define __BASE_TRACE_HH__ + +#include <vector> + +#include "base/cprintf.hh" +#include "base/match.hh" +#include "sim/host.hh" +#include "sim/root.hh" + +#ifndef TRACING_ON +#ifndef NDEBUG +#define TRACING_ON 1 +#else +#define TRACING_ON 0 +#endif +#endif + +#include "base/traceflags.hh" + +namespace Trace { + + typedef std::vector<bool> FlagVec; + + extern FlagVec flags; + +#if TRACING_ON + const bool On = true; +#else + const bool On = false; +#endif + + inline bool + IsOn(int t) + { + return flags[t]; + + } + + void dump(const uint8_t *data, int count); + + class Record + { + protected: + Tick cycle; + + Record(Tick _cycle) + : cycle(_cycle) + { + } + + public: + virtual ~Record() {} + + virtual void dump(std::ostream &) = 0; + }; + + class PrintfRecord : public Record + { + private: + const char *format; + const std::string &name; + cp::ArgList &args; + + public: + PrintfRecord(const char *_format, cp::ArgList &_args, + Tick cycle, const std::string &_name) + : Record(cycle), format(_format), name(_name), args(_args) + { + } + + virtual ~PrintfRecord(); + + virtual void dump(std::ostream &); + }; + + class DataRecord : public Record + { + private: + const std::string &name; + uint8_t *data; + int len; + + public: + DataRecord(Tick cycle, const std::string &name, + const void *_data, int _len); + virtual ~DataRecord(); + + virtual void dump(std::ostream &); + }; + + class Log + { + private: + int size; // number of records in log + Record **buffer; // array of 'size' Record ptrs (circular buf) + Record **nextRecPtr; // next slot to use in buffer + Record **wrapRecPtr; // &buffer[size], for quick wrap check + + public: + + Log(); + ~Log(); + + void init(int _size); + + void append(Record *); // append trace record to log + void dump(std::ostream &); // dump contents to stream + }; + + extern Log theLog; + + extern ObjectMatch ignore; + + inline void + dprintf(const char *format, cp::ArgList &args, Tick cycle, + const std::string &name) + { + if (name.empty() || !ignore.match(name)) + theLog.append(new Trace::PrintfRecord(format, args, cycle, name)); + } + + inline void + dataDump(Tick cycle, const std::string &name, const void *data, int len) + { + theLog.append(new Trace::DataRecord(cycle, name, data, len)); + } + + extern const std::string DefaultName; +}; + +// This silly little class allows us to wrap a string in a functor +// object so that we can give a name() that DPRINTF will like +struct StringWrap +{ + std::string str; + StringWrap(const std::string &s) : str(s) {} + const std::string &operator()() const { return str; } +}; + +inline const std::string &name() { return Trace::DefaultName; } +std::ostream &DebugOut(); + +// +// DPRINTF is a debugging trace facility that allows one to +// selectively enable tracing statements. To use DPRINTF, there must +// be a function or functor called name() that returns a const +// std::string & in the current scope. +// +// If you desire that the automatic printing not occur, use DPRINTFR +// (R for raw) +// + +#if TRACING_ON + +#define DTRACE(x) (Trace::IsOn(Trace::x)) + +#define DCOUT(x) if (Trace::IsOn(Trace::x)) DebugOut() + +#define DDUMP(x, data, count) \ +do { \ + if (Trace::IsOn(Trace::x)) \ + Trace::dataDump(curTick, name(), data, count); \ +} while (0) + +#define __dprintf(cycle, name, format, args...) \ + Trace::dprintf(format, (*(new cp::ArgList), args), cycle, name) + +#define DPRINTF(x, args...) \ +do { \ + if (Trace::IsOn(Trace::x)) \ + __dprintf(curTick, name(), args, cp::ArgListNull()); \ +} while (0) + +#define DPRINTFR(x, args...) \ +do { \ + if (Trace::IsOn(Trace::x)) \ + __dprintf((Tick)-1, std::string(), args, cp::ArgListNull()); \ +} while (0) + +#define DPRINTFN(args...) \ +do { \ + __dprintf(curTick, name(), args, cp::ArgListNull()); \ +} while (0) + +#define DPRINTFNR(args...) \ +do { \ + __dprintf((Tick)-1, string(), args, cp::ArgListNull()); \ +} while (0) + +#else // !TRACING_ON + +#define DTRACE(x) (false) +#define DCOUT(x) if (0) DebugOut() +#define DPRINTF(x, args...) do {} while (0) +#define DPRINTFR(args...) do {} while (0) +#define DPRINTFN(args...) do {} while (0) +#define DPRINTFNR(args...) do {} while (0) +#define DDUMP(x, data, count) do {} while (0) + +#endif // TRACING_ON + +#endif // __BASE_TRACE_HH__ diff --git a/src/base/traceflags.py b/src/base/traceflags.py new file mode 100644 index 000000000..7ff68bcaf --- /dev/null +++ b/src/base/traceflags.py @@ -0,0 +1,331 @@ +#!/usr/bin/env python + +# 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: Nathan Binkert +# Steve Reinhardt + +# +# This file generates the header and source files for the flags +# that control the tracing facility. +# + +import sys + +if len(sys.argv) != 2: + print "%s: Need argument (basename of cc/hh files)" % sys.argv[0] + sys.exit(1) + +hhfilename = sys.argv[1] + '.hh' +ccfilename = sys.argv[1] + '.cc' + +# +# The list of trace flags that can be used to condition DPRINTFs etc. +# To define a new flag, simply add it to this list. +# +baseFlags = [ + 'AlphaConsole', + 'BADADDR', + 'BPredRAS', + 'Bus', + 'BusAddrRanges', + 'BusBridge', + 'Cache', + 'Chains', + 'Checker', + 'Clock', + 'Commit', + 'CommitRate', + 'Config', + 'Console', + 'ConsolePoll', + 'ConsoleVerbose', + 'Context', + 'Cycle', + 'DMA', + 'DMAReadVerbose', + 'DMAWriteVerbose', + 'DebugPrintf', + 'Decode', + 'DiskImage', + 'DiskImageRead', + 'DiskImageWrite', + 'DynInst', + 'Ethernet', + 'EthernetCksum', + 'EthernetDMA', + 'EthernetData', + 'EthernetDesc', + 'EthernetIntr', + 'EthernetPIO', + 'EthernetSM', + 'Event', + 'Fault', + 'Fetch', + 'Flow', + 'FreeList', + 'FullCPU', + 'GDBAcc', + 'GDBExtra', + 'GDBMisc', + 'GDBRead', + 'GDBRecv', + 'GDBSend', + 'GDBWrite', + 'HWPrefetch', + 'IEW', + 'IIC', + 'IICMore', + 'IPI', + 'IQ', + 'ISP', + 'IdeCtrl', + 'IdeDisk', + 'InstExec', + 'Interrupt', + 'LSQ', + 'LSQUnit', + 'Loader', + 'MC146818', + 'MMU', + 'MSHR', + 'Mbox', + 'MemDepUnit', + 'OzoneCPU', + 'FE', + 'IBE', + 'BE', + 'OzoneLSQ', + 'PCEvent', + 'PCIA', + 'PCIDEV', + 'PciConfigAll', + 'Pipeline', + 'Printf', + 'ROB', + 'Regs', + 'Rename', + 'RenameMap', + 'SQL', + 'Sampler', + 'ScsiCtrl', + 'ScsiDisk', + 'ScsiNone', + 'Serialize', + 'SimpleCPU', + 'SimpleDisk', + 'SimpleDiskData', + 'Sparc', + 'Split', + 'Stack', + 'StatEvents', + 'Stats', + 'StoreSet', + 'Syscall', + 'SyscallVerbose', + 'TCPIP', + 'TLB', + 'Thread', + 'Timer', + 'Tsunami', + 'Uart', + 'VtoPhys', + 'WriteBarrier', + 'Activity', + 'Scoreboard', + 'Writeback', + ] + +# +# "Compound" flags correspond to a set of base flags. These exist +# solely for convenience in setting them via the command line: if a +# compound flag is specified, all of the corresponding base flags are +# set. Compound flags cannot be used directly in DPRINTFs etc. +# To define a new compound flag, add a new entry to this hash +# following the existing examples. +# +compoundFlagMap = { + 'GDBAll' : [ 'GDBMisc', 'GDBAcc', 'GDBRead', 'GDBWrite', 'GDBSend', 'GDBRecv', 'GDBExtra' ], + 'ScsiAll' : [ 'ScsiDisk', 'ScsiCtrl', 'ScsiNone' ], + 'DiskImageAll' : [ 'DiskImage', 'DiskImageRead', 'DiskImageWrite' ], + 'EthernetAll' : [ 'Ethernet', 'EthernetPIO', 'EthernetDMA', 'EthernetData' , 'EthernetDesc', 'EthernetIntr', 'EthernetSM', 'EthernetCksum' ], + 'EthernetNoData' : [ 'Ethernet', 'EthernetPIO', 'EthernetDesc', 'EthernetIntr', 'EthernetSM', 'EthernetCksum' ], + 'IdeAll' : [ 'IdeCtrl', 'IdeDisk' ], + 'FullCPUAll' : [ 'Fetch', 'Decode', 'Rename', 'IEW', 'Commit', 'IQ', 'ROB', 'FreeList', 'RenameMap', 'LSQ', 'LSQUnit', 'StoreSet', 'MemDepUnit', 'DynInst', 'FullCPU', 'Activity','Scoreboard','Writeback'], + 'OzoneCPUAll' : [ 'BE', 'FE', 'IBE', 'OzoneLSQ', 'OzoneCPU'] +} + +############################################################# +# +# Everything below this point generates the appropriate C++ +# declarations and definitions for the trace flags. If you are simply +# adding or modifying flag definitions, you should not have to change +# anything below. +# + +import sys + +# extract just the compound flag names into a list +compoundFlags = [] +compoundFlags.extend(compoundFlagMap.keys()) +compoundFlags.sort() + +# +# First generate the header file. This defines the Flag enum +# and some extern declarations for the .cc file. +# +try: + hhfile = file(hhfilename, 'w') +except IOError, e: + sys.exit("can't open %s: %s" % (hhfilename, e)) + +# file header boilerplate +print >>hhfile, ''' +/* + * DO NOT EDIT THIS FILE! + * + * Automatically generated from traceflags.py + */ + +#ifndef __BASE_TRACE_FLAGS_HH__ +#define __BASE_TRACE_FLAGS_HH__ + +namespace Trace { + +enum Flags { +''', + +# Generate the enum. Base flags come first, then compound flags. +idx = 0 +for flag in baseFlags: + print >>hhfile, ' %s = %d,' % (flag, idx) + idx += 1 + +numBaseFlags = idx +print >>hhfile, ' NumFlags = %d,' % idx + +# put a comment in here to separate base from compound flags +print >>hhfile, ''' + // The remaining enum values are *not* valid indices for Trace::flags. + // They are "compound" flags, which correspond to sets of base + // flags, and are used only by TraceParamContext::setFlags(). +''', + +for flag in compoundFlags: + print >>hhfile, ' %s = %d,' % (flag, idx) + idx += 1 + +numCompoundFlags = idx - numBaseFlags +print >>hhfile, ' NumCompoundFlags = %d' % numCompoundFlags + +# trailer boilerplate +print >>hhfile, '''\ +}; // enum Flags + +// Array of strings for SimpleEnumParam +extern const char *flagStrings[]; +extern const int numFlagStrings; + +// Array of arraay pointers: for each compound flag, gives the list of +// base flags to set. Inidividual flag arrays are terminated by -1. +extern const Flags *compoundFlags[]; + +/* namespace Trace */ } + +#endif // __BASE_TRACE_FLAGS_HH__ +''', + +hhfile.close() + +# +# +# Print out .cc file with array definitions. +# +# +try: + ccfile = file(ccfilename, 'w') +except OSError, e: + sys.exit("can't open %s: %s" % (ccfilename, e)) + +# file header +print >>ccfile, ''' +/* + * DO NOT EDIT THIS FILE! + * + * Automatically generated from traceflags.pl. + */ + +#include "base/traceflags.hh" + +using namespace Trace; + +const char *Trace::flagStrings[] = +{ +''', + +# The string array is used by SimpleEnumParam to map the strings +# provided by the user to enum values. +for flag in baseFlags: + print >>ccfile, ' "%s",' % flag + +for flag in compoundFlags: + print >>ccfile, ' "%s",' % flag + +print >>ccfile, '};\n' + +numFlagStrings = len(baseFlags) + len(compoundFlags); + +print >>ccfile, 'const int Trace::numFlagStrings = %d;' % numFlagStrings +print >>ccfile + +# +# Now define the individual compound flag arrays. There is an array +# for each compound flag listing the component base flags. +# + +for flag in compoundFlags: + flags = compoundFlagMap[flag] + flags.append('(Flags)-1') + print >>ccfile, 'static const Flags %sMap[] =' % flag + print >>ccfile, '{ %s };' % (', '.join(flags)) + print >>ccfile + +# +# Finally the compoundFlags[] array maps the compound flags +# to their individual arrays/ +# +print >>ccfile, 'const Flags *Trace::compoundFlags[] =' +print >>ccfile, '{' + +for flag in compoundFlags: + print >>ccfile, ' %sMap,' % flag + +# file trailer +print >>ccfile, '};' + +ccfile.close() + diff --git a/src/base/userinfo.cc b/src/base/userinfo.cc new file mode 100644 index 000000000..62f7b7b5c --- /dev/null +++ b/src/base/userinfo.cc @@ -0,0 +1,43 @@ +/* + * 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: Nathan Binkert + */ + +#include <sys/types.h> +#include <pwd.h> +#include <unistd.h> + +#include <string> + +std::string +username() +{ + struct passwd *pwd = getpwuid(getuid()); + + return pwd->pw_name; +} diff --git a/src/base/userinfo.hh b/src/base/userinfo.hh new file mode 100644 index 000000000..a2838ab3e --- /dev/null +++ b/src/base/userinfo.hh @@ -0,0 +1,38 @@ +/* + * 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: Nathan Binkert + */ + +#ifndef __BASE_USERINFO_HH__ +#define __BASE_USERINFO_HH__ + +#include <string> + +std::string username(); + +#endif // __BASE_USERINFO_HH__ diff --git a/src/cpu/SConscript b/src/cpu/SConscript new file mode 100644 index 000000000..34bad132c --- /dev/null +++ b/src/cpu/SConscript @@ -0,0 +1,180 @@ +# -*- 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 os +import os.path + +# Import build environment variable from SConstruct. +Import('env') + +################################################################# +# +# 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. +# +################################################################# + +# CPU model-specific data is contained in cpu_models.py +# Convert to SCons File node to get path handling +models_db = File('cpu_models.py') +# slurp in contents of file +execfile(models_db.srcnode().abspath) + +# Template for execute() signature. +exec_sig_template = ''' +virtual Fault execute(%s *xc, Trace::InstRecord *traceData) const = 0; +virtual Fault initiateAcc(%s *xc, Trace::InstRecord *traceData) const +{ panic("initiateAcc not defined!"); }; +virtual Fault completeAcc(Packet *pkt, %s *xc, + Trace::InstRecord *traceData) const +{ panic("completeAcc not defined!"); }; +''' + +mem_ini_sig_template = ''' +virtual Fault initiateAcc(%s *xc, Trace::InstRecord *traceData) const { panic("Not defined!"); }; +''' + +mem_comp_sig_template = ''' +virtual Fault completeAcc(uint8_t *data, %s *xc, Trace::InstRecord *traceData) const { panic("Not defined!"); return NoFault; }; +''' + +# 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 env['CPU_MODELS']: + xc_type = CpuModel.dict[cpu].strings['CPU_exec_context'] + print >> f, exec_sig_template % (xc_type, xc_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 "Generating static_inst_exec_sigs.hh: " \ + + ', '.join(env['CPU_MODELS']) + +# Add command to generate header to environment. +env.Command('static_inst_exec_sigs.hh', models_db, + Action(gen_cpu_exec_signatures, gen_sigs_string, + varlist = ['CPU_MODELS'])) + +################################################################# +# +# Include CPU-model-specific files based on set of models +# specified in CPU_MODELS build option. +# +################################################################# + +sources = [] + +need_simple_base = False +if 'AtomicSimpleCPU' in env['CPU_MODELS']: + need_simple_base = True + sources += Split('simple/atomic.cc') + +if 'TimingSimpleCPU' in env['CPU_MODELS']: + need_simple_base = True + sources += Split('simple/timing.cc') + +if need_simple_base: + sources += Split('simple/base.cc') + +if 'FastCPU' in env['CPU_MODELS']: + sources += Split('fast/cpu.cc') + +if 'AlphaFullCPU' in env['CPU_MODELS']: + sources += Split(''' + base_dyn_inst.cc + o3/2bit_local_pred.cc + o3/alpha_dyn_inst.cc + o3/alpha_cpu.cc + o3/alpha_cpu_builder.cc + o3/bpred_unit.cc + o3/btb.cc + o3/commit.cc + o3/decode.cc + o3/fetch.cc + o3/free_list.cc + o3/fu_pool.cc + o3/cpu.cc + o3/iew.cc + o3/inst_queue.cc + o3/lsq_unit.cc + o3/lsq.cc + o3/mem_dep_unit.cc + o3/ras.cc + o3/rename.cc + o3/rename_map.cc + o3/rob.cc + o3/scoreboard.cc + o3/store_set.cc + o3/tournament_pred.cc + ''') + +if 'OzoneSimpleCPU' in env['CPU_MODELS']: + sources += Split(''' + ozone/cpu.cc + ozone/cpu_builder.cc + ozone/dyn_inst.cc + ozone/front_end.cc + ozone/inorder_back_end.cc + ozone/inst_queue.cc + ozone/rename_table.cc + ''') + +if 'OzoneCPU' in env['CPU_MODELS']: + sources += Split(''' + ozone/lsq_unit.cc + ozone/lw_back_end.cc + ozone/lw_lsq.cc + ''') + +if 'CheckerCPU' in env['CPU_MODELS']: + sources += Split(''' + checker/cpu.cc + checker/o3_cpu_builder.cc + ''') + +# FullCPU sources are included from m5/SConscript since they're not +# below this point in the file hierarchy. + +# Convert file names to SCons File objects. This takes care of the +# path relative to the top of the directory tree. +sources = [File(s) for s in sources] + +Return('sources') + diff --git a/src/cpu/activity.cc b/src/cpu/activity.cc new file mode 100644 index 000000000..9a0f6d98d --- /dev/null +++ b/src/cpu/activity.cc @@ -0,0 +1,157 @@ +/* + * 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 "base/timebuf.hh" +#include "cpu/activity.hh" + +ActivityRecorder::ActivityRecorder(int num_stages, int longest_latency, + int activity) + : activityBuffer(longest_latency, 0), longestLatency(longest_latency), + activityCount(activity), numStages(num_stages) +{ + stageActive = new bool[numStages]; + 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; + 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); +} diff --git a/src/cpu/activity.hh b/src/cpu/activity.hh new file mode 100644 index 000000000..e99927339 --- /dev/null +++ b/src/cpu/activity.hh @@ -0,0 +1,126 @@ +/* + * 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/timebuf.hh" +#include "base/trace.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(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: + /** 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__ diff --git a/src/cpu/base.cc b/src/cpu/base.cc new file mode 100644 index 000000000..55c04c498 --- /dev/null +++ b/src/cpu/base.cc @@ -0,0 +1,383 @@ +/* + * 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: Steve Reinhardt + * Nathan Binkert + */ + +#include <iostream> +#include <string> +#include <sstream> + +#include "base/cprintf.hh" +#include "base/loader/symtab.hh" +#include "base/misc.hh" +#include "base/output.hh" +#include "cpu/base.hh" +#include "cpu/cpuevent.hh" +#include "cpu/thread_context.hh" +#include "cpu/profile.hh" +#include "cpu/sampler/sampler.hh" +#include "sim/param.hh" +#include "sim/process.hh" +#include "sim/sim_events.hh" +#include "sim/system.hh" + +#include "base/trace.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; + +#if FULL_SYSTEM +BaseCPU::BaseCPU(Params *p) + : SimObject(p->name), clock(p->clock), checkInterrupts(true), + params(p), number_of_threads(p->numberOfThreads), system(p->system) +#else +BaseCPU::BaseCPU(Params *p) + : SimObject(p->name), clock(p->clock), params(p), + number_of_threads(p->numberOfThreads), system(p->system) +#endif +{ + DPRINTF(FullCPU, "BaseCPU: Creating object, mem address %#x.\n", this); + + // add self to global list of CPUs + cpuList.push_back(this); + + DPRINTF(FullCPU, "BaseCPU: CPU added to cpuList, mem address %#x.\n", + this); + + if (number_of_threads > maxThreadsPerCPU) + maxThreadsPerCPU = number_of_threads; + + // allocate per-thread instruction-based event queues + comInstEventQueue = new EventQueue *[number_of_threads]; + for (int i = 0; i < number_of_threads; ++i) + comInstEventQueue[i] = new EventQueue("instruction-based event queue"); + + // + // set up instruction-count-based termination events, if any + // + if (p->max_insts_any_thread != 0) + for (int i = 0; i < number_of_threads; ++i) + new SimLoopExitEvent(comInstEventQueue[i], p->max_insts_any_thread, + "a thread reached the max instruction count"); + + if (p->max_insts_all_threads != 0) { + // allocate & initialize shared downcounter: each event will + // decrement this when triggered; simulation will terminate + // when counter reaches 0 + int *counter = new int; + *counter = number_of_threads; + for (int i = 0; i < number_of_threads; ++i) + new CountedExitEvent(comInstEventQueue[i], + "all threads reached the max instruction count", + p->max_insts_all_threads, *counter); + } + + // allocate per-thread load-based event queues + comLoadEventQueue = new EventQueue *[number_of_threads]; + for (int i = 0; i < number_of_threads; ++i) + comLoadEventQueue[i] = new EventQueue("load-based event queue"); + + // + // set up instruction-count-based termination events, if any + // + if (p->max_loads_any_thread != 0) + for (int i = 0; i < number_of_threads; ++i) + new SimLoopExitEvent(comLoadEventQueue[i], p->max_loads_any_thread, + "a thread reached the max load count"); + + if (p->max_loads_all_threads != 0) { + // allocate & initialize shared downcounter: each event will + // decrement this when triggered; simulation will terminate + // when counter reaches 0 + int *counter = new int; + *counter = number_of_threads; + for (int i = 0; i < number_of_threads; ++i) + new CountedExitEvent(comLoadEventQueue[i], + "all threads reached the max load count", + p->max_loads_all_threads, *counter); + } + +#if FULL_SYSTEM + memset(interrupts, 0, sizeof(interrupts)); + intstatus = 0; +#endif + + functionTracingEnabled = false; + if (p->functionTrace) { + functionTraceStream = simout.find(csprintf("ftrace.%s", name())); + currentFunctionStart = currentFunctionEnd = 0; + functionEntryTick = p->functionTraceStart; + + if (p->functionTraceStart == 0) { + functionTracingEnabled = true; + } else { + Event *e = + new EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace>(this, + true); + e->schedule(p->functionTraceStart); + } + } +#if FULL_SYSTEM + profileEvent = NULL; + if (params->profile) + profileEvent = new ProfileEvent(this, params->profile); +#endif + +} + +BaseCPU::Params::Params() +{ +#if FULL_SYSTEM + profile = false; +#endif + checker = NULL; +} + +void +BaseCPU::enableFunctionTrace() +{ + functionTracingEnabled = true; +} + +BaseCPU::~BaseCPU() +{ +} + +void +BaseCPU::init() +{ + if (!params->deferRegistration) + registerThreadContexts(); +} + +void +BaseCPU::startup() +{ +#if FULL_SYSTEM + if (!params->deferRegistration && profileEvent) + profileEvent->schedule(curTick); +#endif +} + + +void +BaseCPU::regStats() +{ + using namespace Stats; + + numCycles + .name(name() + ".numCycles") + .desc("number of cpu cycles simulated") + ; + + 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()); + +#if FULL_SYSTEM +#endif +} + + +void +BaseCPU::registerThreadContexts() +{ + for (int i = 0; i < threadContexts.size(); ++i) { + ThreadContext *tc = threadContexts[i]; + +#if FULL_SYSTEM + int id = params->cpu_id; + if (id != -1) + id += i; + + tc->setCpuId(system->registerThreadContext(tc, id)); +#else + tc->setCpuId(tc->getProcessPtr()->registerThreadContext(tc)); +#endif + } +} + + +void +BaseCPU::switchOut(Sampler *sampler) +{ + panic("This CPU doesn't support sampling!"); +} + +void +BaseCPU::takeOverFrom(BaseCPU *oldCPU) +{ + assert(threadContexts.size() == oldCPU->threadContexts.size()); + + for (int i = 0; i < threadContexts.size(); ++i) { + ThreadContext *newTC = threadContexts[i]; + ThreadContext *oldTC = oldCPU->threadContexts[i]; + + newTC->takeOverFrom(oldTC); + + CpuEvent::replaceThreadContext(oldTC, newTC); + + assert(newTC->readCpuId() == oldTC->readCpuId()); +#if FULL_SYSTEM + system->replaceThreadContext(newTC, newTC->readCpuId()); +#else + assert(newTC->getProcessPtr() == oldTC->getProcessPtr()); + newTC->getProcessPtr()->replaceThreadContext(newTC, newTC->readCpuId()); +#endif + } + +#if FULL_SYSTEM + for (int i = 0; i < TheISA::NumInterruptLevels; ++i) + interrupts[i] = oldCPU->interrupts[i]; + intstatus = oldCPU->intstatus; + + for (int i = 0; i < threadContexts.size(); ++i) + threadContexts[i]->profileClear(); + + if (profileEvent) + profileEvent->schedule(curTick); +#endif +} + + +#if FULL_SYSTEM +BaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, int _interval) + : Event(&mainEventQueue), cpu(_cpu), interval(_interval) +{ } + +void +BaseCPU::ProfileEvent::process() +{ + for (int i = 0, size = cpu->threadContexts.size(); i < size; ++i) { + ThreadContext *tc = cpu->threadContexts[i]; + tc->profileSample(); + } + + schedule(curTick + interval); +} + +void +BaseCPU::post_interrupt(int int_num, int index) +{ + DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index); + + if (int_num < 0 || int_num >= TheISA::NumInterruptLevels) + panic("int_num out of bounds\n"); + + if (index < 0 || index >= sizeof(uint64_t) * 8) + panic("int_num out of bounds\n"); + + checkInterrupts = true; + interrupts[int_num] |= 1 << index; + intstatus |= (ULL(1) << int_num); +} + +void +BaseCPU::clear_interrupt(int int_num, int index) +{ + DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index); + + if (int_num < 0 || int_num >= TheISA::NumInterruptLevels) + panic("int_num out of bounds\n"); + + if (index < 0 || index >= sizeof(uint64_t) * 8) + panic("int_num out of bounds\n"); + + interrupts[int_num] &= ~(1 << index); + if (interrupts[int_num] == 0) + intstatus &= ~(ULL(1) << int_num); +} + +void +BaseCPU::clear_interrupts() +{ + DPRINTF(Interrupt, "Interrupts all cleared\n"); + + memset(interrupts, 0, sizeof(interrupts)); + intstatus = 0; +} + + +void +BaseCPU::serialize(std::ostream &os) +{ + SERIALIZE_ARRAY(interrupts, TheISA::NumInterruptLevels); + SERIALIZE_SCALAR(intstatus); +} + +void +BaseCPU::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_ARRAY(interrupts, TheISA::NumInterruptLevels); + UNSERIALIZE_SCALAR(intstatus); +} + +#endif // FULL_SYSTEM + +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; + } +} + + +DEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU) diff --git a/src/cpu/base.hh b/src/cpu/base.hh new file mode 100644 index 000000000..43122f238 --- /dev/null +++ b/src/cpu/base.hh @@ -0,0 +1,241 @@ +/* + * 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: Steve Reinhardt + * Nathan Binkert + */ + +#ifndef __CPU_BASE_HH__ +#define __CPU_BASE_HH__ + +#include <vector> + +#include "base/statistics.hh" +#include "config/full_system.hh" +#include "cpu/sampler/sampler.hh" +#include "sim/eventq.hh" +#include "sim/sim_object.hh" +#include "arch/isa_traits.hh" + +class BranchPred; +class CheckerCPU; +class ThreadContext; +class System; + +class BaseCPU : public SimObject +{ + protected: + // CPU's clock period in terms of the number of ticks of curTime. + Tick clock; + + public: + inline Tick frequency() const { return Clock::Frequency / clock; } + inline Tick cycles(int numCycles) const { return clock * numCycles; } + inline Tick curCycle() const { return curTick / clock; } + +#if FULL_SYSTEM + protected: + uint64_t interrupts[TheISA::NumInterruptLevels]; + uint64_t intstatus; + + public: + virtual void post_interrupt(int int_num, int index); + virtual void clear_interrupt(int int_num, int index); + virtual void clear_interrupts(); + bool checkInterrupts; + + bool check_interrupt(int int_num) const { + if (int_num > TheISA::NumInterruptLevels) + panic("int_num out of bounds\n"); + + return interrupts[int_num] != 0; + } + + bool check_interrupts() const { return intstatus != 0; } + uint64_t intr_status() const { return intstatus; } + + class ProfileEvent : public Event + { + private: + BaseCPU *cpu; + int interval; + + public: + ProfileEvent(BaseCPU *cpu, int interval); + void process(); + }; + ProfileEvent *profileEvent; +#endif + + protected: + std::vector<ThreadContext *> threadContexts; + + public: + + /// 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(int thread_num, int delay) {} + + /// Notify the CPU that the indicated context is now suspended. + virtual void suspendContext(int thread_num) {} + + /// Notify the CPU that the indicated context is now deallocated. + virtual void deallocateContext(int thread_num) {} + + /// Notify the CPU that the indicated context is now halted. + virtual void haltContext(int thread_num) {} + + public: + struct Params + { + std::string name; + int numberOfThreads; + bool deferRegistration; + Counter max_insts_any_thread; + Counter max_insts_all_threads; + Counter max_loads_any_thread; + Counter max_loads_all_threads; + Tick clock; + bool functionTrace; + Tick functionTraceStart; + System *system; +#if FULL_SYSTEM + int cpu_id; + Tick profile; +#endif + BaseCPU *checker; + + Params(); + }; + + const Params *params; + + BaseCPU(Params *params); + virtual ~BaseCPU(); + + virtual void init(); + virtual void startup(); + virtual void regStats(); + + virtual void activateWhenReady(int 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(Sampler *); + + /// 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. + */ + int number_of_threads; + + /** + * 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; + +#if FULL_SYSTEM + /** + * Serialize this object to the given output stream. + * @param os The stream to serialize to. + */ + virtual void serialize(std::ostream &os); + + /** + * Reconstruct the state of this object from a checkpoint. + * @param cp The checkpoint use. + * @param section The section name of this object + */ + virtual void unserialize(Checkpoint *cp, const std::string §ion); + +#endif + + /** + * Return pointer to CPU's branch predictor (NULL if none). + * @return Branch predictor pointer. + */ + virtual BranchPred *getBranchPred() { return NULL; }; + + virtual Counter totalInstructions() const { return 0; } + + // Function tracing + private: + bool functionTracingEnabled; + std::ostream *functionTraceStream; + Addr currentFunctionStart; + Addr currentFunctionEnd; + Tick functionEntryTick; + void enableFunctionTrace(); + void traceFunctionsInternal(Addr pc); + + protected: + void traceFunctions(Addr pc) + { + if (functionTracingEnabled) + traceFunctionsInternal(pc); + } + + private: + static std::vector<BaseCPU *> cpuList; //!< Static global cpu list + + public: + static int numSimulatedCPUs() { return cpuList.size(); } + static Counter numSimulatedInstructions() + { + Counter total = 0; + + int size = cpuList.size(); + for (int i = 0; i < size; ++i) + total += cpuList[i]->totalInstructions(); + + return total; + } + + public: + // Number of CPU cycles simulated + Stats::Scalar<> numCycles; +}; + +#endif // __CPU_BASE_HH__ diff --git a/src/cpu/base_dyn_inst.cc b/src/cpu/base_dyn_inst.cc new file mode 100644 index 000000000..30fa10a6b --- /dev/null +++ b/src/cpu/base_dyn_inst.cc @@ -0,0 +1,406 @@ +/* + * 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 <iostream> +#include <set> +#include <string> +#include <sstream> + +#include "base/cprintf.hh" +#include "base/trace.hh" + +#include "arch/faults.hh" +#include "cpu/exetrace.hh" +#include "mem/request.hh" + +#include "cpu/base_dyn_inst.hh" +#include "cpu/o3/alpha_impl.hh" +#include "cpu/o3/alpha_cpu.hh" +//#include "cpu/ozone/simple_impl.hh" +//#include "cpu/ozone/ozone_impl.hh" + +using namespace std; +using namespace TheISA; + +#define NOHASH +#ifndef NOHASH + +#include "base/hashmap.hh" + +unsigned int MyHashFunc(const BaseDynInst *addr) +{ + unsigned a = (unsigned)addr; + unsigned hash = (((a >> 14) ^ ((a >> 2) & 0xffff))) & 0x7FFFFFFF; + + return hash; +} + +typedef m5::hash_map<const BaseDynInst *, const BaseDynInst *, MyHashFunc> +my_hash_t; + +my_hash_t thishash; +#endif + +template <class Impl> +BaseDynInst<Impl>::BaseDynInst(ExtMachInst machInst, Addr inst_PC, + Addr pred_PC, InstSeqNum seq_num, + FullCPU *cpu) + : staticInst(machInst), traceData(NULL), cpu(cpu)/*, xc(cpu->xcBase())*/ +{ + seqNum = seq_num; + + PC = inst_PC; + nextPC = PC + sizeof(MachInst); + predPC = pred_PC; + + initVars(); +} + +template <class Impl> +BaseDynInst<Impl>::BaseDynInst(StaticInstPtr &_staticInst) + : staticInst(_staticInst), traceData(NULL) +{ + seqNum = 0; + initVars(); +} + +template <class Impl> +void +BaseDynInst<Impl>::initVars() +{ + req = NULL; + memData = NULL; + effAddr = 0; + physEffAddr = 0; + storeSize = 0; + + readyRegs = 0; + + // May want to turn this into a bit vector or something. + completed = false; + resultReady = false; + canIssue = false; + issued = false; + executed = false; + canCommit = false; + committed = false; + squashed = false; + squashedInIQ = false; + squashedInLSQ = false; + squashedInROB = false; + eaCalcDone = false; + memOpDone = false; + lqIdx = -1; + sqIdx = -1; + reachedCommit = false; + + blockingInst = false; + recoverInst = false; + + iqEntry = false; + robEntry = false; + + serializeBefore = false; + serializeAfter = false; + serializeHandled = false; + + // 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; + + ++instcount; + + if (instcount > 1500) { + cpu->dumpInsts(); +#ifdef DEBUG + dumpSNList(); +#endif + assert(instcount <= 1500); + } + + DPRINTF(DynInst, "DynInst: [sn:%lli] Instruction created. Instcount=%i\n", + seqNum, instcount); + +#ifdef DEBUG + cpu->snList.insert(seqNum); +#endif +} + +template <class Impl> +BaseDynInst<Impl>::~BaseDynInst() +{ + if (req) { + delete req; + } + + if (memData) { + delete [] memData; + } + + if (traceData) { + delete traceData; + } + + fault = NoFault; + + --instcount; + + DPRINTF(DynInst, "DynInst: [sn:%lli] Instruction destroyed. Instcount=%i\n", + seqNum, instcount); +#ifdef DEBUG + cpu->snList.erase(seqNum); +#endif +} + +#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>::prefetch(Addr addr, unsigned flags) +{ + // This is the "functional" implementation of prefetch. Not much + // happens here since prefetches don't affect the architectural + // state. +/* + // Generate a MemReq so we can translate the effective address. + MemReqPtr req = new MemReq(addr, thread->getXCProxy(), 1, flags); + req->asid = asid; + + // Prefetches never cause faults. + fault = NoFault; + + // note this is a local, not BaseDynInst::fault + Fault trans_fault = cpu->translateDataReadReq(req); + + if (trans_fault == NoFault && !(req->flags & UNCACHEABLE)) { + // It's a valid address to cacheable space. Record key MemReq + // parameters so we can generate another one just like it for + // the timing access without calling translate() again (which + // might mess up the TLB). + effAddr = req->vaddr; + physEffAddr = req->paddr; + memReqFlags = req->flags; + } else { + // Bogus address (invalid or uncacheable space). Mark it by + // setting the eff_addr to InvalidAddr. + effAddr = physEffAddr = MemReq::inval_addr; + } + + if (traceData) { + traceData->setAddr(addr); + } +*/ +} + +template <class Impl> +void +BaseDynInst<Impl>::writeHint(Addr addr, int size, unsigned flags) +{ + // Need to create a MemReq here so we can do a translation. This + // will casue a TLB miss trap if necessary... not sure whether + // that's the best thing to do or not. We don't really need the + // MemReq otherwise, since wh64 has no functional effect. +/* + MemReqPtr req = new MemReq(addr, thread->getXCProxy(), size, flags); + req->asid = asid; + + fault = cpu->translateDataWriteReq(req); + + if (fault == NoFault && !(req->flags & UNCACHEABLE)) { + // Record key MemReq parameters so we can generate another one + // just like it for the timing access without calling translate() + // again (which might mess up the TLB). + effAddr = req->vaddr; + physEffAddr = req->paddr; + memReqFlags = req->flags; + } else { + // ignore faults & accesses to uncacheable space... treat as no-op + effAddr = physEffAddr = MemReq::inval_addr; + } + + storeSize = size; + storeData = 0; +*/ +} + +/** + * @todo Need to find a way to get the cache block size here. + */ +template <class Impl> +Fault +BaseDynInst<Impl>::copySrcTranslate(Addr src) +{ +/* + MemReqPtr req = new MemReq(src, thread->getXCProxy(), 64); + req->asid = asid; + + // translate to physical address + Fault fault = cpu->translateDataReadReq(req); + + if (fault == NoFault) { + thread->copySrcAddr = src; + thread->copySrcPhysAddr = req->paddr; + } else { + thread->copySrcAddr = 0; + thread->copySrcPhysAddr = 0; + } + return fault; +*/ + return NoFault; +} + +/** + * @todo Need to find a way to get the cache block size here. + */ +template <class Impl> +Fault +BaseDynInst<Impl>::copy(Addr dest) +{ +/* + uint8_t data[64]; + FunctionalMemory *mem = thread->mem; + assert(thread->copySrcPhysAddr); + MemReqPtr req = new MemReq(dest, thread->getXCProxy(), 64); + req->asid = asid; + + // translate to physical address + Fault fault = cpu->translateDataWriteReq(req); + + if (fault == NoFault) { + Addr dest_addr = req->paddr; + // Need to read straight from memory since we have more than 8 bytes. + req->paddr = thread->copySrcPhysAddr; + mem->read(req, data); + req->paddr = dest_addr; + mem->write(req, data); + } + return fault; +*/ + return NoFault; +} + +template <class Impl> +void +BaseDynInst<Impl>::dump() +{ + cprintf("T%d : %#08d `", threadNumber, PC); + cout << staticInst->disassemble(PC); + cprintf("'\n"); +} + +template <class Impl> +void +BaseDynInst<Impl>::dump(std::string &outstring) +{ + std::ostringstream s; + s << "T" << threadNumber << " : 0x" << PC << " " + << staticInst->disassemble(PC); + + outstring = s.str(); +} + +template <class Impl> +void +BaseDynInst<Impl>::markSrcRegReady() +{ + if (++readyRegs == numSrcRegs()) { + canIssue = true; + } +} + +template <class Impl> +void +BaseDynInst<Impl>::markSrcRegReady(RegIndex src_idx) +{ + ++readyRegs; + + _readySrcRegIdx[src_idx] = true; + + if (readyRegs == numSrcRegs()) { + canIssue = true; + } +} + +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; +} + +// Forward declaration +template class BaseDynInst<AlphaSimpleImpl>; + +template <> +int +BaseDynInst<AlphaSimpleImpl>::instcount = 0; +/* +// Forward declaration +template class BaseDynInst<SimpleImpl>; + +template <> +int +BaseDynInst<SimpleImpl>::instcount = 0; + +// Forward declaration +template class BaseDynInst<OzoneImpl>; + +template <> +int +BaseDynInst<OzoneImpl>::instcount = 0; +*/ diff --git a/src/cpu/base_dyn_inst.hh b/src/cpu/base_dyn_inst.hh new file mode 100644 index 000000000..948ee058a --- /dev/null +++ b/src/cpu/base_dyn_inst.hh @@ -0,0 +1,755 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#ifndef __CPU_BASE_DYN_INST_HH__ +#define __CPU_BASE_DYN_INST_HH__ + +#include <list> +#include <string> + +#include "arch/faults.hh" +#include "base/fast_alloc.hh" +#include "base/trace.hh" +#include "config/full_system.hh" +#include "cpu/exetrace.hh" +#include "cpu/inst_seq.hh" +#include "cpu/op_class.hh" +#include "cpu/static_inst.hh" +#include "mem/packet.hh" +#include "sim/system.hh" +/* +#include "encumbered/cpu/full/bpred_update.hh" +#include "encumbered/cpu/full/spec_memory.hh" +#include "encumbered/cpu/full/spec_state.hh" +#include "encumbered/mem/functional/main.hh" +*/ + +/** + * @file + * Defines a dynamic instruction context. + */ + +// Forward declaration. +class StaticInstPtr; + +template <class Impl> +class BaseDynInst : public FastAlloc, public RefCounted +{ + public: + // Typedef for the CPU. + typedef typename Impl::FullCPU FullCPU; + typedef typename FullCPU::ImplState ImplState; + + // Binary machine instruction type. + typedef TheISA::MachInst MachInst; + // Extended machine instruction type + typedef TheISA::ExtMachInst ExtMachInst; + // Logical register index type. + typedef TheISA::RegIndex RegIndex; + // Integer register type. + typedef TheISA::IntReg IntReg; + // Floating point register type. + typedef TheISA::FloatReg FloatReg; + + // The DynInstPtr type. + typedef typename Impl::DynInstPtr DynInstPtr; + + // The list of instructions iterator type. + typedef typename std::list<DynInstPtr>::iterator ListIt; + + enum { + MaxInstSrcRegs = TheISA::MaxInstSrcRegs, /// Max source regs + MaxInstDestRegs = TheISA::MaxInstDestRegs, /// Max dest regs + }; + + /** The StaticInst used by this BaseDynInst. */ + StaticInstPtr staticInst; + + //////////////////////////////////////////// + // + // INSTRUCTION EXECUTION + // + //////////////////////////////////////////// + /** InstRecord that tracks this instructions. */ + Trace::InstRecord *traceData; + + /** + * Does a read to a given address. + * @param addr The address to read. + * @param data The read's data is written into this parameter. + * @param flags The request's flags. + * @return Returns any fault due to the read. + */ + template <class T> + Fault read(Addr addr, T &data, unsigned flags); + + /** + * Does a write to a given address. + * @param data The data to be written. + * @param addr The address to write to. + * @param flags The request's flags. + * @param res The result of the write (for load locked/store conditionals). + * @return Returns any fault due to the write. + */ + template <class T> + Fault write(T data, Addr addr, unsigned flags, + uint64_t *res); + + void prefetch(Addr addr, unsigned flags); + void writeHint(Addr addr, int size, unsigned flags); + Fault copySrcTranslate(Addr src); + Fault copy(Addr dest); + + /** @todo: Consider making this private. */ + public: + /** The sequence number of the instruction. */ + InstSeqNum seqNum; + + /** Is the instruction in the IQ */ + bool iqEntry; + + /** Is the instruction in the ROB */ + bool robEntry; + + /** Is the instruction in the LSQ */ + bool lsqEntry; + + /** Is the instruction completed. */ + bool completed; + + /** Is the instruction's result ready. */ + bool resultReady; + + /** Can this instruction issue. */ + bool canIssue; + + /** Has this instruction issued. */ + bool issued; + + /** Has this instruction executed (or made it through execute) yet. */ + bool executed; + + /** Can this instruction commit. */ + bool canCommit; + + /** Is this instruction committed. */ + bool committed; + + /** Is this instruction squashed. */ + bool squashed; + + /** Is this instruction squashed in the instruction queue. */ + bool squashedInIQ; + + /** Is this instruction squashed in the instruction queue. */ + bool squashedInLSQ; + + /** Is this instruction squashed in the instruction queue. */ + bool squashedInROB; + + /** Is this a recover instruction. */ + bool recoverInst; + + /** Is this a thread blocking instruction. */ + bool blockingInst; /* this inst has called thread_block() */ + + /** Is this a thread syncrhonization instruction. */ + bool threadsyncWait; + + /** The thread this instruction is from. */ + short threadNumber; + + /** data address space ID, for loads & stores. */ + short asid; + + /** How many source registers are ready. */ + unsigned readyRegs; + + /** Pointer to the FullCPU object. */ + FullCPU *cpu; + + /** Pointer to the thread state. */ + ImplState *thread; + + /** The kind of fault this instruction has generated. */ + Fault fault; + + /** The memory request. */ +// MemReqPtr req; + Request *req; +// Packet pkt; + + uint8_t *memData; + + /** The effective virtual address (lds & stores only). */ + Addr effAddr; + + /** The effective physical address. */ + Addr physEffAddr; + + /** Effective virtual address for a copy source. */ + Addr copySrcEffAddr; + + /** Effective physical address for a copy source. */ + Addr copySrcPhysEffAddr; + + /** The memory request flags (from translation). */ + unsigned memReqFlags; + + /** The size of the data to be stored. */ + int storeSize; + + /** The data to be stored. */ + IntReg storeData; + + union Result { + uint64_t integer; + float fp; + double dbl; + }; + + /** The result of the instruction; assumes for now that there's only one + * destination register. + */ + Result instResult; + + /** PC of this instruction. */ + Addr PC; + + /** Next non-speculative PC. It is not filled in at fetch, but rather + * once the target of the branch is truly known (either decode or + * execute). + */ + Addr nextPC; + + /** Predicted next PC. */ + Addr predPC; + + /** Count of total number of dynamic instructions. */ + static int instcount; + +#ifdef DEBUG + void dumpSNList(); +#endif + + /** Whether or not the source register is ready. + * @todo: Not sure this should be here vs the derived class. + */ + bool _readySrcRegIdx[MaxInstSrcRegs]; + + public: + /** BaseDynInst constructor given a binary instruction. + * @param inst The binary instruction. + * @param PC The PC of the instruction. + * @param pred_PC The predicted next PC. + * @param seq_num The sequence number of the instruction. + * @param cpu Pointer to the instruction's CPU. + */ + BaseDynInst(ExtMachInst inst, Addr PC, Addr pred_PC, InstSeqNum seq_num, + FullCPU *cpu); + + /** BaseDynInst constructor given a StaticInst pointer. + * @param _staticInst The StaticInst for this BaseDynInst. + */ + BaseDynInst(StaticInstPtr &_staticInst); + + /** BaseDynInst destructor. */ + ~BaseDynInst(); + + private: + /** Function to initialize variables in the constructors. */ + void initVars(); + + public: + /** + * @todo: Make this function work; currently it is a dummy function. + * @param fault Last fault. + * @param cmd Last command. + * @param addr Virtual address of access. + * @param p Memory accessed. + * @param nbytes Access size. + */ +// void +// trace_mem(Fault fault, +// MemCmd cmd, +// Addr addr, +// void *p, +// int nbytes); + + /** Dumps out contents of this BaseDynInst. */ + void dump(); + + /** Dumps out contents of this BaseDynInst into given string. */ + void dump(std::string &outstring); + + /** Returns the fault type. */ + Fault getFault() { return fault; } + + /** Checks whether or not this instruction has had its branch target + * calculated yet. For now it is not utilized and is hacked to be + * always false. + * @todo: Actually use this instruction. + */ + bool doneTargCalc() { return false; } + + /** Returns the next PC. This could be the speculative next PC if it is + * called prior to the actual branch target being calculated. + */ + Addr readNextPC() { return nextPC; } + + /** Set the predicted target of this current instruction. */ + void setPredTarg(Addr predicted_PC) { predPC = predicted_PC; } + + /** Returns the predicted target of the branch. */ + Addr readPredTarg() { return predPC; } + + /** Returns whether the instruction was predicted taken or not. */ + bool predTaken() { return predPC != (PC + sizeof(MachInst)); } + + /** Returns whether the instruction mispredicted. */ + bool mispredicted() { return predPC != nextPC; } + + // + // Instruction types. Forward checks to StaticInst object. + // + bool isNop() const { return staticInst->isNop(); } + bool isMemRef() const { return staticInst->isMemRef(); } + bool isLoad() const { return staticInst->isLoad(); } + bool isStore() const { return staticInst->isStore(); } + bool isStoreConditional() const + { return staticInst->isStoreConditional(); } + bool isInstPrefetch() const { return staticInst->isInstPrefetch(); } + bool isDataPrefetch() const { return staticInst->isDataPrefetch(); } + bool isCopy() const { return staticInst->isCopy(); } + bool isInteger() const { return staticInst->isInteger(); } + bool isFloating() const { return staticInst->isFloating(); } + bool isControl() const { return staticInst->isControl(); } + bool isCall() const { return staticInst->isCall(); } + bool isReturn() const { return staticInst->isReturn(); } + bool isDirectCtrl() const { return staticInst->isDirectCtrl(); } + bool isIndirectCtrl() const { return staticInst->isIndirectCtrl(); } + bool isCondCtrl() const { return staticInst->isCondCtrl(); } + bool isUncondCtrl() const { return staticInst->isUncondCtrl(); } + bool isThreadSync() const { return staticInst->isThreadSync(); } + bool isSerializing() const { return staticInst->isSerializing(); } + bool isSerializeBefore() const + { return staticInst->isSerializeBefore() || serializeBefore; } + bool isSerializeAfter() const + { return staticInst->isSerializeAfter() || serializeAfter; } + bool isMemBarrier() const { return staticInst->isMemBarrier(); } + bool isWriteBarrier() const { return staticInst->isWriteBarrier(); } + bool isNonSpeculative() const { return staticInst->isNonSpeculative(); } + bool isQuiesce() const { return staticInst->isQuiesce(); } + bool isIprAccess() const { return staticInst->isIprAccess(); } + bool isUnverifiable() const { return staticInst->isUnverifiable(); } + + /** Temporarily sets this instruction as a serialize before instruction. */ + void setSerializeBefore() { serializeBefore = true; } + + /** Clears the serializeBefore part of this instruction. */ + void clearSerializeBefore() { serializeBefore = false; } + + /** Checks if this serializeBefore is only temporarily set. */ + bool isTempSerializeBefore() { return serializeBefore; } + + /** Tracks if instruction has been externally set as serializeBefore. */ + bool serializeBefore; + + /** Temporarily sets this instruction as a serialize after instruction. */ + void setSerializeAfter() { serializeAfter = true; } + + /** Clears the serializeAfter part of this instruction.*/ + void clearSerializeAfter() { serializeAfter = false; } + + /** Checks if this serializeAfter is only temporarily set. */ + bool isTempSerializeAfter() { return serializeAfter; } + + /** Tracks if instruction has been externally set as serializeAfter. */ + bool serializeAfter; + + /** Checks if the serialization part of this instruction has been + * handled. This does not apply to the temporary serializing + * state; it only applies to this instruction's own permanent + * serializing state. + */ + bool isSerializeHandled() { return serializeHandled; } + + /** Sets the serialization part of this instruction as handled. */ + void setSerializeHandled() { serializeHandled = true; } + + /** Whether or not the serialization of this instruction has been handled. */ + bool serializeHandled; + + /** Returns the opclass of this instruction. */ + OpClass opClass() const { return staticInst->opClass(); } + + /** Returns the branch target address. */ + Addr branchTarget() const { return staticInst->branchTarget(PC); } + + /** Returns the number of source registers. */ + int8_t numSrcRegs() const { return staticInst->numSrcRegs(); } + + /** Returns the number of destination registers. */ + int8_t numDestRegs() const { return staticInst->numDestRegs(); } + + // the following are used to track physical register usage + // for machines with separate int & FP reg files + int8_t numFPDestRegs() const { return staticInst->numFPDestRegs(); } + int8_t numIntDestRegs() const { return staticInst->numIntDestRegs(); } + + /** Returns the logical register index of the i'th destination register. */ + RegIndex destRegIdx(int i) const { return staticInst->destRegIdx(i); } + + /** Returns the logical register index of the i'th source register. */ + RegIndex srcRegIdx(int i) const { return staticInst->srcRegIdx(i); } + + /** Returns the result of an integer instruction. */ + uint64_t readIntResult() { return instResult.integer; } + + /** Returns the result of a floating point instruction. */ + float readFloatResult() { return instResult.fp; } + + /** Returns the result of a floating point (double) instruction. */ + double readDoubleResult() { return instResult.dbl; } + + void setIntReg(const StaticInst *si, int idx, uint64_t val) + { + instResult.integer = val; + } + + void setFloatReg(const StaticInst *si, int idx, FloatReg val, int width) + { + if (width == 32) + instResult.fp = val; + else if (width == 64) + instResult.dbl = val; + else + panic("Unsupported width!"); + } + + void setFloatReg(const StaticInst *si, int idx, FloatReg val) + { + instResult.fp = val; + } + + void setFloatRegBits(const StaticInst *si, int idx, uint64_t val, int width) + { + instResult.integer = val; + } + + void setFloatRegBits(const StaticInst *si, int idx, uint64_t val) + { + instResult.integer = val; + } + + /** Records that one of the source registers is ready. */ + void markSrcRegReady(); + + /** Marks a specific register as ready. */ + void markSrcRegReady(RegIndex src_idx); + + /** Returns if a source register is ready. */ + bool isReadySrcRegIdx(int idx) const + { + return this->_readySrcRegIdx[idx]; + } + + /** Sets this instruction as completed. */ + void setCompleted() { completed = true; } + + /** Returns whether or not this instruction is completed. */ + bool isCompleted() const { return completed; } + + void setResultReady() { resultReady = true; } + + bool isResultReady() const { return resultReady; } + + /** Sets this instruction as ready to issue. */ + void setCanIssue() { canIssue = true; } + + /** Returns whether or not this instruction is ready to issue. */ + bool readyToIssue() const { return canIssue; } + + /** Sets this instruction as issued from the IQ. */ + void setIssued() { issued = true; } + + /** Returns whether or not this instruction has issued. */ + bool isIssued() const { return issued; } + + /** Sets this instruction as executed. */ + void setExecuted() { executed = true; } + + /** Returns whether or not this instruction has executed. */ + bool isExecuted() const { return executed; } + + /** Sets this instruction as ready to commit. */ + void setCanCommit() { canCommit = true; } + + /** Clears this instruction as being ready to commit. */ + void clearCanCommit() { canCommit = false; } + + /** Returns whether or not this instruction is ready to commit. */ + bool readyToCommit() const { return canCommit; } + + /** Sets this instruction as committed. */ + void setCommitted() { committed = true; } + + /** Returns whether or not this instruction is committed. */ + bool isCommitted() const { return committed; } + + /** Sets this instruction as squashed. */ + void setSquashed() { squashed = true; } + + /** Returns whether or not this instruction is squashed. */ + bool isSquashed() const { return squashed; } + + //Instruction Queue Entry + //----------------------- + /** Sets this instruction as a entry the IQ. */ + void setInIQ() { iqEntry = true; } + + /** Sets this instruction as a entry the IQ. */ + void removeInIQ() { iqEntry = false; } + + /** Sets this instruction as squashed in the IQ. */ + void setSquashedInIQ() { squashedInIQ = true; squashed = true;} + + /** Returns whether or not this instruction is squashed in the IQ. */ + bool isSquashedInIQ() const { return squashedInIQ; } + + /** Returns whether or not this instruction has issued. */ + bool isInIQ() const { return iqEntry; } + + + //Load / Store Queue Functions + //----------------------- + /** Sets this instruction as a entry the LSQ. */ + void setInLSQ() { lsqEntry = true; } + + /** Sets this instruction as a entry the LSQ. */ + void removeInLSQ() { lsqEntry = false; } + + /** Sets this instruction as squashed in the LSQ. */ + void setSquashedInLSQ() { squashedInLSQ = true;} + + /** Returns whether or not this instruction is squashed in the LSQ. */ + bool isSquashedInLSQ() const { return squashedInLSQ; } + + /** Returns whether or not this instruction is in the LSQ. */ + bool isInLSQ() const { return lsqEntry; } + + + //Reorder Buffer Functions + //----------------------- + /** Sets this instruction as a entry the ROB. */ + void setInROB() { robEntry = true; } + + /** Sets this instruction as a entry the ROB. */ + void removeInROB() { robEntry = false; } + + /** Sets this instruction as squashed in the ROB. */ + void setSquashedInROB() { squashedInROB = true; } + + /** Returns whether or not this instruction is squashed in the ROB. */ + bool isSquashedInROB() const { return squashedInROB; } + + /** Returns whether or not this instruction is in the ROB. */ + bool isInROB() const { return robEntry; } + + /** Read the PC of this instruction. */ + const Addr readPC() const { return PC; } + + /** Set the next PC of this instruction (its actual target). */ + void setNextPC(uint64_t val) + { + nextPC = val; +// instResult.integer = val; + } + + void setASID(short addr_space_id) { asid = addr_space_id; } + + void setThread(unsigned tid) { threadNumber = tid; } + + void setState(ImplState *state) { thread = state; } + + /** Returns the thread context. + */ + ThreadContext *tcBase() { return thread->getTC(); } + + private: + /** Instruction effective address. + * @todo: Consider if this is necessary or not. + */ + Addr instEffAddr; + + /** Whether or not the effective address calculation is completed. + * @todo: Consider if this is necessary or not. + */ + bool eaCalcDone; + + public: + /** Sets the effective address. */ + void setEA(Addr &ea) { instEffAddr = ea; eaCalcDone = true; } + + /** Returns the effective address. */ + const Addr &getEA() const { return instEffAddr; } + + /** Returns whether or not the eff. addr. calculation has been completed. */ + bool doneEACalc() { return eaCalcDone; } + + /** Returns whether or not the eff. addr. source registers are ready. */ + bool eaSrcsReady(); + + /** Whether or not the memory operation is done. */ + bool memOpDone; + + public: + /** Load queue index. */ + int16_t lqIdx; + + /** Store queue index. */ + int16_t sqIdx; + + bool reachedCommit; + + /** Iterator pointing to this BaseDynInst in the list of all insts. */ + ListIt instListIt; + + /** Returns iterator to this instruction in the list of all insts. */ + ListIt &getInstListIt() { return instListIt; } + + /** Sets iterator for this instruction in the list of all insts. */ + void setInstListIt(ListIt _instListIt) { instListIt = _instListIt; } +}; + +template<class Impl> +template<class T> +inline Fault +BaseDynInst<Impl>::read(Addr addr, T &data, unsigned flags) +{ + // Sometimes reads will get retried, so they may come through here + // twice. + if (!req) { + req = new Request(); + req->setVirt(asid, addr, sizeof(T), flags, this->PC); + req->setThreadContext(thread->readCpuId(), threadNumber); + } else { + assert(addr == req->getVaddr()); + } + + if ((req->getVaddr() & (TheISA::VMPageSize - 1)) + req->getSize() > + TheISA::VMPageSize) { + return TheISA::genAlignmentFault(); + } + + fault = cpu->translateDataReadReq(req, thread); + + if (fault == NoFault) { + effAddr = req->getVaddr(); + physEffAddr = req->getPaddr(); + memReqFlags = req->getFlags(); + +#if 0 + if (cpu->system->memctrl->badaddr(physEffAddr)) { + fault = TheISA::genMachineCheckFault(); + data = (T)-1; + this->setExecuted(); + } else { + fault = cpu->read(req, data, lqIdx); + } +#else + fault = cpu->read(req, data, lqIdx); +#endif + } else { + // Return a fixed value to keep simulation deterministic even + // along misspeculated paths. + data = (T)-1; + + // Commit will have to clean up whatever happened. Set this + // instruction as executed. + this->setExecuted(); + } + + if (traceData) { + traceData->setAddr(addr); + traceData->setData(data); + } + + return fault; +} + +template<class Impl> +template<class T> +inline Fault +BaseDynInst<Impl>::write(T data, Addr addr, unsigned flags, uint64_t *res) +{ + if (traceData) { + traceData->setAddr(addr); + traceData->setData(data); + } + + assert(req == NULL); + + req = new Request(); + req->setVirt(asid, addr, sizeof(T), flags, this->PC); + req->setThreadContext(thread->readCpuId(), threadNumber); + + if ((req->getVaddr() & (TheISA::VMPageSize - 1)) + req->getSize() > + TheISA::VMPageSize) { + return TheISA::genAlignmentFault(); + } + + fault = cpu->translateDataWriteReq(req, thread); + + if (fault == NoFault) { + effAddr = req->getVaddr(); + physEffAddr = req->getPaddr(); + memReqFlags = req->getFlags(); +#if 0 + if (cpu->system->memctrl->badaddr(physEffAddr)) { + fault = TheISA::genMachineCheckFault(); + } else { + fault = cpu->write(req, data, sqIdx); + } +#else + fault = cpu->write(req, data, sqIdx); +#endif + } + + if (res) { + // always return some result to keep misspeculated paths + // (which will ignore faults) deterministic + *res = (fault == NoFault) ? req->getScResult() : 0; + } + + return fault; +} + +#endif // __CPU_BASE_DYN_INST_HH__ diff --git a/src/cpu/checker/cpu.cc b/src/cpu/checker/cpu.cc new file mode 100644 index 000000000..ebc02f7be --- /dev/null +++ b/src/cpu/checker/cpu.cc @@ -0,0 +1,784 @@ +/* + * 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 <list> +#include <string> + +#include "base/refcnt.hh" +#include "cpu/base.hh" +#include "cpu/base_dyn_inst.hh" +#include "cpu/checker/cpu.hh" +#include "cpu/simple_thread.hh" +#include "cpu/thread_context.hh" +#include "cpu/static_inst.hh" +#include "sim/byteswap.hh" +#include "sim/sim_object.hh" +#include "sim/stats.hh" + +#include "cpu/o3/alpha_dyn_inst.hh" +#include "cpu/o3/alpha_impl.hh" + +//#include "cpu/ozone/dyn_inst.hh" +//#include "cpu/ozone/ozone_impl.hh" +//#include "cpu/ozone/simple_impl.hh" + +#if FULL_SYSTEM +#include "sim/system.hh" +#include "arch/vtophys.hh" +#endif // FULL_SYSTEM + +using namespace std; +//The CheckerCPU does alpha only +using namespace AlphaISA; + +void +CheckerCPU::init() +{ +} + +CheckerCPU::CheckerCPU(Params *p) + : BaseCPU(p), thread(NULL), tc(NULL) +{ + memReq = NULL; + + numInst = 0; + startNumInst = 0; + numLoad = 0; + startNumLoad = 0; + youngestSN = 0; + + changedPC = willChangePC = changedNextPC = false; + + exitOnError = p->exitOnError; +#if FULL_SYSTEM + itb = p->itb; + dtb = p->dtb; + systemPtr = NULL; +#else + process = p->process; +#endif +} + +CheckerCPU::~CheckerCPU() +{ +} + +void +CheckerCPU::setMemory(MemObject *mem) +{ +#if !FULL_SYSTEM + memPtr = mem; + thread = new SimpleThread(this, /* thread_num */ 0, process, + /* asid */ 0, mem); + + thread->setStatus(ThreadContext::Suspended); + tc = thread->getTC(); + threadContexts.push_back(tc); +#endif +} + +void +CheckerCPU::setSystem(System *system) +{ +#if FULL_SYSTEM + systemPtr = system; + + thread = new SimpleThread(this, 0, systemPtr, itb, dtb, false); + + thread->setStatus(ThreadContext::Suspended); + tc = thread->getTC(); + threadContexts.push_back(tc); + delete thread->kernelStats; + thread->kernelStats = NULL; +#endif +} + +void +CheckerCPU::setIcachePort(Port *icache_port) +{ + icachePort = icache_port; +} + +void +CheckerCPU::setDcachePort(Port *dcache_port) +{ + dcachePort = dcache_port; +} + +void +CheckerCPU::serialize(ostream &os) +{ +/* + BaseCPU::serialize(os); + SERIALIZE_SCALAR(inst); + nameOut(os, csprintf("%s.xc", name())); + thread->serialize(os); + cacheCompletionEvent.serialize(os); +*/ +} + +void +CheckerCPU::unserialize(Checkpoint *cp, const string §ion) +{ +/* + BaseCPU::unserialize(cp, section); + UNSERIALIZE_SCALAR(inst); + thread->unserialize(cp, csprintf("%s.xc", section)); +*/ +} + +Fault +CheckerCPU::copySrcTranslate(Addr src) +{ + panic("Unimplemented!"); +} + +Fault +CheckerCPU::copy(Addr dest) +{ + panic("Unimplemented!"); +} + +template <class T> +Fault +CheckerCPU::read(Addr addr, T &data, unsigned flags) +{ + // need to fill in CPU & thread IDs here + memReq = new Request(); + + memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC()); + + // translate to physical address + translateDataReadReq(memReq); + + Packet *pkt = new Packet(memReq, Packet::ReadReq, Packet::Broadcast); + + pkt->dataStatic(&data); + + if (!(memReq->getFlags() & UNCACHEABLE)) { + // 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, &unverifiedResult.integer, sizeof(T)); + } + + delete pkt; + + return NoFault; +} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +template +Fault +CheckerCPU::read(Addr addr, uint64_t &data, unsigned flags); + +template +Fault +CheckerCPU::read(Addr addr, uint32_t &data, unsigned flags); + +template +Fault +CheckerCPU::read(Addr addr, uint16_t &data, unsigned flags); + +template +Fault +CheckerCPU::read(Addr addr, uint8_t &data, unsigned flags); + +#endif //DOXYGEN_SHOULD_SKIP_THIS + +template<> +Fault +CheckerCPU::read(Addr addr, double &data, unsigned flags) +{ + return read(addr, *(uint64_t*)&data, flags); +} + +template<> +Fault +CheckerCPU::read(Addr addr, float &data, unsigned flags) +{ + return read(addr, *(uint32_t*)&data, flags); +} + +template<> +Fault +CheckerCPU::read(Addr addr, int32_t &data, unsigned flags) +{ + return read(addr, (uint32_t&)data, flags); +} + +template <class T> +Fault +CheckerCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) +{ + // need to fill in CPU & thread IDs here + memReq = new Request(); + + memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC()); + + // translate to physical address + thread->translateDataWriteReq(memReq); + + // Can compare the write data and result only if it's cacheable, + // not a store conditional, or is a store conditional that + // succeeded. + // @todo: Verify that actual memory matches up with these values. + // Right now it only verifies that the instruction data is the + // same as what was in the request that got sent to memory; there + // is no verification that it is the same as what is in memory. + // This is because the LSQ would have to be snooped in the CPU to + // verify this data. + if (unverifiedReq && + !(unverifiedReq->getFlags() & UNCACHEABLE) && + (!(unverifiedReq->getFlags() & LOCKED) || + ((unverifiedReq->getFlags() & LOCKED) && + unverifiedReq->getScResult() == 1))) { + T inst_data; +/* + // This code would work if the LSQ allowed for snooping. + Packet *pkt = new Packet(memReq, Packet::ReadReq, Packet::Broadcast); + pkt.dataStatic(&inst_data); + + dcachePort->sendFunctional(pkt); + + delete pkt; +*/ + memcpy(&inst_data, unverifiedMemData, sizeof(T)); + + if (data != inst_data) { + warn("%lli: Store value does not match value in memory! " + "Instruction: %#x, memory: %#x", + curTick, inst_data, data); + 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 (res && unverifiedReq->scResultValid()) + *res = unverifiedReq->getScResult(); + + return NoFault; +} + + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +template +Fault +CheckerCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res); + +template +Fault +CheckerCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res); + +template +Fault +CheckerCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res); + +template +Fault +CheckerCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res); + +#endif //DOXYGEN_SHOULD_SKIP_THIS + +template<> +Fault +CheckerCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) +{ + return write(*(uint64_t*)&data, addr, flags, res); +} + +template<> +Fault +CheckerCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) +{ + return write(*(uint32_t*)&data, addr, flags, res); +} + +template<> +Fault +CheckerCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) +{ + return write((uint32_t)data, addr, flags, res); +} + + +#if FULL_SYSTEM +Addr +CheckerCPU::dbg_vtophys(Addr addr) +{ + return vtophys(tc, addr); +} +#endif // FULL_SYSTEM + +bool +CheckerCPU::translateInstReq(Request *req) +{ +#if FULL_SYSTEM + return (thread->translateInstReq(req) == NoFault); +#else + thread->translateInstReq(req); + return true; +#endif +} + +void +CheckerCPU::translateDataReadReq(Request *req) +{ + thread->translateDataReadReq(req); + + if (req->getVaddr() != unverifiedReq->getVaddr()) { + warn("%lli: Request virtual addresses do not match! Inst: %#x, " + "checker: %#x", + curTick, unverifiedReq->getVaddr(), req->getVaddr()); + handleError(); + } + req->setPaddr(unverifiedReq->getPaddr()); + + if (checkFlags(req)) { + warn("%lli: Request flags do not match! Inst: %#x, checker: %#x", + curTick, unverifiedReq->getFlags(), req->getFlags()); + handleError(); + } +} + +void +CheckerCPU::translateDataWriteReq(Request *req) +{ + thread->translateDataWriteReq(req); + + if (req->getVaddr() != unverifiedReq->getVaddr()) { + warn("%lli: Request virtual addresses do not match! Inst: %#x, " + "checker: %#x", + curTick, unverifiedReq->getVaddr(), req->getVaddr()); + handleError(); + } + req->setPaddr(unverifiedReq->getPaddr()); + + if (checkFlags(req)) { + warn("%lli: Request flags do not match! Inst: %#x, checker: %#x", + curTick, unverifiedReq->getFlags(), req->getFlags()); + handleError(); + } +} + +bool +CheckerCPU::checkFlags(Request *req) +{ + // Remove any dynamic flags that don't have to do with the request itself. + unsigned flags = unverifiedReq->getFlags(); + unsigned mask = LOCKED | PHYSICAL | VPTE | ALTMODE | UNCACHEABLE | NO_FAULT; + flags = flags & (mask); + if (flags == req->getFlags()) { + return false; + } else { + return true; + } +} + +template <class DynInstPtr> +void +Checker<DynInstPtr>::tick(DynInstPtr &completed_inst) +{ + DynInstPtr inst; + + // 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:%#x to list.\n", + completed_inst->seqNum, completed_inst->readPC()); + 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:%#x to list.\n", + completed_inst->seqNum, completed_inst->readPC()); + 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; + } + } + } + + // 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:%#x.\n", + inst->seqNum, inst->readPC()); + unverifiedResult.integer = inst->readIntResult(); + unverifiedReq = inst->req; + unverifiedMemData = inst->memData; + numCycles++; + + Fault fault = NoFault; + + // maintain $r0 semantics + thread->setIntReg(ZeroReg, 0); +#ifdef TARGET_ALPHA + thread->setFloatRegDouble(ZeroReg, 0.0); +#endif // TARGET_ALPHA + + // 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 %#x\n", + thread->readPC()); + if (willChangePC) { + if (newPC == thread->readPC()) { + DPRINTF(Checker, "Changed PC matches expected PC\n"); + } else { + warn("%lli: Changed PC does not match expected PC, " + "changed: %#x, expected: %#x", + curTick, thread->readPC(), newPC); + handleError(); + } + willChangePC = false; + } + changedPC = false; + } + if (changedNextPC) { + DPRINTF(Checker, "Changed NextPC recently to %#x\n", + thread->readNextPC()); + changedNextPC = false; + } + + // Try to fetch the instruction + +#if FULL_SYSTEM +#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0 +#else +#define IFETCH_FLAGS(pc) 0 +#endif + + uint64_t fetch_PC = thread->readPC() & ~3; + + // set up memory request for instruction fetch + memReq = new Request(inst->threadNumber, fetch_PC, + sizeof(uint32_t), + IFETCH_FLAGS(thread->readPC()), + fetch_PC, thread->readCpuId(), inst->threadNumber); + + bool succeeded = translateInstReq(memReq); + + if (!succeeded) { + if (inst->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 %#x was not found in the ITB!", + curTick, thread->readPC()); + handleError(); + + // go to the next instruction + thread->setPC(thread->readNextPC()); + thread->setNextPC(thread->readNextPC() + sizeof(MachInst)); + + 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 = inst->getFault(); + } + } + + if (fault == NoFault) { + Packet *pkt = new Packet(memReq, Packet::ReadReq, + Packet::Broadcast); + + pkt->dataStatic(&machInst); + + icachePort->sendFunctional(pkt); + + delete pkt; + + // keep an instruction count + numInst++; + + // decode the instruction + machInst = gtoh(machInst); + // Checks that the instruction matches what we expected it to be. + // Checks both the machine instruction and the PC. + validateInst(inst); + + curStaticInst = StaticInst::decode(makeExtMI(machInst, + thread->readPC())); + +#if FULL_SYSTEM + thread->setInst(machInst); +#endif // FULL_SYSTEM + + fault = inst->getFault(); + } + + // Discard fetch's memReq. + delete memReq; + memReq = NULL; + + // 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) { + + thread->funcExeInst++; + + fault = curStaticInst->execute(this, NULL); + + // Checks to make sure instrution results are correct. + validateExecution(inst); + + if (curStaticInst->isLoad()) { + ++numLoad; + } + } + + if (fault != NoFault) { +#if FULL_SYSTEM + fault->invoke(tc); + willChangePC = true; + newPC = thread->readPC(); + DPRINTF(Checker, "Fault, PC is now %#x\n", newPC); +#else // !FULL_SYSTEM + fatal("fault (%d) detected @ PC 0x%08p", fault, thread->readPC()); +#endif // FULL_SYSTEM + } else { +#if THE_ISA != MIPS_ISA + // go to the next instruction + thread->setPC(thread->readNextPC()); + thread->setNextPC(thread->readNextPC() + sizeof(MachInst)); +#else + // go to the next instruction + thread->setPC(thread->readNextPC()); + thread->setNextPC(thread->readNextNPC()); + thread->setNextNPC(thread->readNextNPC() + sizeof(MachInst)); +#endif + + } + +#if FULL_SYSTEM + // @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->readPC(); + system->pcEventQueue.service(tc); + count++; + } while (oldpc != thread->readPC()); + if (count > 1) { + willChangePC = true; + newPC = thread->readPC(); + DPRINTF(Checker, "PC Event, PC is now %#x\n", newPC); + } +#endif + + // @todo: Optionally can check all registers. (Or just those + // that have been modified). + validateState(); + + if (memReq) { + delete memReq; + memReq = NULL; + } + + // Continue verifying instructions if there's another completed + // instruction waiting to be verified. + if (instList.empty()) { + break; + } else if (instList.front()->isCompleted()) { + inst = instList.front(); + instList.pop_front(); + } else { + break; + } + } +} + +template <class DynInstPtr> +void +Checker<DynInstPtr>::switchOut(Sampler *s) +{ + instList.clear(); +} + +template <class DynInstPtr> +void +Checker<DynInstPtr>::takeOverFrom(BaseCPU *oldCPU) +{ +} + +template <class DynInstPtr> +void +Checker<DynInstPtr>::validateInst(DynInstPtr &inst) +{ + if (inst->readPC() != thread->readPC()) { + warn("%lli: PCs do not match! Inst: %#x, checker: %#x", + curTick, inst->readPC(), thread->readPC()); + if (changedPC) { + warn("%lli: Changed PCs recently, may not be an error", + curTick); + } else { + handleError(); + } + } + + MachInst mi = static_cast<MachInst>(inst->staticInst->machInst); + + if (mi != machInst) { + warn("%lli: Binary instructions do not match! Inst: %#x, " + "checker: %#x", + curTick, mi, machInst); + handleError(); + } +} + +template <class DynInstPtr> +void +Checker<DynInstPtr>::validateExecution(DynInstPtr &inst) +{ + if (inst->numDestRegs()) { + // @todo: Support more destination registers. + 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. + RegIndex idx = inst->destRegIdx(0); + if (idx < TheISA::FP_Base_DepTag) { + thread->setIntReg(idx, inst->readIntResult()); + } else if (idx < TheISA::Fpcr_DepTag) { + thread->setFloatRegBits(idx, inst->readIntResult()); + } else { + thread->setMiscReg(idx, inst->readIntResult()); + } + } else if (result.integer != inst->readIntResult()) { + warn("%lli: Instruction results do not match! (Values may not " + "actually be integers) Inst: %#x, checker: %#x", + curTick, inst->readIntResult(), result.integer); + handleError(); + } + } + + if (inst->readNextPC() != thread->readNextPC()) { + warn("%lli: Instruction next PCs do not match! Inst: %#x, " + "checker: %#x", + curTick, inst->readNextPC(), thread->readNextPC()); + handleError(); + } + + // 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()->readMiscReg(misc_reg_idx) != + thread->readMiscReg(misc_reg_idx)) { + warn("%lli: Misc reg idx %i (side effect) does not match! " + "Inst: %#x, checker: %#x", + curTick, misc_reg_idx, + inst->tcBase()->readMiscReg(misc_reg_idx), + thread->readMiscReg(misc_reg_idx)); + handleError(); + } + } +} + +template <class DynInstPtr> +void +Checker<DynInstPtr>::validateState() +{ +} + +template <class DynInstPtr> +void +Checker<DynInstPtr>::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:%#x\n[sn:%lli]\n[tid:%i]\n" + "Completed:%i\n", + (*inst_list_it)->readPC(), + (*inst_list_it)->seqNum, + (*inst_list_it)->threadNumber, + (*inst_list_it)->isCompleted()); + + cprintf("\n"); + + inst_list_it--; + ++num; + } + +} + +//template +//class Checker<RefCountingPtr<OzoneDynInst<OzoneImpl> > >; + +template +class Checker<RefCountingPtr<AlphaDynInst<AlphaSimpleImpl> > >; diff --git a/src/cpu/checker/cpu.hh b/src/cpu/checker/cpu.hh new file mode 100644 index 000000000..c9986d228 --- /dev/null +++ b/src/cpu/checker/cpu.hh @@ -0,0 +1,386 @@ +/* + * 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 <queue> +#include <map> + +#include "arch/types.hh" +#include "base/statistics.hh" +#include "config/full_system.hh" +#include "cpu/base.hh" +#include "cpu/base_dyn_inst.hh" +#include "cpu/simple_thread.hh" +#include "cpu/pc_event.hh" +#include "cpu/static_inst.hh" +#include "sim/eventq.hh" + +// forward declarations +#if FULL_SYSTEM +class Processor; +class AlphaITB; +class AlphaDTB; +class PhysicalMemory; + +class RemoteGDB; +class GDBListener; + +#else + +class Process; + +#endif // FULL_SYSTEM +template <class> +class BaseDynInst; +class ThreadContext; +class MemInterface; +class Checkpoint; +class Request; +class Sampler; + +/** + * 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; + public: + virtual void init(); + + struct Params : public BaseCPU::Params + { +#if FULL_SYSTEM + AlphaITB *itb; + AlphaDTB *dtb; +#else + Process *process; +#endif + bool exitOnError; + }; + + public: + CheckerCPU(Params *p); + virtual ~CheckerCPU(); + + Process *process; + + void setMemory(MemObject *mem); + + MemObject *memPtr; + + void setSystem(System *system); + + System *systemPtr; + + void setIcachePort(Port *icache_port); + + Port *icachePort; + + void setDcachePort(Port *dcache_port); + + Port *dcachePort; + + public: + // Primary thread being run. + SimpleThread *thread; + + ThreadContext *tc; + + AlphaITB *itb; + AlphaDTB *dtb; + +#if FULL_SYSTEM + Addr dbg_vtophys(Addr addr); +#endif + + union Result { + uint64_t integer; + float fp; + double dbl; + }; + + Result result; + + // current instruction + MachInst machInst; + + // Pointer to the one memory request. + RequestPtr memReq; + + StaticInstPtr curStaticInst; + + // number of simulated instructions + Counter numInst; + Counter startNumInst; + + std::queue<int> miscRegIdxs; + + virtual Counter totalInstructions() const + { + return numInst - startNumInst; + } + + // number of simulated loads + Counter numLoad; + Counter startNumLoad; + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + + template <class T> + Fault read(Addr addr, T &data, unsigned flags); + + template <class T> + Fault write(T data, Addr addr, unsigned flags, uint64_t *res); + + // 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"); } + + void prefetch(Addr addr, unsigned flags) + { + // need to do this... + } + + void writeHint(Addr addr, int size, unsigned flags) + { + // need to do this... + } + + Fault copySrcTranslate(Addr src); + + Fault copy(Addr dest); + + // 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 readIntReg(const StaticInst *si, int idx) + { + return thread->readIntReg(si->srcRegIdx(idx)); + } + + FloatReg readFloatReg(const StaticInst *si, int idx, int width) + { + int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag; + return thread->readFloatReg(reg_idx, width); + } + + FloatReg readFloatReg(const StaticInst *si, int idx) + { + int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag; + return thread->readFloatReg(reg_idx); + } + + FloatRegBits readFloatRegBits(const StaticInst *si, int idx, int width) + { + int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag; + return thread->readFloatRegBits(reg_idx, width); + } + + FloatRegBits readFloatRegBits(const StaticInst *si, int idx) + { + int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag; + return thread->readFloatRegBits(reg_idx); + } + + void setIntReg(const StaticInst *si, int idx, uint64_t val) + { + thread->setIntReg(si->destRegIdx(idx), val); + result.integer = val; + } + + void setFloatReg(const StaticInst *si, int idx, FloatReg val, int width) + { + int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag; + thread->setFloatReg(reg_idx, val, width); + switch(width) { + case 32: + result.fp = val; + break; + case 64: + result.dbl = val; + break; + }; + } + + void setFloatReg(const StaticInst *si, int idx, FloatReg val) + { + int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag; + thread->setFloatReg(reg_idx, val); + result.fp = val; + } + + void setFloatRegBits(const StaticInst *si, int idx, FloatRegBits val, + int width) + { + int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag; + thread->setFloatRegBits(reg_idx, val, width); + result.integer = val; + } + + void setFloatRegBits(const StaticInst *si, int idx, FloatRegBits val) + { + int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag; + thread->setFloatRegBits(reg_idx, val); + result.integer = val; + } + + uint64_t readPC() { return thread->readPC(); } + + uint64_t readNextPC() { return thread->readNextPC(); } + + void setNextPC(uint64_t val) { + thread->setNextPC(val); + } + + MiscReg readMiscReg(int misc_reg) + { + return thread->readMiscReg(misc_reg); + } + + MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) + { + return thread->readMiscRegWithEffect(misc_reg, fault); + } + + Fault setMiscReg(int misc_reg, const MiscReg &val) + { + result.integer = val; + miscRegIdxs.push(misc_reg); + return thread->setMiscReg(misc_reg, val); + } + + Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) + { + miscRegIdxs.push(misc_reg); + return thread->setMiscRegWithEffect(misc_reg, val); + } + + void recordPCChange(uint64_t val) { changedPC = true; } + void recordNextPCChange(uint64_t val) { changedNextPC = true; } + + bool translateInstReq(Request *req); + void translateDataWriteReq(Request *req); + void translateDataReadReq(Request *req); + +#if FULL_SYSTEM + Fault hwrei() { return thread->hwrei(); } + int readIntrFlag() { return thread->readIntrFlag(); } + void setIntrFlag(int val) { thread->setIntrFlag(val); } + bool inPalMode() { return thread->inPalMode(); } + void ev5_trap(Fault fault) { fault->invoke(tc); } + bool simPalCheck(int palFunc) { return thread->simPalCheck(palFunc); } +#else + // 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) { } +#endif + + void handleError() + { + if (exitOnError) + panic("Checker found error!"); + } + bool checkFlags(Request *req); + + ThreadContext *tcBase() { return tc; } + SimpleThread *threadBase() { return thread; } + + Result unverifiedResult; + Request *unverifiedReq; + uint8_t *unverifiedMemData; + + bool changedPC; + bool willChangePC; + uint64_t newPC; + bool changedNextPC; + bool exitOnError; + + 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 DynInstPtr> +class Checker : public CheckerCPU +{ + public: + Checker(Params *p) + : CheckerCPU(p) + { } + + void switchOut(Sampler *s); + void takeOverFrom(BaseCPU *oldCPU); + + void tick(DynInstPtr &inst); + + void validateInst(DynInstPtr &inst); + void validateExecution(DynInstPtr &inst); + void validateState(); + + std::list<DynInstPtr> instList; + typedef typename std::list<DynInstPtr>::iterator InstListIt; + void dumpInsts(); +}; + +#endif // __CPU_CHECKER_CPU_HH__ diff --git a/src/cpu/checker/cpu_builder.cc b/src/cpu/checker/cpu_builder.cc new file mode 100644 index 000000000..3b7583294 --- /dev/null +++ b/src/cpu/checker/cpu_builder.cc @@ -0,0 +1,158 @@ +/* + * 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/checker/cpu.hh" +#include "cpu/inst_seq.hh" +#include "cpu/ozone/dyn_inst.hh" +#include "cpu/ozone/ozone_impl.hh" +#include "mem/base_mem.hh" +#include "sim/builder.hh" +#include "sim/process.hh" +#include "sim/sim_object.hh" + +/** + * Specific non-templated derived class used for SimObject configuration. + */ +class OzoneChecker : public Checker<RefCountingPtr<OzoneDynInst<OzoneImpl> > > +{ + public: + OzoneChecker(Params *p) + : Checker<RefCountingPtr<OzoneDynInst<OzoneImpl> > >(p) + { } +}; + +//////////////////////////////////////////////////////////////////////// +// +// CheckerCPU Simulation Object +// +BEGIN_DECLARE_SIM_OBJECT_PARAMS(OzoneChecker) + + Param<Counter> max_insts_any_thread; + Param<Counter> max_insts_all_threads; + Param<Counter> max_loads_any_thread; + Param<Counter> max_loads_all_threads; + +#if FULL_SYSTEM + SimObjectParam<AlphaITB *> itb; + SimObjectParam<AlphaDTB *> dtb; + SimObjectParam<FunctionalMemory *> mem; + SimObjectParam<System *> system; + Param<int> cpu_id; + Param<Tick> profile; +#else + SimObjectParam<Process *> workload; +#endif // FULL_SYSTEM + Param<int> clock; + SimObjectParam<BaseMem *> icache; + SimObjectParam<BaseMem *> dcache; + + Param<bool> defer_registration; + Param<bool> exitOnError; + Param<bool> function_trace; + Param<Tick> function_trace_start; + +END_DECLARE_SIM_OBJECT_PARAMS(OzoneChecker) + +BEGIN_INIT_SIM_OBJECT_PARAMS(OzoneChecker) + + INIT_PARAM(max_insts_any_thread, + "terminate when any thread reaches this inst count"), + INIT_PARAM(max_insts_all_threads, + "terminate when all threads have reached this inst count"), + INIT_PARAM(max_loads_any_thread, + "terminate when any thread reaches this load count"), + INIT_PARAM(max_loads_all_threads, + "terminate when all threads have reached this load count"), + +#if FULL_SYSTEM + INIT_PARAM(itb, "Instruction TLB"), + INIT_PARAM(dtb, "Data TLB"), + INIT_PARAM(mem, "memory"), + INIT_PARAM(system, "system object"), + INIT_PARAM(cpu_id, "processor ID"), + INIT_PARAM(profile, ""), +#else + INIT_PARAM(workload, "processes to run"), +#endif // FULL_SYSTEM + + INIT_PARAM(clock, "clock speed"), + INIT_PARAM(icache, "L1 instruction cache object"), + INIT_PARAM(dcache, "L1 data cache object"), + + INIT_PARAM(defer_registration, "defer system registration (for sampling)"), + INIT_PARAM(exitOnError, "exit on error"), + INIT_PARAM(function_trace, "Enable function trace"), + INIT_PARAM(function_trace_start, "Cycle to start function trace") + +END_INIT_SIM_OBJECT_PARAMS(OzoneChecker) + + +CREATE_SIM_OBJECT(OzoneChecker) +{ + OzoneChecker::Params *params = new OzoneChecker::Params(); + params->name = getInstanceName(); + params->numberOfThreads = 1; + 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->exitOnError = exitOnError; + params->deferRegistration = defer_registration; + params->functionTrace = function_trace; + params->functionTraceStart = function_trace_start; + 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; + BaseMem *cache = icache; + cache = dcache; + +#if FULL_SYSTEM + params->itb = itb; + params->dtb = dtb; + params->mem = mem; + params->system = system; + params->cpu_id = cpu_id; + params->profile = profile; +#else + params->process = workload; +#endif + + OzoneChecker *cpu = new OzoneChecker(params); + return cpu; +} + +REGISTER_SIM_OBJECT("OzoneChecker", OzoneChecker) diff --git a/src/cpu/checker/o3_cpu_builder.cc b/src/cpu/checker/o3_cpu_builder.cc new file mode 100644 index 000000000..59a6c7158 --- /dev/null +++ b/src/cpu/checker/o3_cpu_builder.cc @@ -0,0 +1,150 @@ +/* + * 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/checker/cpu.hh" +#include "cpu/inst_seq.hh" +#include "cpu/o3/alpha_dyn_inst.hh" +#include "cpu/o3/alpha_impl.hh" +#include "sim/builder.hh" +#include "sim/process.hh" +#include "sim/sim_object.hh" + +class MemObject; + +/** + * Specific non-templated derived class used for SimObject configuration. + */ +class O3Checker : public Checker<RefCountingPtr<AlphaDynInst<AlphaSimpleImpl> > > +{ + public: + O3Checker(Params *p) + : Checker<RefCountingPtr<AlphaDynInst<AlphaSimpleImpl> > >(p) + { } +}; + +//////////////////////////////////////////////////////////////////////// +// +// CheckerCPU Simulation Object +// +BEGIN_DECLARE_SIM_OBJECT_PARAMS(O3Checker) + + Param<Counter> max_insts_any_thread; + Param<Counter> max_insts_all_threads; + Param<Counter> max_loads_any_thread; + Param<Counter> max_loads_all_threads; + +#if FULL_SYSTEM + SimObjectParam<AlphaITB *> itb; + SimObjectParam<AlphaDTB *> dtb; + SimObjectParam<System *> system; + Param<int> cpu_id; + Param<Tick> profile; +#else + SimObjectParam<Process *> workload; +#endif // FULL_SYSTEM + Param<int> clock; + + Param<bool> defer_registration; + Param<bool> exitOnError; + Param<bool> function_trace; + Param<Tick> function_trace_start; + +END_DECLARE_SIM_OBJECT_PARAMS(O3Checker) + +BEGIN_INIT_SIM_OBJECT_PARAMS(O3Checker) + + INIT_PARAM(max_insts_any_thread, + "terminate when any thread reaches this inst count"), + INIT_PARAM(max_insts_all_threads, + "terminate when all threads have reached this inst count"), + INIT_PARAM(max_loads_any_thread, + "terminate when any thread reaches this load count"), + INIT_PARAM(max_loads_all_threads, + "terminate when all threads have reached this load count"), + +#if FULL_SYSTEM + INIT_PARAM(itb, "Instruction TLB"), + INIT_PARAM(dtb, "Data TLB"), + INIT_PARAM(system, "system object"), + INIT_PARAM(cpu_id, "processor ID"), + INIT_PARAM(profile, ""), +#else + INIT_PARAM(workload, "processes to run"), +#endif // FULL_SYSTEM + + INIT_PARAM(clock, "clock speed"), + + INIT_PARAM(defer_registration, "defer system registration (for sampling)"), + INIT_PARAM(exitOnError, "exit on error"), + INIT_PARAM(function_trace, "Enable function trace"), + INIT_PARAM(function_trace_start, "Cycle to start function trace") + +END_INIT_SIM_OBJECT_PARAMS(O3Checker) + + +CREATE_SIM_OBJECT(O3Checker) +{ + O3Checker::Params *params = new O3Checker::Params(); + params->name = getInstanceName(); + params->numberOfThreads = 1; + 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->exitOnError = exitOnError; + params->deferRegistration = defer_registration; + params->functionTrace = function_trace; + params->functionTraceStart = function_trace_start; + 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; + +#if FULL_SYSTEM + params->itb = itb; + params->dtb = dtb; + params->system = system; + params->cpu_id = cpu_id; + params->profile = profile; +#else + params->process = workload; +#endif + + O3Checker *cpu = new O3Checker(params); + return cpu; +} + +REGISTER_SIM_OBJECT("O3Checker", O3Checker) diff --git a/src/cpu/checker/thread_context.hh b/src/cpu/checker/thread_context.hh new file mode 100644 index 000000000..c0ac8f01d --- /dev/null +++ b/src/cpu/checker/thread_context.hh @@ -0,0 +1,306 @@ +/* + * 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 "cpu/checker/cpu.hh" +#include "cpu/simple_thread.hh" +#include "cpu/thread_context.hh" + +class EndQuiesceEvent; +namespace Kernel { + class Statistics; +}; + +/** + * 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(); } + + void setCpuId(int id) + { + actualTC->setCpuId(id); + checkerTC->setCpuId(id); + } + + int readCpuId() { return actualTC->readCpuId(); } + +#if FULL_SYSTEM + System *getSystemPtr() { return actualTC->getSystemPtr(); } + + PhysicalMemory *getPhysMemPtr() { return actualTC->getPhysMemPtr(); } + + AlphaITB *getITBPtr() { return actualTC->getITBPtr(); } + + AlphaDTB *getDTBPtr() { return actualTC->getDTBPtr(); } + + Kernel::Statistics *getKernelStats() { return actualTC->getKernelStats(); } + + FunctionalPort *getPhysPort() { return actualTC->getPhysPort(); } + + VirtualPort *getVirtPort(ThreadContext *tc = NULL) + { return actualTC->getVirtPort(); } + + void delVirtPort(VirtualPort *vp) { actualTC->delVirtPort(vp); } +#else + TranslatingPort *getMemPort() { return actualTC->getMemPort(); } + + Process *getProcessPtr() { return actualTC->getProcessPtr(); } +#endif + + 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() { actualTC->suspend(); } + + /// Set the status to Unallocated. + void deallocate() { actualTC->deallocate(); } + + /// Set the status to Halted. + void halt() { actualTC->halt(); } + +#if FULL_SYSTEM + void dumpFuncProfile() { actualTC->dumpFuncProfile(); } +#endif + + void takeOverFrom(ThreadContext *oldContext) + { + actualTC->takeOverFrom(oldContext); + checkerTC->takeOverFrom(oldContext); + } + + void regStats(const std::string &name) { actualTC->regStats(name); } + + void serialize(std::ostream &os) { actualTC->serialize(os); } + void unserialize(Checkpoint *cp, const std::string §ion) + { actualTC->unserialize(cp, section); } + +#if FULL_SYSTEM + 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(); } +#endif + + int getThreadNum() { return actualTC->getThreadNum(); } + + // @todo: Do I need this? + MachInst getInst() { return actualTC->getInst(); } + + // @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, int width) + { return actualTC->readFloatReg(reg_idx, width); } + + FloatReg readFloatReg(int reg_idx) + { return actualTC->readFloatReg(reg_idx); } + + FloatRegBits readFloatRegBits(int reg_idx, int width) + { return actualTC->readFloatRegBits(reg_idx, width); } + + 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, int width) + { + actualTC->setFloatReg(reg_idx, val, width); + checkerTC->setFloatReg(reg_idx, val, width); + } + + void setFloatReg(int reg_idx, FloatReg val) + { + actualTC->setFloatReg(reg_idx, val); + checkerTC->setFloatReg(reg_idx, val); + } + + void setFloatRegBits(int reg_idx, FloatRegBits val, int width) + { + actualTC->setFloatRegBits(reg_idx, val, width); + checkerTC->setFloatRegBits(reg_idx, val, width); + } + + void setFloatRegBits(int reg_idx, FloatRegBits val) + { + actualTC->setFloatRegBits(reg_idx, val); + checkerTC->setFloatRegBits(reg_idx, val); + } + + uint64_t readPC() { return actualTC->readPC(); } + + void setPC(uint64_t val) + { + actualTC->setPC(val); + checkerTC->setPC(val); + checkerCPU->recordPCChange(val); + } + + uint64_t readNextPC() { return actualTC->readNextPC(); } + + void setNextPC(uint64_t val) + { + actualTC->setNextPC(val); + checkerTC->setNextPC(val); + checkerCPU->recordNextPCChange(val); + } + + uint64_t readNextNPC() { return actualTC->readNextNPC(); } + + void setNextNPC(uint64_t val) + { + actualTC->setNextNPC(val); + checkerTC->setNextNPC(val); + checkerCPU->recordNextPCChange(val); + } + + MiscReg readMiscReg(int misc_reg) + { return actualTC->readMiscReg(misc_reg); } + + MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) + { return actualTC->readMiscRegWithEffect(misc_reg, fault); } + + Fault setMiscReg(int misc_reg, const MiscReg &val) + { + checkerTC->setMiscReg(misc_reg, val); + return actualTC->setMiscReg(misc_reg, val); + } + + Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) + { + checkerTC->setMiscRegWithEffect(misc_reg, val); + return actualTC->setMiscRegWithEffect(misc_reg, val); + } + + unsigned readStCondFailures() + { return actualTC->readStCondFailures(); } + + void setStCondFailures(unsigned sc_failures) + { + checkerTC->setStCondFailures(sc_failures); + actualTC->setStCondFailures(sc_failures); + } +#if FULL_SYSTEM + bool inPalMode() { return actualTC->inPalMode(); } +#endif + + // @todo: Fix this! + bool misspeculating() { return actualTC->misspeculating(); } + +#if !FULL_SYSTEM + IntReg getSyscallArg(int i) { return actualTC->getSyscallArg(i); } + + // used to shift args for indirect syscall + void setSyscallArg(int i, IntReg val) + { + checkerTC->setSyscallArg(i, val); + actualTC->setSyscallArg(i, val); + } + + void setSyscallReturn(SyscallReturn return_value) + { + checkerTC->setSyscallReturn(return_value); + actualTC->setSyscallReturn(return_value); + } + + Counter readFuncExeInst() { return actualTC->readFuncExeInst(); } +#endif + void changeRegFileContext(RegFile::ContextParam param, + RegFile::ContextVal val) + { + actualTC->changeRegFileContext(param, val); + checkerTC->changeRegFileContext(param, val); + } +}; + +#endif // __CPU_CHECKER_EXEC_CONTEXT_HH__ diff --git a/src/cpu/cpu_models.py b/src/cpu/cpu_models.py new file mode 100644 index 000000000..1a9724ca6 --- /dev/null +++ b/src/cpu/cpu_models.py @@ -0,0 +1,82 @@ +# 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 + +################ +# CpuModel class +# +# The CpuModel class encapsulates everything the ISA parser needs to +# know about a particular CPU model. + +class CpuModel: + # Dict of available CPU model objects. Accessible as CpuModel.dict. + dict = {} + + # Constructor. Automatically adds models to CpuModel.dict. + def __init__(self, name, filename, includes, strings): + self.name = name + self.filename = filename # filename for output exec code + self.includes = includes # include files needed in exec file + # The 'strings' dict holds all the per-CPU symbols we can + # substitute into templates etc. + self.strings = strings + # Add self to dict + CpuModel.dict[name] = self + + +# +# Define CPU models. +# +# Parameters are: +# - name of model +# - filename for generated ISA execution file +# - includes needed for generated ISA execution file +# - substitution strings for ISA description templates +# + +CpuModel('AtomicSimpleCPU', 'atomic_simple_cpu_exec.cc', + '#include "cpu/simple/atomic.hh"', + { 'CPU_exec_context': 'AtomicSimpleCPU' }) +CpuModel('TimingSimpleCPU', 'timing_simple_cpu_exec.cc', + '#include "cpu/simple/timing.hh"', + { 'CPU_exec_context': 'TimingSimpleCPU' }) +CpuModel('FullCPU', 'full_cpu_exec.cc', + '#include "encumbered/cpu/full/dyn_inst.hh"', + { 'CPU_exec_context': 'DynInst' }) +CpuModel('AlphaFullCPU', 'alpha_o3_exec.cc', + '#include "cpu/o3/alpha_dyn_inst.hh"', + { 'CPU_exec_context': 'AlphaDynInst<AlphaSimpleImpl>' }) +CpuModel('OzoneSimpleCPU', 'ozone_simple_exec.cc', + '#include "cpu/ozone/dyn_inst.hh"', + { 'CPU_exec_context': 'OzoneDynInst<SimpleImpl>' }) +CpuModel('OzoneCPU', 'ozone_exec.cc', + '#include "cpu/ozone/dyn_inst.hh"', + { 'CPU_exec_context': 'OzoneDynInst<OzoneImpl>' }) +CpuModel('CheckerCPU', 'checker_cpu_exec.cc', + '#include "cpu/checker/cpu.hh"', + { 'CPU_exec_context': 'CheckerCPU' }) + diff --git a/src/cpu/cpuevent.cc b/src/cpu/cpuevent.cc new file mode 100644 index 000000000..679244a6b --- /dev/null +++ b/src/cpu/cpuevent.cc @@ -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; + } +} diff --git a/src/cpu/cpuevent.hh b/src/cpu/cpuevent.hh new file mode 100644 index 000000000..11ac7aafb --- /dev/null +++ b/src/cpu/cpuevent.hh @@ -0,0 +1,89 @@ +/* + * 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 than need a pointer to an + * 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 +{ + private: + /** 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(EventQueue *q, ThreadContext *_tc, Priority p = Default_Pri) + : Event(q, 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); +}; + +template <class T, void (T::* F)(ThreadContext *tc)> +class CpuEventWrapper : public CpuEvent +{ + private: + T *object; + + public: + CpuEventWrapper(T *obj, ThreadContext *_tc, EventQueue *q = &mainEventQueue, + Priority p = Default_Pri) + : CpuEvent(q, _tc, p), object(obj) + { } + void process() { (object->*F)(tc); } +}; + +#endif // __CPU_CPUEVENT_HH__ + diff --git a/src/cpu/exetrace.cc b/src/cpu/exetrace.cc new file mode 100644 index 000000000..7fdad5113 --- /dev/null +++ b/src/cpu/exetrace.cc @@ -0,0 +1,235 @@ +/* + * 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 <fstream> +#include <iomanip> + +#include "base/loader/symtab.hh" +#include "cpu/base.hh" +#include "cpu/exetrace.hh" +#include "cpu/static_inst.hh" +#include "sim/param.hh" +#include "sim/system.hh" + +using namespace std; + + +//////////////////////////////////////////////////////////////////////// +// +// Methods for the InstRecord object +// + + +void +Trace::InstRecord::dump(ostream &outs) +{ + if (flags[INTEL_FORMAT]) { +#if FULL_SYSTEM + bool is_trace_system = (cpu->system->name() == trace_system); +#else + bool is_trace_system = true; +#endif + if (is_trace_system) { + ccprintf(outs, "%7d ) ", cycle); + outs << "0x" << hex << PC << ":\t"; + if (staticInst->isLoad()) { + outs << "<RD 0x" << hex << addr; + outs << ">"; + } else if (staticInst->isStore()) { + outs << "<WR 0x" << hex << addr; + outs << ">"; + } + outs << endl; + } + } else { + if (flags[PRINT_CYCLE]) + ccprintf(outs, "%7d: ", cycle); + + outs << cpu->name() << " "; + + if (flags[TRACE_MISSPEC]) + outs << (misspeculating ? "-" : "+") << " "; + + if (flags[PRINT_THREAD_NUM]) + outs << "T" << thread << " : "; + + + std::string sym_str; + Addr sym_addr; + if (debugSymbolTable + && debugSymbolTable->findNearestSymbol(PC, sym_str, sym_addr) + && flags[PC_SYMBOL]) { + if (PC != sym_addr) + sym_str += csprintf("+%d", PC - sym_addr); + outs << "@" << sym_str << " : "; + } + else { + outs << "0x" << hex << PC << " : "; + } + + // + // Print decoded instruction + // + +#if defined(__GNUC__) && (__GNUC__ < 3) + // There's a bug in gcc 2.x library that prevents setw() + // from working properly on strings + string mc(staticInst->disassemble(PC, debugSymbolTable)); + while (mc.length() < 26) + mc += " "; + outs << mc; +#else + outs << setw(26) << left << staticInst->disassemble(PC, debugSymbolTable); +#endif + + outs << " : "; + + if (flags[PRINT_OP_CLASS]) { + outs << opClassStrings[staticInst->opClass()] << " : "; + } + + if (flags[PRINT_RESULT_DATA] && data_status != DataInvalid) { + outs << " D="; +#if 0 + if (data_status == DataDouble) + ccprintf(outs, "%f", data.as_double); + else + ccprintf(outs, "%#018x", data.as_int); +#else + ccprintf(outs, "%#018x", data.as_int); +#endif + } + + if (flags[PRINT_EFF_ADDR] && addr_valid) + outs << " A=0x" << hex << addr; + + if (flags[PRINT_INT_REGS] && regs_valid) { + for (int i = 0; i < TheISA::NumIntRegs;) + for (int j = i + 1; i <= j; i++) + ccprintf(outs, "r%02d = %#018x%s", i, + iregs->regs.readReg(i), + ((i == j) ? "\n" : " ")); + outs << "\n"; + } + + if (flags[PRINT_FETCH_SEQ] && fetch_seq_valid) + outs << " FetchSeq=" << dec << fetch_seq; + + if (flags[PRINT_CP_SEQ] && cp_seq_valid) + outs << " CPSeq=" << dec << cp_seq; + + // + // End of line... + // + outs << endl; + } +} + + +vector<bool> Trace::InstRecord::flags(NUM_BITS); +string Trace::InstRecord::trace_system; + +//////////////////////////////////////////////////////////////////////// +// +// Parameter space for per-cycle execution address tracing options. +// Derive from ParamContext so we can override checkParams() function. +// +class ExecutionTraceParamContext : public ParamContext +{ + public: + ExecutionTraceParamContext(const string &_iniSection) + : ParamContext(_iniSection) + { + } + + void checkParams(); // defined at bottom of file +}; + +ExecutionTraceParamContext exeTraceParams("exetrace"); + +Param<bool> exe_trace_spec(&exeTraceParams, "speculative", + "capture speculative instructions", true); + +Param<bool> exe_trace_print_cycle(&exeTraceParams, "print_cycle", + "print cycle number", true); +Param<bool> exe_trace_print_opclass(&exeTraceParams, "print_opclass", + "print op class", true); +Param<bool> exe_trace_print_thread(&exeTraceParams, "print_thread", + "print thread number", true); +Param<bool> exe_trace_print_effaddr(&exeTraceParams, "print_effaddr", + "print effective address", true); +Param<bool> exe_trace_print_data(&exeTraceParams, "print_data", + "print result data", true); +Param<bool> exe_trace_print_iregs(&exeTraceParams, "print_iregs", + "print all integer regs", false); +Param<bool> exe_trace_print_fetchseq(&exeTraceParams, "print_fetchseq", + "print fetch sequence number", false); +Param<bool> exe_trace_print_cp_seq(&exeTraceParams, "print_cpseq", + "print correct-path sequence number", false); +Param<bool> exe_trace_pc_symbol(&exeTraceParams, "pc_symbol", + "Use symbols for the PC if available", true); +Param<bool> exe_trace_intel_format(&exeTraceParams, "intel_format", + "print trace in intel compatible format", false); +Param<string> exe_trace_system(&exeTraceParams, "trace_system", + "print trace of which system (client or server)", + "client"); + + +// +// Helper function for ExecutionTraceParamContext::checkParams() just +// to get us into the InstRecord namespace +// +void +Trace::InstRecord::setParams() +{ + flags[TRACE_MISSPEC] = exe_trace_spec; + + flags[PRINT_CYCLE] = exe_trace_print_cycle; + flags[PRINT_OP_CLASS] = exe_trace_print_opclass; + flags[PRINT_THREAD_NUM] = exe_trace_print_thread; + flags[PRINT_RESULT_DATA] = exe_trace_print_effaddr; + flags[PRINT_EFF_ADDR] = exe_trace_print_data; + flags[PRINT_INT_REGS] = exe_trace_print_iregs; + flags[PRINT_FETCH_SEQ] = exe_trace_print_fetchseq; + flags[PRINT_CP_SEQ] = exe_trace_print_cp_seq; + flags[PC_SYMBOL] = exe_trace_pc_symbol; + flags[INTEL_FORMAT] = exe_trace_intel_format; + trace_system = exe_trace_system; +} + +void +ExecutionTraceParamContext::checkParams() +{ + Trace::InstRecord::setParams(); +} + diff --git a/src/cpu/exetrace.hh b/src/cpu/exetrace.hh new file mode 100644 index 000000000..95f8b449c --- /dev/null +++ b/src/cpu/exetrace.hh @@ -0,0 +1,192 @@ +/* + * 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 __EXETRACE_HH__ +#define __EXETRACE_HH__ + +#include <fstream> +#include <vector> + +#include "sim/host.hh" +#include "cpu/inst_seq.hh" // for InstSeqNum +#include "base/trace.hh" +#include "cpu/thread_context.hh" +#include "cpu/static_inst.hh" + +class BaseCPU; + + +namespace Trace { + +class InstRecord : public Record +{ + protected: + typedef TheISA::IntRegFile IntRegFile; + + // The following fields are initialized by the constructor and + // thus guaranteed to be valid. + BaseCPU *cpu; + // need to make this ref-counted so it doesn't go away before we + // dump the record + StaticInstPtr staticInst; + Addr PC; + bool misspeculating; + unsigned thread; + + // The remaining fields are only valid for particular instruction + // types (e.g, addresses for memory ops) or when particular + // options are enabled (e.g., tracing full register contents). + // Each data field has an associated valid flag to indicate + // whether the data field is valid. + Addr addr; + bool addr_valid; + + union { + uint64_t as_int; + double as_double; + } data; + enum { + DataInvalid = 0, + DataInt8 = 1, // set to equal number of bytes + DataInt16 = 2, + DataInt32 = 4, + DataInt64 = 8, + DataDouble = 3 + } data_status; + + InstSeqNum fetch_seq; + bool fetch_seq_valid; + + InstSeqNum cp_seq; + bool cp_seq_valid; + + struct iRegFile { + IntRegFile regs; + }; + iRegFile *iregs; + bool regs_valid; + + public: + InstRecord(Tick _cycle, BaseCPU *_cpu, + const StaticInstPtr &_staticInst, + Addr _pc, bool spec, int _thread) + : Record(_cycle), cpu(_cpu), staticInst(_staticInst), PC(_pc), + misspeculating(spec), thread(_thread) + { + data_status = DataInvalid; + addr_valid = false; + regs_valid = false; + + fetch_seq_valid = false; + cp_seq_valid = false; + } + + virtual ~InstRecord() { } + + virtual void dump(std::ostream &outs); + + void setAddr(Addr a) { addr = a; addr_valid = true; } + + void setData(uint64_t d) { data.as_int = d; data_status = DataInt64; } + void setData(uint32_t d) { data.as_int = d; data_status = DataInt32; } + void setData(uint16_t d) { data.as_int = d; data_status = DataInt16; } + void setData(uint8_t d) { data.as_int = d; data_status = DataInt8; } + + void setData(int64_t d) { setData((uint64_t)d); } + void setData(int32_t d) { setData((uint32_t)d); } + void setData(int16_t d) { setData((uint16_t)d); } + void setData(int8_t d) { setData((uint8_t)d); } + + void setData(double d) { data.as_double = d; data_status = DataDouble; } + + void setFetchSeq(InstSeqNum seq) + { fetch_seq = seq; fetch_seq_valid = true; } + + void setCPSeq(InstSeqNum seq) + { cp_seq = seq; cp_seq_valid = true; } + + void setRegs(const IntRegFile ®s); + + void finalize() { theLog.append(this); } + + enum InstExecFlagBits { + TRACE_MISSPEC = 0, + PRINT_CYCLE, + PRINT_OP_CLASS, + PRINT_THREAD_NUM, + PRINT_RESULT_DATA, + PRINT_EFF_ADDR, + PRINT_INT_REGS, + PRINT_FETCH_SEQ, + PRINT_CP_SEQ, + PC_SYMBOL, + INTEL_FORMAT, + NUM_BITS + }; + + static std::vector<bool> flags; + static std::string trace_system; + + static void setParams(); + + static bool traceMisspec() { return flags[TRACE_MISSPEC]; } +}; + + +inline void +InstRecord::setRegs(const IntRegFile ®s) +{ + if (!iregs) + iregs = new iRegFile; + + memcpy(&iregs->regs, ®s, sizeof(IntRegFile)); + regs_valid = true; +} + +inline +InstRecord * +getInstRecord(Tick cycle, ThreadContext *tc, BaseCPU *cpu, + const StaticInstPtr staticInst, + Addr pc, int thread = 0) +{ + if (DTRACE(InstExec) && + (InstRecord::traceMisspec() || !tc->misspeculating())) { + return new InstRecord(cycle, cpu, staticInst, pc, + tc->misspeculating(), thread); + } + + return NULL; +} + + +} + +#endif // __EXETRACE_HH__ diff --git a/src/cpu/inst_seq.hh b/src/cpu/inst_seq.hh new file mode 100644 index 000000000..e7acd215f --- /dev/null +++ b/src/cpu/inst_seq.hh @@ -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 <stdint.h> + +// 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__ diff --git a/src/cpu/intr_control.cc b/src/cpu/intr_control.cc new file mode 100644 index 000000000..4cbc86891 --- /dev/null +++ b/src/cpu/intr_control.cc @@ -0,0 +1,100 @@ +/* + * 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 "cpu/base.hh" +#include "cpu/thread_context.hh" +#include "cpu/intr_control.hh" +#include "sim/builder.hh" +#include "sim/sim_object.hh" + +using namespace std; + +IntrControl::IntrControl(const string &name, BaseCPU *c) + : SimObject(name), cpu(c) +{} + +/* @todo + *Fix the cpu sim object parameter to be a system pointer + *instead, to avoid some extra dereferencing + */ +void +IntrControl::post(int int_num, int index) +{ + std::vector<ThreadContext *> &tcvec = cpu->system->threadContexts; + BaseCPU *temp = tcvec[0]->getCpuPtr(); + temp->post_interrupt(int_num, index); +} + +void +IntrControl::post(int cpu_id, int int_num, int index) +{ + std::vector<ThreadContext *> &tcvec = cpu->system->threadContexts; + BaseCPU *temp = tcvec[cpu_id]->getCpuPtr(); + temp->post_interrupt(int_num, index); +} + +void +IntrControl::clear(int int_num, int index) +{ + std::vector<ThreadContext *> &tcvec = cpu->system->threadContexts; + BaseCPU *temp = tcvec[0]->getCpuPtr(); + temp->clear_interrupt(int_num, index); +} + +void +IntrControl::clear(int cpu_id, int int_num, int index) +{ + std::vector<ThreadContext *> &tcvec = cpu->system->threadContexts; + BaseCPU *temp = tcvec[cpu_id]->getCpuPtr(); + temp->clear_interrupt(int_num, index); +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(IntrControl) + + SimObjectParam<BaseCPU *> cpu; + +END_DECLARE_SIM_OBJECT_PARAMS(IntrControl) + +BEGIN_INIT_SIM_OBJECT_PARAMS(IntrControl) + + INIT_PARAM(cpu, "the cpu") + +END_INIT_SIM_OBJECT_PARAMS(IntrControl) + +CREATE_SIM_OBJECT(IntrControl) +{ + return new IntrControl(getInstanceName(), cpu); +} + +REGISTER_SIM_OBJECT("IntrControl", IntrControl) diff --git a/src/cpu/intr_control.hh b/src/cpu/intr_control.hh new file mode 100644 index 000000000..2e3f9e038 --- /dev/null +++ b/src/cpu/intr_control.hh @@ -0,0 +1,61 @@ +/* + * 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 "sim/sim_object.hh" +#include "sim/system.hh" + + +class IntrControl : public SimObject +{ + public: + BaseCPU *cpu; + IntrControl(const std::string &name, BaseCPU *c); + + void clear(int int_num, int index = 0); + void post(int int_num, int index = 0); + void clear(int cpu_id, int int_num, int index); + void post(int cpu_id, int int_num, int index); +}; + +#endif // __INTR_CONTROL_HH__ + + + + + + + diff --git a/src/cpu/memtest/memtest.cc b/src/cpu/memtest/memtest.cc new file mode 100644 index 000000000..7ea9eaefc --- /dev/null +++ b/src/cpu/memtest/memtest.cc @@ -0,0 +1,443 @@ +/* + * 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: Erik Hallnor + * Steve Reinhardt + */ + +// FIX ME: make trackBlkAddr use blocksize from actual cache, not hard coded + +#include <iomanip> +#include <set> +#include <string> +#include <vector> + +#include "base/misc.hh" +#include "base/statistics.hh" +#include "cpu/simple_thread.hh" +#include "cpu/memtest/memtest.hh" +#include "mem/cache/base_cache.hh" +#include "sim/builder.hh" +#include "sim/sim_events.hh" +#include "sim/stats.hh" + +using namespace std; +using namespace TheISA; + +int TESTER_ALLOCATOR=0; + +MemTest::MemTest(const string &name, + MemInterface *_cache_interface, + FunctionalMemory *main_mem, + FunctionalMemory *check_mem, + unsigned _memorySize, + unsigned _percentReads, + unsigned _percentCopies, + unsigned _percentUncacheable, + unsigned _progressInterval, + unsigned _percentSourceUnaligned, + unsigned _percentDestUnaligned, + Addr _traceAddr, + Counter _max_loads) + : SimObject(name), + tickEvent(this), + cacheInterface(_cache_interface), + mainMem(main_mem), + checkMem(check_mem), + size(_memorySize), + percentReads(_percentReads), + percentCopies(_percentCopies), + percentUncacheable(_percentUncacheable), + progressInterval(_progressInterval), + nextProgressMessage(_progressInterval), + percentSourceUnaligned(_percentSourceUnaligned), + percentDestUnaligned(percentDestUnaligned), + maxLoads(_max_loads) +{ + vector<string> cmd; + cmd.push_back("/bin/ls"); + vector<string> null_vec; + thread = new SimpleThread(NULL, 0, mainMem, 0); + + blockSize = cacheInterface->getBlockSize(); + blockAddrMask = blockSize - 1; + traceBlockAddr = blockAddr(_traceAddr); + + //setup data storage with interesting values + uint8_t *data1 = new uint8_t[size]; + uint8_t *data2 = new uint8_t[size]; + uint8_t *data3 = new uint8_t[size]; + memset(data1, 1, size); + memset(data2, 2, size); + memset(data3, 3, size); + curTick = 0; + + baseAddr1 = 0x100000; + baseAddr2 = 0x400000; + uncacheAddr = 0x800000; + + // set up intial memory contents here + mainMem->prot_write(baseAddr1, data1, size); + checkMem->prot_write(baseAddr1, data1, size); + mainMem->prot_write(baseAddr2, data2, size); + checkMem->prot_write(baseAddr2, data2, size); + mainMem->prot_write(uncacheAddr, data3, size); + checkMem->prot_write(uncacheAddr, data3, size); + + delete [] data1; + delete [] data2; + delete [] data3; + + // set up counters + noResponseCycles = 0; + numReads = 0; + tickEvent.schedule(0); + + id = TESTER_ALLOCATOR++; +} + +static void +printData(ostream &os, uint8_t *data, int nbytes) +{ + os << hex << setfill('0'); + // assume little-endian: print bytes from highest address to lowest + for (uint8_t *dp = data + nbytes - 1; dp >= data; --dp) { + os << setw(2) << (unsigned)*dp; + } + os << dec; +} + +void +MemTest::completeRequest(MemReqPtr &req, uint8_t *data) +{ + //Remove the address from the list of outstanding + std::set<unsigned>::iterator removeAddr = outstandingAddrs.find(req->paddr); + assert(removeAddr != outstandingAddrs.end()); + outstandingAddrs.erase(removeAddr); + + switch (req->cmd) { + case Read: + if (memcmp(req->data, data, req->size) != 0) { + cerr << name() << ": on read of 0x" << hex << req->paddr + << " (0x" << hex << blockAddr(req->paddr) << ")" + << "@ cycle " << dec << curTick + << ", cache returns 0x"; + printData(cerr, req->data, req->size); + cerr << ", expected 0x"; + printData(cerr, data, req->size); + cerr << endl; + fatal(""); + } + + numReads++; + numReadsStat++; + + if (numReads == nextProgressMessage) { + ccprintf(cerr, "%s: completed %d read accesses @%d\n", + name(), numReads, curTick); + nextProgressMessage += progressInterval; + } + + if (numReads >= maxLoads) + SimExit(curTick, "Maximum number of loads reached!"); + break; + + case Write: + numWritesStat++; + break; + + case Copy: + //Also remove dest from outstanding list + removeAddr = outstandingAddrs.find(req->dest); + assert(removeAddr != outstandingAddrs.end()); + outstandingAddrs.erase(removeAddr); + numCopiesStat++; + break; + + default: + panic("invalid command"); + } + + if (blockAddr(req->paddr) == traceBlockAddr) { + cerr << name() << ": completed " + << (req->cmd.isWrite() ? "write" : "read") + << " access of " + << dec << req->size << " bytes at address 0x" + << hex << req->paddr + << " (0x" << hex << blockAddr(req->paddr) << ")" + << ", value = 0x"; + printData(cerr, req->data, req->size); + cerr << " @ cycle " << dec << curTick; + + cerr << endl; + } + + noResponseCycles = 0; + delete [] data; +} + + +void +MemTest::regStats() +{ + using namespace Stats; + + + numReadsStat + .name(name() + ".num_reads") + .desc("number of read accesses completed") + ; + + numWritesStat + .name(name() + ".num_writes") + .desc("number of write accesses completed") + ; + + numCopiesStat + .name(name() + ".num_copies") + .desc("number of copy accesses completed") + ; +} + +void +MemTest::tick() +{ + if (!tickEvent.scheduled()) + tickEvent.schedule(curTick + cycles(1)); + + if (++noResponseCycles >= 500000) { + cerr << name() << ": deadlocked at cycle " << curTick << endl; + fatal(""); + } + + if (cacheInterface->isBlocked()) { + return; + } + + //make new request + unsigned cmd = random() % 100; + unsigned offset = random() % size; + unsigned base = random() % 2; + uint64_t data = random(); + unsigned access_size = random() % 4; + unsigned cacheable = random() % 100; + + //If we aren't doing copies, use id as offset, and do a false sharing + //mem tester + if (percentCopies == 0) { + //We can eliminate the lower bits of the offset, and then use the id + //to offset within the blks + offset &= ~63; //Not the low order bits + offset += id; + access_size = 0; + } + + MemReqPtr req = new MemReq(); + + if (cacheable < percentUncacheable) { + req->flags |= UNCACHEABLE; + req->paddr = uncacheAddr + offset; + } else { + req->paddr = ((base) ? baseAddr1 : baseAddr2) + offset; + } + // bool probe = (random() % 2 == 1) && !req->isUncacheable(); + bool probe = false; + + req->size = 1 << access_size; + req->data = new uint8_t[req->size]; + req->paddr &= ~(req->size - 1); + req->time = curTick; + req->xc = thread->getProxy(); + + if (cmd < percentReads) { + // read + + //For now we only allow one outstanding request per addreess per tester + //This means we assume CPU does write forwarding to reads that alias something + //in the cpu store buffer. + if (outstandingAddrs.find(req->paddr) != outstandingAddrs.end()) return; + else outstandingAddrs.insert(req->paddr); + + req->cmd = Read; + uint8_t *result = new uint8_t[8]; + checkMem->access(Read, req->paddr, result, req->size); + if (blockAddr(req->paddr) == traceBlockAddr) { + cerr << name() + << ": initiating read " + << ((probe) ? "probe of " : "access of ") + << dec << req->size << " bytes from addr 0x" + << hex << req->paddr + << " (0x" << hex << blockAddr(req->paddr) << ")" + << " at cycle " + << dec << curTick << endl; + } + if (probe) { + cacheInterface->probeAndUpdate(req); + completeRequest(req, result); + } else { + req->completionEvent = new MemCompleteEvent(req, result, this); + cacheInterface->access(req); + } + } else if (cmd < (100 - percentCopies)){ + // write + + //For now we only allow one outstanding request per addreess per tester + //This means we assume CPU does write forwarding to reads that alias something + //in the cpu store buffer. + if (outstandingAddrs.find(req->paddr) != outstandingAddrs.end()) return; + else outstandingAddrs.insert(req->paddr); + + req->cmd = Write; + memcpy(req->data, &data, req->size); + checkMem->access(Write, req->paddr, req->data, req->size); + if (blockAddr(req->paddr) == traceBlockAddr) { + cerr << name() << ": initiating write " + << ((probe)?"probe of ":"access of ") + << dec << req->size << " bytes (value = 0x"; + printData(cerr, req->data, req->size); + cerr << ") to addr 0x" + << hex << req->paddr + << " (0x" << hex << blockAddr(req->paddr) << ")" + << " at cycle " + << dec << curTick << endl; + } + if (probe) { + cacheInterface->probeAndUpdate(req); + completeRequest(req, NULL); + } else { + req->completionEvent = new MemCompleteEvent(req, NULL, this); + cacheInterface->access(req); + } + } else { + // copy + unsigned source_align = random() % 100; + unsigned dest_align = random() % 100; + unsigned offset2 = random() % size; + + Addr source = ((base) ? baseAddr1 : baseAddr2) + offset; + Addr dest = ((base) ? baseAddr2 : baseAddr1) + offset2; + if (outstandingAddrs.find(source) != outstandingAddrs.end()) return; + else outstandingAddrs.insert(source); + if (outstandingAddrs.find(dest) != outstandingAddrs.end()) return; + else outstandingAddrs.insert(dest); + + if (source_align >= percentSourceUnaligned) { + source = blockAddr(source); + } + if (dest_align >= percentDestUnaligned) { + dest = blockAddr(dest); + } + req->cmd = Copy; + req->flags &= ~UNCACHEABLE; + req->paddr = source; + req->dest = dest; + delete [] req->data; + req->data = new uint8_t[blockSize]; + req->size = blockSize; + if (source == traceBlockAddr || dest == traceBlockAddr) { + cerr << name() + << ": initiating copy of " + << dec << req->size << " bytes from addr 0x" + << hex << source + << " (0x" << hex << blockAddr(source) << ")" + << " to addr 0x" + << hex << dest + << " (0x" << hex << blockAddr(dest) << ")" + << " at cycle " + << dec << curTick << endl; + } + cacheInterface->access(req); + uint8_t result[blockSize]; + checkMem->access(Read, source, &result, blockSize); + checkMem->access(Write, dest, &result, blockSize); + } +} + + +void +MemCompleteEvent::process() +{ + tester->completeRequest(req, data); + delete this; +} + + +const char * +MemCompleteEvent::description() +{ + return "memory access completion"; +} + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(MemTest) + + SimObjectParam<BaseCache *> cache; + SimObjectParam<FunctionalMemory *> main_mem; + SimObjectParam<FunctionalMemory *> check_mem; + Param<unsigned> memory_size; + Param<unsigned> percent_reads; + Param<unsigned> percent_copies; + Param<unsigned> percent_uncacheable; + Param<unsigned> progress_interval; + Param<unsigned> percent_source_unaligned; + Param<unsigned> percent_dest_unaligned; + Param<Addr> trace_addr; + Param<Counter> max_loads; + +END_DECLARE_SIM_OBJECT_PARAMS(MemTest) + + +BEGIN_INIT_SIM_OBJECT_PARAMS(MemTest) + + INIT_PARAM(cache, "L1 cache"), + INIT_PARAM(main_mem, "hierarchical memory"), + INIT_PARAM(check_mem, "check memory"), + INIT_PARAM(memory_size, "memory size"), + INIT_PARAM(percent_reads, "target read percentage"), + INIT_PARAM(percent_copies, "target copy percentage"), + INIT_PARAM(percent_uncacheable, "target uncacheable percentage"), + INIT_PARAM(progress_interval, "progress report interval (in accesses)"), + INIT_PARAM(percent_source_unaligned, + "percent of copy source address that are unaligned"), + INIT_PARAM(percent_dest_unaligned, + "percent of copy dest address that are unaligned"), + INIT_PARAM(trace_addr, "address to trace"), + INIT_PARAM(max_loads, "terminate when we have reached this load count") + +END_INIT_SIM_OBJECT_PARAMS(MemTest) + + +CREATE_SIM_OBJECT(MemTest) +{ + return new MemTest(getInstanceName(), cache->getInterface(), main_mem, + check_mem, memory_size, percent_reads, percent_copies, + percent_uncacheable, progress_interval, + percent_source_unaligned, percent_dest_unaligned, + trace_addr, max_loads); +} + +REGISTER_SIM_OBJECT("MemTest", MemTest) diff --git a/src/cpu/memtest/memtest.hh b/src/cpu/memtest/memtest.hh new file mode 100644 index 000000000..42fb235db --- /dev/null +++ b/src/cpu/memtest/memtest.hh @@ -0,0 +1,159 @@ +/* + * 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: Erik Hallnor + * Steve Reinhardt + */ + +#ifndef __CPU_MEMTEST_MEMTEST_HH__ +#define __CPU_MEMTEST_MEMTEST_HH__ + +#include <set> + +#include "base/statistics.hh" +#include "mem/functional/functional.hh" +#include "mem/mem_interface.hh" +#include "sim/eventq.hh" +#include "sim/sim_exit.hh" +#include "sim/sim_object.hh" +#include "sim/stats.hh" + +class ThreadContext; +class MemTest : public SimObject +{ + public: + + MemTest(const std::string &name, + MemInterface *_cache_interface, + FunctionalMemory *main_mem, + FunctionalMemory *check_mem, + unsigned _memorySize, + unsigned _percentReads, + unsigned _percentCopies, + unsigned _percentUncacheable, + unsigned _progressInterval, + unsigned _percentSourceUnaligned, + unsigned _percentDestUnaligned, + Addr _traceAddr, + Counter _max_loads); + + // register statistics + virtual void regStats(); + + inline Tick cycles(int numCycles) const { return numCycles; } + + // main simulation loop (one cycle) + void tick(); + + protected: + class TickEvent : public Event + { + private: + MemTest *cpu; + public: + TickEvent(MemTest *c) + : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) {} + void process() {cpu->tick();} + virtual const char *description() { return "tick event"; } + }; + + TickEvent tickEvent; + + MemInterface *cacheInterface; + FunctionalMemory *mainMem; + FunctionalMemory *checkMem; + SimpleThread *thread; + + unsigned size; // size of testing memory region + + unsigned percentReads; // target percentage of read accesses + unsigned percentCopies; // target percentage of copy accesses + unsigned percentUncacheable; + + int id; + + std::set<unsigned> outstandingAddrs; + + unsigned blockSize; + + Addr blockAddrMask; + + Addr blockAddr(Addr addr) + { + return (addr & ~blockAddrMask); + } + + Addr traceBlockAddr; + + Addr baseAddr1; // fix this to option + Addr baseAddr2; // fix this to option + Addr uncacheAddr; + + unsigned progressInterval; // frequency of progress reports + Tick nextProgressMessage; // access # for next progress report + + unsigned percentSourceUnaligned; + unsigned percentDestUnaligned; + + Tick noResponseCycles; + + uint64_t numReads; + uint64_t maxLoads; + Stats::Scalar<> numReadsStat; + Stats::Scalar<> numWritesStat; + Stats::Scalar<> numCopiesStat; + + // called by MemCompleteEvent::process() + void completeRequest(MemReqPtr &req, uint8_t *data); + + friend class MemCompleteEvent; +}; + + +class MemCompleteEvent : public Event +{ + MemReqPtr req; + uint8_t *data; + MemTest *tester; + + public: + + MemCompleteEvent(MemReqPtr &_req, uint8_t *_data, MemTest *_tester) + : Event(&mainEventQueue), + req(_req), data(_data), tester(_tester) + { + } + + void process(); + + virtual const char *description(); +}; + +#endif // __CPU_MEMTEST_MEMTEST_HH__ + + + diff --git a/src/cpu/o3/2bit_local_pred.cc b/src/cpu/o3/2bit_local_pred.cc new file mode 100644 index 000000000..77a45ea26 --- /dev/null +++ b/src/cpu/o3/2bit_local_pred.cc @@ -0,0 +1,146 @@ +/* + * 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 "base/intmath.hh" +#include "base/misc.hh" +#include "base/trace.hh" +#include "cpu/o3/2bit_local_pred.hh" + +LocalBP::LocalBP(unsigned _localPredictorSize, + unsigned _localCtrBits, + unsigned _instShiftAmt) + : localPredictorSize(_localPredictorSize), + localCtrBits(_localCtrBits), + instShiftAmt(_instShiftAmt) +{ + if (!isPowerOf2(localPredictorSize)) { + fatal("Invalid local predictor size!\n"); + } + + localPredictorSets = localPredictorSize / localCtrBits; + + if (!isPowerOf2(localPredictorSets)) { + fatal("Invalid number of local predictor sets! Check localCtrBits.\n"); + } + + // Setup the index mask. + indexMask = localPredictorSets - 1; + + DPRINTF(Fetch, "Branch predictor: index mask: %#x\n", indexMask); + + // Setup the array of counters for the local predictor. + localCtrs.resize(localPredictorSets); + + for (int i = 0; i < localPredictorSets; ++i) + localCtrs[i].setBits(_localCtrBits); + + DPRINTF(Fetch, "Branch predictor: local predictor size: %i\n", + localPredictorSize); + + DPRINTF(Fetch, "Branch predictor: local counter bits: %i\n", localCtrBits); + + DPRINTF(Fetch, "Branch predictor: instruction shift amount: %i\n", + instShiftAmt); +} + +void +LocalBP::reset() +{ + for (int i = 0; i < localPredictorSets; ++i) { + localCtrs[i].reset(); + } +} + +bool +LocalBP::lookup(Addr &branch_addr, void * &bp_history) +{ + bool taken; + uint8_t counter_val; + unsigned local_predictor_idx = getLocalIndex(branch_addr); + + DPRINTF(Fetch, "Branch predictor: Looking up index %#x\n", + local_predictor_idx); + + counter_val = localCtrs[local_predictor_idx].read(); + + DPRINTF(Fetch, "Branch predictor: prediction is %i.\n", + (int)counter_val); + + taken = getPrediction(counter_val); + +#if 0 + // Speculative update. + if (taken) { + DPRINTF(Fetch, "Branch predictor: Branch updated as taken.\n"); + localCtrs[local_predictor_idx].increment(); + } else { + DPRINTF(Fetch, "Branch predictor: Branch updated as not taken.\n"); + localCtrs[local_predictor_idx].decrement(); + } +#endif + + return taken; +} + +void +LocalBP::update(Addr &branch_addr, bool taken, void *bp_history) +{ + assert(bp_history == NULL); + unsigned local_predictor_idx; + + // Update the local predictor. + local_predictor_idx = getLocalIndex(branch_addr); + + DPRINTF(Fetch, "Branch predictor: Looking up index %#x\n", + local_predictor_idx); + + if (taken) { + DPRINTF(Fetch, "Branch predictor: Branch updated as taken.\n"); + localCtrs[local_predictor_idx].increment(); + } else { + DPRINTF(Fetch, "Branch predictor: Branch updated as not taken.\n"); + localCtrs[local_predictor_idx].decrement(); + } +} + +inline +bool +LocalBP::getPrediction(uint8_t &count) +{ + // Get the MSB of the count + return (count >> (localCtrBits - 1)); +} + +inline +unsigned +LocalBP::getLocalIndex(Addr &branch_addr) +{ + return (branch_addr >> instShiftAmt) & indexMask; +} diff --git a/src/cpu/o3/2bit_local_pred.hh b/src/cpu/o3/2bit_local_pred.hh new file mode 100644 index 000000000..0a2a71d3e --- /dev/null +++ b/src/cpu/o3/2bit_local_pred.hh @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#ifndef __CPU_O3_2BIT_LOCAL_PRED_HH__ +#define __CPU_O3_2BIT_LOCAL_PRED_HH__ + +// For Addr type. +#include "arch/isa_traits.hh" +#include "cpu/o3/sat_counter.hh" + +#include <vector> + +/** + * Implements a local predictor that uses the PC to index into a table of + * counters. Note that any time a pointer to the bp_history is given, it + * should be NULL using this predictor because it does not have any branch + * predictor state that needs to be recorded or updated; the update can be + * determined solely by the branch being taken or not taken. + */ +class LocalBP +{ + public: + /** + * Default branch predictor constructor. + * @param localPredictorSize Size of the local predictor. + * @param localCtrBits Number of bits per counter. + * @param instShiftAmt Offset amount for instructions to ignore alignment. + */ + LocalBP(unsigned localPredictorSize, unsigned localCtrBits, + unsigned instShiftAmt); + + /** + * Looks up the given address in the branch predictor and returns + * a true/false value as to whether it is taken. + * @param branch_addr The address of the branch to look up. + * @param bp_history Pointer to any bp history state. + * @return Whether or not the branch is taken. + */ + bool lookup(Addr &branch_addr, void * &bp_history); + + /** + * Updates the branch predictor with the actual result of a branch. + * @param branch_addr The address of the branch to update. + * @param taken Whether or not the branch was taken. + */ + void update(Addr &branch_addr, bool taken, void *bp_history); + + void squash(void *bp_history) + { assert(bp_history == NULL); } + + void reset(); + + private: + /** + * Returns the taken/not taken prediction given the value of the + * counter. + * @param count The value of the counter. + * @return The prediction based on the counter value. + */ + inline bool getPrediction(uint8_t &count); + + /** Calculates the local index based on the PC. */ + inline unsigned getLocalIndex(Addr &PC); + + /** Array of counters that make up the local predictor. */ + std::vector<SatCounter> localCtrs; + + /** Size of the local predictor. */ + unsigned localPredictorSize; + + /** Number of sets. */ + unsigned localPredictorSets; + + /** Number of bits of the local predictor's counters. */ + unsigned localCtrBits; + + /** Number of bits to shift the PC when calculating index. */ + unsigned instShiftAmt; + + /** Mask to get index bits. */ + unsigned indexMask; +}; + +#endif // __CPU_O3_2BIT_LOCAL_PRED_HH__ diff --git a/src/cpu/o3/alpha_cpu.cc b/src/cpu/o3/alpha_cpu.cc new file mode 100644 index 000000000..39cae696b --- /dev/null +++ b/src/cpu/o3/alpha_cpu.cc @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#include "cpu/o3/alpha_impl.hh" +#include "cpu/o3/alpha_cpu_impl.hh" +#include "cpu/o3/alpha_dyn_inst.hh" + +// Force instantiation of AlphaFullCPU for all the implemntations that are +// needed. Consider merging this and alpha_dyn_inst.cc, and maybe all +// classes that depend on a certain impl, into one file (alpha_impl.cc?). +template class AlphaFullCPU<AlphaSimpleImpl>; diff --git a/src/cpu/o3/alpha_cpu.hh b/src/cpu/o3/alpha_cpu.hh new file mode 100644 index 000000000..f81837f3c --- /dev/null +++ b/src/cpu/o3/alpha_cpu.hh @@ -0,0 +1,434 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#ifndef __CPU_O3_ALPHA_FULL_CPU_HH__ +#define __CPU_O3_ALPHA_FULL_CPU_HH__ + +#include "arch/isa_traits.hh" +#include "cpu/thread_context.hh" +#include "cpu/o3/cpu.hh" +#include "sim/byteswap.hh" + +class EndQuiesceEvent; +namespace Kernel { + class Statistics; +}; + +class TranslatingPort; + +/** + * AlphaFullCPU class. Derives from the FullO3CPU class, and + * implements all ISA and implementation specific functions of the + * CPU. This is the CPU class that is used for the SimObjects, and is + * what is given to the DynInsts. Most of its state exists in the + * FullO3CPU; the state is has is mainly for ISA specific + * functionality. + */ +template <class Impl> +class AlphaFullCPU : public FullO3CPU<Impl> +{ + protected: + typedef TheISA::IntReg IntReg; + typedef TheISA::FloatReg FloatReg; + typedef TheISA::FloatRegBits FloatRegBits; + typedef TheISA::MiscReg MiscReg; + typedef TheISA::RegFile RegFile; + typedef TheISA::MiscRegFile MiscRegFile; + + public: + typedef O3ThreadState<Impl> ImplState; + typedef O3ThreadState<Impl> Thread; + typedef typename Impl::Params Params; + + /** Constructs an AlphaFullCPU with the given parameters. */ + AlphaFullCPU(Params *params); + + /** + * Derived ThreadContext class for use with the AlphaFullCPU. 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 AlphaFullCPU 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 AlphaTC : public ThreadContext + { + public: + /** Pointer to the CPU. */ + AlphaFullCPU<Impl> *cpu; + + /** Pointer to the thread state that this TC corrseponds to. */ + O3ThreadState<Impl> *thread; + + /** Returns a pointer to this CPU. */ + virtual BaseCPU *getCpuPtr() { return cpu; } + + /** Sets this CPU's ID. */ + virtual void setCpuId(int id) { cpu->cpu_id = id; } + + /** Reads this CPU's ID. */ + virtual int readCpuId() { return cpu->cpu_id; } + +#if FULL_SYSTEM + /** Returns a pointer to the system. */ + virtual System *getSystemPtr() { return cpu->system; } + + /** Returns a pointer to physical memory. */ + virtual PhysicalMemory *getPhysMemPtr() { return cpu->physmem; } + + /** Returns a pointer to the ITB. */ + virtual AlphaITB *getITBPtr() { return cpu->itb; } + + /** Returns a pointer to the DTB. */ + virtual AlphaDTB *getDTBPtr() { return cpu->dtb; } + + /** Returns a pointer to this thread's kernel statistics. */ + virtual Kernel::Statistics *getKernelStats() + { return thread->kernelStats; } + + virtual FunctionalPort *getPhysPort() { return thread->getPhysPort(); } + + virtual VirtualPort *getVirtPort(ThreadContext *src_tc = NULL); + + void delVirtPort(VirtualPort *vp); +#else + virtual TranslatingPort *getMemPort() { return thread->getMemPort(); } + + /** Returns a pointer to this thread's process. */ + virtual Process *getProcessPtr() { return thread->getProcessPtr(); } +#endif + /** Returns this thread's status. */ + virtual Status status() const { return thread->status(); } + + /** Sets this thread's status. */ + virtual void setStatus(Status new_status) + { thread->setStatus(new_status); } + + /** Set the status to Active. Optional delay indicates number of + * cycles to wait before beginning execution. */ + virtual void activate(int delay = 1); + + /** Set the status to Suspended. */ + virtual void suspend(); + + /** Set the status to Unallocated. */ + virtual void deallocate(); + + /** Set the status to Halted. */ + virtual void halt(); + +#if FULL_SYSTEM + /** Dumps the function profiling information. + * @todo: Implement. + */ + virtual void dumpFuncProfile(); +#endif + /** Takes over execution of a thread from another CPU. */ + virtual void takeOverFrom(ThreadContext *old_context); + + /** Registers statistics associated with this TC. */ + virtual void regStats(const std::string &name); + + /** Serializes state. */ + virtual void serialize(std::ostream &os); + /** Unserializes state. */ + virtual void unserialize(Checkpoint *cp, const std::string §ion); + +#if FULL_SYSTEM + /** Returns pointer to the quiesce event. */ + virtual EndQuiesceEvent *getQuiesceEvent(); + + /** Reads the last tick that this thread was activated on. */ + virtual Tick readLastActivate(); + /** Reads the last tick that this thread was suspended on. */ + virtual Tick readLastSuspend(); + + /** Clears the function profiling information. */ + virtual void profileClear(); + /** Samples the function profiling information. */ + virtual void profileSample(); +#endif + /** Returns this thread's ID number. */ + virtual int getThreadNum() { return thread->readTid(); } + + /** Returns the instruction this thread is currently committing. + * Only used when an instruction faults. + */ + virtual TheISA::MachInst getInst(); + + /** Copies the architectural registers from another TC into this TC. */ + virtual void copyArchRegs(ThreadContext *tc); + + /** Resets all architectural registers to 0. */ + virtual void clearArchRegs(); + + /** Reads an integer register. */ + virtual uint64_t readIntReg(int reg_idx); + + virtual FloatReg readFloatReg(int reg_idx, int width); + + virtual FloatReg readFloatReg(int reg_idx); + + virtual FloatRegBits readFloatRegBits(int reg_idx, int width); + + virtual FloatRegBits readFloatRegBits(int reg_idx); + + /** Sets an integer register to a value. */ + virtual void setIntReg(int reg_idx, uint64_t val); + + virtual void setFloatReg(int reg_idx, FloatReg val, int width); + + virtual void setFloatReg(int reg_idx, FloatReg val); + + virtual void setFloatRegBits(int reg_idx, FloatRegBits val, int width); + + virtual void setFloatRegBits(int reg_idx, FloatRegBits val); + + /** Reads this thread's PC. */ + virtual uint64_t readPC() + { return cpu->readPC(thread->readTid()); } + + /** Sets this thread's PC. */ + virtual void setPC(uint64_t val); + + /** Reads this thread's next PC. */ + virtual uint64_t readNextPC() + { return cpu->readNextPC(thread->readTid()); } + + /** Sets this thread's next PC. */ + virtual void setNextPC(uint64_t val); + + virtual uint64_t readNextNPC() + { + panic("Alpha has no NextNPC!"); + return 0; + } + + virtual void setNextNPC(uint64_t val) + { } + + /** Reads a miscellaneous register. */ + virtual MiscReg readMiscReg(int misc_reg) + { return cpu->readMiscReg(misc_reg, thread->readTid()); } + + /** Reads a misc. register, including any side-effects the + * read might have as defined by the architecture. */ + virtual MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) + { return cpu->readMiscRegWithEffect(misc_reg, fault, thread->readTid()); } + + /** Sets a misc. register. */ + virtual Fault setMiscReg(int misc_reg, const MiscReg &val); + + /** Sets a misc. register, including any side-effects the + * write might have as defined by the architecture. */ + virtual Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val); + + /** Returns the number of consecutive store conditional failures. */ + // @todo: Figure out where these store cond failures should go. + virtual unsigned readStCondFailures() + { return thread->storeCondFailures; } + + /** Sets the number of consecutive store conditional failures. */ + virtual void setStCondFailures(unsigned sc_failures) + { thread->storeCondFailures = sc_failures; } + +#if FULL_SYSTEM + /** Returns if the thread is currently in PAL mode, based on + * the PC's value. */ + virtual bool inPalMode() + { return TheISA::PcPAL(cpu->readPC(thread->readTid())); } +#endif + // Only really makes sense for old CPU model. Lots of code + // outside the CPU still checks this function, so it will + // always return false to keep everything working. + /** Checks if the thread is misspeculating. Because it is + * very difficult to determine if the thread is + * misspeculating, this is set as false. */ + virtual bool misspeculating() { return false; } + +#if !FULL_SYSTEM + /** Gets a syscall argument by index. */ + virtual IntReg getSyscallArg(int i); + + /** Sets a syscall argument. */ + virtual void setSyscallArg(int i, IntReg val); + + /** Sets the syscall return value. */ + virtual void setSyscallReturn(SyscallReturn return_value); + + /** Executes a syscall in SE mode. */ + virtual void syscall(int64_t callnum) + { return cpu->syscall(callnum, thread->readTid()); } + + /** Reads the funcExeInst counter. */ + virtual Counter readFuncExeInst() { return thread->funcExeInst; } +#endif + virtual void changeRegFileContext(TheISA::RegFile::ContextParam param, + TheISA::RegFile::ContextVal val) + { panic("Not supported on Alpha!"); } + }; + +#if FULL_SYSTEM + /** ITB pointer. */ + AlphaITB *itb; + /** DTB pointer. */ + AlphaDTB *dtb; +#endif + + /** Registers statistics. */ + void regStats(); + +#if FULL_SYSTEM + /** Translates instruction requestion. */ + Fault translateInstReq(RequestPtr &req, Thread *thread) + { + return itb->translate(req, thread->getTC()); + } + + /** Translates data read request. */ + Fault translateDataReadReq(RequestPtr &req, Thread *thread) + { + return dtb->translate(req, thread->getTC(), false); + } + + /** Translates data write request. */ + Fault translateDataWriteReq(RequestPtr &req, Thread *thread) + { + return dtb->translate(req, thread->getTC(), true); + } + +#else + /** Translates instruction requestion in syscall emulation mode. */ + Fault translateInstReq(RequestPtr &req, Thread *thread) + { + return thread->getProcessPtr()->pTable->translate(req); + } + + /** Translates data read request in syscall emulation mode. */ + Fault translateDataReadReq(RequestPtr &req, Thread *thread) + { + return thread->getProcessPtr()->pTable->translate(req); + } + + /** Translates data write request in syscall emulation mode. */ + Fault translateDataWriteReq(RequestPtr &req, Thread *thread) + { + return thread->getProcessPtr()->pTable->translate(req); + } + +#endif + /** Reads a miscellaneous register. */ + MiscReg readMiscReg(int misc_reg, unsigned tid); + + /** Reads a misc. register, including any side effects the read + * might have as defined by the architecture. + */ + MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault, unsigned tid); + + /** Sets a miscellaneous register. */ + Fault setMiscReg(int misc_reg, const MiscReg &val, unsigned tid); + + /** Sets a misc. register, including any side effects the write + * might have as defined by the architecture. + */ + Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val, unsigned tid); + + /** Initiates a squash of all in-flight instructions for a given + * thread. The source of the squash is an external update of + * state through the TC. + */ + void squashFromTC(unsigned tid); + +#if FULL_SYSTEM + /** Posts an interrupt. */ + void post_interrupt(int int_num, int index); + /** Reads the interrupt flag. */ + int readIntrFlag(); + /** Sets the interrupt flags. */ + void setIntrFlag(int val); + /** HW return from error interrupt. */ + Fault hwrei(unsigned tid); + /** Returns if a specific PC is a PAL mode PC. */ + bool inPalMode(uint64_t PC) + { return AlphaISA::PcPAL(PC); } + + /** Traps to handle given fault. */ + void trap(Fault fault, unsigned tid); + bool simPalCheck(int palFunc, unsigned tid); + + /** Processes any interrupts. */ + void processInterrupts(); + + /** Halts the CPU. */ + void halt() { panic("Halt not implemented!\n"); } +#endif + + +#if !FULL_SYSTEM + /** Executes a syscall. + * @todo: Determine if this needs to be virtual. + */ + void syscall(int64_t callnum, int tid); + /** Gets a syscall argument. */ + IntReg getSyscallArg(int i, int tid); + + /** Used to shift args for indirect syscall. */ + void setSyscallArg(int i, IntReg val, int tid); + + /** Sets the return value of a syscall. */ + void setSyscallReturn(SyscallReturn return_value, int tid); +#endif + + /** CPU read function, forwards read to LSQ. */ + template <class T> + Fault read(RequestPtr &req, T &data, int load_idx) + { + return this->iew.ldstQueue.read(req, data, load_idx); + } + + /** CPU write function, forwards write to LSQ. */ + template <class T> + Fault write(RequestPtr &req, T &data, int store_idx) + { + return this->iew.ldstQueue.write(req, data, store_idx); + } + + Addr lockAddr; + + /** Temporary fix for the lock flag, works in the UP case. */ + bool lockFlag; +}; + +#endif // __CPU_O3_ALPHA_FULL_CPU_HH__ diff --git a/src/cpu/o3/alpha_cpu_builder.cc b/src/cpu/o3/alpha_cpu_builder.cc new file mode 100644 index 000000000..828977ccb --- /dev/null +++ b/src/cpu/o3/alpha_cpu_builder.cc @@ -0,0 +1,410 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#include <string> + +#include "cpu/base.hh" +#include "cpu/o3/alpha_cpu.hh" +#include "cpu/o3/alpha_impl.hh" +#include "cpu/o3/alpha_params.hh" +#include "cpu/o3/fu_pool.hh" +#include "sim/builder.hh" + +class DerivAlphaFullCPU : public AlphaFullCPU<AlphaSimpleImpl> +{ + public: + DerivAlphaFullCPU(AlphaSimpleParams *p) + : AlphaFullCPU<AlphaSimpleImpl>(p) + { } +}; + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(DerivAlphaFullCPU) + + Param<int> clock; + Param<int> numThreads; +Param<int> activity; + +#if FULL_SYSTEM +SimObjectParam<System *> system; +Param<int> cpu_id; +SimObjectParam<AlphaITB *> itb; +SimObjectParam<AlphaDTB *> dtb; +#else +SimObjectVectorParam<Process *> workload; +#endif // FULL_SYSTEM + +SimObjectParam<MemObject *> mem; + +SimObjectParam<BaseCPU *> checker; + +Param<Counter> max_insts_any_thread; +Param<Counter> max_insts_all_threads; +Param<Counter> max_loads_any_thread; +Param<Counter> max_loads_all_threads; + +Param<unsigned> cachePorts; + +Param<unsigned> decodeToFetchDelay; +Param<unsigned> renameToFetchDelay; +Param<unsigned> iewToFetchDelay; +Param<unsigned> commitToFetchDelay; +Param<unsigned> fetchWidth; + +Param<unsigned> renameToDecodeDelay; +Param<unsigned> iewToDecodeDelay; +Param<unsigned> commitToDecodeDelay; +Param<unsigned> fetchToDecodeDelay; +Param<unsigned> decodeWidth; + +Param<unsigned> iewToRenameDelay; +Param<unsigned> commitToRenameDelay; +Param<unsigned> decodeToRenameDelay; +Param<unsigned> renameWidth; + +Param<unsigned> commitToIEWDelay; +Param<unsigned> renameToIEWDelay; +Param<unsigned> issueToExecuteDelay; +Param<unsigned> issueWidth; +Param<unsigned> executeWidth; +Param<unsigned> executeIntWidth; +Param<unsigned> executeFloatWidth; +Param<unsigned> executeBranchWidth; +Param<unsigned> executeMemoryWidth; +SimObjectParam<FUPool *> fuPool; + +Param<unsigned> iewToCommitDelay; +Param<unsigned> renameToROBDelay; +Param<unsigned> commitWidth; +Param<unsigned> squashWidth; +Param<Tick> trapLatency; +Param<Tick> fetchTrapLatency; + +Param<std::string> predType; +Param<unsigned> localPredictorSize; +Param<unsigned> localCtrBits; +Param<unsigned> localHistoryTableSize; +Param<unsigned> localHistoryBits; +Param<unsigned> globalPredictorSize; +Param<unsigned> globalCtrBits; +Param<unsigned> globalHistoryBits; +Param<unsigned> choicePredictorSize; +Param<unsigned> choiceCtrBits; + +Param<unsigned> BTBEntries; +Param<unsigned> BTBTagSize; + +Param<unsigned> RASSize; + +Param<unsigned> LQEntries; +Param<unsigned> SQEntries; +Param<unsigned> LFSTSize; +Param<unsigned> SSITSize; + +Param<unsigned> numPhysIntRegs; +Param<unsigned> numPhysFloatRegs; +Param<unsigned> numIQEntries; +Param<unsigned> numROBEntries; + +Param<unsigned> smtNumFetchingThreads; +Param<std::string> smtFetchPolicy; +Param<std::string> smtLSQPolicy; +Param<unsigned> smtLSQThreshold; +Param<std::string> smtIQPolicy; +Param<unsigned> smtIQThreshold; +Param<std::string> smtROBPolicy; +Param<unsigned> smtROBThreshold; +Param<std::string> smtCommitPolicy; + +Param<unsigned> instShiftAmt; + +Param<bool> defer_registration; + +Param<bool> function_trace; +Param<Tick> function_trace_start; + +END_DECLARE_SIM_OBJECT_PARAMS(DerivAlphaFullCPU) + +BEGIN_INIT_SIM_OBJECT_PARAMS(DerivAlphaFullCPU) + + INIT_PARAM(clock, "clock speed"), + INIT_PARAM(numThreads, "number of HW thread contexts"), + INIT_PARAM_DFLT(activity, "Initial activity count", 0), + +#if FULL_SYSTEM + INIT_PARAM(system, "System object"), + INIT_PARAM(cpu_id, "processor ID"), + INIT_PARAM(itb, "Instruction translation buffer"), + INIT_PARAM(dtb, "Data translation buffer"), +#else + INIT_PARAM(workload, "Processes to run"), +#endif // FULL_SYSTEM + + INIT_PARAM(mem, "Memory"), + + INIT_PARAM_DFLT(checker, "Checker CPU", NULL), + + INIT_PARAM_DFLT(max_insts_any_thread, + "Terminate when any thread reaches this inst count", + 0), + INIT_PARAM_DFLT(max_insts_all_threads, + "Terminate when all threads have reached" + "this inst count", + 0), + INIT_PARAM_DFLT(max_loads_any_thread, + "Terminate when any thread reaches this load count", + 0), + INIT_PARAM_DFLT(max_loads_all_threads, + "Terminate when all threads have reached this load" + "count", + 0), + + INIT_PARAM_DFLT(cachePorts, "Cache Ports", 200), + + INIT_PARAM(decodeToFetchDelay, "Decode to fetch delay"), + INIT_PARAM(renameToFetchDelay, "Rename to fetch delay"), + INIT_PARAM(iewToFetchDelay, "Issue/Execute/Writeback to fetch" + "delay"), + INIT_PARAM(commitToFetchDelay, "Commit to fetch delay"), + INIT_PARAM(fetchWidth, "Fetch width"), + INIT_PARAM(renameToDecodeDelay, "Rename to decode delay"), + INIT_PARAM(iewToDecodeDelay, "Issue/Execute/Writeback to decode" + "delay"), + INIT_PARAM(commitToDecodeDelay, "Commit to decode delay"), + INIT_PARAM(fetchToDecodeDelay, "Fetch to decode delay"), + INIT_PARAM(decodeWidth, "Decode width"), + + INIT_PARAM(iewToRenameDelay, "Issue/Execute/Writeback to rename" + "delay"), + INIT_PARAM(commitToRenameDelay, "Commit to rename delay"), + INIT_PARAM(decodeToRenameDelay, "Decode to rename delay"), + INIT_PARAM(renameWidth, "Rename width"), + + INIT_PARAM(commitToIEWDelay, "Commit to " + "Issue/Execute/Writeback delay"), + INIT_PARAM(renameToIEWDelay, "Rename to " + "Issue/Execute/Writeback delay"), + INIT_PARAM(issueToExecuteDelay, "Issue to execute delay (internal" + "to the IEW stage)"), + INIT_PARAM(issueWidth, "Issue width"), + INIT_PARAM(executeWidth, "Execute width"), + INIT_PARAM(executeIntWidth, "Integer execute width"), + INIT_PARAM(executeFloatWidth, "Floating point execute width"), + INIT_PARAM(executeBranchWidth, "Branch execute width"), + INIT_PARAM(executeMemoryWidth, "Memory execute width"), + INIT_PARAM_DFLT(fuPool, "Functional unit pool", NULL), + + INIT_PARAM(iewToCommitDelay, "Issue/Execute/Writeback to commit " + "delay"), + INIT_PARAM(renameToROBDelay, "Rename to reorder buffer delay"), + INIT_PARAM(commitWidth, "Commit width"), + INIT_PARAM(squashWidth, "Squash width"), + INIT_PARAM_DFLT(trapLatency, "Number of cycles before the trap is handled", 6), + INIT_PARAM_DFLT(fetchTrapLatency, "Number of cycles before the fetch trap is handled", 12), + + INIT_PARAM(predType, "Type of branch predictor ('local', 'tournament')"), + INIT_PARAM(localPredictorSize, "Size of local predictor"), + INIT_PARAM(localCtrBits, "Bits per counter"), + INIT_PARAM(localHistoryTableSize, "Size of local history table"), + INIT_PARAM(localHistoryBits, "Bits for the local history"), + INIT_PARAM(globalPredictorSize, "Size of global predictor"), + INIT_PARAM(globalCtrBits, "Bits per counter"), + INIT_PARAM(globalHistoryBits, "Bits of history"), + INIT_PARAM(choicePredictorSize, "Size of choice predictor"), + INIT_PARAM(choiceCtrBits, "Bits of choice counters"), + + INIT_PARAM(BTBEntries, "Number of BTB entries"), + INIT_PARAM(BTBTagSize, "Size of the BTB tags, in bits"), + + INIT_PARAM(RASSize, "RAS size"), + + INIT_PARAM(LQEntries, "Number of load queue entries"), + INIT_PARAM(SQEntries, "Number of store queue entries"), + INIT_PARAM(LFSTSize, "Last fetched store table size"), + INIT_PARAM(SSITSize, "Store set ID table size"), + + INIT_PARAM(numPhysIntRegs, "Number of physical integer registers"), + INIT_PARAM(numPhysFloatRegs, "Number of physical floating point " + "registers"), + INIT_PARAM(numIQEntries, "Number of instruction queue entries"), + INIT_PARAM(numROBEntries, "Number of reorder buffer entries"), + + INIT_PARAM_DFLT(smtNumFetchingThreads, "SMT Number of Fetching Threads", 1), + INIT_PARAM_DFLT(smtFetchPolicy, "SMT Fetch Policy", "SingleThread"), + INIT_PARAM_DFLT(smtLSQPolicy, "SMT LSQ Sharing Policy", "Partitioned"), + INIT_PARAM_DFLT(smtLSQThreshold,"SMT LSQ Threshold", 100), + INIT_PARAM_DFLT(smtIQPolicy, "SMT IQ Policy", "Partitioned"), + INIT_PARAM_DFLT(smtIQThreshold, "SMT IQ Threshold", 100), + INIT_PARAM_DFLT(smtROBPolicy, "SMT ROB Sharing Policy", "Partitioned"), + INIT_PARAM_DFLT(smtROBThreshold,"SMT ROB Threshold", 100), + INIT_PARAM_DFLT(smtCommitPolicy,"SMT Commit Fetch Policy", "RoundRobin"), + + INIT_PARAM(instShiftAmt, "Number of bits to shift instructions by"), + INIT_PARAM(defer_registration, "defer system registration (for sampling)"), + + INIT_PARAM(function_trace, "Enable function trace"), + INIT_PARAM(function_trace_start, "Cycle to start function trace") + +END_INIT_SIM_OBJECT_PARAMS(DerivAlphaFullCPU) + +CREATE_SIM_OBJECT(DerivAlphaFullCPU) +{ + DerivAlphaFullCPU *cpu; + +#if FULL_SYSTEM + // Full-system only supports a single thread for the moment. + int actual_num_threads = 1; +#else + // In non-full-system mode, we infer the number of threads from + // the workload if it's not explicitly specified. + int actual_num_threads = + numThreads.isValid() ? numThreads : workload.size(); + + if (workload.size() == 0) { + fatal("Must specify at least one workload!"); + } + +#endif + + AlphaSimpleParams *params = new AlphaSimpleParams; + + params->clock = clock; + + params->name = getInstanceName(); + params->numberOfThreads = actual_num_threads; + params->activity = activity; + +#if FULL_SYSTEM + params->system = system; + params->cpu_id = cpu_id; + params->itb = itb; + params->dtb = dtb; +#else + params->workload = workload; +#endif // FULL_SYSTEM + + params->mem = mem; + + params->checker = checker; + + params->max_insts_any_thread = max_insts_any_thread; + params->max_insts_all_threads = max_insts_all_threads; + params->max_loads_any_thread = max_loads_any_thread; + params->max_loads_all_threads = max_loads_all_threads; + + // + // Caches + // + params->cachePorts = cachePorts; + + params->decodeToFetchDelay = decodeToFetchDelay; + params->renameToFetchDelay = renameToFetchDelay; + params->iewToFetchDelay = iewToFetchDelay; + params->commitToFetchDelay = commitToFetchDelay; + params->fetchWidth = fetchWidth; + + params->renameToDecodeDelay = renameToDecodeDelay; + params->iewToDecodeDelay = iewToDecodeDelay; + params->commitToDecodeDelay = commitToDecodeDelay; + params->fetchToDecodeDelay = fetchToDecodeDelay; + params->decodeWidth = decodeWidth; + + params->iewToRenameDelay = iewToRenameDelay; + params->commitToRenameDelay = commitToRenameDelay; + params->decodeToRenameDelay = decodeToRenameDelay; + params->renameWidth = renameWidth; + + params->commitToIEWDelay = commitToIEWDelay; + params->renameToIEWDelay = renameToIEWDelay; + params->issueToExecuteDelay = issueToExecuteDelay; + params->issueWidth = issueWidth; + params->executeWidth = executeWidth; + params->executeIntWidth = executeIntWidth; + params->executeFloatWidth = executeFloatWidth; + params->executeBranchWidth = executeBranchWidth; + params->executeMemoryWidth = executeMemoryWidth; + params->fuPool = fuPool; + + params->iewToCommitDelay = iewToCommitDelay; + params->renameToROBDelay = renameToROBDelay; + params->commitWidth = commitWidth; + params->squashWidth = squashWidth; + params->trapLatency = trapLatency; + params->fetchTrapLatency = fetchTrapLatency; + + params->predType = predType; + params->localPredictorSize = localPredictorSize; + params->localCtrBits = localCtrBits; + params->localHistoryTableSize = localHistoryTableSize; + params->localHistoryBits = localHistoryBits; + params->globalPredictorSize = globalPredictorSize; + params->globalCtrBits = globalCtrBits; + params->globalHistoryBits = globalHistoryBits; + params->choicePredictorSize = choicePredictorSize; + params->choiceCtrBits = choiceCtrBits; + + params->BTBEntries = BTBEntries; + params->BTBTagSize = BTBTagSize; + + params->RASSize = RASSize; + + params->LQEntries = LQEntries; + params->SQEntries = SQEntries; + + params->SSITSize = SSITSize; + params->LFSTSize = LFSTSize; + + params->numPhysIntRegs = numPhysIntRegs; + params->numPhysFloatRegs = numPhysFloatRegs; + params->numIQEntries = numIQEntries; + params->numROBEntries = numROBEntries; + + params->smtNumFetchingThreads = smtNumFetchingThreads; + params->smtFetchPolicy = smtFetchPolicy; + params->smtIQPolicy = smtIQPolicy; + params->smtLSQPolicy = smtLSQPolicy; + params->smtLSQThreshold = smtLSQThreshold; + params->smtROBPolicy = smtROBPolicy; + params->smtROBThreshold = smtROBThreshold; + params->smtCommitPolicy = smtCommitPolicy; + + params->instShiftAmt = 2; + + params->deferRegistration = defer_registration; + + params->functionTrace = function_trace; + params->functionTraceStart = function_trace_start; + + cpu = new DerivAlphaFullCPU(params); + + return cpu; +} + +REGISTER_SIM_OBJECT("DerivAlphaFullCPU", DerivAlphaFullCPU) + diff --git a/src/cpu/o3/alpha_cpu_impl.hh b/src/cpu/o3/alpha_cpu_impl.hh new file mode 100644 index 000000000..98290e57f --- /dev/null +++ b/src/cpu/o3/alpha_cpu_impl.hh @@ -0,0 +1,872 @@ +/* + * 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 "arch/alpha/faults.hh" +#include "base/cprintf.hh" +#include "base/statistics.hh" +#include "base/timebuf.hh" +#include "cpu/checker/thread_context.hh" +#include "sim/sim_events.hh" +#include "sim/stats.hh" + +#include "cpu/o3/alpha_cpu.hh" +#include "cpu/o3/alpha_params.hh" +#include "cpu/o3/comm.hh" +#include "cpu/o3/thread_state.hh" + +#if FULL_SYSTEM +#include "arch/alpha/osfpal.hh" +#include "arch/isa_traits.hh" +#include "cpu/quiesce_event.hh" +#include "kern/kernel_stats.hh" +#include "sim/system.hh" +#endif + +using namespace TheISA; + +template <class Impl> +AlphaFullCPU<Impl>::AlphaFullCPU(Params *params) +#if FULL_SYSTEM + : FullO3CPU<Impl>(params), itb(params->itb), dtb(params->dtb) +#else + : FullO3CPU<Impl>(params) +#endif +{ + DPRINTF(FullCPU, "AlphaFullCPU: Creating AlphaFullCPU object.\n"); + + // Setup any thread state. + this->thread.resize(this->numThreads); + + for (int i = 0; i < this->numThreads; ++i) { +#if FULL_SYSTEM + // SMT is not supported in FS mode yet. + assert(this->numThreads == 1); + this->thread[i] = new Thread(this, 0); + this->thread[i]->setStatus(ThreadContext::Suspended); +#else + if (i < params->workload.size()) { + DPRINTF(FullCPU, "FullCPU: Workload[%i] process is %#x", + i, this->thread[i]); + this->thread[i] = new Thread(this, i, params->workload[i], + i, params->mem); + + this->thread[i]->setStatus(ThreadContext::Suspended); + +#if !FULL_SYSTEM + /* Use this port to for syscall emulation writes to memory. */ + Port *mem_port; + TranslatingPort *trans_port; + trans_port = new TranslatingPort(csprintf("%s-%d-funcport", + name(), i), + params->workload[i]->pTable, + false); + mem_port = params->mem->getPort("functional"); + mem_port->setPeer(trans_port); + trans_port->setPeer(mem_port); + this->thread[i]->setMemPort(trans_port); +#endif + //usedTids[i] = true; + //threadMap[i] = i; + } else { + //Allocate Empty thread so M5 can use later + //when scheduling threads to CPU + Process* dummy_proc = NULL; + + this->thread[i] = new Thread(this, i, dummy_proc, i, params->mem); + //usedTids[i] = false; + } +#endif // !FULL_SYSTEM + + ThreadContext *tc; + + // Setup the TC that will serve as the interface to the threads/CPU. + AlphaTC *alpha_tc = new AlphaTC; + + // If we're using a checker, then the TC should be the + // CheckerThreadContext. + if (params->checker) { + tc = new CheckerThreadContext<AlphaTC>( + alpha_tc, this->checker); + } else { + tc = alpha_tc; + } + + alpha_tc->cpu = this; + alpha_tc->thread = this->thread[i]; + +#if FULL_SYSTEM + // Setup quiesce event. + this->thread[i]->quiesceEvent = new EndQuiesceEvent(tc); + + Port *mem_port; + FunctionalPort *phys_port; + VirtualPort *virt_port; + phys_port = new FunctionalPort(csprintf("%s-%d-funcport", + name(), i)); + mem_port = this->system->physmem->getPort("functional"); + mem_port->setPeer(phys_port); + phys_port->setPeer(mem_port); + + virt_port = new VirtualPort(csprintf("%s-%d-vport", + name(), i)); + mem_port = this->system->physmem->getPort("functional"); + mem_port->setPeer(virt_port); + virt_port->setPeer(mem_port); + + this->thread[i]->setPhysPort(phys_port); + this->thread[i]->setVirtPort(virt_port); +#endif + // Give the thread the TC. + this->thread[i]->tc = tc; + + // Add the TC to the CPU's list of TC's. + this->threadContexts.push_back(tc); + } + + for (int i=0; i < this->numThreads; i++) { + this->thread[i]->setFuncExeInst(0); + } + + // Sets CPU pointers. These must be set at this level because the CPU + // pointers are defined to be the highest level of CPU class. + this->fetch.setCPU(this); + this->decode.setCPU(this); + this->rename.setCPU(this); + this->iew.setCPU(this); + this->commit.setCPU(this); + + this->rob.setCPU(this); + this->regFile.setCPU(this); + + lockAddr = 0; + lockFlag = false; +} + +template <class Impl> +void +AlphaFullCPU<Impl>::regStats() +{ + // Register stats for everything that has stats. + this->fullCPURegStats(); + this->fetch.regStats(); + this->decode.regStats(); + this->rename.regStats(); + this->iew.regStats(); + this->commit.regStats(); +} + +#if FULL_SYSTEM +template <class Impl> +VirtualPort * +AlphaFullCPU<Impl>::AlphaTC::getVirtPort(ThreadContext *src_tc) +{ + if (!src_tc) + return thread->getVirtPort(); + + VirtualPort *vp; + Port *mem_port; + + vp = new VirtualPort("tc-vport", src_tc); + mem_port = cpu->system->physmem->getPort("functional"); + mem_port->setPeer(vp); + vp->setPeer(mem_port); + return vp; +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaTC::dumpFuncProfile() +{ + // Currently not supported +} +#endif + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaTC::takeOverFrom(ThreadContext *old_context) +{ + // some things should already be set up +#if FULL_SYSTEM + assert(getSystemPtr() == old_context->getSystemPtr()); +#else + assert(getProcessPtr() == old_context->getProcessPtr()); +#endif + + // copy over functional state + setStatus(old_context->status()); + copyArchRegs(old_context); + setCpuId(old_context->readCpuId()); + +#if !FULL_SYSTEM + thread->funcExeInst = old_context->readFuncExeInst(); +#else + EndQuiesceEvent *other_quiesce = old_context->getQuiesceEvent(); + if (other_quiesce) { + // Point the quiesce event's TC at this TC so that it wakes up + // the proper CPU. + other_quiesce->tc = this; + } + if (thread->quiesceEvent) { + thread->quiesceEvent->tc = this; + } + + // Transfer kernel stats from one CPU to the other. + thread->kernelStats = old_context->getKernelStats(); +// storeCondFailures = 0; + cpu->lockFlag = false; +#endif + + old_context->setStatus(ThreadContext::Unallocated); + + thread->inSyscall = false; + thread->trapPending = false; +} + +#if FULL_SYSTEM +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaTC::delVirtPort(VirtualPort *vp) +{ + delete vp->getPeer(); + delete vp; +} +#endif + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaTC::activate(int delay) +{ + DPRINTF(FullCPU, "Calling activate on AlphaTC\n"); + + if (thread->status() == ThreadContext::Active) + return; + +#if FULL_SYSTEM + thread->lastActivate = curTick; +#endif + + if (thread->status() == ThreadContext::Unallocated) { + cpu->activateWhenReady(thread->readTid()); + return; + } + + thread->setStatus(ThreadContext::Active); + + // status() == Suspended + cpu->activateContext(thread->readTid(), delay); +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaTC::suspend() +{ + DPRINTF(FullCPU, "Calling suspend on AlphaTC\n"); + + if (thread->status() == ThreadContext::Suspended) + return; + +#if FULL_SYSTEM + thread->lastActivate = curTick; + thread->lastSuspend = curTick; +#endif +/* +#if FULL_SYSTEM + // Don't change the status from active if there are pending interrupts + if (cpu->check_interrupts()) { + assert(status() == ThreadContext::Active); + return; + } +#endif +*/ + thread->setStatus(ThreadContext::Suspended); + cpu->suspendContext(thread->readTid()); +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaTC::deallocate() +{ + DPRINTF(FullCPU, "Calling deallocate on AlphaTC\n"); + + if (thread->status() == ThreadContext::Unallocated) + return; + + thread->setStatus(ThreadContext::Unallocated); + cpu->deallocateContext(thread->readTid()); +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaTC::halt() +{ + DPRINTF(FullCPU, "Calling halt on AlphaTC\n"); + + if (thread->status() == ThreadContext::Halted) + return; + + thread->setStatus(ThreadContext::Halted); + cpu->haltContext(thread->readTid()); +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaTC::regStats(const std::string &name) +{ +#if FULL_SYSTEM + thread->kernelStats = new Kernel::Statistics(cpu->system); + thread->kernelStats->regStats(name + ".kern"); +#endif +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaTC::serialize(std::ostream &os) +{ +#if FULL_SYSTEM + if (thread->kernelStats) + thread->kernelStats->serialize(os); +#endif + +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaTC::unserialize(Checkpoint *cp, const std::string §ion) +{ +#if FULL_SYSTEM + if (thread->kernelStats) + thread->kernelStats->unserialize(cp, section); +#endif + +} + +#if FULL_SYSTEM +template <class Impl> +EndQuiesceEvent * +AlphaFullCPU<Impl>::AlphaTC::getQuiesceEvent() +{ + return thread->quiesceEvent; +} + +template <class Impl> +Tick +AlphaFullCPU<Impl>::AlphaTC::readLastActivate() +{ + return thread->lastActivate; +} + +template <class Impl> +Tick +AlphaFullCPU<Impl>::AlphaTC::readLastSuspend() +{ + return thread->lastSuspend; +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaTC::profileClear() +{} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaTC::profileSample() +{} +#endif + +template <class Impl> +TheISA::MachInst +AlphaFullCPU<Impl>::AlphaTC:: getInst() +{ + return thread->getInst(); +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaTC::copyArchRegs(ThreadContext *tc) +{ + // This function will mess things up unless the ROB is empty and + // there are no instructions in the pipeline. + unsigned tid = thread->readTid(); + PhysRegIndex renamed_reg; + + // First loop through the integer registers. + for (int i = 0; i < AlphaISA::NumIntRegs; ++i) { + renamed_reg = cpu->renameMap[tid].lookup(i); + + DPRINTF(FullCPU, "FullCPU: Copying over register %i, had data %lli, " + "now has data %lli.\n", + renamed_reg, cpu->readIntReg(renamed_reg), + tc->readIntReg(i)); + + cpu->setIntReg(renamed_reg, tc->readIntReg(i)); + } + + // Then loop through the floating point registers. + for (int i = 0; i < AlphaISA::NumFloatRegs; ++i) { + renamed_reg = cpu->renameMap[tid].lookup(i + AlphaISA::FP_Base_DepTag); + cpu->setFloatRegBits(renamed_reg, + tc->readFloatRegBits(i)); + } + + // Copy the misc regs. + copyMiscRegs(tc, this); + + // Then finally set the PC and the next PC. + cpu->setPC(tc->readPC(), tid); + cpu->setNextPC(tc->readNextPC(), tid); +#if !FULL_SYSTEM + this->thread->funcExeInst = tc->readFuncExeInst(); +#endif +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaTC::clearArchRegs() +{} + +template <class Impl> +uint64_t +AlphaFullCPU<Impl>::AlphaTC::readIntReg(int reg_idx) +{ + return cpu->readArchIntReg(reg_idx, thread->readTid()); +} + +template <class Impl> +FloatReg +AlphaFullCPU<Impl>::AlphaTC::readFloatReg(int reg_idx, int width) +{ + switch(width) { + case 32: + return cpu->readArchFloatRegSingle(reg_idx, thread->readTid()); + case 64: + return cpu->readArchFloatRegDouble(reg_idx, thread->readTid()); + default: + panic("Unsupported width!"); + return 0; + } +} + +template <class Impl> +FloatReg +AlphaFullCPU<Impl>::AlphaTC::readFloatReg(int reg_idx) +{ + return cpu->readArchFloatRegSingle(reg_idx, thread->readTid()); +} + +template <class Impl> +FloatRegBits +AlphaFullCPU<Impl>::AlphaTC::readFloatRegBits(int reg_idx, int width) +{ + DPRINTF(Fault, "Reading floatint register through the TC!\n"); + return cpu->readArchFloatRegInt(reg_idx, thread->readTid()); +} + +template <class Impl> +FloatRegBits +AlphaFullCPU<Impl>::AlphaTC::readFloatRegBits(int reg_idx) +{ + return cpu->readArchFloatRegInt(reg_idx, thread->readTid()); +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaTC::setIntReg(int reg_idx, uint64_t val) +{ + cpu->setArchIntReg(reg_idx, val, thread->readTid()); + + // Squash if we're not already in a state update mode. + if (!thread->trapPending && !thread->inSyscall) { + cpu->squashFromTC(thread->readTid()); + } +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaTC::setFloatReg(int reg_idx, FloatReg val, int width) +{ + switch(width) { + case 32: + cpu->setArchFloatRegSingle(reg_idx, val, thread->readTid()); + break; + case 64: + cpu->setArchFloatRegDouble(reg_idx, val, thread->readTid()); + break; + } + + // Squash if we're not already in a state update mode. + if (!thread->trapPending && !thread->inSyscall) { + cpu->squashFromTC(thread->readTid()); + } +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaTC::setFloatReg(int reg_idx, FloatReg val) +{ + cpu->setArchFloatRegSingle(reg_idx, val, thread->readTid()); + + if (!thread->trapPending && !thread->inSyscall) { + cpu->squashFromTC(thread->readTid()); + } +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaTC::setFloatRegBits(int reg_idx, FloatRegBits val, + int width) +{ + DPRINTF(Fault, "Setting floatint register through the TC!\n"); + cpu->setArchFloatRegInt(reg_idx, val, thread->readTid()); + + // Squash if we're not already in a state update mode. + if (!thread->trapPending && !thread->inSyscall) { + cpu->squashFromTC(thread->readTid()); + } +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaTC::setFloatRegBits(int reg_idx, FloatRegBits val) +{ + cpu->setArchFloatRegInt(reg_idx, val, thread->readTid()); + + // Squash if we're not already in a state update mode. + if (!thread->trapPending && !thread->inSyscall) { + cpu->squashFromTC(thread->readTid()); + } +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaTC::setPC(uint64_t val) +{ + cpu->setPC(val, thread->readTid()); + + // Squash if we're not already in a state update mode. + if (!thread->trapPending && !thread->inSyscall) { + cpu->squashFromTC(thread->readTid()); + } +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaTC::setNextPC(uint64_t val) +{ + cpu->setNextPC(val, thread->readTid()); + + // Squash if we're not already in a state update mode. + if (!thread->trapPending && !thread->inSyscall) { + cpu->squashFromTC(thread->readTid()); + } +} + +template <class Impl> +Fault +AlphaFullCPU<Impl>::AlphaTC::setMiscReg(int misc_reg, const MiscReg &val) +{ + Fault ret_fault = cpu->setMiscReg(misc_reg, val, thread->readTid()); + + // Squash if we're not already in a state update mode. + if (!thread->trapPending && !thread->inSyscall) { + cpu->squashFromTC(thread->readTid()); + } + + return ret_fault; +} + +template <class Impl> +Fault +AlphaFullCPU<Impl>::AlphaTC::setMiscRegWithEffect(int misc_reg, + const MiscReg &val) +{ + Fault ret_fault = cpu->setMiscRegWithEffect(misc_reg, val, + thread->readTid()); + + // Squash if we're not already in a state update mode. + if (!thread->trapPending && !thread->inSyscall) { + cpu->squashFromTC(thread->readTid()); + } + + return ret_fault; +} + +#if !FULL_SYSTEM + +template <class Impl> +TheISA::IntReg +AlphaFullCPU<Impl>::AlphaTC::getSyscallArg(int i) +{ + return cpu->getSyscallArg(i, thread->readTid()); +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaTC::setSyscallArg(int i, IntReg val) +{ + cpu->setSyscallArg(i, val, thread->readTid()); +} + +template <class Impl> +void +AlphaFullCPU<Impl>::AlphaTC::setSyscallReturn(SyscallReturn return_value) +{ + cpu->setSyscallReturn(return_value, thread->readTid()); +} + +#endif // FULL_SYSTEM + +template <class Impl> +MiscReg +AlphaFullCPU<Impl>::readMiscReg(int misc_reg, unsigned tid) +{ + return this->regFile.readMiscReg(misc_reg, tid); +} + +template <class Impl> +MiscReg +AlphaFullCPU<Impl>::readMiscRegWithEffect(int misc_reg, Fault &fault, + unsigned tid) +{ + return this->regFile.readMiscRegWithEffect(misc_reg, fault, tid); +} + +template <class Impl> +Fault +AlphaFullCPU<Impl>::setMiscReg(int misc_reg, const MiscReg &val, unsigned tid) +{ + return this->regFile.setMiscReg(misc_reg, val, tid); +} + +template <class Impl> +Fault +AlphaFullCPU<Impl>::setMiscRegWithEffect(int misc_reg, const MiscReg &val, + unsigned tid) +{ + return this->regFile.setMiscRegWithEffect(misc_reg, val, tid); +} + +template <class Impl> +void +AlphaFullCPU<Impl>::squashFromTC(unsigned tid) +{ + this->thread[tid]->inSyscall = true; + this->commit.generateTCEvent(tid); +} + +#if FULL_SYSTEM + +template <class Impl> +void +AlphaFullCPU<Impl>::post_interrupt(int int_num, int index) +{ + BaseCPU::post_interrupt(int_num, index); + + if (this->thread[0]->status() == ThreadContext::Suspended) { + DPRINTF(IPI,"Suspended Processor awoke\n"); + this->threadContexts[0]->activate(); + } +} + +template <class Impl> +int +AlphaFullCPU<Impl>::readIntrFlag() +{ + return this->regFile.readIntrFlag(); +} + +template <class Impl> +void +AlphaFullCPU<Impl>::setIntrFlag(int val) +{ + this->regFile.setIntrFlag(val); +} + +template <class Impl> +Fault +AlphaFullCPU<Impl>::hwrei(unsigned tid) +{ + // Need to clear the lock flag upon returning from an interrupt. + this->lockFlag = false; + + this->thread[tid]->kernelStats->hwrei(); + + this->checkInterrupts = true; + + // FIXME: XXX check for interrupts? XXX + return NoFault; +} + +template <class Impl> +bool +AlphaFullCPU<Impl>::simPalCheck(int palFunc, unsigned tid) +{ + if (this->thread[tid]->kernelStats) + this->thread[tid]->kernelStats->callpal(palFunc, + this->threadContexts[tid]); + + switch (palFunc) { + case PAL::halt: + halt(); + if (--System::numSystemsRunning == 0) + exitSimLoop("all cpus halted"); + break; + + case PAL::bpt: + case PAL::bugchk: + if (this->system->breakpoint()) + return false; + break; + } + + return true; +} + +template <class Impl> +void +AlphaFullCPU<Impl>::trap(Fault fault, unsigned tid) +{ + // Pass the thread's TC into the invoke method. + fault->invoke(this->threadContexts[tid]); +} + +template <class Impl> +void +AlphaFullCPU<Impl>::processInterrupts() +{ + // Check for interrupts here. For now can copy the code that + // exists within isa_fullsys_traits.hh. Also assume that thread 0 + // is the one that handles the interrupts. + // @todo: Possibly consolidate the interrupt checking code. + // @todo: Allow other threads to handle interrupts. + + // Check if there are any outstanding interrupts + //Handle the interrupts + int ipl = 0; + int summary = 0; + + this->checkInterrupts = false; + + if (this->readMiscReg(IPR_ASTRR, 0)) + panic("asynchronous traps not implemented\n"); + + if (this->readMiscReg(IPR_SIRR, 0)) { + for (int i = INTLEVEL_SOFTWARE_MIN; + i < INTLEVEL_SOFTWARE_MAX; i++) { + if (this->readMiscReg(IPR_SIRR, 0) & (ULL(1) << i)) { + // See table 4-19 of the 21164 hardware reference + ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1; + summary |= (ULL(1) << i); + } + } + } + + uint64_t interrupts = this->intr_status(); + + if (interrupts) { + for (int i = INTLEVEL_EXTERNAL_MIN; + i < INTLEVEL_EXTERNAL_MAX; i++) { + if (interrupts & (ULL(1) << i)) { + // See table 4-19 of the 21164 hardware reference + ipl = i; + summary |= (ULL(1) << i); + } + } + } + + if (ipl && ipl > this->readMiscReg(IPR_IPLR, 0)) { + this->setMiscReg(IPR_ISR, summary, 0); + this->setMiscReg(IPR_INTID, ipl, 0); + // Checker needs to know these two registers were updated. + if (this->checker) { + this->checker->threadBase()->setMiscReg(IPR_ISR, summary); + this->checker->threadBase()->setMiscReg(IPR_INTID, ipl); + } + this->trap(Fault(new InterruptFault), 0); + DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", + this->readMiscReg(IPR_IPLR, 0), ipl, summary); + } +} + +#endif // FULL_SYSTEM + +#if !FULL_SYSTEM + +template <class Impl> +void +AlphaFullCPU<Impl>::syscall(int64_t callnum, int tid) +{ + DPRINTF(FullCPU, "AlphaFullCPU: [tid:%i] Executing syscall().\n\n", tid); + + DPRINTF(Activity,"Activity: syscall() called.\n"); + + // Temporarily increase this by one to account for the syscall + // instruction. + ++(this->thread[tid]->funcExeInst); + + // Execute the actual syscall. + this->thread[tid]->syscall(callnum); + + // Decrease funcExeInst by one as the normal commit will handle + // incrementing it. + --(this->thread[tid]->funcExeInst); +} + +template <class Impl> +TheISA::IntReg +AlphaFullCPU<Impl>::getSyscallArg(int i, int tid) +{ + return this->readArchIntReg(AlphaISA::ArgumentReg0 + i, tid); +} + +template <class Impl> +void +AlphaFullCPU<Impl>::setSyscallArg(int i, IntReg val, int tid) +{ + this->setArchIntReg(AlphaISA::ArgumentReg0 + i, val, tid); +} + +template <class Impl> +void +AlphaFullCPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid) +{ + // check for error condition. Alpha syscall convention is to + // indicate success/failure in reg a3 (r19) and put the + // return value itself in the standard return value reg (v0). + if (return_value.successful()) { + // no error + this->setArchIntReg(SyscallSuccessReg, 0, tid); + this->setArchIntReg(ReturnValueReg, return_value.value(), tid); + } else { + // got an error, return details + this->setArchIntReg(SyscallSuccessReg, (IntReg) -1, tid); + this->setArchIntReg(ReturnValueReg, -return_value.value(), tid); + } +} +#endif diff --git a/src/cpu/o3/alpha_dyn_inst.cc b/src/cpu/o3/alpha_dyn_inst.cc new file mode 100644 index 000000000..0c1723eec --- /dev/null +++ b/src/cpu/o3/alpha_dyn_inst.cc @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#include "cpu/o3/alpha_dyn_inst_impl.hh" +#include "cpu/o3/alpha_impl.hh" + +// Force instantiation of AlphaDynInst for all the implementations that +// are needed. +template class AlphaDynInst<AlphaSimpleImpl>; diff --git a/src/cpu/o3/alpha_dyn_inst.hh b/src/cpu/o3/alpha_dyn_inst.hh new file mode 100644 index 000000000..36a08c4a7 --- /dev/null +++ b/src/cpu/o3/alpha_dyn_inst.hh @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#ifndef __CPU_O3_ALPHA_DYN_INST_HH__ +#define __CPU_O3_ALPHA_DYN_INST_HH__ + +#include "arch/isa_traits.hh" +#include "cpu/base_dyn_inst.hh" +#include "cpu/inst_seq.hh" +#include "cpu/o3/alpha_cpu.hh" +#include "cpu/o3/alpha_impl.hh" + +class Packet; + +/** + * Mostly implementation & ISA specific AlphaDynInst. As with most + * other classes in the new CPU model, it is templated on the Impl to + * allow for passing in of all types, such as the CPU type and the ISA + * type. The AlphaDynInst serves as the primary interface to the CPU + * for instructions that are executing. + */ +template <class Impl> +class AlphaDynInst : public BaseDynInst<Impl> +{ + public: + /** Typedef for the CPU. */ + typedef typename Impl::FullCPU FullCPU; + + /** Binary machine instruction type. */ + typedef TheISA::MachInst MachInst; + /** Extended machine instruction type. */ + typedef TheISA::ExtMachInst ExtMachInst; + /** Logical register index type. */ + typedef TheISA::RegIndex RegIndex; + /** Integer register index type. */ + typedef TheISA::IntReg IntReg; + typedef TheISA::FloatReg FloatReg; + typedef TheISA::FloatRegBits FloatRegBits; + /** Misc register index type. */ + typedef TheISA::MiscReg MiscReg; + + enum { + MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs + MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs + }; + + public: + /** BaseDynInst constructor given a binary instruction. */ + AlphaDynInst(ExtMachInst inst, Addr PC, Addr Pred_PC, InstSeqNum seq_num, + FullCPU *cpu); + + /** BaseDynInst constructor given a static inst pointer. */ + AlphaDynInst(StaticInstPtr &_staticInst); + + /** Executes the instruction.*/ + Fault execute(); + + /** Initiates the access. Only valid for memory operations. */ + Fault initiateAcc(); + + /** Completes the access. Only valid for memory operations. */ + Fault completeAcc(Packet *pkt); + + private: + /** Initializes variables. */ + void initVars(); + + public: + /** Reads a miscellaneous register. */ + MiscReg readMiscReg(int misc_reg) + { + return this->cpu->readMiscReg(misc_reg, this->threadNumber); + } + + /** Reads a misc. register, including any side-effects the read + * might have as defined by the architecture. + */ + MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) + { + return this->cpu->readMiscRegWithEffect(misc_reg, fault, + this->threadNumber); + } + + /** Sets a misc. register. */ + Fault setMiscReg(int misc_reg, const MiscReg &val) + { + this->instResult.integer = val; + return this->cpu->setMiscReg(misc_reg, val, this->threadNumber); + } + + /** Sets a misc. register, including any side-effects the write + * might have as defined by the architecture. + */ + Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) + { + return this->cpu->setMiscRegWithEffect(misc_reg, val, + this->threadNumber); + } + +#if FULL_SYSTEM + /** Calls hardware return from error interrupt. */ + Fault hwrei(); + /** Reads interrupt flag. */ + int readIntrFlag(); + /** Sets interrupt flag. */ + void setIntrFlag(int val); + /** Checks if system is in PAL mode. */ + bool inPalMode(); + /** Traps to handle specified fault. */ + void trap(Fault fault); + bool simPalCheck(int palFunc); +#else + /** Calls a syscall. */ + void syscall(int64_t callnum); +#endif + + private: + /** Physical register index of the destination registers of this + * instruction. + */ + PhysRegIndex _destRegIdx[MaxInstDestRegs]; + + /** Physical register index of the source registers of this + * instruction. + */ + PhysRegIndex _srcRegIdx[MaxInstSrcRegs]; + + /** Physical register index of the previous producers of the + * architected destinations. + */ + PhysRegIndex _prevDestRegIdx[MaxInstDestRegs]; + + public: + + // The register accessor methods provide the index of the + // instruction's operand (e.g., 0 or 1), not the architectural + // register index, to simplify the implementation of register + // renaming. We find the architectural register index by indexing + // into the instruction's own operand index table. Note that a + // raw pointer to the StaticInst is provided instead of a + // ref-counted StaticInstPtr to redice overhead. This is fine as + // long as these methods don't copy the pointer into any long-term + // storage (which is pretty hard to imagine they would have reason + // to do). + + uint64_t readIntReg(const StaticInst *si, int idx) + { + return this->cpu->readIntReg(_srcRegIdx[idx]); + } + + FloatReg readFloatReg(const StaticInst *si, int idx, int width) + { + return this->cpu->readFloatReg(_srcRegIdx[idx], width); + } + + FloatReg readFloatReg(const StaticInst *si, int idx) + { + return this->cpu->readFloatReg(_srcRegIdx[idx]); + } + + FloatRegBits readFloatRegBits(const StaticInst *si, int idx, int width) + { + return this->cpu->readFloatRegBits(_srcRegIdx[idx], width); + } + + FloatRegBits readFloatRegBits(const StaticInst *si, int idx) + { + return this->cpu->readFloatRegBits(_srcRegIdx[idx]); + } + + /** @todo: Make results into arrays so they can handle multiple dest + * registers. + */ + void setIntReg(const StaticInst *si, int idx, uint64_t val) + { + this->cpu->setIntReg(_destRegIdx[idx], val); + BaseDynInst<Impl>::setIntReg(si, idx, val); + } + + void setFloatReg(const StaticInst *si, int idx, FloatReg val, int width) + { + this->cpu->setFloatReg(_destRegIdx[idx], val, width); + BaseDynInst<Impl>::setFloatReg(si, idx, val, width); + } + + void setFloatReg(const StaticInst *si, int idx, FloatReg val) + { + this->cpu->setFloatReg(_destRegIdx[idx], val); + BaseDynInst<Impl>::setFloatReg(si, idx, val); + } + + void setFloatRegBits(const StaticInst *si, int idx, + FloatRegBits val, int width) + { + this->cpu->setFloatRegBits(_destRegIdx[idx], val, width); + BaseDynInst<Impl>::setFloatRegBits(si, idx, val); + } + + void setFloatRegBits(const StaticInst *si, int idx, FloatRegBits val) + { + this->cpu->setFloatRegBits(_destRegIdx[idx], val); + BaseDynInst<Impl>::setFloatRegBits(si, idx, val); + } + + /** Returns the physical register index of the i'th destination + * register. + */ + PhysRegIndex renamedDestRegIdx(int idx) const + { + return _destRegIdx[idx]; + } + + /** Returns the physical register index of the i'th source register. */ + PhysRegIndex renamedSrcRegIdx(int idx) const + { + return _srcRegIdx[idx]; + } + + /** Returns the physical register index of the previous physical register + * that remapped to the same logical register index. + */ + PhysRegIndex prevDestRegIdx(int idx) const + { + return _prevDestRegIdx[idx]; + } + + /** Renames a destination register to a physical register. Also records + * the previous physical register that the logical register mapped to. + */ + void renameDestReg(int idx, + PhysRegIndex renamed_dest, + PhysRegIndex previous_rename) + { + _destRegIdx[idx] = renamed_dest; + _prevDestRegIdx[idx] = previous_rename; + } + + /** Renames a source logical register to the physical register which + * has/will produce that logical register's result. + * @todo: add in whether or not the source register is ready. + */ + void renameSrcReg(int idx, PhysRegIndex renamed_src) + { + _srcRegIdx[idx] = renamed_src; + } + + public: + /** Calculates EA part of a memory instruction. Currently unused, + * though it may be useful in the future if we want to split + * memory operations into EA calculation and memory access parts. + */ + Fault calcEA() + { + return this->staticInst->eaCompInst()->execute(this, this->traceData); + } + + /** Does the memory access part of a memory instruction. Currently unused, + * though it may be useful in the future if we want to split + * memory operations into EA calculation and memory access parts. + */ + Fault memAccess() + { + return this->staticInst->memAccInst()->execute(this, this->traceData); + } +}; + +#endif // __CPU_O3_ALPHA_DYN_INST_HH__ + diff --git a/src/cpu/o3/alpha_dyn_inst_impl.hh b/src/cpu/o3/alpha_dyn_inst_impl.hh new file mode 100644 index 000000000..a73cf4a7d --- /dev/null +++ b/src/cpu/o3/alpha_dyn_inst_impl.hh @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#include "cpu/o3/alpha_dyn_inst.hh" + +template <class Impl> +AlphaDynInst<Impl>::AlphaDynInst(ExtMachInst inst, Addr PC, Addr Pred_PC, + InstSeqNum seq_num, FullCPU *cpu) + : BaseDynInst<Impl>(inst, PC, Pred_PC, seq_num, cpu) +{ + initVars(); +} + +template <class Impl> +AlphaDynInst<Impl>::AlphaDynInst(StaticInstPtr &_staticInst) + : BaseDynInst<Impl>(_staticInst) +{ + initVars(); +} + +template <class Impl> +void +AlphaDynInst<Impl>::initVars() +{ + // Make sure to have the renamed register entries set to the same + // as the normal register entries. It will allow the IQ to work + // without any modifications. + for (int i = 0; i < this->staticInst->numDestRegs(); i++) { + _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; + } +} + +template <class Impl> +Fault +AlphaDynInst<Impl>::execute() +{ + // @todo: Pretty convoluted way to avoid squashing from happening + // when using the TC during an instruction's execution + // (specifically for instructions that have side-effects that use + // the TC). Fix this. + bool in_syscall = this->thread->inSyscall; + this->thread->inSyscall = true; + + this->fault = this->staticInst->execute(this, this->traceData); + + this->thread->inSyscall = in_syscall; + + return this->fault; +} + +template <class Impl> +Fault +AlphaDynInst<Impl>::initiateAcc() +{ + // @todo: Pretty convoluted way to avoid squashing from happening + // when using the TC during an instruction's execution + // (specifically for instructions that have side-effects that use + // the TC). Fix this. + bool in_syscall = this->thread->inSyscall; + this->thread->inSyscall = true; + + this->fault = this->staticInst->initiateAcc(this, this->traceData); + + this->thread->inSyscall = in_syscall; + + return this->fault; +} + +template <class Impl> +Fault +AlphaDynInst<Impl>::completeAcc(Packet *pkt) +{ + if (this->isLoad()) { + this->fault = this->staticInst->completeAcc(pkt, this, + this->traceData); + } else if (this->isStore()) { + this->fault = this->staticInst->completeAcc(pkt, this, + this->traceData); + } else { + panic("Unknown type!"); + } + + return this->fault; +} + +#if FULL_SYSTEM +template <class Impl> +Fault +AlphaDynInst<Impl>::hwrei() +{ + // Can only do a hwrei when in pal mode. + if (!this->cpu->inPalMode(this->readPC())) + return new AlphaISA::UnimplementedOpcodeFault; + + // Set the next PC based on the value of the EXC_ADDR IPR. + this->setNextPC(this->cpu->readMiscReg(AlphaISA::IPR_EXC_ADDR, + this->threadNumber)); + + // Tell CPU to clear any state it needs to if a hwrei is taken. + this->cpu->hwrei(this->threadNumber); + + // FIXME: XXX check for interrupts? XXX + return NoFault; +} + +template <class Impl> +int +AlphaDynInst<Impl>::readIntrFlag() +{ + return this->cpu->readIntrFlag(); +} + +template <class Impl> +void +AlphaDynInst<Impl>::setIntrFlag(int val) +{ + this->cpu->setIntrFlag(val); +} + +template <class Impl> +bool +AlphaDynInst<Impl>::inPalMode() +{ + return this->cpu->inPalMode(this->PC); +} + +template <class Impl> +void +AlphaDynInst<Impl>::trap(Fault fault) +{ + this->cpu->trap(fault, this->threadNumber); +} + +template <class Impl> +bool +AlphaDynInst<Impl>::simPalCheck(int palFunc) +{ + return this->cpu->simPalCheck(palFunc, this->threadNumber); +} +#else +template <class Impl> +void +AlphaDynInst<Impl>::syscall(int64_t callnum) +{ + this->cpu->syscall(callnum, this->threadNumber); +} +#endif + diff --git a/src/cpu/o3/alpha_impl.hh b/src/cpu/o3/alpha_impl.hh new file mode 100644 index 000000000..52f7c2394 --- /dev/null +++ b/src/cpu/o3/alpha_impl.hh @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#ifndef __CPU_O3_ALPHA_IMPL_HH__ +#define __CPU_O3_ALPHA_IMPL_HH__ + +#include "arch/alpha/isa_traits.hh" + +#include "cpu/o3/alpha_params.hh" +#include "cpu/o3/cpu_policy.hh" + +// Forward declarations. +template <class Impl> +class AlphaDynInst; + +template <class Impl> +class AlphaFullCPU; + +/** Implementation specific struct that defines several key types to the + * CPU, the stages within the CPU, the time buffers, and the DynInst. + * The struct defines the ISA, the CPU policy, the specific DynInst, the + * specific FullCPU, and all of the structs from the time buffers to do + * communication. + * This is one of the key things that must be defined for each hardware + * specific CPU implementation. + */ +struct AlphaSimpleImpl +{ + /** The type of MachInst. */ + typedef TheISA::MachInst MachInst; + + /** The CPU policy to be used, which defines all of the CPU stages. */ + typedef SimpleCPUPolicy<AlphaSimpleImpl> CPUPol; + + /** The DynInst type to be used. */ + typedef AlphaDynInst<AlphaSimpleImpl> DynInst; + + /** The refcounted DynInst pointer to be used. In most cases this is + * what should be used, and not DynInst *. + */ + typedef RefCountingPtr<DynInst> DynInstPtr; + + /** The FullCPU type to be used. */ + typedef AlphaFullCPU<AlphaSimpleImpl> FullCPU; + + /** The Params to be passed to each stage. */ + typedef AlphaSimpleParams Params; + + enum { + MaxWidth = 8, + MaxThreads = 4 + }; +}; + +#endif // __CPU_O3_ALPHA_IMPL_HH__ diff --git a/src/cpu/o3/alpha_params.hh b/src/cpu/o3/alpha_params.hh new file mode 100644 index 000000000..f3cf36887 --- /dev/null +++ b/src/cpu/o3/alpha_params.hh @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#ifndef __CPU_O3_ALPHA_PARAMS_HH__ +#define __CPU_O3_ALPHA_PARAMS_HH__ + +#include "cpu/o3/cpu.hh" + +//Forward declarations +class AlphaDTB; +class AlphaITB; +class FUPool; +class MemObject; +class Process; +class System; + +/** + * This file defines the parameters that will be used for the AlphaFullCPU. + * 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 AlphaSimpleParams : public BaseFullCPU::Params +{ + public: + +#if FULL_SYSTEM + AlphaITB *itb; AlphaDTB *dtb; +#else + std::vector<Process *> workload; + Process *process; +#endif // FULL_SYSTEM + + MemObject *mem; + + BaseCPU *checker; + + unsigned activity; + + // + // Caches + // +// MemInterface *icacheInterface; +// MemInterface *dcacheInterface; + + unsigned cachePorts; + + // + // Fetch + // + unsigned decodeToFetchDelay; + unsigned renameToFetchDelay; + unsigned iewToFetchDelay; + unsigned commitToFetchDelay; + unsigned fetchWidth; + + // + // Decode + // + unsigned renameToDecodeDelay; + unsigned iewToDecodeDelay; + unsigned commitToDecodeDelay; + unsigned fetchToDecodeDelay; + unsigned decodeWidth; + + // + // Rename + // + unsigned iewToRenameDelay; + unsigned commitToRenameDelay; + unsigned decodeToRenameDelay; + unsigned renameWidth; + + // + // IEW + // + unsigned commitToIEWDelay; + unsigned renameToIEWDelay; + unsigned issueToExecuteDelay; + unsigned issueWidth; + unsigned executeWidth; + unsigned executeIntWidth; + unsigned executeFloatWidth; + unsigned executeBranchWidth; + unsigned executeMemoryWidth; + FUPool *fuPool; + + // + // Commit + // + unsigned iewToCommitDelay; + unsigned renameToROBDelay; + unsigned commitWidth; + unsigned squashWidth; + Tick trapLatency; + Tick fetchTrapLatency; + + // + // Branch predictor (BP, BTB, RAS) + // + 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; + + // + // Load store queue + // + unsigned LQEntries; + unsigned SQEntries; + + // + // Memory dependence + // + unsigned SSITSize; + unsigned LFSTSize; + + // + // Miscellaneous + // + unsigned numPhysIntRegs; + unsigned numPhysFloatRegs; + unsigned numIQEntries; + unsigned numROBEntries; + + //SMT Parameters + unsigned smtNumFetchingThreads; + + std::string smtFetchPolicy; + + std::string smtIQPolicy; + unsigned smtIQThreshold; + + std::string smtLSQPolicy; + unsigned smtLSQThreshold; + + std::string smtCommitPolicy; + + std::string smtROBPolicy; + unsigned smtROBThreshold; + + // Probably can get this from somewhere. + unsigned instShiftAmt; +}; + +#endif // __CPU_O3_ALPHA_PARAMS_HH__ diff --git a/src/cpu/o3/bpred_unit.cc b/src/cpu/o3/bpred_unit.cc new file mode 100644 index 000000000..b33543bdc --- /dev/null +++ b/src/cpu/o3/bpred_unit.cc @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#include "cpu/o3/bpred_unit_impl.hh" +#include "cpu/o3/alpha_impl.hh" +#include "cpu/o3/alpha_dyn_inst.hh" +#include "cpu/ozone/ozone_impl.hh" +//#include "cpu/ozone/simple_impl.hh" + +template class BPredUnit<AlphaSimpleImpl>; +template class BPredUnit<OzoneImpl>; +//template class BPredUnit<SimpleImpl>; diff --git a/src/cpu/o3/bpred_unit.hh b/src/cpu/o3/bpred_unit.hh new file mode 100644 index 000000000..2c0a39565 --- /dev/null +++ b/src/cpu/o3/bpred_unit.hh @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#ifndef __CPU_O3_BPRED_UNIT_HH__ +#define __CPU_O3_BPRED_UNIT_HH__ + +// For Addr type. +#include "arch/isa_traits.hh" +#include "base/statistics.hh" +#include "cpu/inst_seq.hh" + +#include "cpu/o3/2bit_local_pred.hh" +#include "cpu/o3/btb.hh" +#include "cpu/o3/ras.hh" +#include "cpu/o3/tournament_pred.hh" + +#include <list> + +/** + * Basically a wrapper class to hold both the branch predictor + * and the BTB. + */ +template<class Impl> +class BPredUnit +{ + private: + typedef typename Impl::Params Params; + typedef typename Impl::DynInstPtr DynInstPtr; + + enum PredType { + Local, + Tournament + }; + + PredType predictor; + + public: + + /** + * @param params The params object, that has the size of the BP and BTB. + */ + BPredUnit(Params *params); + + /** + * Registers statistics. + */ + void regStats(); + + void switchOut(); + + void takeOverFrom(); + + /** + * Predicts whether or not the instruction is a taken branch, and the + * target of the branch if it is taken. + * @param inst The branch instruction. + * @param PC The predicted PC is passed back through this parameter. + * @param tid The thread id. + * @return Returns if the branch is taken or not. + */ + bool predict(DynInstPtr &inst, Addr &PC, unsigned tid); + + // @todo: Rename this function. + void BPUncond(void * &bp_history); + + /** + * Tells the branch predictor to commit any updates until the given + * sequence number. + * @param done_sn The sequence number to commit any older updates up until. + * @param tid The thread id. + */ + void update(const InstSeqNum &done_sn, unsigned tid); + + /** + * Squashes all outstanding updates until a given sequence number. + * @param squashed_sn The sequence number to squash any younger updates up + * until. + * @param tid The thread id. + */ + void squash(const InstSeqNum &squashed_sn, unsigned tid); + + /** + * Squashes all outstanding updates until a given sequence number, and + * corrects that sn's update with the proper address and taken/not taken. + * @param squashed_sn The sequence number to squash any younger updates up + * until. + * @param corr_target The correct branch target. + * @param actually_taken The correct branch direction. + * @param tid The thread id. + */ + void squash(const InstSeqNum &squashed_sn, const Addr &corr_target, + bool actually_taken, unsigned tid); + + /** + * @param bp_history Pointer to the history object. The predictor + * will need to update any state and delete the object. + */ + void BPSquash(void *bp_history); + + /** + * Looks up a given PC in the BP to see if it is taken or not taken. + * @param inst_PC The PC to look up. + * @param bp_history Pointer that will be set to an object that + * has the branch predictor state associated with the lookup. + * @return Whether the branch is taken or not taken. + */ + bool BPLookup(Addr &inst_PC, void * &bp_history); + + /** + * Looks up a given PC in the BTB to see if a matching entry exists. + * @param inst_PC The PC to look up. + * @return Whether the BTB contains the given PC. + */ + bool BTBValid(Addr &inst_PC) + { return BTB.valid(inst_PC, 0); } + + /** + * Looks up a given PC in the BTB to get the predicted target. + * @param inst_PC The PC to look up. + * @return The address of the target of the branch. + */ + Addr BTBLookup(Addr &inst_PC) + { return BTB.lookup(inst_PC, 0); } + + /** + * Updates the BP with taken/not taken information. + * @param inst_PC The branch's PC that will be updated. + * @param taken Whether the branch was taken or not taken. + * @param bp_history Pointer to the branch predictor state that is + * associated with the branch lookup that is being updated. + * @todo Make this update flexible enough to handle a global predictor. + */ + void BPUpdate(Addr &inst_PC, bool taken, void *bp_history); + + /** + * Updates the BTB with the target of a branch. + * @param inst_PC The branch's PC that will be updated. + * @param target_PC The branch's target that will be added to the BTB. + */ + void BTBUpdate(Addr &inst_PC, Addr &target_PC) + { BTB.update(inst_PC, target_PC,0); } + + void dump(); + + private: + struct PredictorHistory { + /** + * Makes a predictor history struct that contains any + * information needed to update the predictor, BTB, and RAS. + */ + PredictorHistory(const InstSeqNum &seq_num, const Addr &inst_PC, + const bool pred_taken, void *bp_history, + const unsigned _tid) + : seqNum(seq_num), PC(inst_PC), RASTarget(0), + RASIndex(0), tid(_tid), predTaken(pred_taken), usedRAS(0), + wasCall(0), bpHistory(bp_history) + { } + + /** The sequence number for the predictor history entry. */ + InstSeqNum seqNum; + + /** The PC associated with the sequence number. */ + Addr PC; + + /** The RAS target (only valid if a return). */ + Addr RASTarget; + + /** The RAS index of the instruction (only valid if a call). */ + unsigned RASIndex; + + /** The thread id. */ + unsigned tid; + + /** Whether or not it was predicted taken. */ + bool predTaken; + + /** Whether or not the RAS was used. */ + bool usedRAS; + + /** Whether or not the instruction was a call. */ + bool wasCall; + + /** Pointer to the history object passed back from the branch + * predictor. It is used to update or restore state of the + * branch predictor. + */ + void *bpHistory; + }; + + typedef std::list<PredictorHistory> History; + + /** + * The per-thread predictor history. This is used to update the predictor + * as instructions are committed, or restore it to the proper state after + * a squash. + */ + History predHist[Impl::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[Impl::MaxThreads]; + + /** Stat for number of BP lookups. */ + Stats::Scalar<> lookups; + /** Stat for number of conditional branches predicted. */ + Stats::Scalar<> condPredicted; + /** Stat for number of conditional branches predicted incorrectly. */ + Stats::Scalar<> condIncorrect; + /** Stat for number of BTB lookups. */ + Stats::Scalar<> BTBLookups; + /** Stat for number of BTB hits. */ + Stats::Scalar<> BTBHits; + /** Stat for number of times the BTB is correct. */ + Stats::Scalar<> BTBCorrect; + /** Stat for number of times the RAS is used to get a target. */ + Stats::Scalar<> usedRAS; + /** Stat for number of times the RAS is incorrect. */ + Stats::Scalar<> RASIncorrect; +}; + +#endif // __CPU_O3_BPRED_UNIT_HH__ diff --git a/src/cpu/o3/bpred_unit_impl.hh b/src/cpu/o3/bpred_unit_impl.hh new file mode 100644 index 000000000..0da02145b --- /dev/null +++ b/src/cpu/o3/bpred_unit_impl.hh @@ -0,0 +1,412 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#include <list> +#include <vector> + +#include "base/trace.hh" +#include "base/traceflags.hh" +#include "cpu/o3/bpred_unit.hh" + +using namespace std; + +template<class Impl> +BPredUnit<Impl>::BPredUnit(Params *params) + : BTB(params->BTBEntries, + params->BTBTagSize, + params->instShiftAmt) +{ + // Setup the selected predictor. + if (params->predType == "local") { + localBP = new LocalBP(params->localPredictorSize, + params->localCtrBits, + params->instShiftAmt); + predictor = Local; + } else if (params->predType == "tournament") { + tournamentBP = new TournamentBP(params->localPredictorSize, + params->localCtrBits, + params->localHistoryTableSize, + params->localHistoryBits, + params->globalPredictorSize, + params->globalHistoryBits, + params->globalCtrBits, + params->choicePredictorSize, + params->choiceCtrBits, + params->instShiftAmt); + predictor = Tournament; + } else { + fatal("Invalid BP selected!"); + } + + for (int i=0; i < Impl::MaxThreads; i++) + RAS[i].init(params->RASSize); +} + +template <class Impl> +void +BPredUnit<Impl>::regStats() +{ + lookups + .name(name() + ".BPredUnit.lookups") + .desc("Number of BP lookups") + ; + + condPredicted + .name(name() + ".BPredUnit.condPredicted") + .desc("Number of conditional branches predicted") + ; + + condIncorrect + .name(name() + ".BPredUnit.condIncorrect") + .desc("Number of conditional branches incorrect") + ; + + BTBLookups + .name(name() + ".BPredUnit.BTBLookups") + .desc("Number of BTB lookups") + ; + + BTBHits + .name(name() + ".BPredUnit.BTBHits") + .desc("Number of BTB hits") + ; + + BTBCorrect + .name(name() + ".BPredUnit.BTBCorrect") + .desc("Number of correct BTB predictions (this stat may not " + "work properly.") + ; + + usedRAS + .name(name() + ".BPredUnit.usedRAS") + .desc("Number of times the RAS was used to get a target.") + ; + + RASIncorrect + .name(name() + ".BPredUnit.RASInCorrect") + .desc("Number of incorrect RAS predictions.") + ; +} + +template <class Impl> +void +BPredUnit<Impl>::switchOut() +{ + // Clear any state upon switch out. + for (int i = 0; i < Impl::MaxThreads; ++i) { + squash(0, i); + } +} + +template <class Impl> +void +BPredUnit<Impl>::takeOverFrom() +{ + // Can reset all predictor state, but it's not necessarily better + // than leaving it be. +/* + for (int i = 0; i < Impl::MaxThreads; ++i) + RAS[i].reset(); + + BP.reset(); + BTB.reset(); +*/ +} + +template <class Impl> +bool +BPredUnit<Impl>::predict(DynInstPtr &inst, Addr &PC, unsigned tid) +{ + // See if branch predictor predicts taken. + // If so, get its target addr either from the BTB or the RAS. + // Save off record of branch stuff so the RAS can be fixed + // up once it's done. + + using TheISA::MachInst; + + bool pred_taken = false; + Addr target; + + ++lookups; + + void *bp_history = NULL; + + if (inst->isUncondCtrl()) { + DPRINTF(Fetch, "BranchPred: [tid:%i] Unconditional control.\n", tid); + pred_taken = true; + // Tell the BP there was an unconditional branch. + BPUncond(bp_history); + } else { + ++condPredicted; + + pred_taken = BPLookup(PC, bp_history); + + DPRINTF(Fetch, "BranchPred: [tid:%i]: Branch predictor predicted %i " + "for PC %#x\n", + tid, pred_taken, inst->readPC()); + } + + PredictorHistory predict_record(inst->seqNum, PC, pred_taken, + bp_history, tid); + + // Now lookup in the BTB or RAS. + if (pred_taken) { + if (inst->isReturn()) { + ++usedRAS; + + // If it's a function return call, then look up the address + // in the RAS. + target = RAS[tid].top(); + + // Record the top entry of the RAS, and its index. + predict_record.usedRAS = true; + predict_record.RASIndex = RAS[tid].topIdx(); + predict_record.RASTarget = target; + + assert(predict_record.RASIndex < 16); + + RAS[tid].pop(); + + DPRINTF(Fetch, "BranchPred: [tid:%i]: Instruction %#x is a return, " + "RAS predicted target: %#x, RAS index: %i.\n", + tid, inst->readPC(), target, predict_record.RASIndex); + } else { + ++BTBLookups; + + if (inst->isCall()) { + RAS[tid].push(PC + sizeof(MachInst)); + + // Record that it was a call so that the top RAS entry can + // be popped off if the speculation is incorrect. + predict_record.wasCall = true; + + DPRINTF(Fetch, "BranchPred: [tid:%i] Instruction %#x was a call" + ", adding %#x to the RAS.\n", + tid, inst->readPC(), PC + sizeof(MachInst)); + } + + if (BTB.valid(PC, tid)) { + ++BTBHits; + + // If it's not a return, use the BTB to get the target addr. + target = BTB.lookup(PC, tid); + + DPRINTF(Fetch, "BranchPred: [tid:%i]: Instruction %#x predicted" + " target is %#x.\n", + tid, inst->readPC(), target); + + } else { + DPRINTF(Fetch, "BranchPred: [tid:%i]: BTB doesn't have a " + "valid entry.\n",tid); + pred_taken = false; + } + + } + } + + if (pred_taken) { + // Set the PC and the instruction's predicted target. + PC = target; + inst->setPredTarg(target); + } else { + PC = PC + sizeof(MachInst); + inst->setPredTarg(PC); + } + + predHist[tid].push_front(predict_record); + + DPRINTF(Fetch, "[tid:%i] predHist.size(): %i\n", tid, predHist[tid].size()); + + return pred_taken; +} + +template <class Impl> +void +BPredUnit<Impl>::update(const InstSeqNum &done_sn, unsigned tid) +{ + DPRINTF(Fetch, "BranchPred: [tid:%i]: Commiting branches until sequence" + "number %lli.\n", tid, done_sn); + + while (!predHist[tid].empty() && + predHist[tid].back().seqNum <= done_sn) { + // Update the branch predictor with the correct results. + BPUpdate(predHist[tid].back().PC, + predHist[tid].back().predTaken, + predHist[tid].back().bpHistory); + + predHist[tid].pop_back(); + } +} + +template <class Impl> +void +BPredUnit<Impl>::squash(const InstSeqNum &squashed_sn, unsigned tid) +{ + History &pred_hist = predHist[tid]; + + while (!pred_hist.empty() && + pred_hist.front().seqNum > squashed_sn) { + if (pred_hist.front().usedRAS) { + DPRINTF(Fetch, "BranchPred: [tid:%i]: Restoring top of RAS to: %i," + " target: %#x.\n", + tid, + pred_hist.front().RASIndex, + pred_hist.front().RASTarget); + + RAS[tid].restore(pred_hist.front().RASIndex, + pred_hist.front().RASTarget); + + } else if (pred_hist.front().wasCall) { + DPRINTF(Fetch, "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(); + } + +} + +template <class Impl> +void +BPredUnit<Impl>::squash(const InstSeqNum &squashed_sn, + const Addr &corr_target, + const bool actually_taken, + unsigned tid) +{ + // Now that we know that a branch was mispredicted, we need to undo + // all the branches that have been seen up until this branch and + // fix up everything. + + History &pred_hist = predHist[tid]; + + ++condIncorrect; + + DPRINTF(Fetch, "BranchPred: [tid:%i]: Squashing from sequence number %i, " + "setting target to %#x.\n", + tid, squashed_sn, corr_target); + + squash(squashed_sn, tid); + + // If there's a squash due to a syscall, there may not be an entry + // corresponding to the squash. In that case, don't bother trying to + // fix up the entry. + if (!pred_hist.empty()) { + assert(pred_hist.front().seqNum == squashed_sn); + if (pred_hist.front().usedRAS) { + ++RASIncorrect; + } + + BPUpdate(pred_hist.front().PC, actually_taken, + pred_hist.front().bpHistory); + + BTB.update(pred_hist.front().PC, corr_target, tid); + pred_hist.pop_front(); + } +} + +template <class Impl> +void +BPredUnit<Impl>::BPUncond(void * &bp_history) +{ + // Only the tournament predictor cares about unconditional branches. + if (predictor == Tournament) { + tournamentBP->uncondBr(bp_history); + } +} + +template <class Impl> +void +BPredUnit<Impl>::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!"); + } +} + +template <class Impl> +bool +BPredUnit<Impl>::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!"); + } +} + +template <class Impl> +void +BPredUnit<Impl>::BPUpdate(Addr &inst_PC, bool taken, void *bp_history) +{ + if (predictor == Local) { + localBP->update(inst_PC, taken, bp_history); + } else if (predictor == Tournament) { + tournamentBP->update(inst_PC, taken, bp_history); + } else { + panic("Predictor type is unexpected value!"); + } +} + +template <class Impl> +void +BPredUnit<Impl>::dump() +{ + typename History::iterator pred_hist_it; + + for (int i = 0; i < Impl::MaxThreads; ++i) { + if (!predHist[i].empty()) { + pred_hist_it = predHist[i].begin(); + + cprintf("predHist[%i].size(): %i\n", i, predHist[i].size()); + + while (pred_hist_it != predHist[i].end()) { + cprintf("[sn:%lli], PC:%#x, tid:%i, predTaken:%i, " + "bpHistory:%#x\n", + (*pred_hist_it).seqNum, (*pred_hist_it).PC, + (*pred_hist_it).tid, (*pred_hist_it).predTaken, + (*pred_hist_it).bpHistory); + pred_hist_it++; + } + + cprintf("\n"); + } + } +} diff --git a/src/cpu/o3/btb.cc b/src/cpu/o3/btb.cc new file mode 100644 index 000000000..01640f4d1 --- /dev/null +++ b/src/cpu/o3/btb.cc @@ -0,0 +1,136 @@ +/* + * 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 "base/intmath.hh" +#include "base/trace.hh" +#include "cpu/o3/btb.hh" + +using namespace TheISA; + +DefaultBTB::DefaultBTB(unsigned _numEntries, + unsigned _tagBits, + unsigned _instShiftAmt) + : numEntries(_numEntries), + tagBits(_tagBits), + instShiftAmt(_instShiftAmt) +{ + DPRINTF(Fetch, "BTB: Creating BTB object.\n"); + + if (!isPowerOf2(numEntries)) { + fatal("BTB entries is not a power of 2!"); + } + + btb.resize(numEntries); + + for (int i = 0; i < numEntries; ++i) { + btb[i].valid = false; + } + + idxMask = numEntries - 1; + + tagMask = (1 << tagBits) - 1; + + tagShiftAmt = instShiftAmt + floorLog2(numEntries); +} + +void +DefaultBTB::reset() +{ + for (int i = 0; i < numEntries; ++i) { + btb[i].valid = false; + } +} + +inline +unsigned +DefaultBTB::getIndex(const Addr &inst_PC) +{ + // Need to shift PC over by the word offset. + return (inst_PC >> instShiftAmt) & idxMask; +} + +inline +Addr +DefaultBTB::getTag(const Addr &inst_PC) +{ + return (inst_PC >> tagShiftAmt) & tagMask; +} + +bool +DefaultBTB::valid(const Addr &inst_PC, unsigned tid) +{ + unsigned btb_idx = getIndex(inst_PC); + + Addr inst_tag = getTag(inst_PC); + + assert(btb_idx < numEntries); + + if (btb[btb_idx].valid + && inst_tag == btb[btb_idx].tag + && btb[btb_idx].tid == tid) { + return true; + } else { + return false; + } +} + +// @todo Create some sort of return struct that has both whether or not the +// address is valid, and also the address. For now will just use addr = 0 to +// represent invalid entry. +Addr +DefaultBTB::lookup(const Addr &inst_PC, unsigned tid) +{ + unsigned btb_idx = getIndex(inst_PC); + + Addr inst_tag = getTag(inst_PC); + + assert(btb_idx < numEntries); + + if (btb[btb_idx].valid + && inst_tag == btb[btb_idx].tag + && btb[btb_idx].tid == tid) { + return btb[btb_idx].target; + } else { + return 0; + } +} + +void +DefaultBTB::update(const Addr &inst_PC, const Addr &target, unsigned tid) +{ + unsigned btb_idx = getIndex(inst_PC); + + assert(btb_idx < numEntries); + + btb[btb_idx].tid = tid; + btb[btb_idx].valid = true; + btb[btb_idx].target = target; + btb[btb_idx].tag = getTag(inst_PC); +} diff --git a/src/cpu/o3/btb.hh b/src/cpu/o3/btb.hh new file mode 100644 index 000000000..dfa3b7b06 --- /dev/null +++ b/src/cpu/o3/btb.hh @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#ifndef __CPU_O3_BTB_HH__ +#define __CPU_O3_BTB_HH__ + +// For Addr type. +#include "arch/isa_traits.hh" +#include "base/misc.hh" + +class DefaultBTB +{ + private: + struct BTBEntry + { + BTBEntry() + : tag(0), target(0), valid(false) + { + } + + /** The entry's tag. */ + Addr tag; + + /** The entry's target. */ + Addr target; + + /** The entry's thread id. */ + unsigned tid; + + /** Whether or not the entry is valid. */ + bool valid; + }; + + public: + /** Creates a BTB with the given number of entries, number of bits per + * tag, and instruction offset amount. + * @param numEntries Number of entries for the BTB. + * @param tagBits Number of bits for each tag in the BTB. + * @param instShiftAmt Offset amount for instructions to ignore alignment. + */ + DefaultBTB(unsigned numEntries, unsigned tagBits, + unsigned instShiftAmt); + + void reset(); + + /** Looks up an address in the BTB. Must call valid() first on the address. + * @param inst_PC The address of the branch to look up. + * @param tid The thread id. + * @return Returns the target of the branch. + */ + Addr lookup(const Addr &inst_PC, unsigned tid); + + /** Checks if a branch is in the BTB. + * @param inst_PC The address of the branch to look up. + * @param tid The thread id. + * @return Whether or not the branch exists in the BTB. + */ + bool valid(const Addr &inst_PC, unsigned tid); + + /** Updates the BTB with the target of a branch. + * @param inst_PC The address of the branch being updated. + * @param target_PC The target address of the branch. + * @param tid The thread id. + */ + void update(const Addr &inst_PC, const Addr &target_PC, + unsigned tid); + + private: + /** Returns the index into the BTB, based on the branch's PC. + * @param inst_PC The branch to look up. + * @return Returns the index into the BTB. + */ + inline unsigned getIndex(const Addr &inst_PC); + + /** Returns the tag bits of a given address. + * @param inst_PC The branch's address. + * @return Returns the tag bits. + */ + inline Addr getTag(const Addr &inst_PC); + + /** The actual BTB. */ + std::vector<BTBEntry> btb; + + /** The number of entries in the BTB. */ + unsigned numEntries; + + /** The index mask. */ + unsigned idxMask; + + /** The number of tag bits per entry. */ + unsigned tagBits; + + /** The tag mask. */ + unsigned tagMask; + + /** Number of bits to shift PC when calculating index. */ + unsigned instShiftAmt; + + /** Number of bits to shift PC when calculating tag. */ + unsigned tagShiftAmt; +}; + +#endif // __CPU_O3_BTB_HH__ diff --git a/src/cpu/o3/comm.hh b/src/cpu/o3/comm.hh new file mode 100644 index 000000000..bf1bd08e8 --- /dev/null +++ b/src/cpu/o3/comm.hh @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#ifndef __CPU_O3_COMM_HH__ +#define __CPU_O3_COMM_HH__ + +#include <vector> + +#include "arch/faults.hh" +#include "arch/isa_traits.hh" +#include "cpu/inst_seq.hh" +#include "sim/host.hh" + +// Typedef for physical register index type. Although the Impl would be the +// most likely location for this, there are a few classes that need this +// typedef yet are not templated on the Impl. For now it will be defined here. +typedef short int PhysRegIndex; + +/** Struct that defines the information passed from fetch to decode. */ +template<class Impl> +struct DefaultFetchDefaultDecode { + typedef typename Impl::DynInstPtr DynInstPtr; + + int size; + + DynInstPtr insts[Impl::MaxWidth]; + Fault fetchFault; + InstSeqNum fetchFaultSN; + bool clearFetchFault; +}; + +/** Struct that defines the information passed from decode to rename. */ +template<class Impl> +struct DefaultDecodeDefaultRename { + typedef typename Impl::DynInstPtr DynInstPtr; + + int size; + + DynInstPtr insts[Impl::MaxWidth]; +}; + +/** Struct that defines the information passed from rename to IEW. */ +template<class Impl> +struct DefaultRenameDefaultIEW { + typedef typename Impl::DynInstPtr DynInstPtr; + + int size; + + DynInstPtr insts[Impl::MaxWidth]; +}; + +/** Struct that defines the information passed from IEW to commit. */ +template<class Impl> +struct DefaultIEWDefaultCommit { + typedef typename Impl::DynInstPtr DynInstPtr; + + int size; + + DynInstPtr insts[Impl::MaxWidth]; + + bool squash[Impl::MaxThreads]; + bool branchMispredict[Impl::MaxThreads]; + bool branchTaken[Impl::MaxThreads]; + uint64_t mispredPC[Impl::MaxThreads]; + uint64_t nextPC[Impl::MaxThreads]; + InstSeqNum squashedSeqNum[Impl::MaxThreads]; + + bool includeSquashInst[Impl::MaxThreads]; +}; + +template<class Impl> +struct IssueStruct { + typedef typename Impl::DynInstPtr DynInstPtr; + + int size; + + DynInstPtr insts[Impl::MaxWidth]; +}; + +/** Struct that defines all backwards communication. */ +template<class Impl> +struct TimeBufStruct { + struct decodeComm { + bool squash; + bool predIncorrect; + uint64_t branchAddr; + + InstSeqNum doneSeqNum; + + // @todo: Might want to package this kind of branch stuff into a single + // struct as it is used pretty frequently. + bool branchMispredict; + bool branchTaken; + uint64_t mispredPC; + uint64_t nextPC; + + unsigned branchCount; + }; + + decodeComm decodeInfo[Impl::MaxThreads]; + + struct renameComm { + }; + + renameComm renameInfo[Impl::MaxThreads]; + + struct iewComm { + // Also eventually include skid buffer space. + bool usedIQ; + unsigned freeIQEntries; + bool usedLSQ; + unsigned freeLSQEntries; + + unsigned iqCount; + unsigned ldstqCount; + + unsigned dispatched; + unsigned dispatchedToLSQ; + }; + + iewComm iewInfo[Impl::MaxThreads]; + + struct commitComm { + bool usedROB; + unsigned freeROBEntries; + bool emptyROB; + + bool squash; + bool robSquashing; + + bool branchMispredict; + bool branchTaken; + uint64_t mispredPC; + uint64_t nextPC; + + // Represents the instruction that has either been retired or + // squashed. Similar to having a single bus that broadcasts the + // retired or squashed sequence number. + InstSeqNum doneSeqNum; + + //Just in case we want to do a commit/squash on a cycle + //(necessary for multiple ROBs?) + bool commitInsts; + InstSeqNum squashSeqNum; + + // Communication specifically to the IQ to tell the IQ that it can + // schedule a non-speculative instruction. + InstSeqNum nonSpecSeqNum; + + // Hack for now to send back an uncached access to the IEW stage. + typedef typename Impl::DynInstPtr DynInstPtr; + bool uncached; + DynInstPtr uncachedLoad; + + bool interruptPending; + bool clearInterrupt; + }; + + commitComm commitInfo[Impl::MaxThreads]; + + bool decodeBlock[Impl::MaxThreads]; + bool decodeUnblock[Impl::MaxThreads]; + bool renameBlock[Impl::MaxThreads]; + bool renameUnblock[Impl::MaxThreads]; + bool iewBlock[Impl::MaxThreads]; + bool iewUnblock[Impl::MaxThreads]; + bool commitBlock[Impl::MaxThreads]; + bool commitUnblock[Impl::MaxThreads]; +}; + +#endif //__CPU_O3_COMM_HH__ diff --git a/src/cpu/o3/commit.cc b/src/cpu/o3/commit.cc new file mode 100644 index 000000000..770008a33 --- /dev/null +++ b/src/cpu/o3/commit.cc @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#include "cpu/o3/alpha_dyn_inst.hh" +#include "cpu/o3/alpha_impl.hh" +#include "cpu/o3/commit_impl.hh" + +template class DefaultCommit<AlphaSimpleImpl>; diff --git a/src/cpu/o3/commit.hh b/src/cpu/o3/commit.hh new file mode 100644 index 000000000..b7404c488 --- /dev/null +++ b/src/cpu/o3/commit.hh @@ -0,0 +1,454 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#ifndef __CPU_O3_COMMIT_HH__ +#define __CPU_O3_COMMIT_HH__ + +#include "arch/faults.hh" +#include "base/statistics.hh" +#include "base/timebuf.hh" +#include "cpu/exetrace.hh" +#include "cpu/inst_seq.hh" + +template <class> +class O3ThreadState; + +/** + * DefaultCommit handles single threaded and SMT commit. Its width is + * specified by the parameters; each cycle it tries to commit that + * many instructions. The SMT policy decides which thread it tries to + * commit instructions from. Non- speculative instructions must reach + * the head of the ROB before they are ready to execute; once they + * reach the head, commit will broadcast the instruction's sequence + * number to the previous stages so that they can issue/ execute the + * instruction. Only one non-speculative instruction is handled per + * cycle. Commit is responsible for handling all back-end initiated + * redirects. It receives the redirect, and then broadcasts it to all + * stages, indicating the sequence number they should squash until, + * and any necessary branch misprediction information as well. It + * priortizes redirects by instruction's age, only broadcasting a + * redirect if it corresponds to an instruction that should currently + * be in the ROB. This is done by tracking the sequence number of the + * youngest instruction in the ROB, which gets updated to any + * squashing instruction's sequence number, and only broadcasting a + * redirect if it corresponds to an older instruction. Commit also + * supports multiple cycle squashing, to model a ROB that can only + * remove a certain number of instructions per cycle. + */ +template<class Impl> +class DefaultCommit +{ + public: + // Typedefs from the Impl. + typedef typename Impl::FullCPU FullCPU; + typedef typename Impl::DynInstPtr DynInstPtr; + typedef typename Impl::Params Params; + typedef typename Impl::CPUPol CPUPol; + + typedef typename CPUPol::RenameMap RenameMap; + typedef typename CPUPol::ROB ROB; + + typedef typename CPUPol::TimeStruct TimeStruct; + typedef typename CPUPol::FetchStruct FetchStruct; + typedef typename CPUPol::IEWStruct IEWStruct; + typedef typename CPUPol::RenameStruct RenameStruct; + + typedef typename CPUPol::Fetch Fetch; + typedef typename CPUPol::IEW IEW; + + typedef O3ThreadState<Impl> Thread; + + /** Event class used to schedule a squash due to a trap (fault or + * interrupt) to happen on a specific cycle. + */ + class TrapEvent : public Event { + private: + DefaultCommit<Impl> *commit; + unsigned tid; + + public: + TrapEvent(DefaultCommit<Impl> *_commit, unsigned _tid); + + void process(); + const char *description(); + }; + + /** Overall commit status. Used to determine if the CPU can deschedule + * itself due to a lack of activity. + */ + enum CommitStatus{ + Active, + Inactive + }; + + /** Individual thread status. */ + enum ThreadStatus { + Running, + Idle, + ROBSquashing, + TrapPending, + FetchTrapPending + }; + + /** Commit policy for SMT mode. */ + enum CommitPolicy { + Aggressive, + RoundRobin, + OldestReady + }; + + private: + /** Overall commit status. */ + CommitStatus _status; + /** Next commit status, to be set at the end of the cycle. */ + CommitStatus _nextStatus; + /** Per-thread status. */ + ThreadStatus commitStatus[Impl::MaxThreads]; + /** Commit policy used in SMT mode. */ + CommitPolicy commitPolicy; + + public: + /** Construct a DefaultCommit with the given parameters. */ + DefaultCommit(Params *params); + + /** Returns the name of the DefaultCommit. */ + std::string name() const; + + /** Registers statistics. */ + void regStats(); + + /** Sets the CPU pointer. */ + void setCPU(FullCPU *cpu_ptr); + + /** Sets the list of threads. */ + void setThreads(std::vector<Thread *> &threads); + + /** Sets the main time buffer pointer, used for backwards communication. */ + void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr); + + void setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr); + + /** Sets the pointer to the queue coming from rename. */ + void setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr); + + /** Sets the pointer to the queue coming from IEW. */ + void setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr); + + void setFetchStage(Fetch *fetch_stage); + + Fetch *fetchStage; + + /** Sets the pointer to the IEW stage. */ + void setIEWStage(IEW *iew_stage); + + /** The pointer to the IEW stage. Used solely to ensure that + * various events (traps, interrupts, syscalls) do not occur until + * all stores have written back. + */ + IEW *iewStage; + + /** Sets pointer to list of active threads. */ + void setActiveThreads(std::list<unsigned> *at_ptr); + + /** Sets pointer to the commited state rename map. */ + void setRenameMap(RenameMap rm_ptr[Impl::MaxThreads]); + + /** Sets pointer to the ROB. */ + void setROB(ROB *rob_ptr); + + /** Initializes stage by sending back the number of free entries. */ + void initStage(); + + /** Initializes the switching out of commit. */ + void switchOut(); + + /** Completes the switch out of commit. */ + void doSwitchOut(); + + /** Takes over from another CPU's thread. */ + void takeOverFrom(); + + /** Ticks the commit stage, which tries to commit instructions. */ + void tick(); + + /** Handles any squashes that are sent from IEW, and adds instructions + * to the ROB and tries to commit instructions. + */ + void commit(); + + /** Returns the number of free ROB entries for a specific thread. */ + unsigned numROBFreeEntries(unsigned tid); + + /** Generates an event to schedule a squash due to a trap. */ + void generateTrapEvent(unsigned tid); + + /** Records that commit needs to initiate a squash due to an + * external state update through the TC. + */ + void generateTCEvent(unsigned tid); + + private: + /** Updates the overall status of commit with the nextStatus, and + * tell the CPU if commit is active/inactive. + */ + void updateStatus(); + + /** Sets the next status based on threads' statuses, which becomes the + * current status at the end of the cycle. + */ + void setNextStatus(); + + /** Checks if the ROB is completed with squashing. This is for the case + * where the ROB can take multiple cycles to complete squashing. + */ + bool robDoneSquashing(); + + /** Returns if any of the threads have the number of ROB entries changed + * on this cycle. Used to determine if the number of free ROB entries needs + * to be sent back to previous stages. + */ + bool changedROBEntries(); + + /** Squashes all in flight instructions. */ + void squashAll(unsigned tid); + + /** Handles squashing due to a trap. */ + void squashFromTrap(unsigned tid); + + /** Handles squashing due to an TC write. */ + void squashFromTC(unsigned tid); + + /** Commits as many instructions as possible. */ + void commitInsts(); + + /** Tries to commit the head ROB instruction passed in. + * @param head_inst The instruction to be committed. + */ + bool commitHead(DynInstPtr &head_inst, unsigned inst_num); + + /** Gets instructions from rename and inserts them into the ROB. */ + void getInsts(); + + /** Marks completed instructions using information sent from IEW. */ + void markCompletedInsts(); + + /** Gets the thread to commit, based on the SMT policy. */ + int getCommittingThread(); + + /** Returns the thread ID to use based on a round robin policy. */ + int roundRobin(); + + /** Returns the thread ID to use based on an oldest instruction policy. */ + int oldestReady(); + + public: + /** Returns the PC of the head instruction of the ROB. + * @todo: Probably remove this function as it returns only thread 0. + */ + uint64_t readPC() { return PC[0]; } + + /** Returns the PC of a specific thread. */ + uint64_t readPC(unsigned tid) { return PC[tid]; } + + /** Sets the PC of a specific thread. */ + void setPC(uint64_t val, unsigned tid) { PC[tid] = val; } + + /** Reads the PC of a specific thread. */ + uint64_t readNextPC(unsigned tid) { return nextPC[tid]; } + + /** Sets the next PC of a specific thread. */ + void setNextPC(uint64_t val, unsigned tid) { nextPC[tid] = val; } + + private: + /** Time buffer interface. */ + TimeBuffer<TimeStruct> *timeBuffer; + + /** Wire to write information heading to previous stages. */ + typename TimeBuffer<TimeStruct>::wire toIEW; + + /** Wire to read information from IEW (for ROB). */ + typename TimeBuffer<TimeStruct>::wire robInfoFromIEW; + + TimeBuffer<FetchStruct> *fetchQueue; + + typename TimeBuffer<FetchStruct>::wire fromFetch; + + /** IEW instruction queue interface. */ + TimeBuffer<IEWStruct> *iewQueue; + + /** Wire to read information from IEW queue. */ + typename TimeBuffer<IEWStruct>::wire fromIEW; + + /** Rename instruction queue interface, for ROB. */ + TimeBuffer<RenameStruct> *renameQueue; + + /** Wire to read information from rename queue. */ + typename TimeBuffer<RenameStruct>::wire fromRename; + + public: + /** ROB interface. */ + ROB *rob; + + private: + /** Pointer to FullCPU. */ + FullCPU *cpu; + + /** Vector of all of the threads. */ + std::vector<Thread *> thread; + + Fault fetchFault; + + int fetchTrapWait; + + /** Records that commit has written to the time buffer this cycle. Used for + * the CPU to determine if it can deschedule itself if there is no activity. + */ + bool wroteToTimeBuffer; + + /** Records if the number of ROB entries has changed this cycle. If it has, + * then the number of free entries must be re-broadcast. + */ + bool changedROBNumEntries[Impl::MaxThreads]; + + /** A counter of how many threads are currently squashing. */ + int squashCounter; + + /** Records if a thread has to squash this cycle due to a trap. */ + bool trapSquash[Impl::MaxThreads]; + + /** Records if a thread has to squash this cycle due to an XC write. */ + bool tcSquash[Impl::MaxThreads]; + + /** Priority List used for Commit Policy */ + std::list<unsigned> priority_list; + + /** IEW to Commit delay, in ticks. */ + unsigned iewToCommitDelay; + + /** Commit to IEW delay, in ticks. */ + unsigned commitToIEWDelay; + + /** Rename to ROB delay, in ticks. */ + unsigned renameToROBDelay; + + unsigned fetchToCommitDelay; + + /** Rename width, in instructions. Used so ROB knows how many + * instructions to get from the rename instruction queue. + */ + unsigned renameWidth; + + /** IEW width, in instructions. Used so ROB knows how many + * instructions to get from the IEW instruction queue. + */ + unsigned iewWidth; + + /** Commit width, in instructions. */ + unsigned commitWidth; + + /** Number of Reorder Buffers */ + unsigned numRobs; + + /** Number of Active Threads */ + unsigned numThreads; + + /** Is a switch out pending. */ + bool switchPending; + + /** Is commit switched out. */ + bool switchedOut; + + /** The latency to handle a trap. Used when scheduling trap + * squash event. + */ + Tick trapLatency; + + Tick fetchTrapLatency; + + Tick fetchFaultTick; + + /** The commit PC of each thread. Refers to the instruction that + * is currently being processed/committed. + */ + Addr PC[Impl::MaxThreads]; + + /** The next PC of each thread. */ + Addr nextPC[Impl::MaxThreads]; + + /** The sequence number of the youngest valid instruction in the ROB. */ + InstSeqNum youngestSeqNum[Impl::MaxThreads]; + + /** Pointer to the list of active threads. */ + std::list<unsigned> *activeThreads; + + /** Rename map interface. */ + RenameMap *renameMap[Impl::MaxThreads]; + + /** Updates commit stats based on this instruction. */ + void updateComInstStats(DynInstPtr &inst); + + /** Stat for the total number of committed instructions. */ + Stats::Scalar<> commitCommittedInsts; + /** Stat for the total number of squashed instructions discarded by commit. + */ + Stats::Scalar<> commitSquashedInsts; + /** Stat for the total number of times commit is told to squash. + * @todo: Actually increment this stat. + */ + Stats::Scalar<> commitSquashEvents; + /** Stat for the total number of times commit has had to stall due to a non- + * speculative instruction reaching the head of the ROB. + */ + Stats::Scalar<> commitNonSpecStalls; + /** Stat for the total number of branch mispredicts that caused a squash. */ + Stats::Scalar<> branchMispredicts; + /** Distribution of the number of committed instructions each cycle. */ + Stats::Distribution<> numCommittedDist; + + /** Total number of instructions committed. */ + Stats::Vector<> statComInst; + /** Total number of software prefetches committed. */ + Stats::Vector<> statComSwp; + /** Stat for the total number of committed memory references. */ + Stats::Vector<> statComRefs; + /** Stat for the total number of committed loads. */ + Stats::Vector<> statComLoads; + /** Total number of committed memory barriers. */ + Stats::Vector<> statComMembars; + /** Total number of committed branches. */ + Stats::Vector<> statComBranches; + + /** Number of cycles where the commit bandwidth limit is reached. */ + Stats::Scalar<> commitEligibleSamples; + /** Number of instructions not committed due to bandwidth limits. */ + Stats::Vector<> commitEligible; +}; + +#endif // __CPU_O3_COMMIT_HH__ diff --git a/src/cpu/o3/commit_impl.hh b/src/cpu/o3/commit_impl.hh new file mode 100644 index 000000000..ceb2918e0 --- /dev/null +++ b/src/cpu/o3/commit_impl.hh @@ -0,0 +1,1311 @@ +/* + * 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 <algorithm> +#include <string> + +#include "base/loader/symtab.hh" +#include "base/timebuf.hh" +#include "cpu/checker/cpu.hh" +#include "cpu/exetrace.hh" +#include "cpu/o3/commit.hh" +#include "cpu/o3/thread_state.hh" + +using namespace std; + +template <class Impl> +DefaultCommit<Impl>::TrapEvent::TrapEvent(DefaultCommit<Impl> *_commit, + unsigned _tid) + : Event(&mainEventQueue, CPU_Tick_Pri), commit(_commit), tid(_tid) +{ + this->setFlags(Event::AutoDelete); +} + +template <class Impl> +void +DefaultCommit<Impl>::TrapEvent::process() +{ + // This will get reset by commit if it was switched out at the + // time of this event processing. + commit->trapSquash[tid] = true; +} + +template <class Impl> +const char * +DefaultCommit<Impl>::TrapEvent::description() +{ + return "Trap event"; +} + +template <class Impl> +DefaultCommit<Impl>::DefaultCommit(Params *params) + : squashCounter(0), + iewToCommitDelay(params->iewToCommitDelay), + commitToIEWDelay(params->commitToIEWDelay), + renameToROBDelay(params->renameToROBDelay), + fetchToCommitDelay(params->commitToFetchDelay), + renameWidth(params->renameWidth), + iewWidth(params->executeWidth), + commitWidth(params->commitWidth), + numThreads(params->numberOfThreads), + switchPending(false), + switchedOut(false), + trapLatency(params->trapLatency), + fetchTrapLatency(params->fetchTrapLatency) +{ + _status = Active; + _nextStatus = Inactive; + string policy = params->smtCommitPolicy; + + //Convert string to lowercase + std::transform(policy.begin(), policy.end(), policy.begin(), + (int(*)(int)) tolower); + + //Assign commit policy + if (policy == "aggressive"){ + commitPolicy = Aggressive; + + DPRINTF(Commit,"Commit Policy set to Aggressive."); + } else if (policy == "roundrobin"){ + commitPolicy = RoundRobin; + + //Set-Up Priority List + for (int tid=0; tid < numThreads; tid++) { + priority_list.push_back(tid); + } + + DPRINTF(Commit,"Commit Policy set to Round Robin."); + } else if (policy == "oldestready"){ + commitPolicy = OldestReady; + + DPRINTF(Commit,"Commit Policy set to Oldest Ready."); + } else { + assert(0 && "Invalid SMT Commit Policy. Options Are: {Aggressive," + "RoundRobin,OldestReady}"); + } + + for (int i=0; i < numThreads; i++) { + commitStatus[i] = Idle; + changedROBNumEntries[i] = false; + trapSquash[i] = false; + tcSquash[i] = false; + PC[i] = nextPC[i] = 0; + } + + fetchFaultTick = 0; + fetchTrapWait = 0; +} + +template <class Impl> +std::string +DefaultCommit<Impl>::name() const +{ + return cpu->name() + ".commit"; +} + +template <class Impl> +void +DefaultCommit<Impl>::regStats() +{ + using namespace Stats; + commitCommittedInsts + .name(name() + ".commitCommittedInsts") + .desc("The number of committed instructions") + .prereq(commitCommittedInsts); + commitSquashedInsts + .name(name() + ".commitSquashedInsts") + .desc("The number of squashed insts skipped by commit") + .prereq(commitSquashedInsts); + commitSquashEvents + .name(name() + ".commitSquashEvents") + .desc("The number of times commit is told to squash") + .prereq(commitSquashEvents); + commitNonSpecStalls + .name(name() + ".commitNonSpecStalls") + .desc("The number of times commit has been forced to stall to " + "communicate backwards") + .prereq(commitNonSpecStalls); + branchMispredicts + .name(name() + ".branchMispredicts") + .desc("The number of times a branch was mispredicted") + .prereq(branchMispredicts); + numCommittedDist + .init(0,commitWidth,1) + .name(name() + ".COM:committed_per_cycle") + .desc("Number of insts commited each cycle") + .flags(Stats::pdf) + ; + + statComInst + .init(cpu->number_of_threads) + .name(name() + ".COM:count") + .desc("Number of instructions committed") + .flags(total) + ; + + statComSwp + .init(cpu->number_of_threads) + .name(name() + ".COM:swp_count") + .desc("Number of s/w prefetches committed") + .flags(total) + ; + + statComRefs + .init(cpu->number_of_threads) + .name(name() + ".COM:refs") + .desc("Number of memory references committed") + .flags(total) + ; + + statComLoads + .init(cpu->number_of_threads) + .name(name() + ".COM:loads") + .desc("Number of loads committed") + .flags(total) + ; + + statComMembars + .init(cpu->number_of_threads) + .name(name() + ".COM:membars") + .desc("Number of memory barriers committed") + .flags(total) + ; + + statComBranches + .init(cpu->number_of_threads) + .name(name() + ".COM:branches") + .desc("Number of branches committed") + .flags(total) + ; + + // + // Commit-Eligible instructions... + // + // -> The number of instructions eligible to commit in those + // cycles where we reached our commit BW limit (less the number + // actually committed) + // + // -> The average value is computed over ALL CYCLES... not just + // the BW limited cycles + // + // -> The standard deviation is computed only over cycles where + // we reached the BW limit + // + commitEligible + .init(cpu->number_of_threads) + .name(name() + ".COM:bw_limited") + .desc("number of insts not committed due to BW limits") + .flags(total) + ; + + commitEligibleSamples + .name(name() + ".COM:bw_lim_events") + .desc("number cycles where commit BW limit reached") + ; +} + +template <class Impl> +void +DefaultCommit<Impl>::setCPU(FullCPU *cpu_ptr) +{ + DPRINTF(Commit, "Commit: Setting CPU pointer.\n"); + cpu = cpu_ptr; + + // Commit must broadcast the number of free entries it has at the start of + // the simulation, so it starts as active. + cpu->activateStage(FullCPU::CommitIdx); + + trapLatency = cpu->cycles(trapLatency); + fetchTrapLatency = cpu->cycles(fetchTrapLatency); +} + +template <class Impl> +void +DefaultCommit<Impl>::setThreads(vector<Thread *> &threads) +{ + thread = threads; +} + +template <class Impl> +void +DefaultCommit<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) +{ + DPRINTF(Commit, "Commit: Setting time buffer pointer.\n"); + timeBuffer = tb_ptr; + + // Setup wire to send information back to IEW. + toIEW = timeBuffer->getWire(0); + + // Setup wire to read data from IEW (for the ROB). + robInfoFromIEW = timeBuffer->getWire(-iewToCommitDelay); +} + +template <class Impl> +void +DefaultCommit<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr) +{ + DPRINTF(Commit, "Commit: Setting fetch queue pointer.\n"); + fetchQueue = fq_ptr; + + // Setup wire to get instructions from rename (for the ROB). + fromFetch = fetchQueue->getWire(-fetchToCommitDelay); +} + +template <class Impl> +void +DefaultCommit<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr) +{ + DPRINTF(Commit, "Commit: Setting rename queue pointer.\n"); + renameQueue = rq_ptr; + + // Setup wire to get instructions from rename (for the ROB). + fromRename = renameQueue->getWire(-renameToROBDelay); +} + +template <class Impl> +void +DefaultCommit<Impl>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr) +{ + DPRINTF(Commit, "Commit: Setting IEW queue pointer.\n"); + iewQueue = iq_ptr; + + // Setup wire to get instructions from IEW. + fromIEW = iewQueue->getWire(-iewToCommitDelay); +} + +template <class Impl> +void +DefaultCommit<Impl>::setFetchStage(Fetch *fetch_stage) +{ + fetchStage = fetch_stage; +} + +template <class Impl> +void +DefaultCommit<Impl>::setIEWStage(IEW *iew_stage) +{ + iewStage = iew_stage; +} + +template<class Impl> +void +DefaultCommit<Impl>::setActiveThreads(list<unsigned> *at_ptr) +{ + DPRINTF(Commit, "Commit: Setting active threads list pointer.\n"); + activeThreads = at_ptr; +} + +template <class Impl> +void +DefaultCommit<Impl>::setRenameMap(RenameMap rm_ptr[]) +{ + DPRINTF(Commit, "Setting rename map pointers.\n"); + + for (int i=0; i < numThreads; i++) { + renameMap[i] = &rm_ptr[i]; + } +} + +template <class Impl> +void +DefaultCommit<Impl>::setROB(ROB *rob_ptr) +{ + DPRINTF(Commit, "Commit: Setting ROB pointer.\n"); + rob = rob_ptr; +} + +template <class Impl> +void +DefaultCommit<Impl>::initStage() +{ + rob->setActiveThreads(activeThreads); + rob->resetEntries(); + + // Broadcast the number of free entries. + for (int i=0; i < numThreads; i++) { + toIEW->commitInfo[i].usedROB = true; + toIEW->commitInfo[i].freeROBEntries = rob->numFreeEntries(i); + } + + cpu->activityThisCycle(); +} + +template <class Impl> +void +DefaultCommit<Impl>::switchOut() +{ + switchPending = true; +} + +template <class Impl> +void +DefaultCommit<Impl>::doSwitchOut() +{ + switchedOut = true; + switchPending = false; + rob->switchOut(); +} + +template <class Impl> +void +DefaultCommit<Impl>::takeOverFrom() +{ + switchedOut = false; + _status = Active; + _nextStatus = Inactive; + for (int i=0; i < numThreads; i++) { + commitStatus[i] = Idle; + changedROBNumEntries[i] = false; + trapSquash[i] = false; + tcSquash[i] = false; + } + squashCounter = 0; + rob->takeOverFrom(); +} + +template <class Impl> +void +DefaultCommit<Impl>::updateStatus() +{ + // reset ROB changed variable + list<unsigned>::iterator threads = (*activeThreads).begin(); + while (threads != (*activeThreads).end()) { + unsigned tid = *threads++; + changedROBNumEntries[tid] = false; + + // Also check if any of the threads has a trap pending + if (commitStatus[tid] == TrapPending || + commitStatus[tid] == FetchTrapPending) { + _nextStatus = Active; + } + } + + if (_nextStatus == Inactive && _status == Active) { + DPRINTF(Activity, "Deactivating stage.\n"); + cpu->deactivateStage(FullCPU::CommitIdx); + } else if (_nextStatus == Active && _status == Inactive) { + DPRINTF(Activity, "Activating stage.\n"); + cpu->activateStage(FullCPU::CommitIdx); + } + + _status = _nextStatus; +} + +template <class Impl> +void +DefaultCommit<Impl>::setNextStatus() +{ + int squashes = 0; + + list<unsigned>::iterator threads = (*activeThreads).begin(); + + while (threads != (*activeThreads).end()) { + unsigned tid = *threads++; + + if (commitStatus[tid] == ROBSquashing) { + squashes++; + } + } + + assert(squashes == squashCounter); + + // If commit is currently squashing, then it will have activity for the + // next cycle. Set its next status as active. + if (squashCounter) { + _nextStatus = Active; + } +} + +template <class Impl> +bool +DefaultCommit<Impl>::changedROBEntries() +{ + list<unsigned>::iterator threads = (*activeThreads).begin(); + + while (threads != (*activeThreads).end()) { + unsigned tid = *threads++; + + if (changedROBNumEntries[tid]) { + return true; + } + } + + return false; +} + +template <class Impl> +unsigned +DefaultCommit<Impl>::numROBFreeEntries(unsigned tid) +{ + return rob->numFreeEntries(tid); +} + +template <class Impl> +void +DefaultCommit<Impl>::generateTrapEvent(unsigned tid) +{ + DPRINTF(Commit, "Generating trap event for [tid:%i]\n", tid); + + TrapEvent *trap = new TrapEvent(this, tid); + + trap->schedule(curTick + trapLatency); + + thread[tid]->trapPending = true; +} + +template <class Impl> +void +DefaultCommit<Impl>::generateTCEvent(unsigned tid) +{ + DPRINTF(Commit, "Generating TC squash event for [tid:%i]\n", tid); + + tcSquash[tid] = true; +} + +template <class Impl> +void +DefaultCommit<Impl>::squashAll(unsigned tid) +{ + // If we want to include the squashing instruction in the squash, + // then use one older sequence number. + // Hopefully this doesn't mess things up. Basically I want to squash + // all instructions of this thread. + InstSeqNum squashed_inst = rob->isEmpty() ? + 0 : rob->readHeadInst(tid)->seqNum - 1;; + + // All younger instructions will be squashed. Set the sequence + // number as the youngest instruction in the ROB (0 in this case. + // Hopefully nothing breaks.) + youngestSeqNum[tid] = 0; + + rob->squash(squashed_inst, tid); + changedROBNumEntries[tid] = true; + + // Send back the sequence number of the squashed instruction. + toIEW->commitInfo[tid].doneSeqNum = squashed_inst; + + // Send back the squash signal to tell stages that they should + // squash. + toIEW->commitInfo[tid].squash = true; + + // Send back the rob squashing signal so other stages know that + // the ROB is in the process of squashing. + toIEW->commitInfo[tid].robSquashing = true; + + toIEW->commitInfo[tid].branchMispredict = false; + + toIEW->commitInfo[tid].nextPC = PC[tid]; +} + +template <class Impl> +void +DefaultCommit<Impl>::squashFromTrap(unsigned tid) +{ + squashAll(tid); + + DPRINTF(Commit, "Squashing from trap, restarting at PC %#x\n", PC[tid]); + + thread[tid]->trapPending = false; + thread[tid]->inSyscall = false; + + trapSquash[tid] = false; + + commitStatus[tid] = ROBSquashing; + cpu->activityThisCycle(); + + ++squashCounter; +} + +template <class Impl> +void +DefaultCommit<Impl>::squashFromTC(unsigned tid) +{ + squashAll(tid); + + DPRINTF(Commit, "Squashing from TC, restarting at PC %#x\n", PC[tid]); + + thread[tid]->inSyscall = false; + assert(!thread[tid]->trapPending); + + commitStatus[tid] = ROBSquashing; + cpu->activityThisCycle(); + + tcSquash[tid] = false; + + ++squashCounter; +} + +template <class Impl> +void +DefaultCommit<Impl>::tick() +{ + wroteToTimeBuffer = false; + _nextStatus = Inactive; + + if (switchPending && rob->isEmpty() && !iewStage->hasStoresToWB()) { + cpu->signalSwitched(); + return; + } + + list<unsigned>::iterator threads = (*activeThreads).begin(); + + // Check if any of the threads are done squashing. Change the + // status if they are done. + while (threads != (*activeThreads).end()) { + unsigned tid = *threads++; + + if (commitStatus[tid] == ROBSquashing) { + + if (rob->isDoneSquashing(tid)) { + commitStatus[tid] = Running; + --squashCounter; + } else { + DPRINTF(Commit,"[tid:%u]: Still Squashing, cannot commit any" + "insts this cycle.\n", tid); + } + } + } + + commit(); + + markCompletedInsts(); + + threads = (*activeThreads).begin(); + + while (threads != (*activeThreads).end()) { + unsigned tid = *threads++; + + if (!rob->isEmpty(tid) && rob->readHeadInst(tid)->readyToCommit()) { + // The ROB has more instructions it can commit. Its next status + // will be active. + _nextStatus = Active; + + DynInstPtr inst = rob->readHeadInst(tid); + + DPRINTF(Commit,"[tid:%i]: Instruction [sn:%lli] PC %#x is head of" + " ROB and ready to commit\n", + tid, inst->seqNum, inst->readPC()); + + } else if (!rob->isEmpty(tid)) { + DynInstPtr inst = rob->readHeadInst(tid); + + DPRINTF(Commit,"[tid:%i]: Can't commit, Instruction [sn:%lli] PC " + "%#x is head of ROB and not ready\n", + tid, inst->seqNum, inst->readPC()); + } + + DPRINTF(Commit, "[tid:%i]: ROB has %d insts & %d free entries.\n", + tid, rob->countInsts(tid), rob->numFreeEntries(tid)); + } + + + if (wroteToTimeBuffer) { + DPRINTF(Activity, "Activity This Cycle.\n"); + cpu->activityThisCycle(); + } + + updateStatus(); +} + +template <class Impl> +void +DefaultCommit<Impl>::commit() +{ + + ////////////////////////////////////// + // Check for interrupts + ////////////////////////////////////// + +#if FULL_SYSTEM + // Process interrupts if interrupts are enabled, not in PAL mode, + // and no other traps or external squashes are currently pending. + // @todo: Allow other threads to handle interrupts. + if (cpu->checkInterrupts && + cpu->check_interrupts() && + !cpu->inPalMode(readPC()) && + !trapSquash[0] && + !tcSquash[0]) { + // Tell fetch that there is an interrupt pending. This will + // make fetch wait until it sees a non PAL-mode PC, at which + // point it stops fetching instructions. + toIEW->commitInfo[0].interruptPending = true; + + // Wait until the ROB is empty and all stores have drained in + // order to enter the interrupt. + if (rob->isEmpty() && !iewStage->hasStoresToWB()) { + // Not sure which thread should be the one to interrupt. For now + // always do thread 0. + assert(!thread[0]->inSyscall); + thread[0]->inSyscall = true; + + // CPU will handle implementation of the interrupt. + cpu->processInterrupts(); + + // Now squash or record that I need to squash this cycle. + commitStatus[0] = TrapPending; + + // Exit state update mode to avoid accidental updating. + thread[0]->inSyscall = false; + + // Generate trap squash event. + generateTrapEvent(0); + + toIEW->commitInfo[0].clearInterrupt = true; + + DPRINTF(Commit, "Interrupt detected.\n"); + } else { + DPRINTF(Commit, "Interrupt pending, waiting for ROB to empty.\n"); + } + } +#endif // FULL_SYSTEM + + //////////////////////////////////// + // Check for any possible squashes, handle them first + //////////////////////////////////// + + list<unsigned>::iterator threads = (*activeThreads).begin(); + + while (threads != (*activeThreads).end()) { + unsigned tid = *threads++; +/* + if (fromFetch->fetchFault && commitStatus[0] != TrapPending) { + // Record the fault. Wait until it's empty in the ROB. + // Then handle the trap. Ignore it if there's already a + // trap pending as fetch will be redirected. + fetchFault = fromFetch->fetchFault; + fetchFaultTick = curTick + fetchTrapLatency; + commitStatus[0] = FetchTrapPending; + DPRINTF(Commit, "Fault from fetch recorded. Will trap if the " + "ROB empties without squashing the fault.\n"); + fetchTrapWait = 0; + } + + // Fetch may tell commit to clear the trap if it's been squashed. + if (fromFetch->clearFetchFault) { + DPRINTF(Commit, "Received clear fetch fault signal\n"); + fetchTrapWait = 0; + if (commitStatus[0] == FetchTrapPending) { + DPRINTF(Commit, "Clearing fault from fetch\n"); + commitStatus[0] = Running; + } + } +*/ + // Not sure which one takes priority. I think if we have + // both, that's a bad sign. + if (trapSquash[tid] == true) { + assert(!tcSquash[tid]); + squashFromTrap(tid); + } else if (tcSquash[tid] == true) { + squashFromTC(tid); + } + + // Squashed sequence number must be older than youngest valid + // instruction in the ROB. This prevents squashes from younger + // instructions overriding squashes from older instructions. + if (fromIEW->squash[tid] && + commitStatus[tid] != TrapPending && + fromIEW->squashedSeqNum[tid] <= youngestSeqNum[tid]) { + + DPRINTF(Commit, "[tid:%i]: Squashing due to PC %#x [sn:%i]\n", + tid, + fromIEW->mispredPC[tid], + fromIEW->squashedSeqNum[tid]); + + DPRINTF(Commit, "[tid:%i]: Redirecting to PC %#x\n", + tid, + fromIEW->nextPC[tid]); + + commitStatus[tid] = ROBSquashing; + + ++squashCounter; + + // If we want to include the squashing instruction in the squash, + // then use one older sequence number. + InstSeqNum squashed_inst = fromIEW->squashedSeqNum[tid]; + + if (fromIEW->includeSquashInst[tid] == true) + squashed_inst--; + + // All younger instructions will be squashed. Set the sequence + // number as the youngest instruction in the ROB. + youngestSeqNum[tid] = squashed_inst; + + rob->squash(squashed_inst, tid); + changedROBNumEntries[tid] = true; + + toIEW->commitInfo[tid].doneSeqNum = squashed_inst; + + toIEW->commitInfo[tid].squash = true; + + // Send back the rob squashing signal so other stages know that + // the ROB is in the process of squashing. + toIEW->commitInfo[tid].robSquashing = true; + + toIEW->commitInfo[tid].branchMispredict = + fromIEW->branchMispredict[tid]; + + toIEW->commitInfo[tid].branchTaken = + fromIEW->branchTaken[tid]; + + toIEW->commitInfo[tid].nextPC = fromIEW->nextPC[tid]; + + toIEW->commitInfo[tid].mispredPC = fromIEW->mispredPC[tid]; + + if (toIEW->commitInfo[tid].branchMispredict) { + ++branchMispredicts; + } + } + + } + + setNextStatus(); + + if (squashCounter != numThreads) { + // If we're not currently squashing, then get instructions. + getInsts(); + + // Try to commit any instructions. + commitInsts(); + } + + //Check for any activity + threads = (*activeThreads).begin(); + + while (threads != (*activeThreads).end()) { + unsigned tid = *threads++; + + if (changedROBNumEntries[tid]) { + toIEW->commitInfo[tid].usedROB = true; + toIEW->commitInfo[tid].freeROBEntries = rob->numFreeEntries(tid); + + if (rob->isEmpty(tid)) { + toIEW->commitInfo[tid].emptyROB = true; + } + + wroteToTimeBuffer = true; + changedROBNumEntries[tid] = false; + } + } +} + +template <class Impl> +void +DefaultCommit<Impl>::commitInsts() +{ + //////////////////////////////////// + // Handle commit + // Note that commit will be handled prior to putting new + // instructions in the ROB so that the ROB only tries to commit + // instructions it has in this current cycle, and not instructions + // it is writing in during this cycle. Can't commit and squash + // things at the same time... + //////////////////////////////////// + + DPRINTF(Commit, "Trying to commit instructions in the ROB.\n"); + + unsigned num_committed = 0; + + DynInstPtr head_inst; + + // Commit as many instructions as possible until the commit bandwidth + // limit is reached, or it becomes impossible to commit any more. + while (num_committed < commitWidth) { + int commit_thread = getCommittingThread(); + + if (commit_thread == -1 || !rob->isHeadReady(commit_thread)) + break; + + head_inst = rob->readHeadInst(commit_thread); + + int tid = head_inst->threadNumber; + + assert(tid == commit_thread); + + DPRINTF(Commit, "Trying to commit head instruction, [sn:%i] [tid:%i]\n", + head_inst->seqNum, tid); + + // If the head instruction is squashed, it is ready to retire + // (be removed from the ROB) at any time. + if (head_inst->isSquashed()) { + + DPRINTF(Commit, "Retiring squashed instruction from " + "ROB.\n"); + + rob->retireHead(commit_thread); + + ++commitSquashedInsts; + + // Record that the number of ROB entries has changed. + changedROBNumEntries[tid] = true; + } else { + PC[tid] = head_inst->readPC(); + nextPC[tid] = head_inst->readNextPC(); + + // Increment the total number of non-speculative instructions + // executed. + // Hack for now: it really shouldn't happen until after the + // commit is deemed to be successful, but this count is needed + // for syscalls. + thread[tid]->funcExeInst++; + + // Try to commit the head instruction. + bool commit_success = commitHead(head_inst, num_committed); + + if (commit_success) { + ++num_committed; + + changedROBNumEntries[tid] = true; + + // Set the doneSeqNum to the youngest committed instruction. + toIEW->commitInfo[tid].doneSeqNum = head_inst->seqNum; + + ++commitCommittedInsts; + + // To match the old model, don't count nops and instruction + // prefetches towards the total commit count. + if (!head_inst->isNop() && !head_inst->isInstPrefetch()) { + cpu->instDone(tid); + } + + PC[tid] = nextPC[tid]; + nextPC[tid] = nextPC[tid] + sizeof(TheISA::MachInst); +#if FULL_SYSTEM + int count = 0; + Addr oldpc; + do { + // Debug statement. Checks to make sure we're not + // currently updating state while handling PC events. + if (count == 0) + assert(!thread[tid]->inSyscall && + !thread[tid]->trapPending); + oldpc = PC[tid]; + cpu->system->pcEventQueue.service( + thread[tid]->getTC()); + count++; + } while (oldpc != PC[tid]); + if (count > 1) { + DPRINTF(Commit, "PC skip function event, stopping commit\n"); + break; + } +#endif + } else { + DPRINTF(Commit, "Unable to commit head instruction PC:%#x " + "[tid:%i] [sn:%i].\n", + head_inst->readPC(), tid ,head_inst->seqNum); + break; + } + } + } + + DPRINTF(CommitRate, "%i\n", num_committed); + numCommittedDist.sample(num_committed); + + if (num_committed == commitWidth) { + commitEligibleSamples++; + } +} + +template <class Impl> +bool +DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num) +{ + assert(head_inst); + + int tid = head_inst->threadNumber; + + // If the instruction is not executed yet, then it will need extra + // handling. Signal backwards that it should be executed. + if (!head_inst->isExecuted()) { + // Keep this number correct. We have not yet actually executed + // and committed this instruction. + thread[tid]->funcExeInst--; + + head_inst->reachedCommit = true; + + if (head_inst->isNonSpeculative() || + head_inst->isStoreConditional() || + head_inst->isMemBarrier() || + head_inst->isWriteBarrier()) { + + DPRINTF(Commit, "Encountered a barrier or non-speculative " + "instruction [sn:%lli] at the head of the ROB, PC %#x.\n", + head_inst->seqNum, head_inst->readPC()); + +#if !FULL_SYSTEM + // Hack to make sure syscalls/memory barriers/quiesces + // aren't executed until all stores write back their data. + // This direct communication shouldn't be used for + // anything other than this. + if (inst_num > 0 || iewStage->hasStoresToWB()) +#else + if ((head_inst->isMemBarrier() || head_inst->isWriteBarrier() || + head_inst->isQuiesce()) && + iewStage->hasStoresToWB()) +#endif + { + DPRINTF(Commit, "Waiting for all stores to writeback.\n"); + return false; + } + + toIEW->commitInfo[tid].nonSpecSeqNum = head_inst->seqNum; + + // Change the instruction so it won't try to commit again until + // it is executed. + head_inst->clearCanCommit(); + + ++commitNonSpecStalls; + + return false; + } else if (head_inst->isLoad()) { + DPRINTF(Commit, "[sn:%lli]: Uncached load, PC %#x.\n", + head_inst->seqNum, head_inst->readPC()); + + // Send back the non-speculative instruction's sequence + // number. Tell the lsq to re-execute the load. + toIEW->commitInfo[tid].nonSpecSeqNum = head_inst->seqNum; + toIEW->commitInfo[tid].uncached = true; + toIEW->commitInfo[tid].uncachedLoad = head_inst; + + head_inst->clearCanCommit(); + + return false; + } else { + panic("Trying to commit un-executed instruction " + "of unknown type!\n"); + } + } + + if (head_inst->isThreadSync()) { + // Not handled for now. + panic("Thread sync instructions are not handled yet.\n"); + } + + // Stores mark themselves as completed. + if (!head_inst->isStore()) { + head_inst->setCompleted(); + } + + // Use checker prior to updating anything due to traps or PC + // based events. + if (cpu->checker) { + cpu->checker->tick(head_inst); + } + + // Check if the instruction caused a fault. If so, trap. + Fault inst_fault = head_inst->getFault(); + + if (inst_fault != NoFault) { + head_inst->setCompleted(); +#if FULL_SYSTEM + DPRINTF(Commit, "Inst [sn:%lli] PC %#x has a fault\n", + head_inst->seqNum, head_inst->readPC()); + + if (iewStage->hasStoresToWB() || inst_num > 0) { + DPRINTF(Commit, "Stores outstanding, fault must wait.\n"); + return false; + } + + if (cpu->checker && head_inst->isStore()) { + cpu->checker->tick(head_inst); + } + + assert(!thread[tid]->inSyscall); + + // Mark that we're in state update mode so that the trap's + // execution doesn't generate extra squashes. + thread[tid]->inSyscall = true; + + // DTB will sometimes need the machine instruction for when + // faults happen. So we will set it here, prior to the DTB + // possibly needing it for its fault. + thread[tid]->setInst( + static_cast<TheISA::MachInst>(head_inst->staticInst->machInst)); + + // Execute the trap. Although it's slightly unrealistic in + // terms of timing (as it doesn't wait for the full timing of + // the trap event to complete before updating state), it's + // needed to update the state as soon as possible. This + // prevents external agents from changing any specific state + // that the trap need. + cpu->trap(inst_fault, tid); + + // Exit state update mode to avoid accidental updating. + thread[tid]->inSyscall = false; + + commitStatus[tid] = TrapPending; + + // Generate trap squash event. + generateTrapEvent(tid); + + return false; +#else // !FULL_SYSTEM + panic("fault (%d) detected @ PC %08p", inst_fault, + head_inst->PC); +#endif // FULL_SYSTEM + } + + updateComInstStats(head_inst); + + if (head_inst->traceData) { + head_inst->traceData->setFetchSeq(head_inst->seqNum); + head_inst->traceData->setCPSeq(thread[tid]->numInst); + head_inst->traceData->finalize(); + head_inst->traceData = NULL; + } + + // Update the commit rename map + for (int i = 0; i < head_inst->numDestRegs(); i++) { + renameMap[tid]->setEntry(head_inst->destRegIdx(i), + head_inst->renamedDestRegIdx(i)); + } + + // Finally clear the head ROB entry. + rob->retireHead(tid); + + // Return true to indicate that we have committed an instruction. + return true; +} + +template <class Impl> +void +DefaultCommit<Impl>::getInsts() +{ + // Read any renamed instructions and place them into the ROB. + int insts_to_process = min((int)renameWidth, fromRename->size); + + for (int inst_num = 0; inst_num < insts_to_process; ++inst_num) + { + DynInstPtr inst = fromRename->insts[inst_num]; + int tid = inst->threadNumber; + + if (!inst->isSquashed() && + commitStatus[tid] != ROBSquashing) { + changedROBNumEntries[tid] = true; + + DPRINTF(Commit, "Inserting PC %#x [sn:%i] [tid:%i] into ROB.\n", + inst->readPC(), inst->seqNum, tid); + + rob->insertInst(inst); + + assert(rob->getThreadEntries(tid) <= rob->getMaxEntries(tid)); + + youngestSeqNum[tid] = inst->seqNum; + } else { + DPRINTF(Commit, "Instruction PC %#x [sn:%i] [tid:%i] was " + "squashed, skipping.\n", + inst->readPC(), inst->seqNum, tid); + } + } +} + +template <class Impl> +void +DefaultCommit<Impl>::markCompletedInsts() +{ + // Grab completed insts out of the IEW instruction queue, and mark + // instructions completed within the ROB. + for (int inst_num = 0; + inst_num < fromIEW->size && fromIEW->insts[inst_num]; + ++inst_num) + { + if (!fromIEW->insts[inst_num]->isSquashed()) { + DPRINTF(Commit, "[tid:%i]: Marking PC %#x, [sn:%lli] ready " + "within ROB.\n", + fromIEW->insts[inst_num]->threadNumber, + fromIEW->insts[inst_num]->readPC(), + fromIEW->insts[inst_num]->seqNum); + + // Mark the instruction as ready to commit. + fromIEW->insts[inst_num]->setCanCommit(); + } + } +} + +template <class Impl> +bool +DefaultCommit<Impl>::robDoneSquashing() +{ + list<unsigned>::iterator threads = (*activeThreads).begin(); + + while (threads != (*activeThreads).end()) { + unsigned tid = *threads++; + + if (!rob->isDoneSquashing(tid)) + return false; + } + + return true; +} + +template <class Impl> +void +DefaultCommit<Impl>::updateComInstStats(DynInstPtr &inst) +{ + unsigned thread = inst->threadNumber; + + // + // Pick off the software prefetches + // +#ifdef TARGET_ALPHA + if (inst->isDataPrefetch()) { + statComSwp[thread]++; + } else { + statComInst[thread]++; + } +#else + statComInst[thread]++; +#endif + + // + // Control Instructions + // + if (inst->isControl()) + statComBranches[thread]++; + + // + // Memory references + // + if (inst->isMemRef()) { + statComRefs[thread]++; + + if (inst->isLoad()) { + statComLoads[thread]++; + } + } + + if (inst->isMemBarrier()) { + statComMembars[thread]++; + } +} + +//////////////////////////////////////// +// // +// SMT COMMIT POLICY MAINTAINED HERE // +// // +//////////////////////////////////////// +template <class Impl> +int +DefaultCommit<Impl>::getCommittingThread() +{ + if (numThreads > 1) { + switch (commitPolicy) { + + case Aggressive: + //If Policy is Aggressive, commit will call + //this function multiple times per + //cycle + return oldestReady(); + + case RoundRobin: + return roundRobin(); + + case OldestReady: + return oldestReady(); + + default: + return -1; + } + } else { + int tid = (*activeThreads).front(); + + if (commitStatus[tid] == Running || + commitStatus[tid] == Idle || + commitStatus[tid] == FetchTrapPending) { + return tid; + } else { + return -1; + } + } +} + +template<class Impl> +int +DefaultCommit<Impl>::roundRobin() +{ + list<unsigned>::iterator pri_iter = priority_list.begin(); + list<unsigned>::iterator end = priority_list.end(); + + while (pri_iter != end) { + unsigned tid = *pri_iter; + + if (commitStatus[tid] == Running || + commitStatus[tid] == Idle) { + + if (rob->isHeadReady(tid)) { + priority_list.erase(pri_iter); + priority_list.push_back(tid); + + return tid; + } + } + + pri_iter++; + } + + return -1; +} + +template<class Impl> +int +DefaultCommit<Impl>::oldestReady() +{ + unsigned oldest = 0; + bool first = true; + + list<unsigned>::iterator threads = (*activeThreads).begin(); + + while (threads != (*activeThreads).end()) { + unsigned tid = *threads++; + + if (!rob->isEmpty(tid) && + (commitStatus[tid] == Running || + commitStatus[tid] == Idle || + commitStatus[tid] == FetchTrapPending)) { + + if (rob->isHeadReady(tid)) { + + DynInstPtr head_inst = rob->readHeadInst(tid); + + if (first) { + oldest = tid; + first = false; + } else if (head_inst->seqNum < oldest) { + oldest = tid; + } + } + } + } + + if (!first) { + return oldest; + } else { + return -1; + } +} diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc new file mode 100644 index 000000000..788c6b164 --- /dev/null +++ b/src/cpu/o3/cpu.cc @@ -0,0 +1,1188 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#include "config/full_system.hh" + +#if FULL_SYSTEM +#include "sim/system.hh" +#else +#include "sim/process.hh" +#endif + +#include "cpu/activity.hh" +#include "cpu/checker/cpu.hh" +#include "cpu/simple_thread.hh" +#include "cpu/thread_context.hh" +#include "cpu/o3/alpha_dyn_inst.hh" +#include "cpu/o3/alpha_impl.hh" +#include "cpu/o3/cpu.hh" + +#include "sim/root.hh" +#include "sim/stat_control.hh" + +using namespace std; +using namespace TheISA; + +BaseFullCPU::BaseFullCPU(Params *params) + : BaseCPU(params), cpu_id(0) +{ +} + +void +BaseFullCPU::regStats() +{ + BaseCPU::regStats(); +} + +template <class Impl> +FullO3CPU<Impl>::TickEvent::TickEvent(FullO3CPU<Impl> *c) + : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) +{ +} + +template <class Impl> +void +FullO3CPU<Impl>::TickEvent::process() +{ + cpu->tick(); +} + +template <class Impl> +const char * +FullO3CPU<Impl>::TickEvent::description() +{ + return "FullO3CPU tick event"; +} + +template <class Impl> +FullO3CPU<Impl>::FullO3CPU(Params *params) + : BaseFullCPU(params), + tickEvent(this), + removeInstsThisCycle(false), + fetch(params), + decode(params), + rename(params), + iew(params), + commit(params), + + regFile(params->numPhysIntRegs, params->numPhysFloatRegs), + + freeList(params->numberOfThreads,//number of activeThreads + TheISA::NumIntRegs, params->numPhysIntRegs, + TheISA::NumFloatRegs, params->numPhysFloatRegs), + + rob(params->numROBEntries, params->squashWidth, + params->smtROBPolicy, params->smtROBThreshold, + params->numberOfThreads), + + scoreboard(params->numberOfThreads,//number of activeThreads + TheISA::NumIntRegs, params->numPhysIntRegs, + TheISA::NumFloatRegs, params->numPhysFloatRegs, + TheISA::NumMiscRegs * number_of_threads, + TheISA::ZeroReg), + + // For now just have these time buffers be pretty big. + // @todo: Make these time buffer sizes parameters or derived + // from latencies + timeBuffer(5, 5), + fetchQueue(5, 5), + decodeQueue(5, 5), + renameQueue(5, 5), + iewQueue(5, 5), + activityRec(NumStages, 10, params->activity), + + globalSeqNum(1), + +#if FULL_SYSTEM + system(params->system), + physmem(system->physmem), +#endif // FULL_SYSTEM + mem(params->mem), + switchCount(0), + deferRegistration(params->deferRegistration), + numThreads(number_of_threads) +{ + _status = Idle; + + if (params->checker) { + BaseCPU *temp_checker = params->checker; + checker = dynamic_cast<Checker<DynInstPtr> *>(temp_checker); + checker->setMemory(mem); +#if FULL_SYSTEM + checker->setSystem(params->system); +#endif + } else { + checker = NULL; + } + +#if !FULL_SYSTEM + thread.resize(number_of_threads); + tids.resize(number_of_threads); +#endif + + // The stages also need their CPU pointer setup. However this + // must be done at the upper level CPU because they have pointers + // to the upper level CPU, and not this FullO3CPU. + + // Set up Pointers to the activeThreads list for each stage + fetch.setActiveThreads(&activeThreads); + decode.setActiveThreads(&activeThreads); + rename.setActiveThreads(&activeThreads); + iew.setActiveThreads(&activeThreads); + commit.setActiveThreads(&activeThreads); + + // Give each of the stages the time buffer they will use. + fetch.setTimeBuffer(&timeBuffer); + decode.setTimeBuffer(&timeBuffer); + rename.setTimeBuffer(&timeBuffer); + iew.setTimeBuffer(&timeBuffer); + commit.setTimeBuffer(&timeBuffer); + + // Also setup each of the stages' queues. + fetch.setFetchQueue(&fetchQueue); + decode.setFetchQueue(&fetchQueue); + commit.setFetchQueue(&fetchQueue); + decode.setDecodeQueue(&decodeQueue); + rename.setDecodeQueue(&decodeQueue); + rename.setRenameQueue(&renameQueue); + iew.setRenameQueue(&renameQueue); + iew.setIEWQueue(&iewQueue); + commit.setIEWQueue(&iewQueue); + commit.setRenameQueue(&renameQueue); + + commit.setFetchStage(&fetch); + commit.setIEWStage(&iew); + rename.setIEWStage(&iew); + rename.setCommitStage(&commit); + +#if !FULL_SYSTEM + int active_threads = params->workload.size(); +#else + int active_threads = 1; +#endif + + //Make Sure That this a Valid Architeture + assert(params->numPhysIntRegs >= numThreads * TheISA::NumIntRegs); + assert(params->numPhysFloatRegs >= numThreads * TheISA::NumFloatRegs); + + rename.setScoreboard(&scoreboard); + iew.setScoreboard(&scoreboard); + + // Setup the rename map for whichever stages need it. + PhysRegIndex lreg_idx = 0; + PhysRegIndex freg_idx = params->numPhysIntRegs; //Index to 1 after int regs + + for (int tid=0; tid < numThreads; tid++) { + bool bindRegs = (tid <= active_threads - 1); + + commitRenameMap[tid].init(TheISA::NumIntRegs, + params->numPhysIntRegs, + lreg_idx, //Index for Logical. Regs + + TheISA::NumFloatRegs, + params->numPhysFloatRegs, + freg_idx, //Index for Float Regs + + TheISA::NumMiscRegs, + + TheISA::ZeroReg, + TheISA::ZeroReg, + + tid, + false); + + renameMap[tid].init(TheISA::NumIntRegs, + params->numPhysIntRegs, + lreg_idx, //Index for Logical. Regs + + TheISA::NumFloatRegs, + params->numPhysFloatRegs, + freg_idx, //Index for Float Regs + + TheISA::NumMiscRegs, + + TheISA::ZeroReg, + TheISA::ZeroReg, + + tid, + bindRegs); + } + + rename.setRenameMap(renameMap); + commit.setRenameMap(commitRenameMap); + + // Give renameMap & rename stage access to the freeList; + for (int i=0; i < numThreads; i++) { + renameMap[i].setFreeList(&freeList); + } + rename.setFreeList(&freeList); + + // Setup the ROB for whichever stages need it. + commit.setROB(&rob); + + lastRunningCycle = curTick; + + contextSwitch = false; +} + +template <class Impl> +FullO3CPU<Impl>::~FullO3CPU() +{ +} + +template <class Impl> +void +FullO3CPU<Impl>::fullCPURegStats() +{ + BaseFullCPU::regStats(); + + // Register any of the FullCPU's stats here. + timesIdled + .name(name() + ".timesIdled") + .desc("Number of times that the entire CPU went into an idle state and" + " unscheduled itself") + .prereq(timesIdled); + + idleCycles + .name(name() + ".idleCycles") + .desc("Total number of cycles that the CPU has spent unscheduled due " + "to idling") + .prereq(idleCycles); + + // Number of Instructions simulated + // -------------------------------- + // Should probably be in Base CPU but need templated + // MaxThreads so put in here instead + committedInsts + .init(numThreads) + .name(name() + ".committedInsts") + .desc("Number of Instructions Simulated"); + + totalCommittedInsts + .name(name() + ".committedInsts_total") + .desc("Number of Instructions Simulated"); + + cpi + .name(name() + ".cpi") + .desc("CPI: Cycles Per Instruction") + .precision(6); + cpi = simTicks / committedInsts; + + totalCpi + .name(name() + ".cpi_total") + .desc("CPI: Total CPI of All Threads") + .precision(6); + totalCpi = simTicks / totalCommittedInsts; + + ipc + .name(name() + ".ipc") + .desc("IPC: Instructions Per Cycle") + .precision(6); + ipc = committedInsts / simTicks; + + totalIpc + .name(name() + ".ipc_total") + .desc("IPC: Total IPC of All Threads") + .precision(6); + totalIpc = totalCommittedInsts / simTicks; + +} + +template <class Impl> +void +FullO3CPU<Impl>::tick() +{ + DPRINTF(FullCPU, "\n\nFullCPU: Ticking main, FullO3CPU.\n"); + + ++numCycles; + +// activity = false; + + //Tick each of the stages + fetch.tick(); + + decode.tick(); + + rename.tick(); + + iew.tick(); + + commit.tick(); + +#if !FULL_SYSTEM + doContextSwitch(); +#endif + + // Now advance the time buffers + timeBuffer.advance(); + + fetchQueue.advance(); + decodeQueue.advance(); + renameQueue.advance(); + iewQueue.advance(); + + activityRec.advance(); + + if (removeInstsThisCycle) { + cleanUpRemovedInsts(); + } + + if (!tickEvent.scheduled()) { + if (_status == SwitchedOut) { + // increment stat + lastRunningCycle = curTick; + } else if (!activityRec.active()) { + lastRunningCycle = curTick; + timesIdled++; + } else { + tickEvent.schedule(curTick + cycles(1)); + } + } + +#if !FULL_SYSTEM + updateThreadPriority(); +#endif + +} + +template <class Impl> +void +FullO3CPU<Impl>::init() +{ + if (!deferRegistration) { + registerThreadContexts(); + } + + // Set inSyscall so that the CPU doesn't squash when initially + // setting up registers. + for (int i = 0; i < number_of_threads; ++i) + thread[i]->inSyscall = true; + + for (int tid=0; tid < number_of_threads; tid++) { +#if FULL_SYSTEM + ThreadContext *src_tc = threadContexts[tid]; +#else + ThreadContext *src_tc = thread[tid]->getTC(); +#endif + // Threads start in the Suspended State + if (src_tc->status() != ThreadContext::Suspended) { + continue; + } + +#if FULL_SYSTEM + TheISA::initCPU(src_tc, src_tc->readCpuId()); +#endif + } + + // Clear inSyscall. + for (int i = 0; i < number_of_threads; ++i) + thread[i]->inSyscall = false; + + // Initialize stages. + fetch.initStage(); + iew.initStage(); + rename.initStage(); + commit.initStage(); + + commit.setThreads(thread); +} + +template <class Impl> +void +FullO3CPU<Impl>::insertThread(unsigned tid) +{ + DPRINTF(FullCPU,"[tid:%i] Initializing thread data"); + // Will change now that the PC and thread state is internal to the CPU + // and not in the ThreadContext. +#if 0 +#if FULL_SYSTEM + ThreadContext *src_tc = system->threadContexts[tid]; +#else + ThreadContext *src_tc = thread[tid]; +#endif + + //Bind Int Regs to Rename Map + for (int ireg = 0; ireg < TheISA::NumIntRegs; ireg++) { + PhysRegIndex phys_reg = freeList.getIntReg(); + + renameMap[tid].setEntry(ireg,phys_reg); + scoreboard.setReg(phys_reg); + } + + //Bind Float Regs to Rename Map + for (int freg = 0; freg < TheISA::NumFloatRegs; freg++) { + PhysRegIndex phys_reg = freeList.getFloatReg(); + + renameMap[tid].setEntry(freg,phys_reg); + scoreboard.setReg(phys_reg); + } + + //Copy Thread Data Into RegFile + this->copyFromTC(tid); + + //Set PC/NPC + regFile.pc[tid] = src_tc->readPC(); + regFile.npc[tid] = src_tc->readNextPC(); + + src_tc->setStatus(ThreadContext::Active); + + activateContext(tid,1); + + //Reset ROB/IQ/LSQ Entries + commit.rob->resetEntries(); + iew.resetEntries(); +#endif +} + +template <class Impl> +void +FullO3CPU<Impl>::removeThread(unsigned tid) +{ + DPRINTF(FullCPU,"[tid:%i] Removing thread data"); +#if 0 + //Unbind Int Regs from Rename Map + for (int ireg = 0; ireg < TheISA::NumIntRegs; ireg++) { + PhysRegIndex phys_reg = renameMap[tid].lookup(ireg); + + scoreboard.unsetReg(phys_reg); + freeList.addReg(phys_reg); + } + + //Unbind Float Regs from Rename Map + for (int freg = 0; freg < TheISA::NumFloatRegs; freg++) { + PhysRegIndex phys_reg = renameMap[tid].lookup(freg); + + scoreboard.unsetReg(phys_reg); + freeList.addReg(phys_reg); + } + + //Copy Thread Data From RegFile + /* Fix Me: + * Do we really need to do this if we are removing a thread + * in the sense that it's finished (exiting)? If the thread is just + * being suspended we might... + */ +// this->copyToTC(tid); + + //Squash Throughout Pipeline + fetch.squash(0,tid); + decode.squash(tid); + rename.squash(tid); + + assert(iew.ldstQueue.getCount(tid) == 0); + + //Reset ROB/IQ/LSQ Entries + if (activeThreads.size() >= 1) { + commit.rob->resetEntries(); + iew.resetEntries(); + } +#endif +} + + +template <class Impl> +void +FullO3CPU<Impl>::activateWhenReady(int tid) +{ + DPRINTF(FullCPU,"[tid:%i]: Checking if resources are available for incoming" + "(e.g. PhysRegs/ROB/IQ/LSQ) \n", + tid); + + bool ready = true; + + if (freeList.numFreeIntRegs() >= TheISA::NumIntRegs) { + DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " + "Phys. Int. Regs.\n", + tid); + ready = false; + } else if (freeList.numFreeFloatRegs() >= TheISA::NumFloatRegs) { + DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " + "Phys. Float. Regs.\n", + tid); + ready = false; + } else if (commit.rob->numFreeEntries() >= + commit.rob->entryAmount(activeThreads.size() + 1)) { + DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " + "ROB entries.\n", + tid); + ready = false; + } else if (iew.instQueue.numFreeEntries() >= + iew.instQueue.entryAmount(activeThreads.size() + 1)) { + DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " + "IQ entries.\n", + tid); + ready = false; + } else if (iew.ldstQueue.numFreeEntries() >= + iew.ldstQueue.entryAmount(activeThreads.size() + 1)) { + DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough " + "LSQ entries.\n", + tid); + ready = false; + } + + if (ready) { + insertThread(tid); + + contextSwitch = false; + + cpuWaitList.remove(tid); + } else { + suspendContext(tid); + + //blocks fetch + contextSwitch = true; + + //do waitlist + cpuWaitList.push_back(tid); + } +} + +template <class Impl> +void +FullO3CPU<Impl>::activateContext(int tid, int delay) +{ + // Needs to set each stage to running as well. + list<unsigned>::iterator isActive = find( + activeThreads.begin(), activeThreads.end(), tid); + + if (isActive == activeThreads.end()) { + //May Need to Re-code this if the delay variable is the + //delay needed for thread to activate + DPRINTF(FullCPU, "Adding Thread %i to active threads list\n", + tid); + + activeThreads.push_back(tid); + } + + assert(_status == Idle || _status == SwitchedOut); + + scheduleTickEvent(delay); + + // Be sure to signal that there's some activity so the CPU doesn't + // deschedule itself. + activityRec.activity(); + fetch.wakeFromQuiesce(); + + _status = Running; +} + +template <class Impl> +void +FullO3CPU<Impl>::suspendContext(int tid) +{ + DPRINTF(FullCPU,"[tid: %i]: Suspended ...\n", tid); + unscheduleTickEvent(); + _status = Idle; +/* + //Remove From Active List, if Active + list<unsigned>::iterator isActive = find( + activeThreads.begin(), activeThreads.end(), tid); + + if (isActive != activeThreads.end()) { + DPRINTF(FullCPU,"[tid:%i]: Removing from active threads list\n", + tid); + activeThreads.erase(isActive); + } +*/ +} + +template <class Impl> +void +FullO3CPU<Impl>::deallocateContext(int tid) +{ + DPRINTF(FullCPU,"[tid:%i]: Deallocating ...", tid); +/* + //Remove From Active List, if Active + list<unsigned>::iterator isActive = find( + activeThreads.begin(), activeThreads.end(), tid); + + if (isActive != activeThreads.end()) { + DPRINTF(FullCPU,"[tid:%i]: Removing from active threads list\n", + tid); + activeThreads.erase(isActive); + + removeThread(tid); + } +*/ +} + +template <class Impl> +void +FullO3CPU<Impl>::haltContext(int tid) +{ + DPRINTF(FullCPU,"[tid:%i]: Halted ...", tid); +/* + //Remove From Active List, if Active + list<unsigned>::iterator isActive = find( + activeThreads.begin(), activeThreads.end(), tid); + + if (isActive != activeThreads.end()) { + DPRINTF(FullCPU,"[tid:%i]: Removing from active threads list\n", + tid); + activeThreads.erase(isActive); + + removeThread(tid); + } +*/ +} + +template <class Impl> +void +FullO3CPU<Impl>::switchOut(Sampler *_sampler) +{ + sampler = _sampler; + switchCount = 0; + fetch.switchOut(); + decode.switchOut(); + rename.switchOut(); + iew.switchOut(); + commit.switchOut(); + + // Wake the CPU and record activity so everything can drain out if + // the CPU is currently idle. + wakeCPU(); + activityRec.activity(); +} + +template <class Impl> +void +FullO3CPU<Impl>::signalSwitched() +{ + if (++switchCount == NumStages) { + fetch.doSwitchOut(); + rename.doSwitchOut(); + commit.doSwitchOut(); + instList.clear(); + while (!removeList.empty()) { + removeList.pop(); + } + + if (checker) + checker->switchOut(sampler); + + if (tickEvent.scheduled()) + tickEvent.squash(); + sampler->signalSwitched(); + _status = SwitchedOut; + } + assert(switchCount <= 5); +} + +template <class Impl> +void +FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU) +{ + // Flush out any old data from the time buffers. + for (int i = 0; i < 10; ++i) { + timeBuffer.advance(); + fetchQueue.advance(); + decodeQueue.advance(); + renameQueue.advance(); + iewQueue.advance(); + } + + activityRec.reset(); + + BaseCPU::takeOverFrom(oldCPU); + + fetch.takeOverFrom(); + decode.takeOverFrom(); + rename.takeOverFrom(); + iew.takeOverFrom(); + commit.takeOverFrom(); + + assert(!tickEvent.scheduled()); + + // @todo: Figure out how to properly select the tid to put onto + // the active threads list. + int tid = 0; + + list<unsigned>::iterator isActive = find( + activeThreads.begin(), activeThreads.end(), tid); + + if (isActive == activeThreads.end()) { + //May Need to Re-code this if the delay variable is the delay + //needed for thread to activate + DPRINTF(FullCPU, "Adding Thread %i to active threads list\n", + tid); + + activeThreads.push_back(tid); + } + + // Set all statuses to active, schedule the CPU's tick event. + // @todo: Fix up statuses so this is handled properly + for (int i = 0; i < threadContexts.size(); ++i) { + ThreadContext *tc = threadContexts[i]; + if (tc->status() == ThreadContext::Active && _status != Running) { + _status = Running; + tickEvent.schedule(curTick); + } + } + if (!tickEvent.scheduled()) + tickEvent.schedule(curTick); +} + +template <class Impl> +uint64_t +FullO3CPU<Impl>::readIntReg(int reg_idx) +{ + return regFile.readIntReg(reg_idx); +} + +template <class Impl> +FloatReg +FullO3CPU<Impl>::readFloatReg(int reg_idx, int width) +{ + return regFile.readFloatReg(reg_idx, width); +} + +template <class Impl> +FloatReg +FullO3CPU<Impl>::readFloatReg(int reg_idx) +{ + return regFile.readFloatReg(reg_idx); +} + +template <class Impl> +FloatRegBits +FullO3CPU<Impl>::readFloatRegBits(int reg_idx, int width) +{ + return regFile.readFloatRegBits(reg_idx, width); +} + +template <class Impl> +FloatRegBits +FullO3CPU<Impl>::readFloatRegBits(int reg_idx) +{ + return regFile.readFloatRegBits(reg_idx); +} + +template <class Impl> +void +FullO3CPU<Impl>::setIntReg(int reg_idx, uint64_t val) +{ + regFile.setIntReg(reg_idx, val); +} + +template <class Impl> +void +FullO3CPU<Impl>::setFloatReg(int reg_idx, FloatReg val, int width) +{ + regFile.setFloatReg(reg_idx, val, width); +} + +template <class Impl> +void +FullO3CPU<Impl>::setFloatReg(int reg_idx, FloatReg val) +{ + regFile.setFloatReg(reg_idx, val); +} + +template <class Impl> +void +FullO3CPU<Impl>::setFloatRegBits(int reg_idx, FloatRegBits val, int width) +{ + regFile.setFloatRegBits(reg_idx, val, width); +} + +template <class Impl> +void +FullO3CPU<Impl>::setFloatRegBits(int reg_idx, FloatRegBits val) +{ + regFile.setFloatRegBits(reg_idx, val); +} + +template <class Impl> +uint64_t +FullO3CPU<Impl>::readArchIntReg(int reg_idx, unsigned tid) +{ + PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); + + return regFile.readIntReg(phys_reg); +} + +template <class Impl> +float +FullO3CPU<Impl>::readArchFloatRegSingle(int reg_idx, unsigned tid) +{ + int idx = reg_idx + TheISA::FP_Base_DepTag; + PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx); + + return regFile.readFloatReg(phys_reg); +} + +template <class Impl> +double +FullO3CPU<Impl>::readArchFloatRegDouble(int reg_idx, unsigned tid) +{ + int idx = reg_idx + TheISA::FP_Base_DepTag; + PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx); + + return regFile.readFloatReg(phys_reg, 64); +} + +template <class Impl> +uint64_t +FullO3CPU<Impl>::readArchFloatRegInt(int reg_idx, unsigned tid) +{ + int idx = reg_idx + TheISA::FP_Base_DepTag; + PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx); + + return regFile.readFloatRegBits(phys_reg); +} + +template <class Impl> +void +FullO3CPU<Impl>::setArchIntReg(int reg_idx, uint64_t val, unsigned tid) +{ + PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); + + regFile.setIntReg(phys_reg, val); +} + +template <class Impl> +void +FullO3CPU<Impl>::setArchFloatRegSingle(int reg_idx, float val, unsigned tid) +{ + PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); + + regFile.setFloatReg(phys_reg, val); +} + +template <class Impl> +void +FullO3CPU<Impl>::setArchFloatRegDouble(int reg_idx, double val, unsigned tid) +{ + PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); + + regFile.setFloatReg(phys_reg, val, 64); +} + +template <class Impl> +void +FullO3CPU<Impl>::setArchFloatRegInt(int reg_idx, uint64_t val, unsigned tid) +{ + PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx); + + regFile.setFloatRegBits(phys_reg, val); +} + +template <class Impl> +uint64_t +FullO3CPU<Impl>::readPC(unsigned tid) +{ + return commit.readPC(tid); +} + +template <class Impl> +void +FullO3CPU<Impl>::setPC(Addr new_PC,unsigned tid) +{ + commit.setPC(new_PC, tid); +} + +template <class Impl> +uint64_t +FullO3CPU<Impl>::readNextPC(unsigned tid) +{ + return commit.readNextPC(tid); +} + +template <class Impl> +void +FullO3CPU<Impl>::setNextPC(uint64_t val,unsigned tid) +{ + commit.setNextPC(val, tid); +} + +template <class Impl> +typename FullO3CPU<Impl>::ListIt +FullO3CPU<Impl>::addInst(DynInstPtr &inst) +{ + instList.push_back(inst); + + return --(instList.end()); +} + +template <class Impl> +void +FullO3CPU<Impl>::instDone(unsigned tid) +{ + // Keep an instruction count. + thread[tid]->numInst++; + thread[tid]->numInsts++; + committedInsts[tid]++; + totalCommittedInsts++; + + // Check for instruction-count-based events. + comInstEventQueue[tid]->serviceEvents(thread[tid]->numInst); +} + +template <class Impl> +void +FullO3CPU<Impl>::addToRemoveList(DynInstPtr &inst) +{ + removeInstsThisCycle = true; + + removeList.push(inst->getInstListIt()); +} + +template <class Impl> +void +FullO3CPU<Impl>::removeFrontInst(DynInstPtr &inst) +{ + DPRINTF(FullCPU, "FullCPU: Removing committed instruction [tid:%i] PC %#x " + "[sn:%lli]\n", + inst->threadNumber, inst->readPC(), inst->seqNum); + + removeInstsThisCycle = true; + + // Remove the front instruction. + removeList.push(inst->getInstListIt()); +} + +template <class Impl> +void +FullO3CPU<Impl>::removeInstsNotInROB(unsigned tid) +{ + DPRINTF(FullCPU, "FullCPU: Thread %i: Deleting instructions from instruction" + " list.\n", tid); + + ListIt end_it; + + bool rob_empty = false; + + if (instList.empty()) { + return; + } else if (rob.isEmpty(/*tid*/)) { + DPRINTF(FullCPU, "FullCPU: ROB is empty, squashing all insts.\n"); + end_it = instList.begin(); + rob_empty = true; + } else { + end_it = (rob.readTailInst(tid))->getInstListIt(); + DPRINTF(FullCPU, "FullCPU: ROB is not empty, squashing insts not in ROB.\n"); + } + + removeInstsThisCycle = true; + + ListIt inst_it = instList.end(); + + inst_it--; + + // Walk through the instruction list, removing any instructions + // that were inserted after the given instruction iterator, end_it. + while (inst_it != end_it) { + assert(!instList.empty()); + + squashInstIt(inst_it, tid); + + inst_it--; + } + + // If the ROB was empty, then we actually need to remove the first + // instruction as well. + if (rob_empty) { + squashInstIt(inst_it, tid); + } +} + +template <class Impl> +void +FullO3CPU<Impl>::removeInstsUntil(const InstSeqNum &seq_num, + unsigned tid) +{ + assert(!instList.empty()); + + removeInstsThisCycle = true; + + ListIt inst_iter = instList.end(); + + inst_iter--; + + DPRINTF(FullCPU, "FullCPU: Deleting instructions from instruction " + "list that are from [tid:%i] and above [sn:%lli] (end=%lli).\n", + tid, seq_num, (*inst_iter)->seqNum); + + while ((*inst_iter)->seqNum > seq_num) { + + bool break_loop = (inst_iter == instList.begin()); + + squashInstIt(inst_iter, tid); + + inst_iter--; + + if (break_loop) + break; + } +} + +template <class Impl> +inline void +FullO3CPU<Impl>::squashInstIt(const ListIt &instIt, const unsigned &tid) +{ + if ((*instIt)->threadNumber == tid) { + DPRINTF(FullCPU, "FullCPU: Squashing instruction, " + "[tid:%i] [sn:%lli] PC %#x\n", + (*instIt)->threadNumber, + (*instIt)->seqNum, + (*instIt)->readPC()); + + // Mark it as squashed. + (*instIt)->setSquashed(); + + // @todo: Formulate a consistent method for deleting + // instructions from the instruction list + // Remove the instruction from the list. + removeList.push(instIt); + } +} + +template <class Impl> +void +FullO3CPU<Impl>::cleanUpRemovedInsts() +{ + while (!removeList.empty()) { + DPRINTF(FullCPU, "FullCPU: Removing instruction, " + "[tid:%i] [sn:%lli] PC %#x\n", + (*removeList.front())->threadNumber, + (*removeList.front())->seqNum, + (*removeList.front())->readPC()); + + instList.erase(removeList.front()); + + removeList.pop(); + } + + removeInstsThisCycle = false; +} +/* +template <class Impl> +void +FullO3CPU<Impl>::removeAllInsts() +{ + instList.clear(); +} +*/ +template <class Impl> +void +FullO3CPU<Impl>::dumpInsts() +{ + int num = 0; + + ListIt inst_list_it = instList.begin(); + + cprintf("Dumping Instruction List\n"); + + while (inst_list_it != instList.end()) { + cprintf("Instruction:%i\nPC:%#x\n[tid:%i]\n[sn:%lli]\nIssued:%i\n" + "Squashed:%i\n\n", + num, (*inst_list_it)->readPC(), (*inst_list_it)->threadNumber, + (*inst_list_it)->seqNum, (*inst_list_it)->isIssued(), + (*inst_list_it)->isSquashed()); + inst_list_it++; + ++num; + } +} +/* +template <class Impl> +void +FullO3CPU<Impl>::wakeDependents(DynInstPtr &inst) +{ + iew.wakeDependents(inst); +} +*/ +template <class Impl> +void +FullO3CPU<Impl>::wakeCPU() +{ + if (activityRec.active() || tickEvent.scheduled()) { + DPRINTF(Activity, "CPU already running.\n"); + return; + } + + DPRINTF(Activity, "Waking up CPU\n"); + + idleCycles += (curTick - 1) - lastRunningCycle; + + tickEvent.schedule(curTick); +} + +template <class Impl> +int +FullO3CPU<Impl>::getFreeTid() +{ + for (int i=0; i < numThreads; i++) { + if (!tids[i]) { + tids[i] = true; + return i; + } + } + + return -1; +} + +template <class Impl> +void +FullO3CPU<Impl>::doContextSwitch() +{ + if (contextSwitch) { + + //ADD CODE TO DEACTIVE THREAD HERE (???) + + for (int tid=0; tid < cpuWaitList.size(); tid++) { + activateWhenReady(tid); + } + + if (cpuWaitList.size() == 0) + contextSwitch = true; + } +} + +template <class Impl> +void +FullO3CPU<Impl>::updateThreadPriority() +{ + if (activeThreads.size() > 1) + { + //DEFAULT TO ROUND ROBIN SCHEME + //e.g. Move highest priority to end of thread list + list<unsigned>::iterator list_begin = activeThreads.begin(); + list<unsigned>::iterator list_end = activeThreads.end(); + + unsigned high_thread = *list_begin; + + activeThreads.erase(list_begin); + + activeThreads.push_back(high_thread); + } +} + +// Forward declaration of FullO3CPU. +template class FullO3CPU<AlphaSimpleImpl>; diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh new file mode 100644 index 000000000..ff41a3306 --- /dev/null +++ b/src/cpu/o3/cpu.hh @@ -0,0 +1,537 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#ifndef __CPU_O3_CPU_HH__ +#define __CPU_O3_CPU_HH__ + +#include <iostream> +#include <list> +#include <queue> +#include <set> +#include <vector> + +#include "arch/isa_traits.hh" +#include "base/statistics.hh" +#include "base/timebuf.hh" +#include "config/full_system.hh" +#include "cpu/activity.hh" +#include "cpu/base.hh" +#include "cpu/simple_thread.hh" +#include "cpu/o3/comm.hh" +#include "cpu/o3/cpu_policy.hh" +#include "cpu/o3/scoreboard.hh" +#include "cpu/o3/thread_state.hh" +#include "sim/process.hh" + +template <class> +class Checker; +class ThreadContext; +class MemObject; +class Process; + +class BaseFullCPU : public BaseCPU +{ + //Stuff that's pretty ISA independent will go here. + public: + typedef BaseCPU::Params Params; + + BaseFullCPU(Params *params); + + void regStats(); + + int readCpuId() { return cpu_id; } + + protected: + int cpu_id; +}; + +/** + * FullO3CPU class, has each of the stages (fetch through commit) + * within it, as well as all of the time buffers between stages. The + * tick() function for the CPU is defined here. + */ +template <class Impl> +class FullO3CPU : public BaseFullCPU +{ + public: + typedef TheISA::FloatReg FloatReg; + typedef TheISA::FloatRegBits FloatRegBits; + + // Typedefs from the Impl here. + typedef typename Impl::CPUPol CPUPolicy; + typedef typename Impl::Params Params; + typedef typename Impl::DynInstPtr DynInstPtr; + + typedef O3ThreadState<Impl> Thread; + + typedef typename std::list<DynInstPtr>::iterator ListIt; + + public: + enum Status { + Running, + Idle, + Halted, + Blocked, + SwitchedOut + }; + + /** Overall CPU status. */ + Status _status; + + private: + class TickEvent : public Event + { + private: + /** Pointer to the CPU. */ + FullO3CPU<Impl> *cpu; + + public: + /** Constructs a tick event. */ + TickEvent(FullO3CPU<Impl> *c); + + /** Processes a tick event, calling tick() on the CPU. */ + void process(); + /** Returns the description of the tick event. */ + const char *description(); + }; + + /** The tick event used for scheduling CPU ticks. */ + TickEvent tickEvent; + + /** Schedule tick event, regardless of its current state. */ + void scheduleTickEvent(int delay) + { + if (tickEvent.squashed()) + tickEvent.reschedule(curTick + cycles(delay)); + else if (!tickEvent.scheduled()) + tickEvent.schedule(curTick + cycles(delay)); + } + + /** Unschedule tick event, regardless of its current state. */ + void unscheduleTickEvent() + { + if (tickEvent.scheduled()) + tickEvent.squash(); + } + + public: + /** Constructs a CPU with the given parameters. */ + FullO3CPU(Params *params); + /** Destructor. */ + ~FullO3CPU(); + + /** Registers statistics. */ + void fullCPURegStats(); + + /** 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(); + + /** Setup CPU to insert a thread's context */ + void insertThread(unsigned tid); + + /** Remove all of a thread's context from CPU */ + void removeThread(unsigned tid); + + /** Count the Total Instructions Committed in the CPU. */ + virtual Counter totalInstructions() const + { + Counter total(0); + + for (int i=0; i < thread.size(); i++) + total += thread[i]->numInst; + + return total; + } + + /** Add Thread to Active Threads List. */ + void activateContext(int tid, int delay); + + /** Remove Thread from Active Threads List */ + void suspendContext(int tid); + + /** Remove Thread from Active Threads List && + * Remove Thread Context from CPU. + */ + void deallocateContext(int tid); + + /** Remove Thread from Active Threads List && + * Remove Thread Context from CPU. + */ + void haltContext(int tid); + + /** Activate a Thread When CPU Resources are Available. */ + void activateWhenReady(int tid); + + /** Add or Remove a Thread Context in the CPU. */ + void doContextSwitch(); + + /** Update The Order In Which We Process Threads. */ + void updateThreadPriority(); + + /** Executes a syscall on this cycle. + * --------------------------------------- + * Note: this is a virtual function. CPU-Specific + * functionality defined in derived classes + */ + virtual void syscall(int tid) { panic("Unimplemented!"); } + + /** Switches out this CPU. */ + void switchOut(Sampler *sampler); + + /** Signals to this CPU that a stage has completed switching out. */ + void signalSwitched(); + + /** Takes over from another CPU. */ + void takeOverFrom(BaseCPU *oldCPU); + + /** Get the current instruction sequence number, and increment it. */ + InstSeqNum getAndIncrementInstSeq() + { return globalSeqNum++; } + +#if FULL_SYSTEM + /** 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; } + + /** Get instruction asid. */ + int getInstAsid(unsigned tid) + { return regFile.miscRegs[tid].getInstAsid(); } + + /** Get data asid. */ + int getDataAsid(unsigned tid) + { return regFile.miscRegs[tid].getDataAsid(); } +#else + /** Get instruction asid. */ + int getInstAsid(unsigned tid) + { return thread[tid]->getInstAsid(); } + + /** Get data asid. */ + int getDataAsid(unsigned tid) + { return thread[tid]->getDataAsid(); } + +#endif + + /** Register accessors. Index refers to the physical register index. */ + uint64_t readIntReg(int reg_idx); + + FloatReg readFloatReg(int reg_idx); + + FloatReg readFloatReg(int reg_idx, int width); + + FloatRegBits readFloatRegBits(int reg_idx); + + FloatRegBits readFloatRegBits(int reg_idx, int width); + + void setIntReg(int reg_idx, uint64_t val); + + void setFloatReg(int reg_idx, FloatReg val); + + void setFloatReg(int reg_idx, FloatReg val, int width); + + void setFloatRegBits(int reg_idx, FloatRegBits val); + + void setFloatRegBits(int reg_idx, FloatRegBits val, int width); + + uint64_t readArchIntReg(int reg_idx, unsigned tid); + + float readArchFloatRegSingle(int reg_idx, unsigned tid); + + double readArchFloatRegDouble(int reg_idx, unsigned tid); + + uint64_t readArchFloatRegInt(int reg_idx, unsigned tid); + + /** Architectural register accessors. Looks up in the commit + * rename table to obtain the true physical index of the + * architected register first, then accesses that physical + * register. + */ + void setArchIntReg(int reg_idx, uint64_t val, unsigned tid); + + void setArchFloatRegSingle(int reg_idx, float val, unsigned tid); + + void setArchFloatRegDouble(int reg_idx, double val, unsigned tid); + + void setArchFloatRegInt(int reg_idx, uint64_t val, unsigned tid); + + /** Reads the commit PC of a specific thread. */ + uint64_t readPC(unsigned tid); + + /** Sets the commit PC of a specific thread. */ + void setPC(Addr new_PC, unsigned tid); + + /** Reads the next PC of a specific thread. */ + uint64_t readNextPC(unsigned tid); + + /** Sets the next PC of a specific thread. */ + void setNextPC(uint64_t val, unsigned tid); + + /** Function to add instruction onto the head of the list of the + * instructions. Used when new instructions are fetched. + */ + ListIt addInst(DynInstPtr &inst); + + /** Function to tell the CPU that an instruction has completed. */ + void instDone(unsigned tid); + + /** Add Instructions to the CPU Remove List*/ + void addToRemoveList(DynInstPtr &inst); + + /** Remove an instruction from the front end of the list. There's + * no restriction on location of the instruction. + */ + void removeFrontInst(DynInstPtr &inst); + + /** Remove all instructions that are not currently in the ROB. */ + void removeInstsNotInROB(unsigned tid); + + /** Remove all instructions younger than the given sequence number. */ + void removeInstsUntil(const InstSeqNum &seq_num,unsigned tid); + + /** Removes the instruction pointed to by the iterator. */ + inline void squashInstIt(const ListIt &instIt, const unsigned &tid); + + /** Cleans up all instructions on the remove list. */ + void cleanUpRemovedInsts(); + + /** Debug function to print all instructions on the list. */ + void dumpInsts(); + + public: + /** List of all the instructions in flight. */ + std::list<DynInstPtr> instList; + + /** List of all the instructions that will be removed at the end of this + * cycle. + */ + std::queue<ListIt> removeList; + +#ifdef DEBUG + /** Debug structure to keep track of the sequence numbers still in + * flight. + */ + std::set<InstSeqNum> snList; +#endif + + /** Records if instructions need to be removed this cycle due to + * being retired or squashed. + */ + bool removeInstsThisCycle; + + protected: + /** The fetch stage. */ + typename CPUPolicy::Fetch fetch; + + /** The decode stage. */ + typename CPUPolicy::Decode decode; + + /** The dispatch stage. */ + typename CPUPolicy::Rename rename; + + /** The issue/execute/writeback stages. */ + typename CPUPolicy::IEW iew; + + /** The commit stage. */ + typename CPUPolicy::Commit commit; + + /** The register file. */ + typename CPUPolicy::RegFile regFile; + + /** The free list. */ + typename CPUPolicy::FreeList freeList; + + /** The rename map. */ + typename CPUPolicy::RenameMap renameMap[Impl::MaxThreads]; + + /** The commit rename map. */ + typename CPUPolicy::RenameMap commitRenameMap[Impl::MaxThreads]; + + /** The re-order buffer. */ + typename CPUPolicy::ROB rob; + + /** Active Threads List */ + std::list<unsigned> activeThreads; + + /** Integer Register Scoreboard */ + Scoreboard scoreboard; + + public: + /** Enum to give each stage a specific index, so when calling + * activateStage() or deactivateStage(), they can specify which stage + * is being activated/deactivated. + */ + enum StageIdx { + FetchIdx, + DecodeIdx, + RenameIdx, + IEWIdx, + CommitIdx, + NumStages }; + + /** Typedefs from the Impl to get the structs that each of the + * time buffers should use. + */ + typedef typename CPUPolicy::TimeStruct TimeStruct; + + typedef typename CPUPolicy::FetchStruct FetchStruct; + + typedef typename CPUPolicy::DecodeStruct DecodeStruct; + + typedef typename CPUPolicy::RenameStruct RenameStruct; + + typedef typename CPUPolicy::IEWStruct IEWStruct; + + /** The main time buffer to do backwards communication. */ + TimeBuffer<TimeStruct> timeBuffer; + + /** The fetch stage's instruction queue. */ + TimeBuffer<FetchStruct> fetchQueue; + + /** The decode stage's instruction queue. */ + TimeBuffer<DecodeStruct> decodeQueue; + + /** The rename stage's instruction queue. */ + TimeBuffer<RenameStruct> renameQueue; + + /** The IEW stage's instruction queue. */ + TimeBuffer<IEWStruct> iewQueue; + + 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: + /** 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 StageIdx idx) + { activityRec.activateStage(idx); } + + /** Changes a stage's status to inactive within the activity recorder. */ + void deactivateStage(const StageIdx idx) + { activityRec.deactivateStage(idx); } + + /** Wakes the CPU, rescheduling the CPU if it's not already active. */ + void wakeCPU(); + + /** Gets a free thread id. Use if thread ids change across system. */ + int getFreeTid(); + + public: + /** Returns a pointer to a thread context. */ + ThreadContext *tcBase(unsigned tid) + { + return thread[tid]->getTC(); + } + + /** The global sequence number counter. */ + InstSeqNum globalSeqNum; + + /** Pointer to the checker, which can dynamically verify + * instruction results at run time. This can be set to NULL if it + * is not being used. + */ + Checker<DynInstPtr> *checker; + +#if FULL_SYSTEM + /** Pointer to the system. */ + System *system; + + /** Pointer to physical memory. */ + PhysicalMemory *physmem; +#endif + + /** Pointer to memory. */ + MemObject *mem; + + /** Pointer to the sampler */ + Sampler *sampler; + + /** Counter of how many stages have completed switching out. */ + int switchCount; + + /** Pointers to all of the threads in the CPU. */ + std::vector<Thread *> thread; + + /** Pointer to the icache interface. */ + MemInterface *icacheInterface; + /** Pointer to the dcache interface. */ + MemInterface *dcacheInterface; + + /** Whether or not the CPU should defer its registration. */ + bool deferRegistration; + + /** Is there a context switch pending? */ + bool contextSwitch; + + /** Threads Scheduled to Enter CPU */ + std::list<int> cpuWaitList; + + /** The cycle that the CPU was last running, used for statistics. */ + Tick lastRunningCycle; + + /** Number of Threads CPU can process */ + unsigned numThreads; + + /** Mapping for system thread id to cpu id */ + std::map<unsigned,unsigned> threadMap; + + /** Available thread ids in the cpu*/ + std::vector<unsigned> tids; + + /** Stat for total number of times the CPU is descheduled. */ + Stats::Scalar<> timesIdled; + /** Stat for total number of cycles the CPU spends descheduled. */ + Stats::Scalar<> idleCycles; + /** Stat for the number of committed instructions per thread. */ + Stats::Vector<> committedInsts; + /** Stat for the total number of committed instructions. */ + Stats::Scalar<> totalCommittedInsts; + /** Stat for the CPI per thread. */ + Stats::Formula cpi; + /** Stat for the total CPI. */ + Stats::Formula totalCpi; + /** Stat for the IPC per thread. */ + Stats::Formula ipc; + /** Stat for the total IPC. */ + Stats::Formula totalIpc; +}; + +#endif // __CPU_O3_CPU_HH__ diff --git a/src/cpu/o3/cpu_policy.hh b/src/cpu/o3/cpu_policy.hh new file mode 100644 index 000000000..32a0adcf1 --- /dev/null +++ b/src/cpu/o3/cpu_policy.hh @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#ifndef __CPU_O3_CPU_POLICY_HH__ +#define __CPU_O3_CPU_POLICY_HH__ + +#include "cpu/o3/bpred_unit.hh" +#include "cpu/o3/free_list.hh" +#include "cpu/o3/inst_queue.hh" +#include "cpu/o3/lsq.hh" +#include "cpu/o3/lsq_unit.hh" +#include "cpu/o3/mem_dep_unit.hh" +#include "cpu/o3/regfile.hh" +#include "cpu/o3/rename_map.hh" +#include "cpu/o3/rob.hh" +#include "cpu/o3/store_set.hh" + +#include "cpu/o3/commit.hh" +#include "cpu/o3/decode.hh" +#include "cpu/o3/fetch.hh" +#include "cpu/o3/iew.hh" +#include "cpu/o3/rename.hh" + +#include "cpu/o3/comm.hh" + +/** + * Struct that defines the key classes to be used by the CPU. All + * classes use the typedefs defined here to determine what are the + * classes of the other stages and communication buffers. In order to + * change a structure such as the IQ, simply change the typedef here + * to use the desired class instead, and recompile. In order to + * create a different CPU to be used simultaneously with this one, see + * the alpha_impl.hh file for instructions. + */ +template<class Impl> +struct SimpleCPUPolicy +{ + /** Typedef for the branch prediction unit (which includes the BP, + * RAS, and BTB). + */ + typedef BPredUnit<Impl> BPredUnit; + /** Typedef for the register file. Most classes assume a unified + * physical register file. + */ + typedef PhysRegFile<Impl> RegFile; + /** Typedef for the freelist of registers. */ + typedef SimpleFreeList FreeList; + /** Typedef for the rename map. */ + typedef SimpleRenameMap RenameMap; + /** Typedef for the ROB. */ + typedef ROB<Impl> ROB; + /** Typedef for the instruction queue/scheduler. */ + typedef InstructionQueue<Impl> IQ; + /** Typedef for the memory dependence unit. */ + typedef MemDepUnit<StoreSet, Impl> MemDepUnit; + /** Typedef for the LSQ. */ + typedef LSQ<Impl> LSQ; + /** Typedef for the thread-specific LSQ units. */ + typedef LSQUnit<Impl> LSQUnit; + + /** Typedef for fetch. */ + typedef DefaultFetch<Impl> Fetch; + /** Typedef for decode. */ + typedef DefaultDecode<Impl> Decode; + /** Typedef for rename. */ + typedef DefaultRename<Impl> Rename; + /** Typedef for Issue/Execute/Writeback. */ + typedef DefaultIEW<Impl> IEW; + /** Typedef for commit. */ + typedef DefaultCommit<Impl> Commit; + + /** The struct for communication between fetch and decode. */ + typedef DefaultFetchDefaultDecode<Impl> FetchStruct; + + /** The struct for communication between decode and rename. */ + typedef DefaultDecodeDefaultRename<Impl> DecodeStruct; + + /** The struct for communication between rename and IEW. */ + typedef DefaultRenameDefaultIEW<Impl> RenameStruct; + + /** The struct for communication between IEW and commit. */ + typedef DefaultIEWDefaultCommit<Impl> IEWStruct; + + /** The struct for communication within the IEW stage. */ + typedef IssueStruct<Impl> IssueStruct; + + /** The struct for all backwards communication. */ + typedef TimeBufStruct<Impl> TimeStruct; + +}; + +#endif //__CPU_O3_CPU_POLICY_HH__ diff --git a/src/cpu/o3/decode.cc b/src/cpu/o3/decode.cc new file mode 100644 index 000000000..4924f018a --- /dev/null +++ b/src/cpu/o3/decode.cc @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#include "cpu/o3/alpha_dyn_inst.hh" +#include "cpu/o3/alpha_impl.hh" +#include "cpu/o3/decode_impl.hh" + +template class DefaultDecode<AlphaSimpleImpl>; diff --git a/src/cpu/o3/decode.hh b/src/cpu/o3/decode.hh new file mode 100644 index 000000000..ff88358d6 --- /dev/null +++ b/src/cpu/o3/decode.hh @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#ifndef __CPU_O3_DECODE_HH__ +#define __CPU_O3_DECODE_HH__ + +#include <queue> + +#include "base/statistics.hh" +#include "base/timebuf.hh" + +/** + * DefaultDecode class handles both single threaded and SMT + * decode. Its width is specified by the parameters; each cycles it + * tries to decode that many instructions. Because instructions are + * actually decoded when the StaticInst is created, this stage does + * not do much other than check any PC-relative branches. + */ +template<class Impl> +class DefaultDecode +{ + private: + // Typedefs from the Impl. + typedef typename Impl::FullCPU FullCPU; + typedef typename Impl::DynInstPtr DynInstPtr; + typedef typename Impl::Params Params; + typedef typename Impl::CPUPol CPUPol; + + // Typedefs from the CPU policy. + typedef typename CPUPol::FetchStruct FetchStruct; + typedef typename CPUPol::DecodeStruct DecodeStruct; + typedef typename CPUPol::TimeStruct TimeStruct; + + public: + /** Overall decode stage status. Used to determine if the CPU can + * deschedule itself due to a lack of activity. + */ + enum DecodeStatus { + Active, + Inactive + }; + + /** Individual thread status. */ + enum ThreadStatus { + Running, + Idle, + StartSquash, + Squashing, + Blocked, + Unblocking + }; + + private: + /** Decode status. */ + DecodeStatus _status; + + /** Per-thread status. */ + ThreadStatus decodeStatus[Impl::MaxThreads]; + + public: + /** DefaultDecode constructor. */ + DefaultDecode(Params *params); + + /** Returns the name of decode. */ + std::string name() const; + + /** Registers statistics. */ + void regStats(); + + /** Sets CPU pointer. */ + void setCPU(FullCPU *cpu_ptr); + + /** Sets the main backwards communication time buffer pointer. */ + void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr); + + /** Sets pointer to time buffer used to communicate to the next stage. */ + void setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr); + + /** Sets pointer to time buffer coming from fetch. */ + void setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr); + + /** Sets pointer to list of active threads. */ + void setActiveThreads(std::list<unsigned> *at_ptr); + + /** Switches out the decode stage. */ + void switchOut(); + + /** Takes over from another CPU's thread. */ + void takeOverFrom(); + + /** Ticks decode, processing all input signals and decoding as many + * instructions as possible. + */ + void tick(); + + /** Determines what to do based on decode's current status. + * @param status_change decode() sets this variable if there was a status + * change (ie switching from from blocking to unblocking). + * @param tid Thread id to decode instructions from. + */ + void decode(bool &status_change, unsigned tid); + + /** Processes instructions from fetch and passes them on to rename. + * Decoding of instructions actually happens when they are created in + * fetch, so this function mostly checks if PC-relative branches are + * correct. + */ + void decodeInsts(unsigned tid); + + private: + /** Inserts a thread's instructions into the skid buffer, to be decoded + * once decode unblocks. + */ + void skidInsert(unsigned tid); + + /** Returns if all of the skid buffers are empty. */ + bool skidsEmpty(); + + /** Updates overall decode 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(unsigned tid); + + /** Checks all input signals and updates decode's status appropriately. */ + bool checkSignalsAndUpdate(unsigned tid); + + /** Checks all stall signals, and returns if any are true. */ + bool checkStall(unsigned tid) const; + + /** Returns if there any instructions from fetch on this cycle. */ + inline bool fetchInstsValid(); + + /** Switches decode to blocking, and signals back that decode has + * become blocked. + * @return Returns true if there is a status change. + */ + bool block(unsigned tid); + + /** Switches decode to unblocking if the skid buffer is empty, and + * signals back that decode has unblocked. + * @return Returns true if there is a status change. + */ + bool unblock(unsigned tid); + + /** Squashes if there is a PC-relative branch that was predicted + * incorrectly. Sends squash information back to fetch. + */ + void squash(DynInstPtr &inst, unsigned tid); + + public: + /** Squashes due to commit signalling a squash. Changes status to + * squashing and clears block/unblock signals as needed. + */ + unsigned squash(unsigned tid); + + private: + // Interfaces to objects outside of decode. + /** CPU interface. */ + FullCPU *cpu; + + /** Time buffer interface. */ + TimeBuffer<TimeStruct> *timeBuffer; + + /** Wire to get rename's output from backwards time buffer. */ + typename TimeBuffer<TimeStruct>::wire fromRename; + + /** Wire to get iew's information from backwards time buffer. */ + typename TimeBuffer<TimeStruct>::wire fromIEW; + + /** Wire to get commit's information from backwards time buffer. */ + typename TimeBuffer<TimeStruct>::wire fromCommit; + + /** Wire to write information heading to previous stages. */ + // Might not be the best name as not only fetch will read it. + typename TimeBuffer<TimeStruct>::wire toFetch; + + /** Decode instruction queue. */ + TimeBuffer<DecodeStruct> *decodeQueue; + + /** Wire used to write any information heading to rename. */ + typename TimeBuffer<DecodeStruct>::wire toRename; + + /** Fetch instruction queue interface. */ + TimeBuffer<FetchStruct> *fetchQueue; + + /** Wire to get fetch's output from fetch queue. */ + typename TimeBuffer<FetchStruct>::wire fromFetch; + + /** Queue of all instructions coming from fetch this cycle. */ + std::queue<DynInstPtr> insts[Impl::MaxThreads]; + + /** Skid buffer between fetch and decode. */ + std::queue<DynInstPtr> skidBuffer[Impl::MaxThreads]; + + /** Variable that tracks if decode has written to the time buffer this + * cycle. Used to tell CPU if there is activity this cycle. + */ + bool wroteToTimeBuffer; + + /** Source of possible stalls. */ + struct Stalls { + bool rename; + bool iew; + bool commit; + }; + + /** Tracks which stages are telling decode to stall. */ + Stalls stalls[Impl::MaxThreads]; + + /** Rename to decode delay, in ticks. */ + unsigned renameToDecodeDelay; + + /** IEW to decode delay, in ticks. */ + unsigned iewToDecodeDelay; + + /** Commit to decode delay, in ticks. */ + unsigned commitToDecodeDelay; + + /** Fetch to decode delay, in ticks. */ + unsigned fetchToDecodeDelay; + + /** The width of decode, in instructions. */ + unsigned decodeWidth; + + /** Index of instructions being sent to rename. */ + unsigned toRenameIndex; + + /** number of Active Threads*/ + unsigned numThreads; + + /** List of active thread ids */ + std::list<unsigned> *activeThreads; + + /** Number of branches in flight. */ + unsigned branchCount[Impl::MaxThreads]; + + /** Maximum size of the skid buffer. */ + unsigned skidBufferMax; + + /** Stat for total number of idle cycles. */ + Stats::Scalar<> decodeIdleCycles; + /** Stat for total number of blocked cycles. */ + Stats::Scalar<> decodeBlockedCycles; + /** Stat for total number of normal running cycles. */ + Stats::Scalar<> decodeRunCycles; + /** Stat for total number of unblocking cycles. */ + Stats::Scalar<> decodeUnblockCycles; + /** Stat for total number of squashing cycles. */ + Stats::Scalar<> decodeSquashCycles; + /** Stat for number of times a branch is resolved at decode. */ + Stats::Scalar<> decodeBranchResolved; + /** Stat for number of times a branch mispredict is detected. */ + Stats::Scalar<> decodeBranchMispred; + /** Stat for number of times decode detected a non-control instruction + * incorrectly predicted as a branch. + */ + Stats::Scalar<> decodeControlMispred; + /** Stat for total number of decoded instructions. */ + Stats::Scalar<> decodeDecodedInsts; + /** Stat for total number of squashed instructions. */ + Stats::Scalar<> decodeSquashedInsts; +}; + +#endif // __CPU_O3_DECODE_HH__ diff --git a/src/cpu/o3/decode_impl.hh b/src/cpu/o3/decode_impl.hh new file mode 100644 index 000000000..8a6ea6626 --- /dev/null +++ b/src/cpu/o3/decode_impl.hh @@ -0,0 +1,751 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#include "cpu/o3/decode.hh" + +using namespace std; + +template<class Impl> +DefaultDecode<Impl>::DefaultDecode(Params *params) + : renameToDecodeDelay(params->renameToDecodeDelay), + iewToDecodeDelay(params->iewToDecodeDelay), + commitToDecodeDelay(params->commitToDecodeDelay), + fetchToDecodeDelay(params->fetchToDecodeDelay), + decodeWidth(params->decodeWidth), + numThreads(params->numberOfThreads) +{ + _status = Inactive; + + // Setup status, make sure stall signals are clear. + for (int i = 0; i < numThreads; ++i) { + decodeStatus[i] = Idle; + + stalls[i].rename = false; + stalls[i].iew = false; + stalls[i].commit = false; + } + + // @todo: Make into a parameter + skidBufferMax = (fetchToDecodeDelay * params->fetchWidth) + decodeWidth; +} + +template <class Impl> +std::string +DefaultDecode<Impl>::name() const +{ + return cpu->name() + ".decode"; +} + +template <class Impl> +void +DefaultDecode<Impl>::regStats() +{ + decodeIdleCycles + .name(name() + ".DECODE:IdleCycles") + .desc("Number of cycles decode is idle") + .prereq(decodeIdleCycles); + decodeBlockedCycles + .name(name() + ".DECODE:BlockedCycles") + .desc("Number of cycles decode is blocked") + .prereq(decodeBlockedCycles); + decodeRunCycles + .name(name() + ".DECODE:RunCycles") + .desc("Number of cycles decode is running") + .prereq(decodeRunCycles); + decodeUnblockCycles + .name(name() + ".DECODE:UnblockCycles") + .desc("Number of cycles decode is unblocking") + .prereq(decodeUnblockCycles); + decodeSquashCycles + .name(name() + ".DECODE:SquashCycles") + .desc("Number of cycles decode is squashing") + .prereq(decodeSquashCycles); + decodeBranchResolved + .name(name() + ".DECODE:BranchResolved") + .desc("Number of times decode resolved a branch") + .prereq(decodeBranchResolved); + decodeBranchMispred + .name(name() + ".DECODE:BranchMispred") + .desc("Number of times decode detected a branch misprediction") + .prereq(decodeBranchMispred); + decodeControlMispred + .name(name() + ".DECODE:ControlMispred") + .desc("Number of times decode detected an instruction incorrectly" + " predicted as a control") + .prereq(decodeControlMispred); + decodeDecodedInsts + .name(name() + ".DECODE:DecodedInsts") + .desc("Number of instructions handled by decode") + .prereq(decodeDecodedInsts); + decodeSquashedInsts + .name(name() + ".DECODE:SquashedInsts") + .desc("Number of squashed instructions handled by decode") + .prereq(decodeSquashedInsts); +} + +template<class Impl> +void +DefaultDecode<Impl>::setCPU(FullCPU *cpu_ptr) +{ + DPRINTF(Decode, "Setting CPU pointer.\n"); + cpu = cpu_ptr; +} + +template<class Impl> +void +DefaultDecode<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) +{ + DPRINTF(Decode, "Setting time buffer pointer.\n"); + timeBuffer = tb_ptr; + + // Setup wire to write information back to fetch. + toFetch = timeBuffer->getWire(0); + + // Create wires to get information from proper places in time buffer. + fromRename = timeBuffer->getWire(-renameToDecodeDelay); + fromIEW = timeBuffer->getWire(-iewToDecodeDelay); + fromCommit = timeBuffer->getWire(-commitToDecodeDelay); +} + +template<class Impl> +void +DefaultDecode<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr) +{ + DPRINTF(Decode, "Setting decode queue pointer.\n"); + decodeQueue = dq_ptr; + + // Setup wire to write information to proper place in decode queue. + toRename = decodeQueue->getWire(0); +} + +template<class Impl> +void +DefaultDecode<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr) +{ + DPRINTF(Decode, "Setting fetch queue pointer.\n"); + fetchQueue = fq_ptr; + + // Setup wire to read information from fetch queue. + fromFetch = fetchQueue->getWire(-fetchToDecodeDelay); +} + +template<class Impl> +void +DefaultDecode<Impl>::setActiveThreads(list<unsigned> *at_ptr) +{ + DPRINTF(Decode, "Setting active threads list pointer.\n"); + activeThreads = at_ptr; +} + +template <class Impl> +void +DefaultDecode<Impl>::switchOut() +{ + // Decode can immediately switch out. + cpu->signalSwitched(); +} + +template <class Impl> +void +DefaultDecode<Impl>::takeOverFrom() +{ + _status = Inactive; + + // Be sure to reset state and clear out any old instructions. + for (int i = 0; i < numThreads; ++i) { + decodeStatus[i] = Idle; + + stalls[i].rename = false; + stalls[i].iew = false; + stalls[i].commit = false; + while (!insts[i].empty()) + insts[i].pop(); + while (!skidBuffer[i].empty()) + skidBuffer[i].pop(); + branchCount[i] = 0; + } + wroteToTimeBuffer = false; +} + +template<class Impl> +bool +DefaultDecode<Impl>::checkStall(unsigned tid) const +{ + bool ret_val = false; + + if (stalls[tid].rename) { + DPRINTF(Decode,"[tid:%i]: Stall fom Rename stage detected.\n", tid); + ret_val = true; + } else if (stalls[tid].iew) { + DPRINTF(Decode,"[tid:%i]: Stall fom IEW stage detected.\n", tid); + ret_val = true; + } else if (stalls[tid].commit) { + DPRINTF(Decode,"[tid:%i]: Stall fom Commit stage detected.\n", tid); + ret_val = true; + } + + return ret_val; +} + +template<class Impl> +inline bool +DefaultDecode<Impl>::fetchInstsValid() +{ + return fromFetch->size > 0; +} + +template<class Impl> +bool +DefaultDecode<Impl>::block(unsigned tid) +{ + DPRINTF(Decode, "[tid:%u]: Blocking.\n", tid); + + // Add the current inputs to the skid buffer so they can be + // reprocessed when this stage unblocks. + skidInsert(tid); + + // If the decode status is blocked or unblocking then decode has not yet + // signalled fetch to unblock. In that case, there is no need to tell + // fetch to block. + if (decodeStatus[tid] != Blocked) { + // Set the status to Blocked. + decodeStatus[tid] = Blocked; + + if (decodeStatus[tid] != Unblocking) { + toFetch->decodeBlock[tid] = true; + wroteToTimeBuffer = true; + } + + return true; + } + + return false; +} + +template<class Impl> +bool +DefaultDecode<Impl>::unblock(unsigned tid) +{ + // Decode is done unblocking only if the skid buffer is empty. + if (skidBuffer[tid].empty()) { + DPRINTF(Decode, "[tid:%u]: Done unblocking.\n", tid); + toFetch->decodeUnblock[tid] = true; + wroteToTimeBuffer = true; + + decodeStatus[tid] = Running; + return true; + } + + DPRINTF(Decode, "[tid:%u]: Currently unblocking.\n", tid); + + return false; +} + +template<class Impl> +void +DefaultDecode<Impl>::squash(DynInstPtr &inst, unsigned tid) +{ + DPRINTF(Decode, "[tid:%i]: Squashing due to incorrect branch prediction " + "detected at decode.\n", tid); + + // Send back mispredict information. + toFetch->decodeInfo[tid].branchMispredict = true; + toFetch->decodeInfo[tid].doneSeqNum = inst->seqNum; + toFetch->decodeInfo[tid].predIncorrect = true; + toFetch->decodeInfo[tid].squash = true; + toFetch->decodeInfo[tid].nextPC = inst->branchTarget(); + toFetch->decodeInfo[tid].branchTaken = + inst->readNextPC() != (inst->readPC() + sizeof(TheISA::MachInst)); + + // Might have to tell fetch to unblock. + if (decodeStatus[tid] == Blocked || + decodeStatus[tid] == Unblocking) { + toFetch->decodeUnblock[tid] = 1; + } + + // Set status to squashing. + decodeStatus[tid] = Squashing; + + for (int i=0; i<fromFetch->size; i++) { + if (fromFetch->insts[i]->threadNumber == tid && + fromFetch->insts[i]->seqNum > inst->seqNum) { + fromFetch->insts[i]->squashed = true; + } + } + + // Clear the instruction list and skid buffer in case they have any + // insts in them. + while (!insts[tid].empty()) { + insts[tid].pop(); + } + + while (!skidBuffer[tid].empty()) { + skidBuffer[tid].pop(); + } + + // Squash instructions up until this one + cpu->removeInstsUntil(inst->seqNum, tid); +} + +template<class Impl> +unsigned +DefaultDecode<Impl>::squash(unsigned tid) +{ + DPRINTF(Decode, "[tid:%i]: Squashing.\n",tid); + + if (decodeStatus[tid] == Blocked || + decodeStatus[tid] == Unblocking) { +#if !FULL_SYSTEM + // In syscall emulation, we can have both a block and a squash due + // to a syscall in the same cycle. This would cause both signals to + // be high. This shouldn't happen in full system. + // @todo: Determine if this still happens. + if (toFetch->decodeBlock[tid]) { + toFetch->decodeBlock[tid] = 0; + } else { + toFetch->decodeUnblock[tid] = 1; + } +#else + toFetch->decodeUnblock[tid] = 1; +#endif + } + + // Set status to squashing. + decodeStatus[tid] = Squashing; + + // Go through incoming instructions from fetch and squash them. + unsigned squash_count = 0; + + for (int i=0; i<fromFetch->size; i++) { + if (fromFetch->insts[i]->threadNumber == tid) { + fromFetch->insts[i]->squashed = true; + squash_count++; + } + } + + // Clear the instruction list and skid buffer in case they have any + // insts in them. + while (!insts[tid].empty()) { + insts[tid].pop(); + } + + while (!skidBuffer[tid].empty()) { + skidBuffer[tid].pop(); + } + + return squash_count; +} + +template<class Impl> +void +DefaultDecode<Impl>::skidInsert(unsigned tid) +{ + DynInstPtr inst = NULL; + + while (!insts[tid].empty()) { + inst = insts[tid].front(); + + insts[tid].pop(); + + assert(tid == inst->threadNumber); + + DPRINTF(Decode,"Inserting [sn:%lli] PC:%#x into decode skidBuffer %i\n", + inst->seqNum, inst->readPC(), inst->threadNumber); + + skidBuffer[tid].push(inst); + } + + // @todo: Eventually need to enforce this by not letting a thread + // fetch past its skidbuffer + assert(skidBuffer[tid].size() <= skidBufferMax); +} + +template<class Impl> +bool +DefaultDecode<Impl>::skidsEmpty() +{ + list<unsigned>::iterator threads = (*activeThreads).begin(); + + while (threads != (*activeThreads).end()) { + if (!skidBuffer[*threads++].empty()) + return false; + } + + return true; +} + +template<class Impl> +void +DefaultDecode<Impl>::updateStatus() +{ + bool any_unblocking = false; + + list<unsigned>::iterator threads = (*activeThreads).begin(); + + threads = (*activeThreads).begin(); + + while (threads != (*activeThreads).end()) { + unsigned tid = *threads++; + + if (decodeStatus[tid] == Unblocking) { + any_unblocking = true; + break; + } + } + + // Decode will have activity if it's unblocking. + if (any_unblocking) { + if (_status == Inactive) { + _status = Active; + + DPRINTF(Activity, "Activating stage.\n"); + + cpu->activateStage(FullCPU::DecodeIdx); + } + } else { + // If it's not unblocking, then decode will not have any internal + // activity. Switch it to inactive. + if (_status == Active) { + _status = Inactive; + DPRINTF(Activity, "Deactivating stage.\n"); + + cpu->deactivateStage(FullCPU::DecodeIdx); + } + } +} + +template <class Impl> +void +DefaultDecode<Impl>::sortInsts() +{ + int insts_from_fetch = fromFetch->size; +#ifdef DEBUG + for (int i=0; i < numThreads; i++) + assert(insts[i].empty()); +#endif + for (int i = 0; i < insts_from_fetch; ++i) { + insts[fromFetch->insts[i]->threadNumber].push(fromFetch->insts[i]); + } +} + +template<class Impl> +void +DefaultDecode<Impl>::readStallSignals(unsigned tid) +{ + if (fromRename->renameBlock[tid]) { + stalls[tid].rename = true; + } + + if (fromRename->renameUnblock[tid]) { + assert(stalls[tid].rename); + stalls[tid].rename = false; + } + + if (fromIEW->iewBlock[tid]) { + stalls[tid].iew = true; + } + + if (fromIEW->iewUnblock[tid]) { + assert(stalls[tid].iew); + stalls[tid].iew = false; + } + + if (fromCommit->commitBlock[tid]) { + stalls[tid].commit = true; + } + + if (fromCommit->commitUnblock[tid]) { + assert(stalls[tid].commit); + stalls[tid].commit = false; + } +} + +template <class Impl> +bool +DefaultDecode<Impl>::checkSignalsAndUpdate(unsigned tid) +{ + // Check if there's a squash signal, squash if there is. + // Check stall signals, block if necessary. + // If status was blocked + // Check if stall conditions have passed + // if so then go to unblocking + // If status was Squashing + // check if squashing is not high. Switch to running this cycle. + + // Update the per thread stall statuses. + readStallSignals(tid); + + // Check squash signals from commit. + if (fromCommit->commitInfo[tid].squash) { + + DPRINTF(Decode, "[tid:%u]: Squashing instructions due to squash " + "from commit.\n", tid); + + squash(tid); + + return true; + } + + // Check ROB squash signals from commit. + if (fromCommit->commitInfo[tid].robSquashing) { + DPRINTF(Decode, "[tid:%]: ROB is still squashing.\n",tid); + + // Continue to squash. + decodeStatus[tid] = Squashing; + + return true; + } + + if (checkStall(tid)) { + return block(tid); + } + + if (decodeStatus[tid] == Blocked) { + DPRINTF(Decode, "[tid:%u]: Done blocking, switching to unblocking.\n", + tid); + + decodeStatus[tid] = Unblocking; + + unblock(tid); + + return true; + } + + if (decodeStatus[tid] == Squashing) { + // Switch status to running if decode isn't being told to block or + // squash this cycle. + DPRINTF(Decode, "[tid:%u]: Done squashing, switching to running.\n", + tid); + + decodeStatus[tid] = Running; + + return false; + } + + // If we've reached this point, we have not gotten any signals that + // cause decode to change its status. Decode remains the same as before. + return false; +} + +template<class Impl> +void +DefaultDecode<Impl>::tick() +{ + wroteToTimeBuffer = false; + + bool status_change = false; + + toRenameIndex = 0; + + list<unsigned>::iterator threads = (*activeThreads).begin(); + + sortInsts(); + + //Check stall and squash signals. + while (threads != (*activeThreads).end()) { + unsigned tid = *threads++; + + DPRINTF(Decode,"Processing [tid:%i]\n",tid); + status_change = checkSignalsAndUpdate(tid) || status_change; + + decode(status_change, tid); + } + + if (status_change) { + updateStatus(); + } + + if (wroteToTimeBuffer) { + DPRINTF(Activity, "Activity this cycle.\n"); + + cpu->activityThisCycle(); + } +} + +template<class Impl> +void +DefaultDecode<Impl>::decode(bool &status_change, unsigned tid) +{ + // If status is Running or idle, + // call decodeInsts() + // If status is Unblocking, + // buffer any instructions coming from fetch + // continue trying to empty skid buffer + // check if stall conditions have passed + + if (decodeStatus[tid] == Blocked) { + ++decodeBlockedCycles; + } else if (decodeStatus[tid] == Squashing) { + ++decodeSquashCycles; + } + + // Decode should try to decode as many instructions as its bandwidth + // will allow, as long as it is not currently blocked. + if (decodeStatus[tid] == Running || + decodeStatus[tid] == Idle) { + DPRINTF(Decode, "[tid:%u] Not blocked, so attempting to run " + "stage.\n",tid); + + decodeInsts(tid); + } else if (decodeStatus[tid] == Unblocking) { + // Make sure that the skid buffer has something in it if the + // status is unblocking. + assert(!skidsEmpty()); + + // If the status was unblocking, then instructions from the skid + // buffer were used. Remove those instructions and handle + // the rest of unblocking. + decodeInsts(tid); + + if (fetchInstsValid()) { + // Add the current inputs to the skid buffer so they can be + // reprocessed when this stage unblocks. + skidInsert(tid); + } + + status_change = unblock(tid) || status_change; + } +} + +template <class Impl> +void +DefaultDecode<Impl>::decodeInsts(unsigned tid) +{ + // Instructions can come either from the skid buffer or the list of + // instructions coming from fetch, depending on decode's status. + int insts_available = decodeStatus[tid] == Unblocking ? + skidBuffer[tid].size() : insts[tid].size(); + + if (insts_available == 0) { + DPRINTF(Decode, "[tid:%u] Nothing to do, breaking out" + " early.\n",tid); + // Should I change the status to idle? + ++decodeIdleCycles; + return; + } else if (decodeStatus[tid] == Unblocking) { + DPRINTF(Decode, "[tid:%u] Unblocking, removing insts from skid " + "buffer.\n",tid); + ++decodeUnblockCycles; + } else if (decodeStatus[tid] == Running) { + ++decodeRunCycles; + } + + DynInstPtr inst; + + std::queue<DynInstPtr> + &insts_to_decode = decodeStatus[tid] == Unblocking ? + skidBuffer[tid] : insts[tid]; + + DPRINTF(Decode, "[tid:%u]: Sending instruction to rename.\n",tid); + + while (insts_available > 0 && toRenameIndex < decodeWidth) { + assert(!insts_to_decode.empty()); + + inst = insts_to_decode.front(); + + insts_to_decode.pop(); + + DPRINTF(Decode, "[tid:%u]: Processing instruction [sn:%lli] with " + "PC %#x\n", + tid, inst->seqNum, inst->readPC()); + + if (inst->isSquashed()) { + DPRINTF(Decode, "[tid:%u]: Instruction %i with PC %#x is " + "squashed, skipping.\n", + tid, inst->seqNum, inst->readPC()); + + ++decodeSquashedInsts; + + --insts_available; + + continue; + } + + // Also check if instructions have no source registers. Mark + // them as ready to issue at any time. Not sure if this check + // should exist here or at a later stage; however it doesn't matter + // too much for function correctness. + if (inst->numSrcRegs() == 0) { + inst->setCanIssue(); + } + + // This current instruction is valid, so add it into the decode + // queue. The next instruction may not be valid, so check to + // see if branches were predicted correctly. + toRename->insts[toRenameIndex] = inst; + + ++(toRename->size); + ++toRenameIndex; + ++decodeDecodedInsts; + --insts_available; + + // Ensure that if it was predicted as a branch, it really is a + // branch. + if (inst->predTaken() && !inst->isControl()) { + panic("Instruction predicted as a branch!"); + + ++decodeControlMispred; + + // Might want to set some sort of boolean and just do + // a check at the end + squash(inst, inst->threadNumber); + + break; + } + + // Go ahead and compute any PC-relative branches. + if (inst->isDirectCtrl() && inst->isUncondCtrl()) { + ++decodeBranchResolved; + + if (inst->branchTarget() != inst->readPredTarg()) { + ++decodeBranchMispred; + + // Might want to set some sort of boolean and just do + // a check at the end + squash(inst, inst->threadNumber); + inst->setPredTarg(inst->branchTarget()); + + break; + } + } + } + + // If we didn't process all instructions, then we will need to block + // and put all those instructions into the skid buffer. + if (!insts_to_decode.empty()) { + block(tid); + } + + // Record that decode has written to the time buffer for activity + // tracking. + if (toRenameIndex) { + wroteToTimeBuffer = true; + } +} diff --git a/src/cpu/o3/dep_graph.hh b/src/cpu/o3/dep_graph.hh new file mode 100644 index 000000000..3659b1a37 --- /dev/null +++ b/src/cpu/o3/dep_graph.hh @@ -0,0 +1,264 @@ +/* + * 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_O3_DEP_GRAPH_HH__ +#define __CPU_O3_DEP_GRAPH_HH__ + +#include "cpu/o3/comm.hh" + +/** Node in a linked list. */ +template <class DynInstPtr> +class DependencyEntry +{ + public: + DependencyEntry() + : inst(NULL), next(NULL) + { } + + DynInstPtr inst; + //Might want to include data about what arch. register the + //dependence is waiting on. + DependencyEntry<DynInstPtr> *next; +}; + +/** Array of linked list that maintains the dependencies between + * producing instructions and consuming instructions. Each linked + * list represents a single physical register, having the future + * producer of the register's value, and all consumers waiting on that + * value on the list. The head node of each linked list represents + * the producing instruction of that register. Instructions are put + * on the list upon reaching the IQ, and are removed from the list + * either when the producer completes, or the instruction is squashed. +*/ +template <class DynInstPtr> +class DependencyGraph +{ + public: + typedef DependencyEntry<DynInstPtr> DepEntry; + + /** Default construction. Must call resize() prior to use. */ + DependencyGraph() + : numEntries(0), memAllocCounter(0), nodesTraversed(0), nodesRemoved(0) + { } + + /** Resize the dependency graph to have num_entries registers. */ + void resize(int num_entries); + + /** Clears all of the linked lists. */ + void reset(); + + /** Inserts an instruction to be dependent on the given index. */ + void insert(PhysRegIndex idx, DynInstPtr &new_inst); + + /** Sets the producing instruction of a given register. */ + void setInst(PhysRegIndex idx, DynInstPtr &new_inst) + { dependGraph[idx].inst = new_inst; } + + /** Clears the producing instruction. */ + void clearInst(PhysRegIndex idx) + { dependGraph[idx].inst = NULL; } + + /** Removes an instruction from a single linked list. */ + void remove(PhysRegIndex idx, DynInstPtr &inst_to_remove); + + /** Removes and returns the newest dependent of a specific register. */ + DynInstPtr pop(PhysRegIndex idx); + + /** Checks if there are any dependents on a specific register. */ + bool empty(PhysRegIndex idx) { return !dependGraph[idx].next; } + + /** Debugging function to dump out the dependency graph. + */ + void dump(); + + private: + /** Array of linked lists. Each linked list is a list of all the + * instructions that depend upon a given register. The actual + * register's index is used to index into the graph; ie all + * instructions in flight that are dependent upon r34 will be + * in the linked list of dependGraph[34]. + */ + DepEntry *dependGraph; + + /** Number of linked lists; identical to the number of registers. */ + int numEntries; + + // Debug variable, remove when done testing. + unsigned memAllocCounter; + + public: + // Debug variable, remove when done testing. + uint64_t nodesTraversed; + // Debug variable, remove when done testing. + uint64_t nodesRemoved; +}; + +template <class DynInstPtr> +void +DependencyGraph<DynInstPtr>::resize(int num_entries) +{ + numEntries = num_entries; + dependGraph = new DepEntry[numEntries]; +} + +template <class DynInstPtr> +void +DependencyGraph<DynInstPtr>::reset() +{ + // Clear the dependency graph + DepEntry *curr; + DepEntry *prev; + + for (int i = 0; i < numEntries; ++i) { + curr = dependGraph[i].next; + + while (curr) { + memAllocCounter--; + + prev = curr; + curr = prev->next; + prev->inst = NULL; + + delete prev; + } + + if (dependGraph[i].inst) { + dependGraph[i].inst = NULL; + } + + dependGraph[i].next = NULL; + } +} + +template <class DynInstPtr> +void +DependencyGraph<DynInstPtr>::insert(PhysRegIndex idx, DynInstPtr &new_inst) +{ + //Add this new, dependent instruction at the head of the dependency + //chain. + + // First create the entry that will be added to the head of the + // dependency chain. + DepEntry *new_entry = new DepEntry; + new_entry->next = dependGraph[idx].next; + new_entry->inst = new_inst; + + // Then actually add it to the chain. + dependGraph[idx].next = new_entry; + + ++memAllocCounter; +} + + +template <class DynInstPtr> +void +DependencyGraph<DynInstPtr>::remove(PhysRegIndex idx, + DynInstPtr &inst_to_remove) +{ + DepEntry *prev = &dependGraph[idx]; + DepEntry *curr = dependGraph[idx].next; + + // Make sure curr isn't NULL. Because this instruction is being + // removed from a dependency list, it must have been placed there at + // an earlier time. The dependency chain should not be empty, + // unless the instruction dependent upon it is already ready. + if (curr == NULL) { + return; + } + + nodesRemoved++; + + // Find the instruction to remove within the dependency linked list. + while (curr->inst != inst_to_remove) { + prev = curr; + curr = curr->next; + nodesTraversed++; + + assert(curr != NULL); + } + + // Now remove this instruction from the list. + prev->next = curr->next; + + --memAllocCounter; + + // Could push this off to the destructor of DependencyEntry + curr->inst = NULL; + + delete curr; +} + +template <class DynInstPtr> +DynInstPtr +DependencyGraph<DynInstPtr>::pop(PhysRegIndex idx) +{ + DepEntry *node; + node = dependGraph[idx].next; + DynInstPtr inst = NULL; + if (node) { + inst = node->inst; + dependGraph[idx].next = node->next; + node->inst = NULL; + memAllocCounter--; + delete node; + } + return inst; +} + +template <class DynInstPtr> +void +DependencyGraph<DynInstPtr>::dump() +{ + DepEntry *curr; + + for (int i = 0; i < numEntries; ++i) + { + curr = &dependGraph[i]; + + if (curr->inst) { + cprintf("dependGraph[%i]: producer: %#x [sn:%lli] consumer: ", + i, curr->inst->readPC(), curr->inst->seqNum); + } else { + cprintf("dependGraph[%i]: No producer. consumer: ", i); + } + + while (curr->next != NULL) { + curr = curr->next; + + cprintf("%#x [sn:%lli] ", + curr->inst->readPC(), curr->inst->seqNum); + } + + cprintf("\n"); + } + cprintf("memAllocCounter: %i\n", memAllocCounter); +} + +#endif // __CPU_O3_DEP_GRAPH_HH__ diff --git a/src/cpu/o3/fetch.cc b/src/cpu/o3/fetch.cc new file mode 100644 index 000000000..5f52d0fca --- /dev/null +++ b/src/cpu/o3/fetch.cc @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#include "cpu/o3/alpha_dyn_inst.hh" +#include "cpu/o3/alpha_impl.hh" +#include "cpu/o3/fetch_impl.hh" + +template class DefaultFetch<AlphaSimpleImpl>; diff --git a/src/cpu/o3/fetch.hh b/src/cpu/o3/fetch.hh new file mode 100644 index 000000000..76b32de68 --- /dev/null +++ b/src/cpu/o3/fetch.hh @@ -0,0 +1,455 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#ifndef __CPU_O3_FETCH_HH__ +#define __CPU_O3_FETCH_HH__ + +#include "arch/utility.hh" +#include "base/statistics.hh" +#include "base/timebuf.hh" +#include "cpu/pc_event.hh" +#include "mem/packet.hh" +#include "mem/port.hh" +#include "sim/eventq.hh" + +class Sampler; + +/** + * DefaultFetch class handles both single threaded and SMT fetch. Its + * width is specified by the parameters; each cycle it tries to fetch + * that many instructions. It supports using a branch predictor to + * predict direction and targets. + * It supports the idling functionality of the CPU by indicating to + * the CPU when it is active and inactive. + */ +template <class Impl> +class DefaultFetch +{ + public: + /** Typedefs from Impl. */ + typedef typename Impl::CPUPol CPUPol; + typedef typename Impl::DynInst DynInst; + typedef typename Impl::DynInstPtr DynInstPtr; + typedef typename Impl::FullCPU FullCPU; + typedef typename Impl::Params Params; + + /** Typedefs from the CPU policy. */ + typedef typename CPUPol::BPredUnit BPredUnit; + typedef typename CPUPol::FetchStruct FetchStruct; + typedef typename CPUPol::TimeStruct TimeStruct; + + /** Typedefs from ISA. */ + typedef TheISA::MachInst MachInst; + typedef TheISA::ExtMachInst ExtMachInst; + + /** IcachePort class for DefaultFetch. Handles doing the + * communication with the cache/memory. + */ + class IcachePort : public Port + { + protected: + /** Pointer to fetch. */ + DefaultFetch<Impl> *fetch; + + public: + /** Default constructor. */ + IcachePort(DefaultFetch<Impl> *_fetch) + : Port(_fetch->name() + "-iport"), fetch(_fetch) + { } + + protected: + /** Atomic version of receive. Panics. */ + virtual Tick recvAtomic(PacketPtr pkt); + + /** Functional version of receive. Panics. */ + virtual void recvFunctional(PacketPtr pkt); + + /** Receives status change. Other than range changing, panics. */ + virtual void recvStatusChange(Status status); + + /** Returns the address ranges of this device. */ + virtual void getDeviceAddressRanges(AddrRangeList &resp, + AddrRangeList &snoop) + { resp.clear(); snoop.clear(); } + + /** Timing version of receive. Handles setting fetch to the + * proper status to start fetching. */ + virtual bool recvTiming(PacketPtr pkt); + + /** Handles doing a retry of a failed fetch. */ + virtual void recvRetry(); + }; + + public: + /** Overall fetch status. Used to determine if the CPU can + * deschedule itsef due to a lack of activity. + */ + enum FetchStatus { + Active, + Inactive + }; + + /** Individual thread status. */ + enum ThreadStatus { + Running, + Idle, + Squashing, + Blocked, + Fetching, + TrapPending, + QuiescePending, + SwitchOut, + IcacheWaitResponse, + IcacheWaitRetry, + IcacheAccessComplete + }; + + /** Fetching Policy, Add new policies here.*/ + enum FetchPriority { + SingleThread, + RoundRobin, + Branch, + IQ, + LSQ + }; + + private: + /** Fetch status. */ + FetchStatus _status; + + /** Per-thread status. */ + ThreadStatus fetchStatus[Impl::MaxThreads]; + + /** Fetch policy. */ + FetchPriority fetchPolicy; + + /** List that has the threads organized by priority. */ + std::list<unsigned> priorityList; + + public: + /** DefaultFetch constructor. */ + DefaultFetch(Params *params); + + /** Returns the name of fetch. */ + std::string name() const; + + /** Registers statistics. */ + void regStats(); + + /** Sets CPU pointer. */ + void setCPU(FullCPU *cpu_ptr); + + /** Sets the main backwards communication time buffer pointer. */ + void setTimeBuffer(TimeBuffer<TimeStruct> *time_buffer); + + /** Sets pointer to list of active threads. */ + void setActiveThreads(std::list<unsigned> *at_ptr); + + /** Sets pointer to time buffer used to communicate to the next stage. */ + void setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr); + + /** Initialize stage. */ + void initStage(); + + /** Processes cache completion event. */ + void processCacheCompletion(PacketPtr pkt); + + /** Begins the switch out of the fetch stage. */ + void switchOut(); + + /** Completes the switch out of the fetch stage. */ + void doSwitchOut(); + + /** Takes over from another CPU's thread. */ + void takeOverFrom(); + + /** Checks if the fetch stage is switched out. */ + bool isSwitchedOut() { return switchedOut; } + + /** Tells fetch to wake up from a quiesce instruction. */ + void wakeFromQuiesce(); + + private: + /** 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(); + + /** + * Looks up in the branch predictor to see if the next PC should be + * either next PC+=MachInst or a branch target. + * @param next_PC Next PC variable passed in by reference. It is + * expected to be set to the current PC; it will be updated with what + * the next PC will be. + * @return Whether or not a branch was predicted as taken. + */ + bool lookupAndUpdateNextPC(DynInstPtr &inst, Addr &next_PC); + + /** + * Fetches the cache line that contains fetch_PC. Returns any + * fault that happened. Puts the data into the class variable + * cacheData. + * @param fetch_PC The PC address that is being fetched from. + * @param ret_fault The fault reference that will be set to the result of + * the icache access. + * @param tid Thread id. + * @return Any fault that occured. + */ + bool fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid); + + /** Squashes a specific thread and resets the PC. */ + inline void doSquash(const Addr &new_PC, unsigned tid); + + /** Squashes a specific thread and resets the PC. Also tells the CPU to + * remove any instructions between fetch and decode that should be sqaushed. + */ + void squashFromDecode(const Addr &new_PC, const InstSeqNum &seq_num, + unsigned tid); + + /** Checks if a thread is stalled. */ + bool checkStall(unsigned tid) const; + + /** Updates overall fetch stage status; to be called at the end of each + * cycle. */ + FetchStatus updateFetchStatus(); + + public: + /** Squashes a specific thread and resets the PC. Also tells the CPU to + * remove any instructions that are not in the ROB. The source of this + * squash should be the commit stage. + */ + void squash(const Addr &new_PC, unsigned tid); + + /** Ticks the fetch stage, processing all inputs signals and fetching + * as many instructions as possible. + */ + void tick(); + + /** Checks all input signals and updates the status as necessary. + * @return: Returns if the status has changed due to input signals. + */ + bool checkSignalsAndUpdate(unsigned tid); + + /** Does the actual fetching of instructions and passing them on to the + * next stage. + * @param status_change fetch() sets this variable if there was a status + * change (ie switching to IcacheMissStall). + */ + void fetch(bool &status_change); + + /** Align a PC to the start of an I-cache block. */ + Addr icacheBlockAlignPC(Addr addr) + { + addr = TheISA::realPCToFetchPC(addr); + return (addr & ~(cacheBlkMask)); + } + + private: + /** Handles retrying the fetch access. */ + void recvRetry(); + + /** Returns the appropriate thread to fetch, given the fetch policy. */ + int getFetchingThread(FetchPriority &fetch_priority); + + /** Returns the appropriate thread to fetch using a round robin policy. */ + int roundRobin(); + + /** Returns the appropriate thread to fetch using the IQ count policy. */ + int iqCount(); + + /** Returns the appropriate thread to fetch using the LSQ count policy. */ + int lsqCount(); + + /** Returns the appropriate thread to fetch using the branch count policy. */ + int branchCount(); + + private: + /** Pointer to the FullCPU. */ + FullCPU *cpu; + + /** Time buffer interface. */ + TimeBuffer<TimeStruct> *timeBuffer; + + /** Wire to get decode's information from backwards time buffer. */ + typename TimeBuffer<TimeStruct>::wire fromDecode; + + /** Wire to get rename's information from backwards time buffer. */ + typename TimeBuffer<TimeStruct>::wire fromRename; + + /** Wire to get iew's information from backwards time buffer. */ + typename TimeBuffer<TimeStruct>::wire fromIEW; + + /** Wire to get commit's information from backwards time buffer. */ + typename TimeBuffer<TimeStruct>::wire fromCommit; + + /** Internal fetch instruction queue. */ + TimeBuffer<FetchStruct> *fetchQueue; + + //Might be annoying how this name is different than the queue. + /** Wire used to write any information heading to decode. */ + typename TimeBuffer<FetchStruct>::wire toDecode; + + MemObject *mem; + + /** Icache interface. */ + IcachePort *icachePort; + + /** BPredUnit. */ + BPredUnit branchPred; + + /** Per-thread fetch PC. */ + Addr PC[Impl::MaxThreads]; + + /** Per-thread next PC. */ + Addr nextPC[Impl::MaxThreads]; + + /** Memory request used to access cache. */ + RequestPtr memReq[Impl::MaxThreads]; + + /** Variable that tracks if fetch has written to the time buffer this + * cycle. Used to tell CPU if there is activity this cycle. + */ + bool wroteToTimeBuffer; + + /** Tracks how many instructions has been fetched this cycle. */ + int numInst; + + /** Source of possible stalls. */ + struct Stalls { + bool decode; + bool rename; + bool iew; + bool commit; + }; + + /** Tracks which stages are telling fetch to stall. */ + Stalls stalls[Impl::MaxThreads]; + + /** Decode to fetch delay, in ticks. */ + unsigned decodeToFetchDelay; + + /** Rename to fetch delay, in ticks. */ + unsigned renameToFetchDelay; + + /** IEW to fetch delay, in ticks. */ + unsigned iewToFetchDelay; + + /** Commit to fetch delay, in ticks. */ + unsigned commitToFetchDelay; + + /** The width of fetch in instructions. */ + unsigned fetchWidth; + + /** Is the cache blocked? If so no threads can access it. */ + bool cacheBlocked; + + /** The packet that is waiting to be retried. */ + PacketPtr retryPkt; + + /** The thread that is waiting on the cache to tell fetch to retry. */ + int retryTid; + + /** Cache block size. */ + int cacheBlkSize; + + /** Mask to get a cache block's address. */ + Addr cacheBlkMask; + + /** The cache line being fetched. */ + uint8_t *cacheData[Impl::MaxThreads]; + + /** Size of instructions. */ + int instSize; + + /** Icache stall statistics. */ + Counter lastIcacheStall[Impl::MaxThreads]; + + /** List of Active Threads */ + std::list<unsigned> *activeThreads; + + /** Number of threads. */ + unsigned numThreads; + + /** Number of threads that are actively fetching. */ + unsigned numFetchingThreads; + + /** Thread ID being fetched. */ + int threadFetched; + + /** Checks if there is an interrupt pending. If there is, fetch + * must stop once it is not fetching PAL instructions. + */ + bool interruptPending; + + /** Records if fetch is switched out. */ + bool switchedOut; + + // @todo: Consider making these vectors and tracking on a per thread basis. + /** Stat for total number of cycles stalled due to an icache miss. */ + Stats::Scalar<> icacheStallCycles; + /** Stat for total number of fetched instructions. */ + Stats::Scalar<> fetchedInsts; + Stats::Scalar<> fetchedBranches; + /** Stat for total number of predicted branches. */ + Stats::Scalar<> predictedBranches; + /** Stat for total number of cycles spent fetching. */ + Stats::Scalar<> fetchCycles; + /** Stat for total number of cycles spent squashing. */ + Stats::Scalar<> fetchSquashCycles; + /** Stat for total number of cycles spent blocked due to other stages in + * the pipeline. + */ + Stats::Scalar<> fetchIdleCycles; + /** Total number of cycles spent blocked. */ + Stats::Scalar<> fetchBlockedCycles; + /** Total number of cycles spent in any other state. */ + Stats::Scalar<> fetchMiscStallCycles; + /** Stat for total number of fetched cache lines. */ + Stats::Scalar<> fetchedCacheLines; + /** Total number of outstanding icache accesses that were dropped + * due to a squash. + */ + Stats::Scalar<> fetchIcacheSquashes; + /** Distribution of number of instructions fetched each cycle. */ + Stats::Distribution<> fetchNisnDist; + /** Rate of how often fetch was idle. */ + Stats::Formula idleRate; + /** Number of branch fetches per cycle. */ + Stats::Formula branchRate; + /** Number of instruction fetched per cycle. */ + Stats::Formula fetchRate; +}; + +#endif //__CPU_O3_FETCH_HH__ diff --git a/src/cpu/o3/fetch_impl.hh b/src/cpu/o3/fetch_impl.hh new file mode 100644 index 000000000..c0a2a5d09 --- /dev/null +++ b/src/cpu/o3/fetch_impl.hh @@ -0,0 +1,1261 @@ +/* + * 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 "arch/isa_traits.hh" +#include "arch/utility.hh" +#include "cpu/checker/cpu.hh" +#include "cpu/exetrace.hh" +#include "cpu/o3/fetch.hh" +#include "mem/packet.hh" +#include "mem/request.hh" +#include "sim/byteswap.hh" +#include "sim/host.hh" +#include "sim/root.hh" + +#if FULL_SYSTEM +#include "arch/tlb.hh" +#include "arch/vtophys.hh" +#include "base/remote_gdb.hh" +#include "sim/system.hh" +#endif // FULL_SYSTEM + +#include <algorithm> + +using namespace std; +using namespace TheISA; + +template<class Impl> +Tick +DefaultFetch<Impl>::IcachePort::recvAtomic(PacketPtr pkt) +{ + panic("DefaultFetch doesn't expect recvAtomic callback!"); + return curTick; +} + +template<class Impl> +void +DefaultFetch<Impl>::IcachePort::recvFunctional(PacketPtr pkt) +{ + panic("DefaultFetch doesn't expect recvFunctional callback!"); +} + +template<class Impl> +void +DefaultFetch<Impl>::IcachePort::recvStatusChange(Status status) +{ + if (status == RangeChange) + return; + + panic("DefaultFetch doesn't expect recvStatusChange callback!"); +} + +template<class Impl> +bool +DefaultFetch<Impl>::IcachePort::recvTiming(Packet *pkt) +{ + fetch->processCacheCompletion(pkt); + return true; +} + +template<class Impl> +void +DefaultFetch<Impl>::IcachePort::recvRetry() +{ + fetch->recvRetry(); +} + +template<class Impl> +DefaultFetch<Impl>::DefaultFetch(Params *params) + : mem(params->mem), + branchPred(params), + decodeToFetchDelay(params->decodeToFetchDelay), + renameToFetchDelay(params->renameToFetchDelay), + iewToFetchDelay(params->iewToFetchDelay), + commitToFetchDelay(params->commitToFetchDelay), + fetchWidth(params->fetchWidth), + cacheBlocked(false), + retryPkt(NULL), + retryTid(-1), + numThreads(params->numberOfThreads), + numFetchingThreads(params->smtNumFetchingThreads), + interruptPending(false), + switchedOut(false) +{ + if (numThreads > Impl::MaxThreads) + fatal("numThreads is not a valid value\n"); + + DPRINTF(Fetch, "Fetch constructor called\n"); + + // Set fetch stage's status to inactive. + _status = Inactive; + + string policy = params->smtFetchPolicy; + + // Convert string to lowercase + std::transform(policy.begin(), policy.end(), policy.begin(), + (int(*)(int)) tolower); + + // Figure out fetch policy + if (policy == "singlethread") { + fetchPolicy = SingleThread; + } else if (policy == "roundrobin") { + fetchPolicy = RoundRobin; + DPRINTF(Fetch, "Fetch policy set to Round Robin\n"); + } else if (policy == "branch") { + fetchPolicy = Branch; + DPRINTF(Fetch, "Fetch policy set to Branch Count\n"); + } else if (policy == "iqcount") { + fetchPolicy = IQ; + DPRINTF(Fetch, "Fetch policy set to IQ count\n"); + } else if (policy == "lsqcount") { + fetchPolicy = LSQ; + DPRINTF(Fetch, "Fetch policy set to LSQ count\n"); + } else { + fatal("Invalid Fetch Policy. Options Are: {SingleThread," + " RoundRobin,LSQcount,IQcount}\n"); + } + + // Size of cache block. + cacheBlkSize = 64; + + // Create mask to get rid of offset bits. + cacheBlkMask = (cacheBlkSize - 1); + + for (int tid=0; tid < numThreads; tid++) { + + fetchStatus[tid] = Running; + + priorityList.push_back(tid); + + memReq[tid] = NULL; + + // Create space to store a cache line. + cacheData[tid] = new uint8_t[cacheBlkSize]; + + stalls[tid].decode = 0; + stalls[tid].rename = 0; + stalls[tid].iew = 0; + stalls[tid].commit = 0; + } + + // Get the size of an instruction. + instSize = sizeof(MachInst); +} + +template <class Impl> +std::string +DefaultFetch<Impl>::name() const +{ + return cpu->name() + ".fetch"; +} + +template <class Impl> +void +DefaultFetch<Impl>::regStats() +{ + icacheStallCycles + .name(name() + ".icacheStallCycles") + .desc("Number of cycles fetch is stalled on an Icache miss") + .prereq(icacheStallCycles); + + fetchedInsts + .name(name() + ".Insts") + .desc("Number of instructions fetch has processed") + .prereq(fetchedInsts); + + fetchedBranches + .name(name() + ".Branches") + .desc("Number of branches that fetch encountered") + .prereq(fetchedBranches); + + predictedBranches + .name(name() + ".predictedBranches") + .desc("Number of branches that fetch has predicted taken") + .prereq(predictedBranches); + + fetchCycles + .name(name() + ".Cycles") + .desc("Number of cycles fetch has run and was not squashing or" + " blocked") + .prereq(fetchCycles); + + fetchSquashCycles + .name(name() + ".SquashCycles") + .desc("Number of cycles fetch has spent squashing") + .prereq(fetchSquashCycles); + + fetchIdleCycles + .name(name() + ".IdleCycles") + .desc("Number of cycles fetch was idle") + .prereq(fetchIdleCycles); + + fetchBlockedCycles + .name(name() + ".BlockedCycles") + .desc("Number of cycles fetch has spent blocked") + .prereq(fetchBlockedCycles); + + fetchedCacheLines + .name(name() + ".CacheLines") + .desc("Number of cache lines fetched") + .prereq(fetchedCacheLines); + + fetchMiscStallCycles + .name(name() + ".MiscStallCycles") + .desc("Number of cycles fetch has spent waiting on interrupts, or " + "bad addresses, or out of MSHRs") + .prereq(fetchMiscStallCycles); + + fetchIcacheSquashes + .name(name() + ".IcacheSquashes") + .desc("Number of outstanding Icache misses that were squashed") + .prereq(fetchIcacheSquashes); + + fetchNisnDist + .init(/* base value */ 0, + /* last value */ fetchWidth, + /* bucket size */ 1) + .name(name() + ".rateDist") + .desc("Number of instructions fetched each cycle (Total)") + .flags(Stats::pdf); + + idleRate + .name(name() + ".idleRate") + .desc("Percent of cycles fetch was idle") + .prereq(idleRate); + idleRate = fetchIdleCycles * 100 / cpu->numCycles; + + branchRate + .name(name() + ".branchRate") + .desc("Number of branch fetches per cycle") + .flags(Stats::total); + branchRate = fetchedBranches / cpu->numCycles; + + fetchRate + .name(name() + ".rate") + .desc("Number of inst fetches per cycle") + .flags(Stats::total); + fetchRate = fetchedInsts / cpu->numCycles; + + branchPred.regStats(); +} + +template<class Impl> +void +DefaultFetch<Impl>::setCPU(FullCPU *cpu_ptr) +{ + DPRINTF(Fetch, "Setting the CPU pointer.\n"); + cpu = cpu_ptr; + + // Name is finally available, so create the port. + icachePort = new IcachePort(this); + + Port *mem_dport = mem->getPort(""); + icachePort->setPeer(mem_dport); + mem_dport->setPeer(icachePort); + + if (cpu->checker) { + cpu->checker->setIcachePort(icachePort); + } + + // Fetch needs to start fetching instructions at the very beginning, + // so it must start up in active state. + switchToActive(); +} + +template<class Impl> +void +DefaultFetch<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *time_buffer) +{ + DPRINTF(Fetch, "Setting the time buffer pointer.\n"); + timeBuffer = time_buffer; + + // Create wires to get information from proper places in time buffer. + fromDecode = timeBuffer->getWire(-decodeToFetchDelay); + fromRename = timeBuffer->getWire(-renameToFetchDelay); + fromIEW = timeBuffer->getWire(-iewToFetchDelay); + fromCommit = timeBuffer->getWire(-commitToFetchDelay); +} + +template<class Impl> +void +DefaultFetch<Impl>::setActiveThreads(list<unsigned> *at_ptr) +{ + DPRINTF(Fetch, "Setting active threads list pointer.\n"); + activeThreads = at_ptr; +} + +template<class Impl> +void +DefaultFetch<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr) +{ + DPRINTF(Fetch, "Setting the fetch queue pointer.\n"); + fetchQueue = fq_ptr; + + // Create wire to write information to proper place in fetch queue. + toDecode = fetchQueue->getWire(0); +} + +template<class Impl> +void +DefaultFetch<Impl>::initStage() +{ + // Setup PC and nextPC with initial state. + for (int tid = 0; tid < numThreads; tid++) { + PC[tid] = cpu->readPC(tid); + nextPC[tid] = cpu->readNextPC(tid); + } +} + +template<class Impl> +void +DefaultFetch<Impl>::processCacheCompletion(PacketPtr pkt) +{ + unsigned tid = pkt->req->getThreadNum(); + + DPRINTF(Fetch, "[tid:%u] Waking up from cache miss.\n",tid); + + // Only change the status if it's still waiting on the icache access + // to return. + if (fetchStatus[tid] != IcacheWaitResponse || + pkt->req != memReq[tid] || + isSwitchedOut()) { + ++fetchIcacheSquashes; + delete pkt->req; + delete pkt; + memReq[tid] = NULL; + return; + } + + // Wake up the CPU (if it went to sleep and was waiting on this completion + // event). + cpu->wakeCPU(); + + DPRINTF(Activity, "[tid:%u] Activating fetch due to cache completion\n", + tid); + + switchToActive(); + + // Only switch to IcacheAccessComplete if we're not stalled as well. + if (checkStall(tid)) { + fetchStatus[tid] = Blocked; + } else { + fetchStatus[tid] = IcacheAccessComplete; + } + + // Reset the mem req to NULL. + delete pkt->req; + delete pkt; + memReq[tid] = NULL; +} + +template <class Impl> +void +DefaultFetch<Impl>::switchOut() +{ + // Fetch is ready to switch out at any time. + switchedOut = true; + cpu->signalSwitched(); +} + +template <class Impl> +void +DefaultFetch<Impl>::doSwitchOut() +{ + // Branch predictor needs to have its state cleared. + branchPred.switchOut(); +} + +template <class Impl> +void +DefaultFetch<Impl>::takeOverFrom() +{ + // Reset all state + for (int i = 0; i < Impl::MaxThreads; ++i) { + stalls[i].decode = 0; + stalls[i].rename = 0; + stalls[i].iew = 0; + stalls[i].commit = 0; + PC[i] = cpu->readPC(i); + nextPC[i] = cpu->readNextPC(i); + fetchStatus[i] = Running; + } + numInst = 0; + wroteToTimeBuffer = false; + _status = Inactive; + switchedOut = false; + branchPred.takeOverFrom(); +} + +template <class Impl> +void +DefaultFetch<Impl>::wakeFromQuiesce() +{ + DPRINTF(Fetch, "Waking up from quiesce\n"); + // Hopefully this is safe + // @todo: Allow other threads to wake from quiesce. + fetchStatus[0] = Running; +} + +template <class Impl> +inline void +DefaultFetch<Impl>::switchToActive() +{ + if (_status == Inactive) { + DPRINTF(Activity, "Activating stage.\n"); + + cpu->activateStage(FullCPU::FetchIdx); + + _status = Active; + } +} + +template <class Impl> +inline void +DefaultFetch<Impl>::switchToInactive() +{ + if (_status == Active) { + DPRINTF(Activity, "Deactivating stage.\n"); + + cpu->deactivateStage(FullCPU::FetchIdx); + + _status = Inactive; + } +} + +template <class Impl> +bool +DefaultFetch<Impl>::lookupAndUpdateNextPC(DynInstPtr &inst, Addr &next_PC) +{ + // Do branch prediction check here. + // A bit of a misnomer...next_PC is actually the current PC until + // this function updates it. + bool predict_taken; + + if (!inst->isControl()) { + next_PC = next_PC + instSize; + inst->setPredTarg(next_PC); + return false; + } + + predict_taken = branchPred.predict(inst, next_PC, inst->threadNumber); + + ++fetchedBranches; + + if (predict_taken) { + ++predictedBranches; + } + + return predict_taken; +} + +template <class Impl> +bool +DefaultFetch<Impl>::fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid) +{ + Fault fault = NoFault; + +#if FULL_SYSTEM + // Flag to say whether or not address is physical addr. + unsigned flags = cpu->inPalMode(fetch_PC) ? PHYSICAL : 0; +#else + unsigned flags = 0; +#endif // FULL_SYSTEM + + if (cacheBlocked || (interruptPending && flags == 0) || switchedOut) { + // Hold off fetch from getting new instructions when: + // Cache is blocked, or + // while an interrupt is pending and we're not in PAL mode, or + // fetch is switched out. + return false; + } + + // Align the fetch PC so it's at the start of a cache block. + fetch_PC = icacheBlockAlignPC(fetch_PC); + + // Setup the memReq to do a read of the first instruction's address. + // Set the appropriate read size and flags as well. + // Build request here. + RequestPtr mem_req = new Request(tid, fetch_PC, cacheBlkSize, flags, + fetch_PC, cpu->readCpuId(), tid); + + memReq[tid] = mem_req; + + // Translate the instruction request. + fault = cpu->translateInstReq(mem_req, cpu->thread[tid]); + + // In the case of faults, the fetch stage may need to stall and wait + // for the ITB miss to be handled. + + // If translation was successful, attempt to read the first + // instruction. + if (fault == NoFault) { +#if 0 + if (cpu->system->memctrl->badaddr(memReq[tid]->paddr) || + memReq[tid]->flags & UNCACHEABLE) { + DPRINTF(Fetch, "Fetch: Bad address %#x (hopefully on a " + "misspeculating path)!", + memReq[tid]->paddr); + ret_fault = TheISA::genMachineCheckFault(); + return false; + } +#endif + + // Build packet here. + PacketPtr data_pkt = new Packet(mem_req, + Packet::ReadReq, Packet::Broadcast); + data_pkt->dataStatic(cacheData[tid]); + + DPRINTF(Fetch, "Fetch: Doing instruction read.\n"); + + fetchedCacheLines++; + + // Now do the timing access to see whether or not the instruction + // exists within the cache. + if (!icachePort->sendTiming(data_pkt)) { + assert(retryPkt == NULL); + assert(retryTid == -1); + DPRINTF(Fetch, "[tid:%i] Out of MSHRs!\n", tid); + fetchStatus[tid] = IcacheWaitRetry; + retryPkt = data_pkt; + retryTid = tid; + cacheBlocked = true; + return false; + } + + DPRINTF(Fetch, "Doing cache access.\n"); + + lastIcacheStall[tid] = curTick; + + DPRINTF(Activity, "[tid:%i]: Activity: Waiting on I-cache " + "response.\n", tid); + + fetchStatus[tid] = IcacheWaitResponse; + } else { + delete mem_req; + memReq[tid] = NULL; + } + + ret_fault = fault; + return true; +} + +template <class Impl> +inline void +DefaultFetch<Impl>::doSquash(const Addr &new_PC, unsigned tid) +{ + DPRINTF(Fetch, "[tid:%i]: Squashing, setting PC to: %#x.\n", + tid, new_PC); + + PC[tid] = new_PC; + nextPC[tid] = new_PC + instSize; + + // Clear the icache miss if it's outstanding. + if (fetchStatus[tid] == IcacheWaitResponse) { + DPRINTF(Fetch, "[tid:%i]: Squashing outstanding Icache miss.\n", + tid); + memReq[tid] = NULL; + } + + // Get rid of the retrying packet if it was from this thread. + if (retryTid == tid) { + assert(cacheBlocked); + cacheBlocked = false; + retryTid = -1; + retryPkt = NULL; + delete retryPkt->req; + delete retryPkt; + } + + fetchStatus[tid] = Squashing; + + ++fetchSquashCycles; +} + +template<class Impl> +void +DefaultFetch<Impl>::squashFromDecode(const Addr &new_PC, + const InstSeqNum &seq_num, + unsigned tid) +{ + DPRINTF(Fetch, "[tid:%i]: Squashing from decode.\n",tid); + + doSquash(new_PC, tid); + + // Tell the CPU to remove any instructions that are in flight between + // fetch and decode. + cpu->removeInstsUntil(seq_num, tid); +} + +template<class Impl> +bool +DefaultFetch<Impl>::checkStall(unsigned tid) const +{ + bool ret_val = false; + + if (cpu->contextSwitch) { + DPRINTF(Fetch,"[tid:%i]: Stalling for a context switch.\n",tid); + ret_val = true; + } else if (stalls[tid].decode) { + DPRINTF(Fetch,"[tid:%i]: Stall from Decode stage detected.\n",tid); + ret_val = true; + } else if (stalls[tid].rename) { + DPRINTF(Fetch,"[tid:%i]: Stall from Rename stage detected.\n",tid); + ret_val = true; + } else if (stalls[tid].iew) { + DPRINTF(Fetch,"[tid:%i]: Stall from IEW stage detected.\n",tid); + ret_val = true; + } else if (stalls[tid].commit) { + DPRINTF(Fetch,"[tid:%i]: Stall from Commit stage detected.\n",tid); + ret_val = true; + } + + return ret_val; +} + +template<class Impl> +typename DefaultFetch<Impl>::FetchStatus +DefaultFetch<Impl>::updateFetchStatus() +{ + //Check Running + list<unsigned>::iterator threads = (*activeThreads).begin(); + + while (threads != (*activeThreads).end()) { + + unsigned tid = *threads++; + + if (fetchStatus[tid] == Running || + fetchStatus[tid] == Squashing || + fetchStatus[tid] == IcacheAccessComplete) { + + if (_status == Inactive) { + DPRINTF(Activity, "[tid:%i]: Activating stage.\n",tid); + + if (fetchStatus[tid] == IcacheAccessComplete) { + DPRINTF(Activity, "[tid:%i]: Activating fetch due to cache" + "completion\n",tid); + } + + cpu->activateStage(FullCPU::FetchIdx); + } + + return Active; + } + } + + // Stage is switching from active to inactive, notify CPU of it. + if (_status == Active) { + DPRINTF(Activity, "Deactivating stage.\n"); + + cpu->deactivateStage(FullCPU::FetchIdx); + } + + return Inactive; +} + +template <class Impl> +void +DefaultFetch<Impl>::squash(const Addr &new_PC, unsigned tid) +{ + DPRINTF(Fetch, "[tid:%u]: Squash from commit.\n",tid); + + doSquash(new_PC, tid); + + // Tell the CPU to remove any instructions that are not in the ROB. + cpu->removeInstsNotInROB(tid); +} + +template <class Impl> +void +DefaultFetch<Impl>::tick() +{ + list<unsigned>::iterator threads = (*activeThreads).begin(); + bool status_change = false; + + wroteToTimeBuffer = false; + + while (threads != (*activeThreads).end()) { + unsigned tid = *threads++; + + // Check the signals for each thread to determine the proper status + // for each thread. + bool updated_status = checkSignalsAndUpdate(tid); + status_change = status_change || updated_status; + } + + DPRINTF(Fetch, "Running stage.\n"); + + // Reset the number of the instruction we're fetching. + numInst = 0; + + if (fromCommit->commitInfo[0].interruptPending) { + interruptPending = true; + } + if (fromCommit->commitInfo[0].clearInterrupt) { + interruptPending = false; + } + + for (threadFetched = 0; threadFetched < numFetchingThreads; + threadFetched++) { + // Fetch each of the actively fetching threads. + fetch(status_change); + } + + // Record number of instructions fetched this cycle for distribution. + fetchNisnDist.sample(numInst); + + if (status_change) { + // Change the fetch stage status if there was a status change. + _status = updateFetchStatus(); + } + + // If there was activity this cycle, inform the CPU of it. + if (wroteToTimeBuffer || cpu->contextSwitch) { + DPRINTF(Activity, "Activity this cycle.\n"); + + cpu->activityThisCycle(); + } +} + +template <class Impl> +bool +DefaultFetch<Impl>::checkSignalsAndUpdate(unsigned tid) +{ + // Update the per thread stall statuses. + if (fromDecode->decodeBlock[tid]) { + stalls[tid].decode = true; + } + + if (fromDecode->decodeUnblock[tid]) { + assert(stalls[tid].decode); + assert(!fromDecode->decodeBlock[tid]); + stalls[tid].decode = false; + } + + if (fromRename->renameBlock[tid]) { + stalls[tid].rename = true; + } + + if (fromRename->renameUnblock[tid]) { + assert(stalls[tid].rename); + assert(!fromRename->renameBlock[tid]); + stalls[tid].rename = false; + } + + if (fromIEW->iewBlock[tid]) { + stalls[tid].iew = true; + } + + if (fromIEW->iewUnblock[tid]) { + assert(stalls[tid].iew); + assert(!fromIEW->iewBlock[tid]); + stalls[tid].iew = false; + } + + if (fromCommit->commitBlock[tid]) { + stalls[tid].commit = true; + } + + if (fromCommit->commitUnblock[tid]) { + assert(stalls[tid].commit); + assert(!fromCommit->commitBlock[tid]); + stalls[tid].commit = false; + } + + // Check squash signals from commit. + if (fromCommit->commitInfo[tid].squash) { + + DPRINTF(Fetch, "[tid:%u]: Squashing instructions due to squash " + "from commit.\n",tid); + + // In any case, squash. + squash(fromCommit->commitInfo[tid].nextPC,tid); + + // Also check if there's a mispredict that happened. + if (fromCommit->commitInfo[tid].branchMispredict) { + branchPred.squash(fromCommit->commitInfo[tid].doneSeqNum, + fromCommit->commitInfo[tid].nextPC, + fromCommit->commitInfo[tid].branchTaken, + tid); + } else { + branchPred.squash(fromCommit->commitInfo[tid].doneSeqNum, + tid); + } + + return true; + } else if (fromCommit->commitInfo[tid].doneSeqNum) { + // Update the branch predictor if it wasn't a squashed instruction + // that was broadcasted. + branchPred.update(fromCommit->commitInfo[tid].doneSeqNum, tid); + } + + // Check ROB squash signals from commit. + if (fromCommit->commitInfo[tid].robSquashing) { + DPRINTF(Fetch, "[tid:%u]: ROB is still squashing Thread %u.\n", tid); + + // Continue to squash. + fetchStatus[tid] = Squashing; + + return true; + } + + // Check squash signals from decode. + if (fromDecode->decodeInfo[tid].squash) { + DPRINTF(Fetch, "[tid:%u]: Squashing instructions due to squash " + "from decode.\n",tid); + + // Update the branch predictor. + if (fromDecode->decodeInfo[tid].branchMispredict) { + branchPred.squash(fromDecode->decodeInfo[tid].doneSeqNum, + fromDecode->decodeInfo[tid].nextPC, + fromDecode->decodeInfo[tid].branchTaken, + tid); + } else { + branchPred.squash(fromDecode->decodeInfo[tid].doneSeqNum, + tid); + } + + if (fetchStatus[tid] != Squashing) { + // Squash unless we're already squashing + squashFromDecode(fromDecode->decodeInfo[tid].nextPC, + fromDecode->decodeInfo[tid].doneSeqNum, + tid); + + return true; + } + } + + if (checkStall(tid) && fetchStatus[tid] != IcacheWaitResponse) { + DPRINTF(Fetch, "[tid:%i]: Setting to blocked\n",tid); + + fetchStatus[tid] = Blocked; + + return true; + } + + if (fetchStatus[tid] == Blocked || + fetchStatus[tid] == Squashing) { + // Switch status to running if fetch isn't being told to block or + // squash this cycle. + DPRINTF(Fetch, "[tid:%i]: Done squashing, switching to running.\n", + tid); + + fetchStatus[tid] = Running; + + return true; + } + + // If we've reached this point, we have not gotten any signals that + // cause fetch to change its status. Fetch remains the same as before. + return false; +} + +template<class Impl> +void +DefaultFetch<Impl>::fetch(bool &status_change) +{ + ////////////////////////////////////////// + // Start actual fetch + ////////////////////////////////////////// + int tid = getFetchingThread(fetchPolicy); + + if (tid == -1) { + DPRINTF(Fetch,"There are no more threads available to fetch from.\n"); + + // Breaks looping condition in tick() + threadFetched = numFetchingThreads; + return; + } + + // The current PC. + Addr &fetch_PC = PC[tid]; + + // Fault code for memory access. + Fault fault = NoFault; + + // If returning from the delay of a cache miss, then update the status + // to running, otherwise do the cache access. Possibly move this up + // to tick() function. + if (fetchStatus[tid] == IcacheAccessComplete) { + DPRINTF(Fetch, "[tid:%i]: Icache miss is complete.\n", + tid); + + fetchStatus[tid] = Running; + status_change = true; + } else if (fetchStatus[tid] == Running) { + DPRINTF(Fetch, "[tid:%i]: Attempting to translate and read " + "instruction, starting at PC %08p.\n", + tid, fetch_PC); + + bool fetch_success = fetchCacheLine(fetch_PC, fault, tid); + if (!fetch_success) { + ++fetchMiscStallCycles; + return; + } + } else { + if (fetchStatus[tid] == Idle) { + ++fetchIdleCycles; + } else if (fetchStatus[tid] == Blocked) { + ++fetchBlockedCycles; + } else if (fetchStatus[tid] == Squashing) { + ++fetchSquashCycles; + } else if (fetchStatus[tid] == IcacheWaitResponse) { + ++icacheStallCycles; + } + + // Status is Idle, Squashing, Blocked, or IcacheWaitResponse, so + // fetch should do nothing. + return; + } + + ++fetchCycles; + + // If we had a stall due to an icache miss, then return. + if (fetchStatus[tid] == IcacheWaitResponse) { + ++icacheStallCycles; + status_change = true; + return; + } + + Addr next_PC = fetch_PC; + InstSeqNum inst_seq; + MachInst inst; + ExtMachInst ext_inst; + // @todo: Fix this hack. + unsigned offset = (fetch_PC & cacheBlkMask) & ~3; + + if (fault == NoFault) { + // If the read of the first instruction was successful, then grab the + // instructions from the rest of the cache line and put them into the + // queue heading to decode. + + DPRINTF(Fetch, "[tid:%i]: Adding instructions to queue to " + "decode.\n",tid); + + // Need to keep track of whether or not a predicted branch + // ended this fetch block. + bool predicted_branch = false; + + for (; + offset < cacheBlkSize && + numInst < fetchWidth && + !predicted_branch; + ++numInst) { + + // Get a sequence number. + inst_seq = cpu->getAndIncrementInstSeq(); + + // Make sure this is a valid index. + assert(offset <= cacheBlkSize - instSize); + + // Get the instruction from the array of the cache line. + inst = gtoh(*reinterpret_cast<MachInst *> + (&cacheData[tid][offset])); + + ext_inst = TheISA::makeExtMI(inst, fetch_PC); + + // Create a new DynInst from the instruction fetched. + DynInstPtr instruction = new DynInst(ext_inst, fetch_PC, + next_PC, + inst_seq, cpu); + instruction->setThread(tid); + + instruction->setASID(tid); + + instruction->setState(cpu->thread[tid]); + + DPRINTF(Fetch, "[tid:%i]: Instruction PC %#x created " + "[sn:%lli]\n", + tid, instruction->readPC(), inst_seq); + + DPRINTF(Fetch, "[tid:%i]: Instruction is: %s\n", + tid, instruction->staticInst->disassemble(fetch_PC)); + + instruction->traceData = + Trace::getInstRecord(curTick, cpu->tcBase(tid), cpu, + instruction->staticInst, + instruction->readPC(),tid); + + predicted_branch = lookupAndUpdateNextPC(instruction, next_PC); + + // Add instruction to the CPU's list of instructions. + instruction->setInstListIt(cpu->addInst(instruction)); + + // Write the instruction to the first slot in the queue + // that heads to decode. + toDecode->insts[numInst] = instruction; + + toDecode->size++; + + // Increment stat of fetched instructions. + ++fetchedInsts; + + // Move to the next instruction, unless we have a branch. + fetch_PC = next_PC; + + if (instruction->isQuiesce()) { + warn("%lli: Quiesce instruction encountered, halting fetch!", + curTick); + fetchStatus[tid] = QuiescePending; + ++numInst; + status_change = true; + break; + } + + offset+= instSize; + } + } + + if (numInst > 0) { + wroteToTimeBuffer = true; + } + + // Now that fetching is completed, update the PC to signify what the next + // cycle will be. + if (fault == NoFault) { + DPRINTF(Fetch, "[tid:%i]: Setting PC to %08p.\n",tid, next_PC); + + PC[tid] = next_PC; + nextPC[tid] = next_PC + instSize; + } else { + // We shouldn't be in an icache miss and also have a fault (an ITB + // miss) + if (fetchStatus[tid] == IcacheWaitResponse) { + panic("Fetch should have exited prior to this!"); + } + + // Send the fault to commit. This thread will not do anything + // until commit handles the fault. The only other way it can + // wake up is if a squash comes along and changes the PC. +#if FULL_SYSTEM + assert(numInst != fetchWidth); + // Get a sequence number. + inst_seq = cpu->getAndIncrementInstSeq(); + // We will use a nop in order to carry the fault. + ext_inst = TheISA::NoopMachInst; + + // Create a new DynInst from the dummy nop. + DynInstPtr instruction = new DynInst(ext_inst, fetch_PC, + next_PC, + inst_seq, cpu); + instruction->setPredTarg(next_PC + instSize); + instruction->setThread(tid); + + instruction->setASID(tid); + + instruction->setState(cpu->thread[tid]); + + instruction->traceData = NULL; + + instruction->setInstListIt(cpu->addInst(instruction)); + + instruction->fault = fault; + + toDecode->insts[numInst] = instruction; + toDecode->size++; + + DPRINTF(Fetch, "[tid:%i]: Blocked, need to handle the trap.\n",tid); + + fetchStatus[tid] = TrapPending; + status_change = true; + + warn("%lli fault (%d) detected @ PC %08p", curTick, fault, PC[tid]); +#else // !FULL_SYSTEM + warn("%lli fault (%d) detected @ PC %08p", curTick, fault, PC[tid]); +#endif // FULL_SYSTEM + } +} + +template<class Impl> +void +DefaultFetch<Impl>::recvRetry() +{ + assert(cacheBlocked); + if (retryPkt != NULL) { + assert(retryTid != -1); + assert(fetchStatus[retryTid] == IcacheWaitRetry); + + if (icachePort->sendTiming(retryPkt)) { + fetchStatus[retryTid] = IcacheWaitResponse; + retryPkt = NULL; + retryTid = -1; + cacheBlocked = false; + } + } else { + assert(retryTid == -1); + // Access has been squashed since it was sent out. Just clear + // the cache being blocked. + cacheBlocked = false; + } +} + +/////////////////////////////////////// +// // +// SMT FETCH POLICY MAINTAINED HERE // +// // +/////////////////////////////////////// +template<class Impl> +int +DefaultFetch<Impl>::getFetchingThread(FetchPriority &fetch_priority) +{ + if (numThreads > 1) { + switch (fetch_priority) { + + case SingleThread: + return 0; + + case RoundRobin: + return roundRobin(); + + case IQ: + return iqCount(); + + case LSQ: + return lsqCount(); + + case Branch: + return branchCount(); + + default: + return -1; + } + } else { + int tid = *((*activeThreads).begin()); + + if (fetchStatus[tid] == Running || + fetchStatus[tid] == IcacheAccessComplete || + fetchStatus[tid] == Idle) { + return tid; + } else { + return -1; + } + } + +} + + +template<class Impl> +int +DefaultFetch<Impl>::roundRobin() +{ + list<unsigned>::iterator pri_iter = priorityList.begin(); + list<unsigned>::iterator end = priorityList.end(); + + int high_pri; + + while (pri_iter != end) { + high_pri = *pri_iter; + + assert(high_pri <= numThreads); + + if (fetchStatus[high_pri] == Running || + fetchStatus[high_pri] == IcacheAccessComplete || + fetchStatus[high_pri] == Idle) { + + priorityList.erase(pri_iter); + priorityList.push_back(high_pri); + + return high_pri; + } + + pri_iter++; + } + + return -1; +} + +template<class Impl> +int +DefaultFetch<Impl>::iqCount() +{ + priority_queue<unsigned> PQ; + + list<unsigned>::iterator threads = (*activeThreads).begin(); + + while (threads != (*activeThreads).end()) { + unsigned tid = *threads++; + + PQ.push(fromIEW->iewInfo[tid].iqCount); + } + + while (!PQ.empty()) { + + unsigned high_pri = PQ.top(); + + if (fetchStatus[high_pri] == Running || + fetchStatus[high_pri] == IcacheAccessComplete || + fetchStatus[high_pri] == Idle) + return high_pri; + else + PQ.pop(); + + } + + return -1; +} + +template<class Impl> +int +DefaultFetch<Impl>::lsqCount() +{ + priority_queue<unsigned> PQ; + + + list<unsigned>::iterator threads = (*activeThreads).begin(); + + while (threads != (*activeThreads).end()) { + unsigned tid = *threads++; + + PQ.push(fromIEW->iewInfo[tid].ldstqCount); + } + + while (!PQ.empty()) { + + unsigned high_pri = PQ.top(); + + if (fetchStatus[high_pri] == Running || + fetchStatus[high_pri] == IcacheAccessComplete || + fetchStatus[high_pri] == Idle) + return high_pri; + else + PQ.pop(); + + } + + return -1; +} + +template<class Impl> +int +DefaultFetch<Impl>::branchCount() +{ + list<unsigned>::iterator threads = (*activeThreads).begin(); + + return *threads; +} diff --git a/src/cpu/o3/free_list.cc b/src/cpu/o3/free_list.cc new file mode 100644 index 000000000..ae651398b --- /dev/null +++ b/src/cpu/o3/free_list.cc @@ -0,0 +1,72 @@ +/* + * 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 "base/trace.hh" + +#include "cpu/o3/free_list.hh" + +SimpleFreeList::SimpleFreeList(unsigned activeThreads, + unsigned _numLogicalIntRegs, + unsigned _numPhysicalIntRegs, + unsigned _numLogicalFloatRegs, + unsigned _numPhysicalFloatRegs) + : numLogicalIntRegs(_numLogicalIntRegs), + numPhysicalIntRegs(_numPhysicalIntRegs), + numLogicalFloatRegs(_numLogicalFloatRegs), + numPhysicalFloatRegs(_numPhysicalFloatRegs), + numPhysicalRegs(numPhysicalIntRegs + numPhysicalFloatRegs) +{ + DPRINTF(FreeList, "Creating new free list object.\n"); + + // Put all of the extra physical registers onto the free list. This + // means excluding all of the base logical registers. + for (PhysRegIndex i = numLogicalIntRegs * activeThreads; + i < numPhysicalIntRegs; ++i) + { + freeIntRegs.push(i); + } + + // Put all of the extra physical registers onto the free list. This + // means excluding all of the base logical registers. Because the + // float registers' indices start where the physical registers end, + // some math must be done to determine where the free registers start. + PhysRegIndex i = numPhysicalIntRegs + (numLogicalFloatRegs * activeThreads); + + for ( ; i < numPhysicalRegs; ++i) + { + freeFloatRegs.push(i); + } +} + +std::string +SimpleFreeList::name() const +{ + return "cpu.freelist"; +} diff --git a/src/cpu/o3/free_list.hh b/src/cpu/o3/free_list.hh new file mode 100644 index 000000000..c669b0b34 --- /dev/null +++ b/src/cpu/o3/free_list.hh @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#ifndef __CPU_O3_FREE_LIST_HH__ +#define __CPU_O3_FREE_LIST_HH__ + +#include <iostream> +#include <queue> + +#include "arch/isa_traits.hh" +#include "base/misc.hh" +#include "base/trace.hh" +#include "base/traceflags.hh" +#include "cpu/o3/comm.hh" + +/** + * FreeList class that simply holds the list of free integer and floating + * point registers. Can request for a free register of either type, and + * also send back free registers of either type. This is a very simple + * class, but it should be sufficient for most implementations. Like all + * other classes, it assumes that the indices for the floating point + * registers starts after the integer registers end. Hence the variable + * numPhysicalIntRegs is logically equivalent to the baseFP dependency. + * Note that while this most likely should be called FreeList, the name + * "FreeList" is used in a typedef within the CPU Policy, and therefore no + * class can be named simply "FreeList". + * @todo: Give a better name to the base FP dependency. + */ +class SimpleFreeList +{ + private: + /** The list of free integer registers. */ + std::queue<PhysRegIndex> freeIntRegs; + + /** The list of free floating point registers. */ + std::queue<PhysRegIndex> freeFloatRegs; + + /** Number of logical integer registers. */ + int numLogicalIntRegs; + + /** Number of physical integer registers. */ + int numPhysicalIntRegs; + + /** Number of logical floating point registers. */ + int numLogicalFloatRegs; + + /** Number of physical floating point registers. */ + int numPhysicalFloatRegs; + + /** Total number of physical registers. */ + int numPhysicalRegs; + + public: + /** Constructs a free list. + * @param activeThreads Number of active threads. + * @param _numLogicalIntRegs Number of logical integer registers. + * @param _numPhysicalIntRegs Number of physical integer registers. + * @param _numLogicalFloatRegs Number of logical fp registers. + * @param _numPhysicalFloatRegs Number of physical fp registers. + */ + SimpleFreeList(unsigned activeThreads, + unsigned _numLogicalIntRegs, + unsigned _numPhysicalIntRegs, + unsigned _numLogicalFloatRegs, + unsigned _numPhysicalFloatRegs); + + /** Gives the name of the freelist. */ + std::string name() const; + + /** Gets a free integer register. */ + inline PhysRegIndex getIntReg(); + + /** Gets a free fp register. */ + inline PhysRegIndex getFloatReg(); + + /** Adds a register back to the free list. */ + inline void addReg(PhysRegIndex freed_reg); + + /** Adds an integer register back to the free list. */ + inline void addIntReg(PhysRegIndex freed_reg); + + /** Adds a fp register back to the free list. */ + inline void addFloatReg(PhysRegIndex freed_reg); + + /** Checks if there are any free integer registers. */ + bool hasFreeIntRegs() + { return !freeIntRegs.empty(); } + + /** Checks if there are any free fp registers. */ + bool hasFreeFloatRegs() + { return !freeFloatRegs.empty(); } + + /** Returns the number of free integer registers. */ + int numFreeIntRegs() + { return freeIntRegs.size(); } + + /** Returns the number of free fp registers. */ + int numFreeFloatRegs() + { return freeFloatRegs.size(); } +}; + +inline PhysRegIndex +SimpleFreeList::getIntReg() +{ + DPRINTF(FreeList, "Trying to get free integer register.\n"); + + if (freeIntRegs.empty()) { + panic("No free integer registers!"); + } + + PhysRegIndex free_reg = freeIntRegs.front(); + + freeIntRegs.pop(); + + return(free_reg); +} + +inline PhysRegIndex +SimpleFreeList::getFloatReg() +{ + DPRINTF(FreeList, "Trying to get free float register.\n"); + + if (freeFloatRegs.empty()) { + panic("No free integer registers!"); + } + + PhysRegIndex free_reg = freeFloatRegs.front(); + + freeFloatRegs.pop(); + + return(free_reg); +} + +inline void +SimpleFreeList::addReg(PhysRegIndex freed_reg) +{ + DPRINTF(FreeList,"Freeing register %i.\n", freed_reg); + //Might want to add in a check for whether or not this register is + //already in there. A bit vector or something similar would be useful. + if (freed_reg < numPhysicalIntRegs) { + if (freed_reg != TheISA::ZeroReg) + freeIntRegs.push(freed_reg); + } else if (freed_reg < numPhysicalRegs) { + if (freed_reg != (TheISA::ZeroReg + numPhysicalIntRegs)) + freeFloatRegs.push(freed_reg); + } +} + +inline void +SimpleFreeList::addIntReg(PhysRegIndex freed_reg) +{ + DPRINTF(FreeList,"Freeing int register %i.\n", freed_reg); + + freeIntRegs.push(freed_reg); +} + +inline void +SimpleFreeList::addFloatReg(PhysRegIndex freed_reg) +{ + DPRINTF(FreeList,"Freeing float register %i.\n", freed_reg); + + freeFloatRegs.push(freed_reg); +} + +#endif // __CPU_O3_FREE_LIST_HH__ diff --git a/src/cpu/o3/fu_pool.cc b/src/cpu/o3/fu_pool.cc new file mode 100644 index 000000000..545deea9b --- /dev/null +++ b/src/cpu/o3/fu_pool.cc @@ -0,0 +1,299 @@ +/* + * 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 <sstream> + +#include "cpu/o3/fu_pool.hh" +#include "encumbered/cpu/full/fu_pool.hh" +#include "sim/builder.hh" + +using namespace std; + +//////////////////////////////////////////////////////////////////////////// +// +// A pool of function units +// + +inline void +FUPool::FUIdxQueue::addFU(int fu_idx) +{ + funcUnitsIdx.push_back(fu_idx); + ++size; +} + +inline int +FUPool::FUIdxQueue::getFU() +{ + int retval = funcUnitsIdx[idx++]; + + if (idx == size) + idx = 0; + + return retval; +} + +FUPool::~FUPool() +{ + fuListIterator i = funcUnits.begin(); + fuListIterator end = funcUnits.end(); + for (; i != end; ++i) + delete *i; +} + + +// Constructor +FUPool::FUPool(string name, vector<FUDesc *> paramList) + : SimObject(name) +{ + numFU = 0; + + funcUnits.clear(); + + for (int i = 0; i < Num_OpClasses; ++i) { + maxOpLatencies[i] = 0; + maxIssueLatencies[i] = 0; + } + + // + // Iterate through the list of FUDescData structures + // + for (FUDDiterator i = paramList.begin(); i != paramList.end(); ++i) { + + // + // Don't bother with this if we're not going to create any FU's + // + if ((*i)->number) { + // + // Create the FuncUnit object from this structure + // - add the capabilities listed in the FU's operation + // description + // + // We create the first unit, then duplicate it as needed + // + FuncUnit *fu = new FuncUnit; + + OPDDiterator j = (*i)->opDescList.begin(); + OPDDiterator end = (*i)->opDescList.end(); + for (; j != end; ++j) { + // indicate that this pool has this capability + capabilityList.set((*j)->opClass); + + // Add each of the FU's that will have this capability to the + // appropriate queue. + for (int k = 0; k < (*i)->number; ++k) + fuPerCapList[(*j)->opClass].addFU(numFU + k); + + // indicate that this FU has the capability + fu->addCapability((*j)->opClass, (*j)->opLat, (*j)->issueLat); + + if ((*j)->opLat > maxOpLatencies[(*j)->opClass]) + maxOpLatencies[(*j)->opClass] = (*j)->opLat; + + if ((*j)->issueLat > maxIssueLatencies[(*j)->opClass]) + maxIssueLatencies[(*j)->opClass] = (*j)->issueLat; + } + + numFU++; + + // Add the appropriate number of copies of this FU to the list + ostringstream s; + + s << (*i)->name() << "(0)"; + fu->name = s.str(); + funcUnits.push_back(fu); + + for (int c = 1; c < (*i)->number; ++c) { + ostringstream s; + numFU++; + FuncUnit *fu2 = new FuncUnit(*fu); + + s << (*i)->name() << "(" << c << ")"; + fu2->name = s.str(); + funcUnits.push_back(fu2); + } + } + } + + unitBusy.resize(numFU); + + for (int i = 0; i < numFU; i++) { + unitBusy[i] = false; + } +} + +void +FUPool::annotateMemoryUnits(unsigned hit_latency) +{ + maxOpLatencies[MemReadOp] = hit_latency; + + fuListIterator i = funcUnits.begin(); + fuListIterator iend = funcUnits.end(); + for (; i != iend; ++i) { + if ((*i)->provides(MemReadOp)) + (*i)->opLatency(MemReadOp) = hit_latency; + + if ((*i)->provides(MemWriteOp)) + (*i)->opLatency(MemWriteOp) = hit_latency; + } +} + +int +FUPool::getUnit(OpClass capability) +{ + // If this pool doesn't have the specified capability, + // return this information to the caller + if (!capabilityList[capability]) + return -2; + + int fu_idx = fuPerCapList[capability].getFU(); + int start_idx = fu_idx; + + // Iterate through the circular queue if needed, stopping if we've reached + // the first element again. + while (unitBusy[fu_idx]) { + fu_idx = fuPerCapList[capability].getFU(); + if (fu_idx == start_idx) { + // No FU available + return -1; + } + } + + assert(fu_idx < numFU); + + unitBusy[fu_idx] = true; + + return fu_idx; +} + +void +FUPool::freeUnitNextCycle(int fu_idx) +{ + assert(unitBusy[fu_idx]); + unitsToBeFreed.push_back(fu_idx); +} + +void +FUPool::processFreeUnits() +{ + while (!unitsToBeFreed.empty()) { + int fu_idx = unitsToBeFreed.back(); + unitsToBeFreed.pop_back(); + + assert(unitBusy[fu_idx]); + + unitBusy[fu_idx] = false; + } +} + +void +FUPool::dump() +{ + cout << "Function Unit Pool (" << name() << ")\n"; + cout << "======================================\n"; + cout << "Free List:\n"; + + for (int i = 0; i < numFU; ++i) { + if (unitBusy[i]) { + continue; + } + + cout << " [" << i << "] : "; + + cout << funcUnits[i]->name << " "; + + cout << "\n"; + } + + cout << "======================================\n"; + cout << "Busy List:\n"; + for (int i = 0; i < numFU; ++i) { + if (!unitBusy[i]) { + continue; + } + + cout << " [" << i << "] : "; + + cout << funcUnits[i]->name << " "; + + cout << "\n"; + } +} + +void +FUPool::switchOut() +{ +} + +void +FUPool::takeOverFrom() +{ + for (int i = 0; i < numFU; i++) { + unitBusy[i] = false; + } + unitsToBeFreed.clear(); +} + +// + +//////////////////////////////////////////////////////////////////////////// +// +// The SimObjects we use to get the FU information into the simulator +// +//////////////////////////////////////////////////////////////////////////// + +// +// FUPool - Contails a list of FUDesc objects to make available +// + +// +// The FuPool object +// + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(FUPool) + + SimObjectVectorParam<FUDesc *> FUList; + +END_DECLARE_SIM_OBJECT_PARAMS(FUPool) + + +BEGIN_INIT_SIM_OBJECT_PARAMS(FUPool) + + INIT_PARAM(FUList, "list of FU's for this pool") + +END_INIT_SIM_OBJECT_PARAMS(FUPool) + + +CREATE_SIM_OBJECT(FUPool) +{ + return new FUPool(getInstanceName(), FUList); +} + +REGISTER_SIM_OBJECT("FUPool", FUPool) + diff --git a/src/cpu/o3/fu_pool.hh b/src/cpu/o3/fu_pool.hh new file mode 100644 index 000000000..52d83f056 --- /dev/null +++ b/src/cpu/o3/fu_pool.hh @@ -0,0 +1,167 @@ +/* + * 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_O3_FU_POOL_HH__ +#define __CPU_O3_FU_POOL_HH__ + +#include <bitset> +#include <list> +#include <string> +#include <vector> + +#include "base/sched_list.hh" +#include "cpu/op_class.hh" +#include "sim/sim_object.hh" + +class FUDesc; +class FuncUnit; + +/** + * Pool of FU's, specific to the new CPU model. The old FU pool had lists of + * free units and busy units, and whenever a FU was needed it would iterate + * through the free units to find a FU that provided the capability. This pool + * has lists of units specific to each of the capabilities, and whenever a FU + * is needed, it iterates through that list to find a free unit. The previous + * FU pool would have to be ticked each cycle to update which units became + * free. This FU pool lets the IEW stage handle freeing units, which frees + * them as their scheduled execution events complete. This limits units in this + * model to either have identical issue and op latencies, or 1 cycle issue + * latencies. + */ +class FUPool : public SimObject +{ + private: + /** Maximum op execution latencies, per op class. */ + unsigned maxOpLatencies[Num_OpClasses]; + /** Maximum issue latencies, per op class. */ + unsigned maxIssueLatencies[Num_OpClasses]; + + /** Bitvector listing capabilities of this FU pool. */ + std::bitset<Num_OpClasses> capabilityList; + + /** Bitvector listing which FUs are busy. */ + std::vector<bool> unitBusy; + + /** List of units to be freed at the end of this cycle. */ + std::vector<int> unitsToBeFreed; + + /** + * Class that implements a circular queue to hold FU indices. The hope is + * that FUs that have been just used will be moved to the end of the queue + * by iterating through it, thus leaving free units at the head of the + * queue. + */ + class FUIdxQueue { + public: + /** Constructs a circular queue of FU indices. */ + FUIdxQueue() + : idx(0), size(0) + { } + + /** Adds a FU to the queue. */ + inline void addFU(int fu_idx); + + /** Returns the index of the FU at the head of the queue, and changes + * the index to the next element. + */ + inline int getFU(); + + private: + /** Circular queue index. */ + int idx; + + /** Size of the queue. */ + int size; + + /** Queue of FU indices. */ + std::vector<int> funcUnitsIdx; + }; + + /** Per op class queues of FUs that provide that capability. */ + FUIdxQueue fuPerCapList[Num_OpClasses]; + + /** Number of FUs. */ + int numFU; + + /** Functional units. */ + std::vector<FuncUnit *> funcUnits; + + typedef std::vector<FuncUnit *>::iterator fuListIterator; + + public: + + /** Constructs a FU pool. */ + FUPool(std::string name, std::vector<FUDesc *> l); + ~FUPool(); + + /** Annotates units that provide memory operations. Included only because + * old FU pool provided this function. + */ + void annotateMemoryUnits(unsigned hit_latency); + + /** + * Gets a FU providing the requested capability. Will mark the unit as busy, + * but leaves the freeing of the unit up to the IEW stage. + * @param capability The capability requested. + * @return Returns -2 if the FU pool does not have the capability, -1 if + * there is no free FU, and the FU's index otherwise. + */ + int getUnit(OpClass capability); + + /** Frees a FU at the end of this cycle. */ + void freeUnitNextCycle(int fu_idx); + + /** Frees all FUs on the list. */ + void processFreeUnits(); + + /** Returns the total number of FUs. */ + int size() { return numFU; } + + /** Debugging function used to dump FU information. */ + void dump(); + + /** Returns the operation execution latency of the given capability. */ + unsigned getOpLatency(OpClass capability) { + return maxOpLatencies[capability]; + } + + /** Returns the issue latency of the given capability. */ + unsigned getIssueLatency(OpClass capability) { + return maxIssueLatencies[capability]; + } + + /** Switches out functional unit pool. */ + void switchOut(); + + /** Takes over from another CPU's thread. */ + void takeOverFrom(); +}; + +#endif // __CPU_O3_FU_POOL_HH__ diff --git a/src/cpu/o3/iew.cc b/src/cpu/o3/iew.cc new file mode 100644 index 000000000..8145f4cc7 --- /dev/null +++ b/src/cpu/o3/iew.cc @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#include "cpu/o3/alpha_dyn_inst.hh" +#include "cpu/o3/alpha_impl.hh" +#include "cpu/o3/iew_impl.hh" +#include "cpu/o3/inst_queue.hh" + +template class DefaultIEW<AlphaSimpleImpl>; diff --git a/src/cpu/o3/iew.hh b/src/cpu/o3/iew.hh new file mode 100644 index 000000000..2e61af5fc --- /dev/null +++ b/src/cpu/o3/iew.hh @@ -0,0 +1,502 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#ifndef __CPU_O3_IEW_HH__ +#define __CPU_O3_IEW_HH__ + +#include <queue> + +#include "base/statistics.hh" +#include "base/timebuf.hh" +#include "config/full_system.hh" +#include "cpu/o3/comm.hh" +#include "cpu/o3/scoreboard.hh" +#include "cpu/o3/lsq.hh" + +class FUPool; + +/** + * DefaultIEW handles both single threaded and SMT IEW + * (issue/execute/writeback). It handles the dispatching of + * instructions to the LSQ/IQ as part of the issue stage, and has the + * IQ try to issue instructions each cycle. The execute latency is + * actually tied into the issue latency to allow the IQ to be able to + * do back-to-back scheduling without having to speculatively schedule + * instructions. This happens by having the IQ have access to the + * functional units, and the IQ gets the execution latencies from the + * FUs when it issues instructions. Instructions reach the execute + * stage on the last cycle of their execution, which is when the IQ + * knows to wake up any dependent instructions, allowing back to back + * scheduling. The execute portion of IEW separates memory + * instructions from non-memory instructions, either telling the LSQ + * to execute the instruction, or executing the instruction directly. + * The writeback portion of IEW completes the instructions by waking + * up any dependents, and marking the register ready on the + * scoreboard. + */ +template<class Impl> +class DefaultIEW +{ + private: + //Typedefs from Impl + typedef typename Impl::CPUPol CPUPol; + typedef typename Impl::DynInstPtr DynInstPtr; + typedef typename Impl::FullCPU FullCPU; + typedef typename Impl::Params Params; + + typedef typename CPUPol::IQ IQ; + typedef typename CPUPol::RenameMap RenameMap; + typedef typename CPUPol::LSQ LSQ; + + typedef typename CPUPol::TimeStruct TimeStruct; + typedef typename CPUPol::IEWStruct IEWStruct; + typedef typename CPUPol::RenameStruct RenameStruct; + typedef typename CPUPol::IssueStruct IssueStruct; + + friend class Impl::FullCPU; + friend class CPUPol::IQ; + + public: + /** Overall IEW stage status. Used to determine if the CPU can + * deschedule itself due to a lack of activity. + */ + enum Status { + Active, + Inactive + }; + + /** Status for Issue, Execute, and Writeback stages. */ + enum StageStatus { + Running, + Blocked, + Idle, + StartSquash, + Squashing, + Unblocking + }; + + private: + /** Overall stage status. */ + Status _status; + /** Dispatch status. */ + StageStatus dispatchStatus[Impl::MaxThreads]; + /** Execute status. */ + StageStatus exeStatus; + /** Writeback status. */ + StageStatus wbStatus; + + public: + /** Constructs a DefaultIEW with the given parameters. */ + DefaultIEW(Params *params); + + /** Returns the name of the DefaultIEW stage. */ + std::string name() const; + + /** Registers statistics. */ + void regStats(); + + /** Initializes stage; sends back the number of free IQ and LSQ entries. */ + void initStage(); + + /** Sets CPU pointer for IEW, IQ, and LSQ. */ + void setCPU(FullCPU *cpu_ptr); + + /** Sets main time buffer used for backwards communication. */ + void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr); + + /** Sets time buffer for getting instructions coming from rename. */ + void setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr); + + /** Sets time buffer to pass on instructions to commit. */ + void setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr); + + /** Sets pointer to list of active threads. */ + void setActiveThreads(std::list<unsigned> *at_ptr); + + /** Sets pointer to the scoreboard. */ + void setScoreboard(Scoreboard *sb_ptr); + + /** Starts switch out of IEW stage. */ + void switchOut(); + + /** Completes switch out of IEW stage. */ + void doSwitchOut(); + + /** Takes over from another CPU's thread. */ + void takeOverFrom(); + + /** Returns if IEW is switched out. */ + bool isSwitchedOut() { return switchedOut; } + + /** Squashes instructions in IEW for a specific thread. */ + void squash(unsigned tid); + + /** Wakes all dependents of a completed instruction. */ + void wakeDependents(DynInstPtr &inst); + + /** Tells memory dependence unit that a memory instruction needs to be + * rescheduled. It will re-execute once replayMemInst() is called. + */ + void rescheduleMemInst(DynInstPtr &inst); + + /** Re-executes all rescheduled memory instructions. */ + void replayMemInst(DynInstPtr &inst); + + /** Sends an instruction to commit through the time buffer. */ + void instToCommit(DynInstPtr &inst); + + /** Inserts unused instructions of a thread into the skid buffer. */ + void skidInsert(unsigned tid); + + /** Returns the max of the number of entries in all of the skid buffers. */ + int skidCount(); + + /** Returns if all of the skid buffers are empty. */ + bool skidsEmpty(); + + /** Updates overall IEW status based on all of the stages' statuses. */ + void updateStatus(); + + /** Resets entries of the IQ and the LSQ. */ + void resetEntries(); + + /** Tells the CPU to wakeup if it has descheduled itself due to no + * activity. Used mainly by the LdWritebackEvent. + */ + void wakeCPU(); + + /** Reports to the CPU that there is activity this cycle. */ + void activityThisCycle(); + + /** Tells CPU that the IEW stage is active and running. */ + inline void activateStage(); + + /** Tells CPU that the IEW stage is inactive and idle. */ + inline void deactivateStage(); + + /** Returns if the LSQ has any stores to writeback. */ + bool hasStoresToWB() { return ldstQueue.hasStoresToWB(); } + + private: + /** Sends commit proper information for a squash due to a branch + * mispredict. + */ + void squashDueToBranch(DynInstPtr &inst, unsigned thread_id); + + /** Sends commit proper information for a squash due to a memory order + * violation. + */ + void squashDueToMemOrder(DynInstPtr &inst, unsigned thread_id); + + /** Sends commit proper information for a squash due to memory becoming + * blocked (younger issued instructions must be retried). + */ + void squashDueToMemBlocked(DynInstPtr &inst, unsigned thread_id); + + /** Sets Dispatch to blocked, and signals back to other stages to block. */ + void block(unsigned thread_id); + + /** Unblocks Dispatch if the skid buffer is empty, and signals back to + * other stages to unblock. + */ + void unblock(unsigned thread_id); + + /** Determines proper actions to take given Dispatch's status. */ + void dispatch(unsigned tid); + + /** Dispatches instructions to IQ and LSQ. */ + void dispatchInsts(unsigned tid); + + /** Executes instructions. In the case of memory operations, it informs the + * LSQ to execute the instructions. Also handles any redirects that occur + * due to the executed instructions. + */ + void executeInsts(); + + /** Writebacks instructions. In our model, the instruction's execute() + * function atomically reads registers, executes, and writes registers. + * Thus this writeback only wakes up dependent instructions, and informs + * the scoreboard of registers becoming ready. + */ + void writebackInsts(); + + /** Returns the number of valid, non-squashed instructions coming from + * rename to dispatch. + */ + unsigned validInstsFromRename(); + + /** Reads the stall signals. */ + void readStallSignals(unsigned tid); + + /** Checks if any of the stall conditions are currently true. */ + bool checkStall(unsigned tid); + + /** Processes inputs and changes state accordingly. */ + void checkSignalsAndUpdate(unsigned tid); + + /** Sorts instructions coming from rename into lists separated by thread. */ + void sortInsts(); + + public: + /** Ticks IEW stage, causing Dispatch, the IQ, the LSQ, Execute, and + * Writeback to run for one cycle. + */ + void tick(); + + private: + /** Updates execution stats based on the instruction. */ + void updateExeInstStats(DynInstPtr &inst); + + /** Pointer to main time buffer used for backwards communication. */ + TimeBuffer<TimeStruct> *timeBuffer; + + /** Wire to write information heading to previous stages. */ + typename TimeBuffer<TimeStruct>::wire toFetch; + + /** Wire to get commit's output from backwards time buffer. */ + typename TimeBuffer<TimeStruct>::wire fromCommit; + + /** Wire to write information heading to previous stages. */ + typename TimeBuffer<TimeStruct>::wire toRename; + + /** Rename instruction queue interface. */ + TimeBuffer<RenameStruct> *renameQueue; + + /** Wire to get rename's output from rename queue. */ + typename TimeBuffer<RenameStruct>::wire fromRename; + + /** Issue stage queue. */ + TimeBuffer<IssueStruct> issueToExecQueue; + + /** Wire to read information from the issue stage time queue. */ + typename TimeBuffer<IssueStruct>::wire fromIssue; + + /** + * IEW stage time buffer. Holds ROB indices of instructions that + * can be marked as completed. + */ + TimeBuffer<IEWStruct> *iewQueue; + + /** Wire to write infromation heading to commit. */ + typename TimeBuffer<IEWStruct>::wire toCommit; + + /** Queue of all instructions coming from rename this cycle. */ + std::queue<DynInstPtr> insts[Impl::MaxThreads]; + + /** Skid buffer between rename and IEW. */ + std::queue<DynInstPtr> skidBuffer[Impl::MaxThreads]; + + /** Scoreboard pointer. */ + Scoreboard* scoreboard; + + public: + /** Instruction queue. */ + IQ instQueue; + + /** Load / store queue. */ + LSQ ldstQueue; + + /** Pointer to the functional unit pool. */ + FUPool *fuPool; + + private: + /** CPU pointer. */ + FullCPU *cpu; + + /** Records if IEW has written to the time buffer this cycle, so that the + * CPU can deschedule itself if there is no activity. + */ + bool wroteToTimeBuffer; + + /** Source of possible stalls. */ + struct Stalls { + bool commit; + }; + + /** Stages that are telling IEW to stall. */ + Stalls stalls[Impl::MaxThreads]; + + /** Debug function to print instructions that are issued this cycle. */ + void printAvailableInsts(); + + public: + /** Records if the LSQ needs to be updated on the next cycle, so that + * IEW knows if there will be activity on the next cycle. + */ + bool updateLSQNextCycle; + + private: + /** Records if there is a fetch redirect on this cycle for each thread. */ + bool fetchRedirect[Impl::MaxThreads]; + + /** Used to track if all instructions have been dispatched this cycle. + * If they have not, then blocking must have occurred, and the instructions + * would already be added to the skid buffer. + * @todo: Fix this hack. + */ + bool dispatchedAllInsts; + + /** Records if the queues have been changed (inserted or issued insts), + * so that IEW knows to broadcast the updated amount of free entries. + */ + bool updatedQueues; + + /** Commit to IEW delay, in ticks. */ + unsigned commitToIEWDelay; + + /** Rename to IEW delay, in ticks. */ + unsigned renameToIEWDelay; + + /** + * Issue to execute delay, in ticks. What this actually represents is + * the amount of time it takes for an instruction to wake up, be + * scheduled, and sent to a FU for execution. + */ + unsigned issueToExecuteDelay; + + /** Width of issue's read path, in instructions. The read path is both + * the skid buffer and the rename instruction queue. + * Note to self: is this really different than issueWidth? + */ + unsigned issueReadWidth; + + /** Width of issue, in instructions. */ + unsigned issueWidth; + + /** Width of execute, in instructions. Might make more sense to break + * down into FP vs int. + */ + unsigned executeWidth; + + /** Index into queue of instructions being written back. */ + unsigned wbNumInst; + + /** Cycle number within the queue of instructions being written back. + * Used in case there are too many instructions writing back at the current + * cycle and writesbacks need to be scheduled for the future. See comments + * in instToCommit(). + */ + unsigned wbCycle; + + /** Number of active threads. */ + unsigned numThreads; + + /** Pointer to list of active threads. */ + std::list<unsigned> *activeThreads; + + /** Maximum size of the skid buffer. */ + unsigned skidBufferMax; + + /** Is this stage switched out. */ + bool switchedOut; + + /** Stat for total number of idle cycles. */ + Stats::Scalar<> iewIdleCycles; + /** Stat for total number of squashing cycles. */ + Stats::Scalar<> iewSquashCycles; + /** Stat for total number of blocking cycles. */ + Stats::Scalar<> iewBlockCycles; + /** Stat for total number of unblocking cycles. */ + Stats::Scalar<> iewUnblockCycles; + /** Stat for total number of instructions dispatched. */ + Stats::Scalar<> iewDispatchedInsts; + /** Stat for total number of squashed instructions dispatch skips. */ + Stats::Scalar<> iewDispSquashedInsts; + /** Stat for total number of dispatched load instructions. */ + Stats::Scalar<> iewDispLoadInsts; + /** Stat for total number of dispatched store instructions. */ + Stats::Scalar<> iewDispStoreInsts; + /** Stat for total number of dispatched non speculative instructions. */ + Stats::Scalar<> iewDispNonSpecInsts; + /** Stat for number of times the IQ becomes full. */ + Stats::Scalar<> iewIQFullEvents; + /** Stat for number of times the LSQ becomes full. */ + Stats::Scalar<> iewLSQFullEvents; + /** Stat for total number of executed instructions. */ + Stats::Scalar<> iewExecutedInsts; + /** Stat for total number of executed load instructions. */ + Stats::Vector<> iewExecLoadInsts; + /** Stat for total number of executed store instructions. */ +// Stats::Scalar<> iewExecStoreInsts; + /** Stat for total number of squashed instructions skipped at execute. */ + Stats::Scalar<> iewExecSquashedInsts; + /** Stat for total number of memory ordering violation events. */ + Stats::Scalar<> memOrderViolationEvents; + /** Stat for total number of incorrect predicted taken branches. */ + Stats::Scalar<> predictedTakenIncorrect; + /** Stat for total number of incorrect predicted not taken branches. */ + Stats::Scalar<> predictedNotTakenIncorrect; + /** Stat for total number of mispredicted branches detected at execute. */ + Stats::Formula branchMispredicts; + + /** Number of executed software prefetches. */ + Stats::Vector<> exeSwp; + /** Number of executed nops. */ + Stats::Vector<> exeNop; + /** Number of executed meomory references. */ + Stats::Vector<> exeRefs; + /** Number of executed branches. */ + Stats::Vector<> exeBranches; + +// Stats::Vector<> issued_ops; +/* + Stats::Vector<> stat_fu_busy; + Stats::Vector2d<> stat_fuBusy; + Stats::Vector<> dist_unissued; + Stats::Vector2d<> stat_issued_inst_type; +*/ + /** Number of instructions issued per cycle. */ + Stats::Formula issueRate; + /** Number of executed store instructions. */ + Stats::Formula iewExecStoreInsts; +// Stats::Formula issue_op_rate; +// Stats::Formula fu_busy_rate; + /** Number of instructions sent to commit. */ + Stats::Vector<> iewInstsToCommit; + /** Number of instructions that writeback. */ + Stats::Vector<> writebackCount; + /** Number of instructions that wake consumers. */ + Stats::Vector<> producerInst; + /** Number of instructions that wake up from producers. */ + Stats::Vector<> consumerInst; + /** Number of instructions that were delayed in writing back due + * to resource contention. + */ + Stats::Vector<> wbPenalized; + + /** Number of instructions per cycle written back. */ + Stats::Formula wbRate; + /** Average number of woken instructions per writeback. */ + Stats::Formula wbFanout; + /** Number of instructions per cycle delayed in writing back . */ + Stats::Formula wbPenalizedRate; +}; + +#endif // __CPU_O3_IEW_HH__ diff --git a/src/cpu/o3/iew_impl.hh b/src/cpu/o3/iew_impl.hh new file mode 100644 index 000000000..3929f2e19 --- /dev/null +++ b/src/cpu/o3/iew_impl.hh @@ -0,0 +1,1527 @@ +/* + * 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 + */ + +// @todo: Fix the instantaneous communication among all the stages within +// iew. There's a clear delay between issue and execute, yet backwards +// communication happens simultaneously. + +#include <queue> + +#include "base/timebuf.hh" +#include "cpu/o3/fu_pool.hh" +#include "cpu/o3/iew.hh" + +using namespace std; + +template<class Impl> +DefaultIEW<Impl>::DefaultIEW(Params *params) + : // @todo: Make this into a parameter. + issueToExecQueue(5, 5), + instQueue(params), + ldstQueue(params), + fuPool(params->fuPool), + commitToIEWDelay(params->commitToIEWDelay), + renameToIEWDelay(params->renameToIEWDelay), + issueToExecuteDelay(params->issueToExecuteDelay), + issueReadWidth(params->issueWidth), + issueWidth(params->issueWidth), + executeWidth(params->executeWidth), + numThreads(params->numberOfThreads), + switchedOut(false) +{ + _status = Active; + exeStatus = Running; + wbStatus = Idle; + + // Setup wire to read instructions coming from issue. + fromIssue = issueToExecQueue.getWire(-issueToExecuteDelay); + + // Instruction queue needs the queue between issue and execute. + instQueue.setIssueToExecuteQueue(&issueToExecQueue); + + instQueue.setIEW(this); + ldstQueue.setIEW(this); + + for (int i=0; i < numThreads; i++) { + dispatchStatus[i] = Running; + stalls[i].commit = false; + fetchRedirect[i] = false; + } + + updateLSQNextCycle = false; + + skidBufferMax = (3 * (renameToIEWDelay * params->renameWidth)) + issueWidth; +} + +template <class Impl> +std::string +DefaultIEW<Impl>::name() const +{ + return cpu->name() + ".iew"; +} + +template <class Impl> +void +DefaultIEW<Impl>::regStats() +{ + using namespace Stats; + + instQueue.regStats(); + + iewIdleCycles + .name(name() + ".iewIdleCycles") + .desc("Number of cycles IEW is idle"); + + iewSquashCycles + .name(name() + ".iewSquashCycles") + .desc("Number of cycles IEW is squashing"); + + iewBlockCycles + .name(name() + ".iewBlockCycles") + .desc("Number of cycles IEW is blocking"); + + iewUnblockCycles + .name(name() + ".iewUnblockCycles") + .desc("Number of cycles IEW is unblocking"); + + iewDispatchedInsts + .name(name() + ".iewDispatchedInsts") + .desc("Number of instructions dispatched to IQ"); + + iewDispSquashedInsts + .name(name() + ".iewDispSquashedInsts") + .desc("Number of squashed instructions skipped by dispatch"); + + iewDispLoadInsts + .name(name() + ".iewDispLoadInsts") + .desc("Number of dispatched load instructions"); + + iewDispStoreInsts + .name(name() + ".iewDispStoreInsts") + .desc("Number of dispatched store instructions"); + + iewDispNonSpecInsts + .name(name() + ".iewDispNonSpecInsts") + .desc("Number of dispatched non-speculative instructions"); + + iewIQFullEvents + .name(name() + ".iewIQFullEvents") + .desc("Number of times the IQ has become full, causing a stall"); + + iewLSQFullEvents + .name(name() + ".iewLSQFullEvents") + .desc("Number of times the LSQ has become full, causing a stall"); + + iewExecutedInsts + .name(name() + ".iewExecutedInsts") + .desc("Number of executed instructions"); + + iewExecLoadInsts + .init(cpu->number_of_threads) + .name(name() + ".iewExecLoadInsts") + .desc("Number of load instructions executed") + .flags(total); + + iewExecSquashedInsts + .name(name() + ".iewExecSquashedInsts") + .desc("Number of squashed instructions skipped in execute"); + + memOrderViolationEvents + .name(name() + ".memOrderViolationEvents") + .desc("Number of memory order violations"); + + predictedTakenIncorrect + .name(name() + ".predictedTakenIncorrect") + .desc("Number of branches that were predicted taken incorrectly"); + + predictedNotTakenIncorrect + .name(name() + ".predictedNotTakenIncorrect") + .desc("Number of branches that were predicted not taken incorrectly"); + + branchMispredicts + .name(name() + ".branchMispredicts") + .desc("Number of branch mispredicts detected at execute"); + + branchMispredicts = predictedTakenIncorrect + predictedNotTakenIncorrect; + + exeSwp + .init(cpu->number_of_threads) + .name(name() + ".EXEC:swp") + .desc("number of swp insts executed") + .flags(total) + ; + + exeNop + .init(cpu->number_of_threads) + .name(name() + ".EXEC:nop") + .desc("number of nop insts executed") + .flags(total) + ; + + exeRefs + .init(cpu->number_of_threads) + .name(name() + ".EXEC:refs") + .desc("number of memory reference insts executed") + .flags(total) + ; + + exeBranches + .init(cpu->number_of_threads) + .name(name() + ".EXEC:branches") + .desc("Number of branches executed") + .flags(total) + ; + + issueRate + .name(name() + ".EXEC:rate") + .desc("Inst execution rate") + .flags(total) + ; + issueRate = iewExecutedInsts / cpu->numCycles; + + iewExecStoreInsts + .name(name() + ".EXEC:stores") + .desc("Number of stores executed") + .flags(total) + ; + iewExecStoreInsts = exeRefs - iewExecLoadInsts; +/* + for (int i=0; i<Num_OpClasses; ++i) { + stringstream subname; + subname << opClassStrings[i] << "_delay"; + issue_delay_dist.subname(i, subname.str()); + } +*/ + // + // Other stats + // + + iewInstsToCommit + .init(cpu->number_of_threads) + .name(name() + ".WB:sent") + .desc("cumulative count of insts sent to commit") + .flags(total) + ; + + writebackCount + .init(cpu->number_of_threads) + .name(name() + ".WB:count") + .desc("cumulative count of insts written-back") + .flags(total) + ; + + producerInst + .init(cpu->number_of_threads) + .name(name() + ".WB:producers") + .desc("num instructions producing a value") + .flags(total) + ; + + consumerInst + .init(cpu->number_of_threads) + .name(name() + ".WB:consumers") + .desc("num instructions consuming a value") + .flags(total) + ; + + wbPenalized + .init(cpu->number_of_threads) + .name(name() + ".WB:penalized") + .desc("number of instrctions required to write to 'other' IQ") + .flags(total) + ; + + wbPenalizedRate + .name(name() + ".WB:penalized_rate") + .desc ("fraction of instructions written-back that wrote to 'other' IQ") + .flags(total) + ; + + wbPenalizedRate = wbPenalized / writebackCount; + + wbFanout + .name(name() + ".WB:fanout") + .desc("average fanout of values written-back") + .flags(total) + ; + + wbFanout = producerInst / consumerInst; + + wbRate + .name(name() + ".WB:rate") + .desc("insts written-back per cycle") + .flags(total) + ; + wbRate = writebackCount / cpu->numCycles; +} + +template<class Impl> +void +DefaultIEW<Impl>::initStage() +{ + for (int tid=0; tid < numThreads; tid++) { + toRename->iewInfo[tid].usedIQ = true; + toRename->iewInfo[tid].freeIQEntries = + instQueue.numFreeEntries(tid); + + toRename->iewInfo[tid].usedLSQ = true; + toRename->iewInfo[tid].freeLSQEntries = + ldstQueue.numFreeEntries(tid); + } +} + +template<class Impl> +void +DefaultIEW<Impl>::setCPU(FullCPU *cpu_ptr) +{ + DPRINTF(IEW, "Setting CPU pointer.\n"); + cpu = cpu_ptr; + + instQueue.setCPU(cpu_ptr); + ldstQueue.setCPU(cpu_ptr); + + cpu->activateStage(FullCPU::IEWIdx); +} + +template<class Impl> +void +DefaultIEW<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) +{ + DPRINTF(IEW, "Setting time buffer pointer.\n"); + timeBuffer = tb_ptr; + + // Setup wire to read information from time buffer, from commit. + fromCommit = timeBuffer->getWire(-commitToIEWDelay); + + // Setup wire to write information back to previous stages. + toRename = timeBuffer->getWire(0); + + toFetch = timeBuffer->getWire(0); + + // Instruction queue also needs main time buffer. + instQueue.setTimeBuffer(tb_ptr); +} + +template<class Impl> +void +DefaultIEW<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr) +{ + DPRINTF(IEW, "Setting rename queue pointer.\n"); + renameQueue = rq_ptr; + + // Setup wire to read information from rename queue. + fromRename = renameQueue->getWire(-renameToIEWDelay); +} + +template<class Impl> +void +DefaultIEW<Impl>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr) +{ + DPRINTF(IEW, "Setting IEW queue pointer.\n"); + iewQueue = iq_ptr; + + // Setup wire to write instructions to commit. + toCommit = iewQueue->getWire(0); +} + +template<class Impl> +void +DefaultIEW<Impl>::setActiveThreads(list<unsigned> *at_ptr) +{ + DPRINTF(IEW, "Setting active threads list pointer.\n"); + activeThreads = at_ptr; + + ldstQueue.setActiveThreads(at_ptr); + instQueue.setActiveThreads(at_ptr); +} + +template<class Impl> +void +DefaultIEW<Impl>::setScoreboard(Scoreboard *sb_ptr) +{ + DPRINTF(IEW, "Setting scoreboard pointer.\n"); + scoreboard = sb_ptr; +} + +template <class Impl> +void +DefaultIEW<Impl>::switchOut() +{ + // IEW is ready to switch out at any time. + cpu->signalSwitched(); +} + +template <class Impl> +void +DefaultIEW<Impl>::doSwitchOut() +{ + // Clear any state. + switchedOut = true; + + instQueue.switchOut(); + ldstQueue.switchOut(); + fuPool->switchOut(); + + for (int i = 0; i < numThreads; i++) { + while (!insts[i].empty()) + insts[i].pop(); + while (!skidBuffer[i].empty()) + skidBuffer[i].pop(); + } +} + +template <class Impl> +void +DefaultIEW<Impl>::takeOverFrom() +{ + // Reset all state. + _status = Active; + exeStatus = Running; + wbStatus = Idle; + switchedOut = false; + + instQueue.takeOverFrom(); + ldstQueue.takeOverFrom(); + fuPool->takeOverFrom(); + + initStage(); + cpu->activityThisCycle(); + + for (int i=0; i < numThreads; i++) { + dispatchStatus[i] = Running; + stalls[i].commit = false; + fetchRedirect[i] = false; + } + + updateLSQNextCycle = false; + + // @todo: Fix hardcoded number + for (int i = 0; i < 6; ++i) { + issueToExecQueue.advance(); + } +} + +template<class Impl> +void +DefaultIEW<Impl>::squash(unsigned tid) +{ + DPRINTF(IEW, "[tid:%i]: Squashing all instructions.\n", + tid); + + // Tell the IQ to start squashing. + instQueue.squash(tid); + + // Tell the LDSTQ to start squashing. + ldstQueue.squash(fromCommit->commitInfo[tid].doneSeqNum, tid); + + updatedQueues = true; + + // Clear the skid buffer in case it has any data in it. + while (!skidBuffer[tid].empty()) { + + if (skidBuffer[tid].front()->isLoad() || + skidBuffer[tid].front()->isStore() ) { + toRename->iewInfo[tid].dispatchedToLSQ++; + } + + toRename->iewInfo[tid].dispatched++; + + skidBuffer[tid].pop(); + } + + while (!insts[tid].empty()) { + if (insts[tid].front()->isLoad() || + insts[tid].front()->isStore() ) { + toRename->iewInfo[tid].dispatchedToLSQ++; + } + + toRename->iewInfo[tid].dispatched++; + + insts[tid].pop(); + } +} + +template<class Impl> +void +DefaultIEW<Impl>::squashDueToBranch(DynInstPtr &inst, unsigned tid) +{ + DPRINTF(IEW, "[tid:%i]: Squashing from a specific instruction, PC: %#x " + "[sn:%i].\n", tid, inst->readPC(), inst->seqNum); + + toCommit->squash[tid] = true; + toCommit->squashedSeqNum[tid] = inst->seqNum; + toCommit->mispredPC[tid] = inst->readPC(); + toCommit->nextPC[tid] = inst->readNextPC(); + toCommit->branchMispredict[tid] = true; + toCommit->branchTaken[tid] = inst->readNextPC() != + (inst->readPC() + sizeof(TheISA::MachInst)); + + toCommit->includeSquashInst[tid] = false; + + wroteToTimeBuffer = true; +} + +template<class Impl> +void +DefaultIEW<Impl>::squashDueToMemOrder(DynInstPtr &inst, unsigned tid) +{ + DPRINTF(IEW, "[tid:%i]: Squashing from a specific instruction, " + "PC: %#x [sn:%i].\n", tid, inst->readPC(), inst->seqNum); + + toCommit->squash[tid] = true; + toCommit->squashedSeqNum[tid] = inst->seqNum; + toCommit->nextPC[tid] = inst->readNextPC(); + + toCommit->includeSquashInst[tid] = false; + + wroteToTimeBuffer = true; +} + +template<class Impl> +void +DefaultIEW<Impl>::squashDueToMemBlocked(DynInstPtr &inst, unsigned tid) +{ + DPRINTF(IEW, "[tid:%i]: Memory blocked, squashing load and younger insts, " + "PC: %#x [sn:%i].\n", tid, inst->readPC(), inst->seqNum); + + toCommit->squash[tid] = true; + toCommit->squashedSeqNum[tid] = inst->seqNum; + toCommit->nextPC[tid] = inst->readPC(); + + // Must include the broadcasted SN in the squash. + toCommit->includeSquashInst[tid] = true; + + ldstQueue.setLoadBlockedHandled(tid); + + wroteToTimeBuffer = true; +} + +template<class Impl> +void +DefaultIEW<Impl>::block(unsigned tid) +{ + DPRINTF(IEW, "[tid:%u]: Blocking.\n", tid); + + if (dispatchStatus[tid] != Blocked && + dispatchStatus[tid] != Unblocking) { + toRename->iewBlock[tid] = true; + wroteToTimeBuffer = true; + } + + // Add the current inputs to the skid buffer so they can be + // reprocessed when this stage unblocks. + skidInsert(tid); + + dispatchStatus[tid] = Blocked; +} + +template<class Impl> +void +DefaultIEW<Impl>::unblock(unsigned tid) +{ + DPRINTF(IEW, "[tid:%i]: Reading instructions out of the skid " + "buffer %u.\n",tid, tid); + + // If the skid bufffer is empty, signal back to previous stages to unblock. + // Also switch status to running. + if (skidBuffer[tid].empty()) { + toRename->iewUnblock[tid] = true; + wroteToTimeBuffer = true; + DPRINTF(IEW, "[tid:%i]: Done unblocking.\n",tid); + dispatchStatus[tid] = Running; + } +} + +template<class Impl> +void +DefaultIEW<Impl>::wakeDependents(DynInstPtr &inst) +{ + instQueue.wakeDependents(inst); +} + +template<class Impl> +void +DefaultIEW<Impl>::rescheduleMemInst(DynInstPtr &inst) +{ + instQueue.rescheduleMemInst(inst); +} + +template<class Impl> +void +DefaultIEW<Impl>::replayMemInst(DynInstPtr &inst) +{ + instQueue.replayMemInst(inst); +} + +template<class Impl> +void +DefaultIEW<Impl>::instToCommit(DynInstPtr &inst) +{ + // First check the time slot that this instruction will write + // to. If there are free write ports at the time, then go ahead + // and write the instruction to that time. If there are not, + // keep looking back to see where's the first time there's a + // free slot. + while ((*iewQueue)[wbCycle].insts[wbNumInst]) { + ++wbNumInst; + if (wbNumInst == issueWidth) { + ++wbCycle; + wbNumInst = 0; + } + + assert(wbCycle < 5); + } + + // Add finished instruction to queue to commit. + (*iewQueue)[wbCycle].insts[wbNumInst] = inst; + (*iewQueue)[wbCycle].size++; +} + +template <class Impl> +unsigned +DefaultIEW<Impl>::validInstsFromRename() +{ + unsigned inst_count = 0; + + for (int i=0; i<fromRename->size; i++) { + if (!fromRename->insts[i]->squashed) + inst_count++; + } + + return inst_count; +} + +template<class Impl> +void +DefaultIEW<Impl>::skidInsert(unsigned tid) +{ + DynInstPtr inst = NULL; + + while (!insts[tid].empty()) { + inst = insts[tid].front(); + + insts[tid].pop(); + + DPRINTF(Decode,"[tid:%i]: Inserting [sn:%lli] PC:%#x into " + "dispatch skidBuffer %i\n",tid, inst->seqNum, + inst->readPC(),tid); + + skidBuffer[tid].push(inst); + } + + assert(skidBuffer[tid].size() <= skidBufferMax && + "Skidbuffer Exceeded Max Size"); +} + +template<class Impl> +int +DefaultIEW<Impl>::skidCount() +{ + int max=0; + + list<unsigned>::iterator threads = (*activeThreads).begin(); + + while (threads != (*activeThreads).end()) { + unsigned thread_count = skidBuffer[*threads++].size(); + if (max < thread_count) + max = thread_count; + } + + return max; +} + +template<class Impl> +bool +DefaultIEW<Impl>::skidsEmpty() +{ + list<unsigned>::iterator threads = (*activeThreads).begin(); + + while (threads != (*activeThreads).end()) { + if (!skidBuffer[*threads++].empty()) + return false; + } + + return true; +} + +template <class Impl> +void +DefaultIEW<Impl>::updateStatus() +{ + bool any_unblocking = false; + + list<unsigned>::iterator threads = (*activeThreads).begin(); + + threads = (*activeThreads).begin(); + + while (threads != (*activeThreads).end()) { + unsigned tid = *threads++; + + if (dispatchStatus[tid] == Unblocking) { + any_unblocking = true; + break; + } + } + + // If there are no ready instructions waiting to be scheduled by the IQ, + // and there's no stores waiting to write back, and dispatch is not + // unblocking, then there is no internal activity for the IEW stage. + if (_status == Active && !instQueue.hasReadyInsts() && + !ldstQueue.willWB() && !any_unblocking) { + DPRINTF(IEW, "IEW switching to idle\n"); + + deactivateStage(); + + _status = Inactive; + } else if (_status == Inactive && (instQueue.hasReadyInsts() || + ldstQueue.willWB() || + any_unblocking)) { + // Otherwise there is internal activity. Set to active. + DPRINTF(IEW, "IEW switching to active\n"); + + activateStage(); + + _status = Active; + } +} + +template <class Impl> +void +DefaultIEW<Impl>::resetEntries() +{ + instQueue.resetEntries(); + ldstQueue.resetEntries(); +} + +template <class Impl> +void +DefaultIEW<Impl>::readStallSignals(unsigned tid) +{ + if (fromCommit->commitBlock[tid]) { + stalls[tid].commit = true; + } + + if (fromCommit->commitUnblock[tid]) { + assert(stalls[tid].commit); + stalls[tid].commit = false; + } +} + +template <class Impl> +bool +DefaultIEW<Impl>::checkStall(unsigned tid) +{ + bool ret_val(false); + + if (stalls[tid].commit) { + DPRINTF(IEW,"[tid:%i]: Stall from Commit stage detected.\n",tid); + ret_val = true; + } else if (instQueue.isFull(tid)) { + DPRINTF(IEW,"[tid:%i]: Stall: IQ is full.\n",tid); + ret_val = true; + } else if (ldstQueue.isFull(tid)) { + DPRINTF(IEW,"[tid:%i]: Stall: LSQ is full\n",tid); + + if (ldstQueue.numLoads(tid) > 0 ) { + + DPRINTF(IEW,"[tid:%i]: LSQ oldest load: [sn:%i] \n", + tid,ldstQueue.getLoadHeadSeqNum(tid)); + } + + if (ldstQueue.numStores(tid) > 0) { + + DPRINTF(IEW,"[tid:%i]: LSQ oldest store: [sn:%i] \n", + tid,ldstQueue.getStoreHeadSeqNum(tid)); + } + + ret_val = true; + } else if (ldstQueue.isStalled(tid)) { + DPRINTF(IEW,"[tid:%i]: Stall: LSQ stall detected.\n",tid); + ret_val = true; + } + + return ret_val; +} + +template <class Impl> +void +DefaultIEW<Impl>::checkSignalsAndUpdate(unsigned tid) +{ + // Check if there's a squash signal, squash if there is + // Check stall signals, block if there is. + // If status was Blocked + // if so then go to unblocking + // If status was Squashing + // check if squashing is not high. Switch to running this cycle. + + readStallSignals(tid); + + if (fromCommit->commitInfo[tid].squash) { + squash(tid); + + if (dispatchStatus[tid] == Blocked || + dispatchStatus[tid] == Unblocking) { + toRename->iewUnblock[tid] = true; + wroteToTimeBuffer = true; + } + + dispatchStatus[tid] = Squashing; + + fetchRedirect[tid] = false; + return; + } + + if (fromCommit->commitInfo[tid].robSquashing) { + DPRINTF(IEW, "[tid:%i]: ROB is still squashing.\n"); + + dispatchStatus[tid] = Squashing; + + return; + } + + if (checkStall(tid)) { + block(tid); + dispatchStatus[tid] = Blocked; + return; + } + + if (dispatchStatus[tid] == Blocked) { + // Status from previous cycle was blocked, but there are no more stall + // conditions. Switch over to unblocking. + DPRINTF(IEW, "[tid:%i]: Done blocking, switching to unblocking.\n", + tid); + + dispatchStatus[tid] = Unblocking; + + unblock(tid); + + return; + } + + if (dispatchStatus[tid] == Squashing) { + // Switch status to running if rename isn't being told to block or + // squash this cycle. + DPRINTF(IEW, "[tid:%i]: Done squashing, switching to running.\n", + tid); + + dispatchStatus[tid] = Running; + + return; + } +} + +template <class Impl> +void +DefaultIEW<Impl>::sortInsts() +{ + int insts_from_rename = fromRename->size; +#ifdef DEBUG + for (int i = 0; i < numThreads; i++) + assert(insts[i].empty()); +#endif + for (int i = 0; i < insts_from_rename; ++i) { + insts[fromRename->insts[i]->threadNumber].push(fromRename->insts[i]); + } +} + +template <class Impl> +void +DefaultIEW<Impl>::wakeCPU() +{ + cpu->wakeCPU(); +} + +template <class Impl> +void +DefaultIEW<Impl>::activityThisCycle() +{ + DPRINTF(Activity, "Activity this cycle.\n"); + cpu->activityThisCycle(); +} + +template <class Impl> +inline void +DefaultIEW<Impl>::activateStage() +{ + DPRINTF(Activity, "Activating stage.\n"); + cpu->activateStage(FullCPU::IEWIdx); +} + +template <class Impl> +inline void +DefaultIEW<Impl>::deactivateStage() +{ + DPRINTF(Activity, "Deactivating stage.\n"); + cpu->deactivateStage(FullCPU::IEWIdx); +} + +template<class Impl> +void +DefaultIEW<Impl>::dispatch(unsigned tid) +{ + // If status is Running or idle, + // call dispatchInsts() + // If status is Unblocking, + // buffer any instructions coming from rename + // continue trying to empty skid buffer + // check if stall conditions have passed + + if (dispatchStatus[tid] == Blocked) { + ++iewBlockCycles; + + } else if (dispatchStatus[tid] == Squashing) { + ++iewSquashCycles; + } + + // Dispatch should try to dispatch as many instructions as its bandwidth + // will allow, as long as it is not currently blocked. + if (dispatchStatus[tid] == Running || + dispatchStatus[tid] == Idle) { + DPRINTF(IEW, "[tid:%i] Not blocked, so attempting to run " + "dispatch.\n", tid); + + dispatchInsts(tid); + } else if (dispatchStatus[tid] == Unblocking) { + // Make sure that the skid buffer has something in it if the + // status is unblocking. + assert(!skidsEmpty()); + + // If the status was unblocking, then instructions from the skid + // buffer were used. Remove those instructions and handle + // the rest of unblocking. + dispatchInsts(tid); + + ++iewUnblockCycles; + + if (validInstsFromRename() && dispatchedAllInsts) { + // Add the current inputs to the skid buffer so they can be + // reprocessed when this stage unblocks. + skidInsert(tid); + } + + unblock(tid); + } +} + +template <class Impl> +void +DefaultIEW<Impl>::dispatchInsts(unsigned tid) +{ + dispatchedAllInsts = true; + + // Obtain instructions from skid buffer if unblocking, or queue from rename + // otherwise. + std::queue<DynInstPtr> &insts_to_dispatch = + dispatchStatus[tid] == Unblocking ? + skidBuffer[tid] : insts[tid]; + + int insts_to_add = insts_to_dispatch.size(); + + DynInstPtr inst; + bool add_to_iq = false; + int dis_num_inst = 0; + + // Loop through the instructions, putting them in the instruction + // queue. + for ( ; dis_num_inst < insts_to_add && + dis_num_inst < issueReadWidth; + ++dis_num_inst) + { + inst = insts_to_dispatch.front(); + + if (dispatchStatus[tid] == Unblocking) { + DPRINTF(IEW, "[tid:%i]: Issue: Examining instruction from skid " + "buffer\n", tid); + } + + // Make sure there's a valid instruction there. + assert(inst); + + DPRINTF(IEW, "[tid:%i]: Issue: Adding PC %#x [sn:%lli] [tid:%i] to " + "IQ.\n", + tid, inst->readPC(), inst->seqNum, inst->threadNumber); + + // Be sure to mark these instructions as ready so that the + // commit stage can go ahead and execute them, and mark + // them as issued so the IQ doesn't reprocess them. + + // Check for squashed instructions. + if (inst->isSquashed()) { + DPRINTF(IEW, "[tid:%i]: Issue: Squashed instruction encountered, " + "not adding to IQ.\n", tid); + + ++iewDispSquashedInsts; + + insts_to_dispatch.pop(); + + //Tell Rename That An Instruction has been processed + if (inst->isLoad() || inst->isStore()) { + toRename->iewInfo[tid].dispatchedToLSQ++; + } + toRename->iewInfo[tid].dispatched++; + + continue; + } + + // Check for full conditions. + if (instQueue.isFull(tid)) { + DPRINTF(IEW, "[tid:%i]: Issue: IQ has become full.\n", tid); + + // Call function to start blocking. + block(tid); + + // Set unblock to false. Special case where we are using + // skidbuffer (unblocking) instructions but then we still + // get full in the IQ. + toRename->iewUnblock[tid] = false; + + dispatchedAllInsts = false; + + ++iewIQFullEvents; + break; + } else if (ldstQueue.isFull(tid)) { + DPRINTF(IEW, "[tid:%i]: Issue: LSQ has become full.\n",tid); + + // Call function to start blocking. + block(tid); + + // Set unblock to false. Special case where we are using + // skidbuffer (unblocking) instructions but then we still + // get full in the IQ. + toRename->iewUnblock[tid] = false; + + dispatchedAllInsts = false; + + ++iewLSQFullEvents; + break; + } + + // Otherwise issue the instruction just fine. + if (inst->isLoad()) { + DPRINTF(IEW, "[tid:%i]: Issue: Memory instruction " + "encountered, adding to LSQ.\n", tid); + + // Reserve a spot in the load store queue for this + // memory access. + ldstQueue.insertLoad(inst); + + ++iewDispLoadInsts; + + add_to_iq = true; + + toRename->iewInfo[tid].dispatchedToLSQ++; + } else if (inst->isStore()) { + DPRINTF(IEW, "[tid:%i]: Issue: Memory instruction " + "encountered, adding to LSQ.\n", tid); + + ldstQueue.insertStore(inst); + + ++iewDispStoreInsts; + + if (inst->isStoreConditional()) { + // Store conditionals need to be set as "canCommit()" + // so that commit can process them when they reach the + // head of commit. + // @todo: This is somewhat specific to Alpha. + inst->setCanCommit(); + instQueue.insertNonSpec(inst); + add_to_iq = false; + + ++iewDispNonSpecInsts; + } else { + add_to_iq = true; + } + + toRename->iewInfo[tid].dispatchedToLSQ++; +#if FULL_SYSTEM + } else if (inst->isMemBarrier() || inst->isWriteBarrier()) { + // Same as non-speculative stores. + inst->setCanCommit(); + instQueue.insertBarrier(inst); + add_to_iq = false; +#endif + } else if (inst->isNonSpeculative()) { + DPRINTF(IEW, "[tid:%i]: Issue: Nonspeculative instruction " + "encountered, skipping.\n", tid); + + // Same as non-speculative stores. + inst->setCanCommit(); + + // Specifically insert it as nonspeculative. + instQueue.insertNonSpec(inst); + + ++iewDispNonSpecInsts; + + add_to_iq = false; + } else if (inst->isNop()) { + DPRINTF(IEW, "[tid:%i]: Issue: Nop instruction encountered, " + "skipping.\n", tid); + + inst->setIssued(); + inst->setExecuted(); + inst->setCanCommit(); + + instQueue.recordProducer(inst); + + exeNop[tid]++; + + add_to_iq = false; + } else if (inst->isExecuted()) { + assert(0 && "Instruction shouldn't be executed.\n"); + DPRINTF(IEW, "Issue: Executed branch encountered, " + "skipping.\n"); + + inst->setIssued(); + inst->setCanCommit(); + + instQueue.recordProducer(inst); + + add_to_iq = false; + } else { + add_to_iq = true; + } + + // If the instruction queue is not full, then add the + // instruction. + if (add_to_iq) { + instQueue.insert(inst); + } + + insts_to_dispatch.pop(); + + toRename->iewInfo[tid].dispatched++; + + ++iewDispatchedInsts; + } + + if (!insts_to_dispatch.empty()) { + DPRINTF(IEW,"[tid:%i]: Issue: Bandwidth Full. Blocking.\n"); + block(tid); + toRename->iewUnblock[tid] = false; + } + + if (dispatchStatus[tid] == Idle && dis_num_inst) { + dispatchStatus[tid] = Running; + + updatedQueues = true; + } + + dis_num_inst = 0; +} + +template <class Impl> +void +DefaultIEW<Impl>::printAvailableInsts() +{ + int inst = 0; + + cout << "Available Instructions: "; + + while (fromIssue->insts[inst]) { + + if (inst%3==0) cout << "\n\t"; + + cout << "PC: " << fromIssue->insts[inst]->readPC() + << " TN: " << fromIssue->insts[inst]->threadNumber + << " SN: " << fromIssue->insts[inst]->seqNum << " | "; + + inst++; + + } + + cout << "\n"; +} + +template <class Impl> +void +DefaultIEW<Impl>::executeInsts() +{ + wbNumInst = 0; + wbCycle = 0; + + list<unsigned>::iterator threads = (*activeThreads).begin(); + + while (threads != (*activeThreads).end()) { + unsigned tid = *threads++; + fetchRedirect[tid] = false; + } + + // Uncomment this if you want to see all available instructions. +// printAvailableInsts(); + + // Execute/writeback any instructions that are available. + int insts_to_execute = fromIssue->size; + int inst_num = 0; + for (; inst_num < insts_to_execute; + ++inst_num) { + + DPRINTF(IEW, "Execute: Executing instructions from IQ.\n"); + + DynInstPtr inst = instQueue.getInstToExecute(); + + DPRINTF(IEW, "Execute: Processing PC %#x, [tid:%i] [sn:%i].\n", + inst->readPC(), inst->threadNumber,inst->seqNum); + + // Check if the instruction is squashed; if so then skip it + if (inst->isSquashed()) { + DPRINTF(IEW, "Execute: Instruction was squashed.\n"); + + // Consider this instruction executed so that commit can go + // ahead and retire the instruction. + inst->setExecuted(); + + // Not sure if I should set this here or just let commit try to + // commit any squashed instructions. I like the latter a bit more. + inst->setCanCommit(); + + ++iewExecSquashedInsts; + + continue; + } + + Fault fault = NoFault; + + // Execute instruction. + // Note that if the instruction faults, it will be handled + // at the commit stage. + if (inst->isMemRef() && + (!inst->isDataPrefetch() && !inst->isInstPrefetch())) { + DPRINTF(IEW, "Execute: Calculating address for memory " + "reference.\n"); + + // Tell the LDSTQ to execute this instruction (if it is a load). + if (inst->isLoad()) { + // Loads will mark themselves as executed, and their writeback + // event adds the instruction to the queue to commit + fault = ldstQueue.executeLoad(inst); + } else if (inst->isStore()) { + ldstQueue.executeStore(inst); + + // If the store had a fault then it may not have a mem req + if (inst->req && !(inst->req->getFlags() & LOCKED)) { + inst->setExecuted(); + + instToCommit(inst); + } + + // Store conditionals will mark themselves as + // executed, and their writeback event will add the + // instruction to the queue to commit. + } else { + panic("Unexpected memory type!\n"); + } + + } else { + inst->execute(); + + inst->setExecuted(); + + instToCommit(inst); + } + + updateExeInstStats(inst); + + // Check if branch prediction was correct, if not then we need + // to tell commit to squash in flight instructions. Only + // handle this if there hasn't already been something that + // redirects fetch in this group of instructions. + + // This probably needs to prioritize the redirects if a different + // scheduler is used. Currently the scheduler schedules the oldest + // instruction first, so the branch resolution order will be correct. + unsigned tid = inst->threadNumber; + + if (!fetchRedirect[tid]) { + + if (inst->mispredicted()) { + fetchRedirect[tid] = true; + + DPRINTF(IEW, "Execute: Branch mispredict detected.\n"); + DPRINTF(IEW, "Execute: Redirecting fetch to PC: %#x.\n", + inst->nextPC); + + // If incorrect, then signal the ROB that it must be squashed. + squashDueToBranch(inst, tid); + + if (inst->predTaken()) { + predictedTakenIncorrect++; + } else { + predictedNotTakenIncorrect++; + } + } else if (ldstQueue.violation(tid)) { + fetchRedirect[tid] = true; + + // If there was an ordering violation, then get the + // DynInst that caused the violation. Note that this + // clears the violation signal. + DynInstPtr violator; + violator = ldstQueue.getMemDepViolator(tid); + + DPRINTF(IEW, "LDSTQ detected a violation. Violator PC: " + "%#x, inst PC: %#x. Addr is: %#x.\n", + violator->readPC(), inst->readPC(), inst->physEffAddr); + + // Tell the instruction queue that a violation has occured. + instQueue.violation(inst, violator); + + // Squash. + squashDueToMemOrder(inst,tid); + + ++memOrderViolationEvents; + } else if (ldstQueue.loadBlocked(tid) && + !ldstQueue.isLoadBlockedHandled(tid)) { + fetchRedirect[tid] = true; + + DPRINTF(IEW, "Load operation couldn't execute because the " + "memory system is blocked. PC: %#x [sn:%lli]\n", + inst->readPC(), inst->seqNum); + + squashDueToMemBlocked(inst, tid); + } + } + } + + // Update and record activity if we processed any instructions. + if (inst_num) { + if (exeStatus == Idle) { + exeStatus = Running; + } + + updatedQueues = true; + + cpu->activityThisCycle(); + } + + // Need to reset this in case a writeback event needs to write into the + // iew queue. That way the writeback event will write into the correct + // spot in the queue. + wbNumInst = 0; +} + +template <class Impl> +void +DefaultIEW<Impl>::writebackInsts() +{ + // Loop through the head of the time buffer and wake any + // dependents. These instructions are about to write back. Also + // mark scoreboard that this instruction is finally complete. + // Either have IEW have direct access to scoreboard, or have this + // as part of backwards communication. + for (int inst_num = 0; inst_num < issueWidth && + toCommit->insts[inst_num]; inst_num++) { + DynInstPtr inst = toCommit->insts[inst_num]; + int tid = inst->threadNumber; + + DPRINTF(IEW, "Sending instructions to commit, [sn:%lli] PC %#x.\n", + inst->seqNum, inst->readPC()); + + iewInstsToCommit[tid]++; + + // Some instructions will be sent to commit without having + // executed because they need commit to handle them. + // E.g. Uncached loads have not actually executed when they + // are first sent to commit. Instead commit must tell the LSQ + // when it's ready to execute the uncached load. + if (!inst->isSquashed() && inst->isExecuted()) { + int dependents = instQueue.wakeDependents(inst); + + for (int i = 0; i < inst->numDestRegs(); i++) { + //mark as Ready + DPRINTF(IEW,"Setting Destination Register %i\n", + inst->renamedDestRegIdx(i)); + scoreboard->setReg(inst->renamedDestRegIdx(i)); + } + + if (dependents) { + producerInst[tid]++; + consumerInst[tid]+= dependents; + } + writebackCount[tid]++; + } + } +} + +template<class Impl> +void +DefaultIEW<Impl>::tick() +{ + wbNumInst = 0; + wbCycle = 0; + + wroteToTimeBuffer = false; + updatedQueues = false; + + sortInsts(); + + // Free function units marked as being freed this cycle. + fuPool->processFreeUnits(); + + list<unsigned>::iterator threads = (*activeThreads).begin(); + + // Check stall and squash signals, dispatch any instructions. + while (threads != (*activeThreads).end()) { + unsigned tid = *threads++; + + DPRINTF(IEW,"Issue: Processing [tid:%i]\n",tid); + + checkSignalsAndUpdate(tid); + dispatch(tid); + } + + if (exeStatus != Squashing) { + executeInsts(); + + writebackInsts(); + + // Have the instruction queue try to schedule any ready instructions. + // (In actuality, this scheduling is for instructions that will + // be executed next cycle.) + instQueue.scheduleReadyInsts(); + + // Also should advance its own time buffers if the stage ran. + // Not the best place for it, but this works (hopefully). + issueToExecQueue.advance(); + } + + bool broadcast_free_entries = false; + + if (updatedQueues || exeStatus == Running || updateLSQNextCycle) { + exeStatus = Idle; + updateLSQNextCycle = false; + + broadcast_free_entries = true; + } + + // Writeback any stores using any leftover bandwidth. + ldstQueue.writebackStores(); + + // Check the committed load/store signals to see if there's a load + // or store to commit. Also check if it's being told to execute a + // nonspeculative instruction. + // This is pretty inefficient... + + threads = (*activeThreads).begin(); + while (threads != (*activeThreads).end()) { + unsigned tid = (*threads++); + + DPRINTF(IEW,"Processing [tid:%i]\n",tid); + + // Update structures based on instructions committed. + if (fromCommit->commitInfo[tid].doneSeqNum != 0 && + !fromCommit->commitInfo[tid].squash && + !fromCommit->commitInfo[tid].robSquashing) { + + ldstQueue.commitStores(fromCommit->commitInfo[tid].doneSeqNum,tid); + + ldstQueue.commitLoads(fromCommit->commitInfo[tid].doneSeqNum,tid); + + updateLSQNextCycle = true; + instQueue.commit(fromCommit->commitInfo[tid].doneSeqNum,tid); + } + + if (fromCommit->commitInfo[tid].nonSpecSeqNum != 0) { + + //DPRINTF(IEW,"NonspecInst from thread %i",tid); + if (fromCommit->commitInfo[tid].uncached) { + instQueue.replayMemInst(fromCommit->commitInfo[tid].uncachedLoad); + } else { + instQueue.scheduleNonSpec( + fromCommit->commitInfo[tid].nonSpecSeqNum); + } + } + + if (broadcast_free_entries) { + toFetch->iewInfo[tid].iqCount = + instQueue.getCount(tid); + toFetch->iewInfo[tid].ldstqCount = + ldstQueue.getCount(tid); + + toRename->iewInfo[tid].usedIQ = true; + toRename->iewInfo[tid].freeIQEntries = + instQueue.numFreeEntries(); + toRename->iewInfo[tid].usedLSQ = true; + toRename->iewInfo[tid].freeLSQEntries = + ldstQueue.numFreeEntries(tid); + + wroteToTimeBuffer = true; + } + + DPRINTF(IEW, "[tid:%i], Dispatch dispatched %i instructions.\n", + tid, toRename->iewInfo[tid].dispatched); + } + + DPRINTF(IEW, "IQ has %i free entries (Can schedule: %i). " + "LSQ has %i free entries.\n", + instQueue.numFreeEntries(), instQueue.hasReadyInsts(), + ldstQueue.numFreeEntries()); + + updateStatus(); + + if (wroteToTimeBuffer) { + DPRINTF(Activity, "Activity this cycle.\n"); + cpu->activityThisCycle(); + } +} + +template <class Impl> +void +DefaultIEW<Impl>::updateExeInstStats(DynInstPtr &inst) +{ + int thread_number = inst->threadNumber; + + // + // Pick off the software prefetches + // +#ifdef TARGET_ALPHA + if (inst->isDataPrefetch()) + exeSwp[thread_number]++; + else + iewExecutedInsts++; +#else + iewExecutedInsts++; +#endif + + // + // Control operations + // + if (inst->isControl()) + exeBranches[thread_number]++; + + // + // Memory operations + // + if (inst->isMemRef()) { + exeRefs[thread_number]++; + + if (inst->isLoad()) { + iewExecLoadInsts[thread_number]++; + } + } +} diff --git a/src/cpu/o3/inst_queue.cc b/src/cpu/o3/inst_queue.cc new file mode 100644 index 000000000..f2c6b8213 --- /dev/null +++ b/src/cpu/o3/inst_queue.cc @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#include "cpu/o3/alpha_dyn_inst.hh" +#include "cpu/o3/alpha_impl.hh" +#include "cpu/o3/inst_queue_impl.hh" + +// Force instantiation of InstructionQueue. +template class InstructionQueue<AlphaSimpleImpl>; diff --git a/src/cpu/o3/inst_queue.hh b/src/cpu/o3/inst_queue.hh new file mode 100644 index 000000000..60a713020 --- /dev/null +++ b/src/cpu/o3/inst_queue.hh @@ -0,0 +1,503 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#ifndef __CPU_O3_INST_QUEUE_HH__ +#define __CPU_O3_INST_QUEUE_HH__ + +#include <list> +#include <map> +#include <queue> +#include <vector> + +#include "base/statistics.hh" +#include "base/timebuf.hh" +#include "cpu/inst_seq.hh" +#include "cpu/o3/dep_graph.hh" +#include "cpu/op_class.hh" +#include "sim/host.hh" + +class FUPool; +class MemInterface; + +/** + * A standard instruction queue class. It holds ready instructions, in + * order, in seperate priority queues to facilitate the scheduling of + * instructions. The IQ uses a separate linked list to track dependencies. + * Similar to the rename map and the free list, it expects that + * floating point registers have their indices start after the integer + * registers (ie with 96 int and 96 fp registers, regs 0-95 are integer + * and 96-191 are fp). This remains true even for both logical and + * physical register indices. The IQ depends on the memory dependence unit to + * track when memory operations are ready in terms of ordering; register + * dependencies are tracked normally. Right now the IQ also handles the + * execution timing; this is mainly to allow back-to-back scheduling without + * requiring IEW to be able to peek into the IQ. At the end of the execution + * latency, the instruction is put into the queue to execute, where it will + * have the execute() function called on it. + * @todo: Make IQ able to handle multiple FU pools. + */ +template <class Impl> +class InstructionQueue +{ + public: + //Typedefs from the Impl. + typedef typename Impl::FullCPU FullCPU; + typedef typename Impl::DynInstPtr DynInstPtr; + typedef typename Impl::Params Params; + + typedef typename Impl::CPUPol::IEW IEW; + typedef typename Impl::CPUPol::MemDepUnit MemDepUnit; + typedef typename Impl::CPUPol::IssueStruct IssueStruct; + typedef typename Impl::CPUPol::TimeStruct TimeStruct; + + // Typedef of iterator through the list of instructions. + typedef typename std::list<DynInstPtr>::iterator ListIt; + + friend class Impl::FullCPU; + + /** FU completion event class. */ + class FUCompletion : public Event { + private: + /** Executing instruction. */ + DynInstPtr inst; + + /** Index of the FU used for executing. */ + int fuIdx; + + /** Pointer back to the instruction queue. */ + InstructionQueue<Impl> *iqPtr; + + /** Should the FU be added to the list to be freed upon + * completing this event. + */ + bool freeFU; + + public: + /** Construct a FU completion event. */ + FUCompletion(DynInstPtr &_inst, int fu_idx, + InstructionQueue<Impl> *iq_ptr); + + virtual void process(); + virtual const char *description(); + void setFreeFU() { freeFU = true; } + }; + + /** Constructs an IQ. */ + InstructionQueue(Params *params); + + /** Destructs the IQ. */ + ~InstructionQueue(); + + /** Returns the name of the IQ. */ + std::string name() const; + + /** Registers statistics. */ + void regStats(); + + /** Resets all instruction queue state. */ + void resetState(); + + /** Sets CPU pointer. */ + void setCPU(FullCPU *_cpu) { cpu = _cpu; } + + /** Sets active threads list. */ + void setActiveThreads(std::list<unsigned> *at_ptr); + + /** Sets the IEW pointer. */ + void setIEW(IEW *iew_ptr) { iewStage = iew_ptr; } + + /** Sets the timer buffer between issue and execute. */ + void setIssueToExecuteQueue(TimeBuffer<IssueStruct> *i2eQueue); + + /** Sets the global time buffer. */ + void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr); + + /** Switches out the instruction queue. */ + void switchOut(); + + /** Takes over execution from another CPU's thread. */ + void takeOverFrom(); + + /** Returns if the IQ is switched out. */ + bool isSwitchedOut() { return switchedOut; } + + /** Number of entries needed for given amount of threads. */ + int entryAmount(int num_threads); + + /** Resets max entries for all threads. */ + void resetEntries(); + + /** Returns total number of free entries. */ + unsigned numFreeEntries(); + + /** Returns number of free entries for a thread. */ + unsigned numFreeEntries(unsigned tid); + + /** Returns whether or not the IQ is full. */ + bool isFull(); + + /** Returns whether or not the IQ is full for a specific thread. */ + bool isFull(unsigned tid); + + /** Returns if there are any ready instructions in the IQ. */ + bool hasReadyInsts(); + + /** Inserts a new instruction into the IQ. */ + void insert(DynInstPtr &new_inst); + + /** Inserts a new, non-speculative instruction into the IQ. */ + void insertNonSpec(DynInstPtr &new_inst); + + /** Inserts a memory or write barrier into the IQ to make sure + * loads and stores are ordered properly. + */ + void insertBarrier(DynInstPtr &barr_inst); + + /** Returns the oldest scheduled instruction, and removes it from + * the list of instructions waiting to execute. + */ + DynInstPtr getInstToExecute(); + + /** + * Records the instruction as the producer of a register without + * adding it to the rest of the IQ. + */ + void recordProducer(DynInstPtr &inst) + { addToProducers(inst); } + + /** Process FU completion event. */ + void processFUCompletion(DynInstPtr &inst, int fu_idx); + + /** + * Schedules ready instructions, adding the ready ones (oldest first) to + * the queue to execute. + */ + void scheduleReadyInsts(); + + /** Schedules a single specific non-speculative instruction. */ + void scheduleNonSpec(const InstSeqNum &inst); + + /** + * Commits all instructions up to and including the given sequence number, + * for a specific thread. + */ + void commit(const InstSeqNum &inst, unsigned tid = 0); + + /** Wakes all dependents of a completed instruction. */ + int wakeDependents(DynInstPtr &completed_inst); + + /** Adds a ready memory instruction to the ready list. */ + void addReadyMemInst(DynInstPtr &ready_inst); + + /** + * Reschedules a memory instruction. It will be ready to issue once + * replayMemInst() is called. + */ + void rescheduleMemInst(DynInstPtr &resched_inst); + + /** Replays a memory instruction. It must be rescheduled first. */ + void replayMemInst(DynInstPtr &replay_inst); + + /** Completes a memory operation. */ + void completeMemInst(DynInstPtr &completed_inst); + + /** Indicates an ordering violation between a store and a load. */ + void violation(DynInstPtr &store, DynInstPtr &faulting_load); + + /** + * Squashes instructions for a thread. Squashing information is obtained + * from the time buffer. + */ + void squash(unsigned tid); + + /** Returns the number of used entries for a thread. */ + unsigned getCount(unsigned tid) { return count[tid]; }; + + /** Debug function to print all instructions. */ + void printInsts(); + + private: + /** Does the actual squashing. */ + void doSquash(unsigned tid); + + ///////////////////////// + // Various pointers + ///////////////////////// + + /** Pointer to the CPU. */ + FullCPU *cpu; + + /** Cache interface. */ + MemInterface *dcacheInterface; + + /** Pointer to IEW stage. */ + IEW *iewStage; + + /** The memory dependence unit, which tracks/predicts memory dependences + * between instructions. + */ + MemDepUnit memDepUnit[Impl::MaxThreads]; + + /** The queue to the execute stage. Issued instructions will be written + * into it. + */ + TimeBuffer<IssueStruct> *issueToExecuteQueue; + + /** The backwards time buffer. */ + TimeBuffer<TimeStruct> *timeBuffer; + + /** Wire to read information from timebuffer. */ + typename TimeBuffer<TimeStruct>::wire fromCommit; + + /** Function unit pool. */ + FUPool *fuPool; + + ////////////////////////////////////// + // Instruction lists, ready queues, and ordering + ////////////////////////////////////// + + /** List of all the instructions in the IQ (some of which may be issued). */ + std::list<DynInstPtr> instList[Impl::MaxThreads]; + + /** List of instructions that are ready to be executed. */ + std::list<DynInstPtr> instsToExecute; + + /** + * Struct for comparing entries to be added to the priority queue. + * This gives reverse ordering to the instructions in terms of + * sequence numbers: the instructions with smaller sequence + * numbers (and hence are older) will be at the top of the + * priority queue. + */ + struct pqCompare { + bool operator() (const DynInstPtr &lhs, const DynInstPtr &rhs) const + { + return lhs->seqNum > rhs->seqNum; + } + }; + + typedef std::priority_queue<DynInstPtr, std::vector<DynInstPtr>, pqCompare> + ReadyInstQueue; + + /** List of ready instructions, per op class. They are separated by op + * class to allow for easy mapping to FUs. + */ + ReadyInstQueue readyInsts[Num_OpClasses]; + + /** List of non-speculative instructions that will be scheduled + * once the IQ gets a signal from commit. While it's redundant to + * have the key be a part of the value (the sequence number is stored + * inside of DynInst), when these instructions are woken up only + * the sequence number will be available. Thus it is most efficient to be + * able to search by the sequence number alone. + */ + std::map<InstSeqNum, DynInstPtr> nonSpecInsts; + + typedef typename std::map<InstSeqNum, DynInstPtr>::iterator NonSpecMapIt; + + /** Entry for the list age ordering by op class. */ + struct ListOrderEntry { + OpClass queueType; + InstSeqNum oldestInst; + }; + + /** List that contains the age order of the oldest instruction of each + * ready queue. Used to select the oldest instruction available + * among op classes. + * @todo: Might be better to just move these entries around instead + * of creating new ones every time the position changes due to an + * instruction issuing. Not sure std::list supports this. + */ + std::list<ListOrderEntry> listOrder; + + typedef typename std::list<ListOrderEntry>::iterator ListOrderIt; + + /** Tracks if each ready queue is on the age order list. */ + bool queueOnList[Num_OpClasses]; + + /** Iterators of each ready queue. Points to their spot in the age order + * list. + */ + ListOrderIt readyIt[Num_OpClasses]; + + /** Add an op class to the age order list. */ + void addToOrderList(OpClass op_class); + + /** + * Called when the oldest instruction has been removed from a ready queue; + * this places that ready queue into the proper spot in the age order list. + */ + void moveToYoungerInst(ListOrderIt age_order_it); + + DependencyGraph<DynInstPtr> dependGraph; + + ////////////////////////////////////// + // Various parameters + ////////////////////////////////////// + + /** IQ Resource Sharing Policy */ + enum IQPolicy { + Dynamic, + Partitioned, + Threshold + }; + + /** IQ sharing policy for SMT. */ + IQPolicy iqPolicy; + + /** Number of Total Threads*/ + unsigned numThreads; + + /** Pointer to list of active threads. */ + std::list<unsigned> *activeThreads; + + /** Per Thread IQ count */ + unsigned count[Impl::MaxThreads]; + + /** Max IQ Entries Per Thread */ + unsigned maxEntries[Impl::MaxThreads]; + + /** Number of free IQ entries left. */ + unsigned freeEntries; + + /** The number of entries in the instruction queue. */ + unsigned numEntries; + + /** The total number of instructions that can be issued in one cycle. */ + unsigned totalWidth; + + /** The number of physical registers in the CPU. */ + unsigned numPhysRegs; + + /** The number of physical integer registers in the CPU. */ + unsigned numPhysIntRegs; + + /** The number of floating point registers in the CPU. */ + unsigned numPhysFloatRegs; + + /** Delay between commit stage and the IQ. + * @todo: Make there be a distinction between the delays within IEW. + */ + unsigned commitToIEWDelay; + + /** Is the IQ switched out. */ + bool switchedOut; + + /** The sequence number of the squashed instruction. */ + InstSeqNum squashedSeqNum[Impl::MaxThreads]; + + /** A cache of the recently woken registers. It is 1 if the register + * has been woken up recently, and 0 if the register has been added + * to the dependency graph and has not yet received its value. It + * is basically a secondary scoreboard, and should pretty much mirror + * the scoreboard that exists in the rename map. + */ + std::vector<bool> regScoreboard; + + /** Adds an instruction to the dependency graph, as a consumer. */ + bool addToDependents(DynInstPtr &new_inst); + + /** Adds an instruction to the dependency graph, as a producer. */ + void addToProducers(DynInstPtr &new_inst); + + /** Moves an instruction to the ready queue if it is ready. */ + void addIfReady(DynInstPtr &inst); + + /** Debugging function to count how many entries are in the IQ. It does + * a linear walk through the instructions, so do not call this function + * during normal execution. + */ + int countInsts(); + + /** Debugging function to dump all the list sizes, as well as print + * out the list of nonspeculative instructions. Should not be used + * in any other capacity, but it has no harmful sideaffects. + */ + void dumpLists(); + + /** Debugging function to dump out all instructions that are in the + * IQ. + */ + void dumpInsts(); + + /** Stat for number of instructions added. */ + Stats::Scalar<> iqInstsAdded; + /** Stat for number of non-speculative instructions added. */ + Stats::Scalar<> iqNonSpecInstsAdded; + + Stats::Scalar<> iqInstsIssued; + /** Stat for number of integer instructions issued. */ + Stats::Scalar<> iqIntInstsIssued; + /** Stat for number of floating point instructions issued. */ + Stats::Scalar<> iqFloatInstsIssued; + /** Stat for number of branch instructions issued. */ + Stats::Scalar<> iqBranchInstsIssued; + /** Stat for number of memory instructions issued. */ + Stats::Scalar<> iqMemInstsIssued; + /** Stat for number of miscellaneous instructions issued. */ + Stats::Scalar<> iqMiscInstsIssued; + /** Stat for number of squashed instructions that were ready to issue. */ + Stats::Scalar<> iqSquashedInstsIssued; + /** Stat for number of squashed instructions examined when squashing. */ + Stats::Scalar<> iqSquashedInstsExamined; + /** Stat for number of squashed instruction operands examined when + * squashing. + */ + Stats::Scalar<> iqSquashedOperandsExamined; + /** Stat for number of non-speculative instructions removed due to a squash. + */ + Stats::Scalar<> iqSquashedNonSpecRemoved; + + /** Distribution of number of instructions in the queue. */ + Stats::VectorDistribution<> queueResDist; + /** Distribution of the number of instructions issued. */ + Stats::Distribution<> numIssuedDist; + /** Distribution of the cycles it takes to issue an instruction. */ + Stats::VectorDistribution<> issueDelayDist; + + /** Number of times an instruction could not be issued because a + * FU was busy. + */ + Stats::Vector<> statFuBusy; +// Stats::Vector<> dist_unissued; + /** Stat for total number issued for each instruction type. */ + Stats::Vector2d<> statIssuedInstType; + + /** Number of instructions issued per cycle. */ + Stats::Formula issueRate; +// Stats::Formula issue_stores; +// Stats::Formula issue_op_rate; + /** Number of times the FU was busy. */ + Stats::Vector<> fuBusy; + /** Number of times the FU was busy per instruction issued. */ + Stats::Formula fuBusyRate; +}; + +#endif //__CPU_O3_INST_QUEUE_HH__ diff --git a/src/cpu/o3/inst_queue_impl.hh b/src/cpu/o3/inst_queue_impl.hh new file mode 100644 index 000000000..06a052c6f --- /dev/null +++ b/src/cpu/o3/inst_queue_impl.hh @@ -0,0 +1,1403 @@ +/* + * 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 <limits> +#include <vector> + +#include "sim/root.hh" + +#include "cpu/o3/fu_pool.hh" +#include "cpu/o3/inst_queue.hh" + +using namespace std; + +template <class Impl> +InstructionQueue<Impl>::FUCompletion::FUCompletion(DynInstPtr &_inst, + int fu_idx, + InstructionQueue<Impl> *iq_ptr) + : Event(&mainEventQueue, Stat_Event_Pri), + inst(_inst), fuIdx(fu_idx), iqPtr(iq_ptr), freeFU(false) +{ + this->setFlags(Event::AutoDelete); +} + +template <class Impl> +void +InstructionQueue<Impl>::FUCompletion::process() +{ + iqPtr->processFUCompletion(inst, freeFU ? fuIdx : -1); + inst = NULL; +} + + +template <class Impl> +const char * +InstructionQueue<Impl>::FUCompletion::description() +{ + return "Functional unit completion event"; +} + +template <class Impl> +InstructionQueue<Impl>::InstructionQueue(Params *params) + : fuPool(params->fuPool), + numEntries(params->numIQEntries), + totalWidth(params->issueWidth), + numPhysIntRegs(params->numPhysIntRegs), + numPhysFloatRegs(params->numPhysFloatRegs), + commitToIEWDelay(params->commitToIEWDelay) +{ + assert(fuPool); + + switchedOut = false; + + numThreads = params->numberOfThreads; + + // Set the number of physical registers as the number of int + float + numPhysRegs = numPhysIntRegs + numPhysFloatRegs; + + DPRINTF(IQ, "There are %i physical registers.\n", numPhysRegs); + + //Create an entry for each physical register within the + //dependency graph. + dependGraph.resize(numPhysRegs); + + // Resize the register scoreboard. + regScoreboard.resize(numPhysRegs); + + //Initialize Mem Dependence Units + for (int i = 0; i < numThreads; i++) { + memDepUnit[i].init(params,i); + memDepUnit[i].setIQ(this); + } + + resetState(); + + string policy = params->smtIQPolicy; + + //Convert string to lowercase + std::transform(policy.begin(), policy.end(), policy.begin(), + (int(*)(int)) tolower); + + //Figure out resource sharing policy + if (policy == "dynamic") { + iqPolicy = Dynamic; + + //Set Max Entries to Total ROB Capacity + for (int i = 0; i < numThreads; i++) { + maxEntries[i] = numEntries; + } + + } else if (policy == "partitioned") { + iqPolicy = Partitioned; + + //@todo:make work if part_amt doesnt divide evenly. + int part_amt = numEntries / numThreads; + + //Divide ROB up evenly + for (int i = 0; i < numThreads; i++) { + maxEntries[i] = part_amt; + } + + DPRINTF(Fetch, "IQ sharing policy set to Partitioned:" + "%i entries per thread.\n",part_amt); + + } else if (policy == "threshold") { + iqPolicy = Threshold; + + double threshold = (double)params->smtIQThreshold / 100; + + int thresholdIQ = (int)((double)threshold * numEntries); + + //Divide up by threshold amount + for (int i = 0; i < numThreads; i++) { + maxEntries[i] = thresholdIQ; + } + + DPRINTF(Fetch, "IQ sharing policy set to Threshold:" + "%i entries per thread.\n",thresholdIQ); + } else { + assert(0 && "Invalid IQ Sharing Policy.Options Are:{Dynamic," + "Partitioned, Threshold}"); + } +} + +template <class Impl> +InstructionQueue<Impl>::~InstructionQueue() +{ + dependGraph.reset(); +#ifdef DEBUG + cprintf("Nodes traversed: %i, removed: %i\n", + dependGraph.nodesTraversed, dependGraph.nodesRemoved); +#endif +} + +template <class Impl> +std::string +InstructionQueue<Impl>::name() const +{ + return cpu->name() + ".iq"; +} + +template <class Impl> +void +InstructionQueue<Impl>::regStats() +{ + using namespace Stats; + iqInstsAdded + .name(name() + ".iqInstsAdded") + .desc("Number of instructions added to the IQ (excludes non-spec)") + .prereq(iqInstsAdded); + + iqNonSpecInstsAdded + .name(name() + ".iqNonSpecInstsAdded") + .desc("Number of non-speculative instructions added to the IQ") + .prereq(iqNonSpecInstsAdded); + + iqInstsIssued + .name(name() + ".iqInstsIssued") + .desc("Number of instructions issued") + .prereq(iqInstsIssued); + + iqIntInstsIssued + .name(name() + ".iqIntInstsIssued") + .desc("Number of integer instructions issued") + .prereq(iqIntInstsIssued); + + iqFloatInstsIssued + .name(name() + ".iqFloatInstsIssued") + .desc("Number of float instructions issued") + .prereq(iqFloatInstsIssued); + + iqBranchInstsIssued + .name(name() + ".iqBranchInstsIssued") + .desc("Number of branch instructions issued") + .prereq(iqBranchInstsIssued); + + iqMemInstsIssued + .name(name() + ".iqMemInstsIssued") + .desc("Number of memory instructions issued") + .prereq(iqMemInstsIssued); + + iqMiscInstsIssued + .name(name() + ".iqMiscInstsIssued") + .desc("Number of miscellaneous instructions issued") + .prereq(iqMiscInstsIssued); + + iqSquashedInstsIssued + .name(name() + ".iqSquashedInstsIssued") + .desc("Number of squashed instructions issued") + .prereq(iqSquashedInstsIssued); + + iqSquashedInstsExamined + .name(name() + ".iqSquashedInstsExamined") + .desc("Number of squashed instructions iterated over during squash;" + " mainly for profiling") + .prereq(iqSquashedInstsExamined); + + iqSquashedOperandsExamined + .name(name() + ".iqSquashedOperandsExamined") + .desc("Number of squashed operands that are examined and possibly " + "removed from graph") + .prereq(iqSquashedOperandsExamined); + + iqSquashedNonSpecRemoved + .name(name() + ".iqSquashedNonSpecRemoved") + .desc("Number of squashed non-spec instructions that were removed") + .prereq(iqSquashedNonSpecRemoved); + + queueResDist + .init(Num_OpClasses, 0, 99, 2) + .name(name() + ".IQ:residence:") + .desc("cycles from dispatch to issue") + .flags(total | pdf | cdf ) + ; + for (int i = 0; i < Num_OpClasses; ++i) { + queueResDist.subname(i, opClassStrings[i]); + } + numIssuedDist + .init(0,totalWidth,1) + .name(name() + ".ISSUE:issued_per_cycle") + .desc("Number of insts issued each cycle") + .flags(pdf) + ; +/* + dist_unissued + .init(Num_OpClasses+2) + .name(name() + ".ISSUE:unissued_cause") + .desc("Reason ready instruction not issued") + .flags(pdf | dist) + ; + for (int i=0; i < (Num_OpClasses + 2); ++i) { + dist_unissued.subname(i, unissued_names[i]); + } +*/ + statIssuedInstType + .init(numThreads,Num_OpClasses) + .name(name() + ".ISSUE:FU_type") + .desc("Type of FU issued") + .flags(total | pdf | dist) + ; + statIssuedInstType.ysubnames(opClassStrings); + + // + // How long did instructions for a particular FU type wait prior to issue + // + + issueDelayDist + .init(Num_OpClasses,0,99,2) + .name(name() + ".ISSUE:") + .desc("cycles from operands ready to issue") + .flags(pdf | cdf) + ; + + for (int i=0; i<Num_OpClasses; ++i) { + stringstream subname; + subname << opClassStrings[i] << "_delay"; + issueDelayDist.subname(i, subname.str()); + } + + issueRate + .name(name() + ".ISSUE:rate") + .desc("Inst issue rate") + .flags(total) + ; + issueRate = iqInstsIssued / cpu->numCycles; +/* + issue_stores + .name(name() + ".ISSUE:stores") + .desc("Number of stores issued") + .flags(total) + ; + issue_stores = exe_refs - exe_loads; +*/ +/* + issue_op_rate + .name(name() + ".ISSUE:op_rate") + .desc("Operation issue rate") + .flags(total) + ; + issue_op_rate = issued_ops / numCycles; +*/ + statFuBusy + .init(Num_OpClasses) + .name(name() + ".ISSUE:fu_full") + .desc("attempts to use FU when none available") + .flags(pdf | dist) + ; + for (int i=0; i < Num_OpClasses; ++i) { + statFuBusy.subname(i, opClassStrings[i]); + } + + fuBusy + .init(numThreads) + .name(name() + ".ISSUE:fu_busy_cnt") + .desc("FU busy when requested") + .flags(total) + ; + + fuBusyRate + .name(name() + ".ISSUE:fu_busy_rate") + .desc("FU busy rate (busy events/executed inst)") + .flags(total) + ; + fuBusyRate = fuBusy / iqInstsIssued; + + for ( int i=0; i < numThreads; i++) { + // Tell mem dependence unit to reg stats as well. + memDepUnit[i].regStats(); + } +} + +template <class Impl> +void +InstructionQueue<Impl>::resetState() +{ + //Initialize thread IQ counts + for (int i = 0; i <numThreads; i++) { + count[i] = 0; + instList[i].clear(); + } + + // Initialize the number of free IQ entries. + freeEntries = numEntries; + + // Note that in actuality, the registers corresponding to the logical + // registers start off as ready. However this doesn't matter for the + // IQ as the instruction should have been correctly told if those + // registers are ready in rename. Thus it can all be initialized as + // unready. + for (int i = 0; i < numPhysRegs; ++i) { + regScoreboard[i] = false; + } + + for (int i = 0; i < numThreads; ++i) { + squashedSeqNum[i] = 0; + } + + for (int i = 0; i < Num_OpClasses; ++i) { + while (!readyInsts[i].empty()) + readyInsts[i].pop(); + queueOnList[i] = false; + readyIt[i] = listOrder.end(); + } + nonSpecInsts.clear(); + listOrder.clear(); +} + +template <class Impl> +void +InstructionQueue<Impl>::setActiveThreads(list<unsigned> *at_ptr) +{ + DPRINTF(IQ, "Setting active threads list pointer.\n"); + activeThreads = at_ptr; +} + +template <class Impl> +void +InstructionQueue<Impl>::setIssueToExecuteQueue(TimeBuffer<IssueStruct> *i2e_ptr) +{ + DPRINTF(IQ, "Set the issue to execute queue.\n"); + issueToExecuteQueue = i2e_ptr; +} + +template <class Impl> +void +InstructionQueue<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) +{ + DPRINTF(IQ, "Set the time buffer.\n"); + timeBuffer = tb_ptr; + + fromCommit = timeBuffer->getWire(-commitToIEWDelay); +} + +template <class Impl> +void +InstructionQueue<Impl>::switchOut() +{ + resetState(); + dependGraph.reset(); + switchedOut = true; + for (int i = 0; i < numThreads; ++i) { + memDepUnit[i].switchOut(); + } +} + +template <class Impl> +void +InstructionQueue<Impl>::takeOverFrom() +{ + switchedOut = false; +} + +template <class Impl> +int +InstructionQueue<Impl>::entryAmount(int num_threads) +{ + if (iqPolicy == Partitioned) { + return numEntries / num_threads; + } else { + return 0; + } +} + + +template <class Impl> +void +InstructionQueue<Impl>::resetEntries() +{ + if (iqPolicy != Dynamic || numThreads > 1) { + int active_threads = (*activeThreads).size(); + + list<unsigned>::iterator threads = (*activeThreads).begin(); + list<unsigned>::iterator list_end = (*activeThreads).end(); + + while (threads != list_end) { + if (iqPolicy == Partitioned) { + maxEntries[*threads++] = numEntries / active_threads; + } else if(iqPolicy == Threshold && active_threads == 1) { + maxEntries[*threads++] = numEntries; + } + } + } +} + +template <class Impl> +unsigned +InstructionQueue<Impl>::numFreeEntries() +{ + return freeEntries; +} + +template <class Impl> +unsigned +InstructionQueue<Impl>::numFreeEntries(unsigned tid) +{ + return maxEntries[tid] - count[tid]; +} + +// Might want to do something more complex if it knows how many instructions +// will be issued this cycle. +template <class Impl> +bool +InstructionQueue<Impl>::isFull() +{ + if (freeEntries == 0) { + return(true); + } else { + return(false); + } +} + +template <class Impl> +bool +InstructionQueue<Impl>::isFull(unsigned tid) +{ + if (numFreeEntries(tid) == 0) { + return(true); + } else { + return(false); + } +} + +template <class Impl> +bool +InstructionQueue<Impl>::hasReadyInsts() +{ + if (!listOrder.empty()) { + return true; + } + + for (int i = 0; i < Num_OpClasses; ++i) { + if (!readyInsts[i].empty()) { + return true; + } + } + + return false; +} + +template <class Impl> +void +InstructionQueue<Impl>::insert(DynInstPtr &new_inst) +{ + // Make sure the instruction is valid + assert(new_inst); + + DPRINTF(IQ, "Adding instruction [sn:%lli] PC %#x to the IQ.\n", + new_inst->seqNum, new_inst->readPC()); + + assert(freeEntries != 0); + + instList[new_inst->threadNumber].push_back(new_inst); + + --freeEntries; + + new_inst->setInIQ(); + + // Look through its source registers (physical regs), and mark any + // dependencies. + addToDependents(new_inst); + + // Have this instruction set itself as the producer of its destination + // register(s). + addToProducers(new_inst); + + if (new_inst->isMemRef()) { + memDepUnit[new_inst->threadNumber].insert(new_inst); + } else { + addIfReady(new_inst); + } + + ++iqInstsAdded; + + count[new_inst->threadNumber]++; + + assert(freeEntries == (numEntries - countInsts())); +} + +template <class Impl> +void +InstructionQueue<Impl>::insertNonSpec(DynInstPtr &new_inst) +{ + // @todo: Clean up this code; can do it by setting inst as unable + // to issue, then calling normal insert on the inst. + + assert(new_inst); + + nonSpecInsts[new_inst->seqNum] = new_inst; + + DPRINTF(IQ, "Adding non-speculative instruction [sn:%lli] PC %#x " + "to the IQ.\n", + new_inst->seqNum, new_inst->readPC()); + + assert(freeEntries != 0); + + instList[new_inst->threadNumber].push_back(new_inst); + + --freeEntries; + + new_inst->setInIQ(); + + // Have this instruction set itself as the producer of its destination + // register(s). + addToProducers(new_inst); + + // If it's a memory instruction, add it to the memory dependency + // unit. + if (new_inst->isMemRef()) { + memDepUnit[new_inst->threadNumber].insertNonSpec(new_inst); + } + + ++iqNonSpecInstsAdded; + + count[new_inst->threadNumber]++; + + assert(freeEntries == (numEntries - countInsts())); +} + +template <class Impl> +void +InstructionQueue<Impl>::insertBarrier(DynInstPtr &barr_inst) +{ + memDepUnit[barr_inst->threadNumber].insertBarrier(barr_inst); + + insertNonSpec(barr_inst); +} + +template <class Impl> +typename Impl::DynInstPtr +InstructionQueue<Impl>::getInstToExecute() +{ + assert(!instsToExecute.empty()); + DynInstPtr inst = instsToExecute.front(); + instsToExecute.pop_front(); + return inst; +} + +template <class Impl> +void +InstructionQueue<Impl>::addToOrderList(OpClass op_class) +{ + assert(!readyInsts[op_class].empty()); + + ListOrderEntry queue_entry; + + queue_entry.queueType = op_class; + + queue_entry.oldestInst = readyInsts[op_class].top()->seqNum; + + ListOrderIt list_it = listOrder.begin(); + ListOrderIt list_end_it = listOrder.end(); + + while (list_it != list_end_it) { + if ((*list_it).oldestInst > queue_entry.oldestInst) { + break; + } + + list_it++; + } + + readyIt[op_class] = listOrder.insert(list_it, queue_entry); + queueOnList[op_class] = true; +} + +template <class Impl> +void +InstructionQueue<Impl>::moveToYoungerInst(ListOrderIt list_order_it) +{ + // Get iterator of next item on the list + // Delete the original iterator + // Determine if the next item is either the end of the list or younger + // than the new instruction. If so, then add in a new iterator right here. + // If not, then move along. + ListOrderEntry queue_entry; + OpClass op_class = (*list_order_it).queueType; + ListOrderIt next_it = list_order_it; + + ++next_it; + + queue_entry.queueType = op_class; + queue_entry.oldestInst = readyInsts[op_class].top()->seqNum; + + while (next_it != listOrder.end() && + (*next_it).oldestInst < queue_entry.oldestInst) { + ++next_it; + } + + readyIt[op_class] = listOrder.insert(next_it, queue_entry); +} + +template <class Impl> +void +InstructionQueue<Impl>::processFUCompletion(DynInstPtr &inst, int fu_idx) +{ + // The CPU could have been sleeping until this op completed (*extremely* + // long latency op). Wake it if it was. This may be overkill. + if (isSwitchedOut()) { + return; + } + + iewStage->wakeCPU(); + + if (fu_idx > -1) + fuPool->freeUnitNextCycle(fu_idx); + + // @todo: Ensure that these FU Completions happen at the beginning + // of a cycle, otherwise they could add too many instructions to + // the queue. + issueToExecuteQueue->access(0)->size++; + instsToExecute.push_back(inst); +} + +// @todo: Figure out a better way to remove the squashed items from the +// lists. Checking the top item of each list to see if it's squashed +// wastes time and forces jumps. +template <class Impl> +void +InstructionQueue<Impl>::scheduleReadyInsts() +{ + DPRINTF(IQ, "Attempting to schedule ready instructions from " + "the IQ.\n"); + + IssueStruct *i2e_info = issueToExecuteQueue->access(0); + + // Have iterator to head of the list + // While I haven't exceeded bandwidth or reached the end of the list, + // Try to get a FU that can do what this op needs. + // If successful, change the oldestInst to the new top of the list, put + // the queue in the proper place in the list. + // Increment the iterator. + // This will avoid trying to schedule a certain op class if there are no + // FUs that handle it. + ListOrderIt order_it = listOrder.begin(); + ListOrderIt order_end_it = listOrder.end(); + int total_issued = 0; + + while (total_issued < totalWidth && + order_it != order_end_it) { + OpClass op_class = (*order_it).queueType; + + assert(!readyInsts[op_class].empty()); + + DynInstPtr issuing_inst = readyInsts[op_class].top(); + + assert(issuing_inst->seqNum == (*order_it).oldestInst); + + if (issuing_inst->isSquashed()) { + readyInsts[op_class].pop(); + + if (!readyInsts[op_class].empty()) { + moveToYoungerInst(order_it); + } else { + readyIt[op_class] = listOrder.end(); + queueOnList[op_class] = false; + } + + listOrder.erase(order_it++); + + ++iqSquashedInstsIssued; + + continue; + } + + int idx = -2; + int op_latency = 1; + int tid = issuing_inst->threadNumber; + + if (op_class != No_OpClass) { + idx = fuPool->getUnit(op_class); + + if (idx > -1) { + op_latency = fuPool->getOpLatency(op_class); + } + } + + // If we have an instruction that doesn't require a FU, or a + // valid FU, then schedule for execution. + if (idx == -2 || idx != -1) { + if (op_latency == 1) { + i2e_info->size++; + instsToExecute.push_back(issuing_inst); + + // Add the FU onto the list of FU's to be freed next + // cycle if we used one. + if (idx >= 0) + fuPool->freeUnitNextCycle(idx); + } else { + int issue_latency = fuPool->getIssueLatency(op_class); + // Generate completion event for the FU + FUCompletion *execution = new FUCompletion(issuing_inst, + idx, this); + + execution->schedule(curTick + cpu->cycles(issue_latency - 1)); + + // @todo: Enforce that issue_latency == 1 or op_latency + if (issue_latency > 1) { + // If FU isn't pipelined, then it must be freed + // upon the execution completing. + execution->setFreeFU(); + } else { + // Add the FU onto the list of FU's to be freed next cycle. + fuPool->freeUnitNextCycle(idx); + } + } + + DPRINTF(IQ, "Thread %i: Issuing instruction PC %#x " + "[sn:%lli]\n", + tid, issuing_inst->readPC(), + issuing_inst->seqNum); + + readyInsts[op_class].pop(); + + if (!readyInsts[op_class].empty()) { + moveToYoungerInst(order_it); + } else { + readyIt[op_class] = listOrder.end(); + queueOnList[op_class] = false; + } + + issuing_inst->setIssued(); + ++total_issued; + + if (!issuing_inst->isMemRef()) { + // Memory instructions can not be freed from the IQ until they + // complete. + ++freeEntries; + count[tid]--; + issuing_inst->removeInIQ(); + } else { + memDepUnit[tid].issue(issuing_inst); + } + + listOrder.erase(order_it++); + statIssuedInstType[tid][op_class]++; + } else { + statFuBusy[op_class]++; + fuBusy[tid]++; + ++order_it; + } + } + + numIssuedDist.sample(total_issued); + iqInstsIssued+= total_issued; + + // If we issued any instructions, tell the CPU we had activity. + if (total_issued) { + cpu->activityThisCycle(); + } else { + DPRINTF(IQ, "Not able to schedule any instructions.\n"); + } +} + +template <class Impl> +void +InstructionQueue<Impl>::scheduleNonSpec(const InstSeqNum &inst) +{ + DPRINTF(IQ, "Marking nonspeculative instruction [sn:%lli] as ready " + "to execute.\n", inst); + + NonSpecMapIt inst_it = nonSpecInsts.find(inst); + + assert(inst_it != nonSpecInsts.end()); + + unsigned tid = (*inst_it).second->threadNumber; + + (*inst_it).second->setCanIssue(); + + if (!(*inst_it).second->isMemRef()) { + addIfReady((*inst_it).second); + } else { + memDepUnit[tid].nonSpecInstReady((*inst_it).second); + } + + (*inst_it).second = NULL; + + nonSpecInsts.erase(inst_it); +} + +template <class Impl> +void +InstructionQueue<Impl>::commit(const InstSeqNum &inst, unsigned tid) +{ + DPRINTF(IQ, "[tid:%i]: Committing instructions older than [sn:%i]\n", + tid,inst); + + ListIt iq_it = instList[tid].begin(); + + while (iq_it != instList[tid].end() && + (*iq_it)->seqNum <= inst) { + ++iq_it; + instList[tid].pop_front(); + } + + assert(freeEntries == (numEntries - countInsts())); +} + +template <class Impl> +int +InstructionQueue<Impl>::wakeDependents(DynInstPtr &completed_inst) +{ + int dependents = 0; + + DPRINTF(IQ, "Waking dependents of completed instruction.\n"); + + assert(!completed_inst->isSquashed()); + + // Tell the memory dependence unit to wake any dependents on this + // instruction if it is a memory instruction. Also complete the memory + // instruction at this point since we know it executed without issues. + // @todo: Might want to rename "completeMemInst" to something that + // indicates that it won't need to be replayed, and call this + // earlier. Might not be a big deal. + if (completed_inst->isMemRef()) { + memDepUnit[completed_inst->threadNumber].wakeDependents(completed_inst); + completeMemInst(completed_inst); + } else if (completed_inst->isMemBarrier() || + completed_inst->isWriteBarrier()) { + memDepUnit[completed_inst->threadNumber].completeBarrier(completed_inst); + } + + for (int dest_reg_idx = 0; + dest_reg_idx < completed_inst->numDestRegs(); + dest_reg_idx++) + { + PhysRegIndex dest_reg = + completed_inst->renamedDestRegIdx(dest_reg_idx); + + // Special case of uniq or control registers. They are not + // handled by the IQ and thus have no dependency graph entry. + // @todo Figure out a cleaner way to handle this. + if (dest_reg >= numPhysRegs) { + continue; + } + + DPRINTF(IQ, "Waking any dependents on register %i.\n", + (int) dest_reg); + + //Go through the dependency chain, marking the registers as + //ready within the waiting instructions. + DynInstPtr dep_inst = dependGraph.pop(dest_reg); + + while (dep_inst) { + DPRINTF(IQ, "Waking up a dependent instruction, PC%#x.\n", + dep_inst->readPC()); + + // Might want to give more information to the instruction + // so that it knows which of its source registers is + // ready. However that would mean that the dependency + // graph entries would need to hold the src_reg_idx. + dep_inst->markSrcRegReady(); + + addIfReady(dep_inst); + + dep_inst = dependGraph.pop(dest_reg); + + ++dependents; + } + + // Reset the head node now that all of its dependents have + // been woken up. + assert(dependGraph.empty(dest_reg)); + dependGraph.clearInst(dest_reg); + + // Mark the scoreboard as having that register ready. + regScoreboard[dest_reg] = true; + } + return dependents; +} + +template <class Impl> +void +InstructionQueue<Impl>::addReadyMemInst(DynInstPtr &ready_inst) +{ + OpClass op_class = ready_inst->opClass(); + + readyInsts[op_class].push(ready_inst); + + // Will need to reorder the list if either a queue is not on the list, + // or it has an older instruction than last time. + if (!queueOnList[op_class]) { + addToOrderList(op_class); + } else if (readyInsts[op_class].top()->seqNum < + (*readyIt[op_class]).oldestInst) { + listOrder.erase(readyIt[op_class]); + addToOrderList(op_class); + } + + DPRINTF(IQ, "Instruction is ready to issue, putting it onto " + "the ready list, PC %#x opclass:%i [sn:%lli].\n", + ready_inst->readPC(), op_class, ready_inst->seqNum); +} + +template <class Impl> +void +InstructionQueue<Impl>::rescheduleMemInst(DynInstPtr &resched_inst) +{ + memDepUnit[resched_inst->threadNumber].reschedule(resched_inst); +} + +template <class Impl> +void +InstructionQueue<Impl>::replayMemInst(DynInstPtr &replay_inst) +{ + memDepUnit[replay_inst->threadNumber].replay(replay_inst); +} + +template <class Impl> +void +InstructionQueue<Impl>::completeMemInst(DynInstPtr &completed_inst) +{ + int tid = completed_inst->threadNumber; + + DPRINTF(IQ, "Completing mem instruction PC:%#x [sn:%lli]\n", + completed_inst->readPC(), completed_inst->seqNum); + + ++freeEntries; + + completed_inst->memOpDone = true; + + memDepUnit[tid].completed(completed_inst); + + count[tid]--; +} + +template <class Impl> +void +InstructionQueue<Impl>::violation(DynInstPtr &store, + DynInstPtr &faulting_load) +{ + memDepUnit[store->threadNumber].violation(store, faulting_load); +} + +template <class Impl> +void +InstructionQueue<Impl>::squash(unsigned tid) +{ + DPRINTF(IQ, "[tid:%i]: Starting to squash instructions in " + "the IQ.\n", tid); + + // Read instruction sequence number of last instruction out of the + // time buffer. + squashedSeqNum[tid] = fromCommit->commitInfo[tid].doneSeqNum; + + // Call doSquash if there are insts in the IQ + if (count[tid] > 0) { + doSquash(tid); + } + + // Also tell the memory dependence unit to squash. + memDepUnit[tid].squash(squashedSeqNum[tid], tid); +} + +template <class Impl> +void +InstructionQueue<Impl>::doSquash(unsigned tid) +{ + // Start at the tail. + ListIt squash_it = instList[tid].end(); + --squash_it; + + DPRINTF(IQ, "[tid:%i]: Squashing until sequence number %i!\n", + tid, squashedSeqNum[tid]); + + // Squash any instructions younger than the squashed sequence number + // given. + while (squash_it != instList[tid].end() && + (*squash_it)->seqNum > squashedSeqNum[tid]) { + + DynInstPtr squashed_inst = (*squash_it); + + // Only handle the instruction if it actually is in the IQ and + // hasn't already been squashed in the IQ. + if (squashed_inst->threadNumber != tid || + squashed_inst->isSquashedInIQ()) { + --squash_it; + continue; + } + + if (!squashed_inst->isIssued() || + (squashed_inst->isMemRef() && + !squashed_inst->memOpDone)) { + + // Remove the instruction from the dependency list. + if (!squashed_inst->isNonSpeculative() && + !squashed_inst->isStoreConditional() && + !squashed_inst->isMemBarrier() && + !squashed_inst->isWriteBarrier()) { + + for (int src_reg_idx = 0; + src_reg_idx < squashed_inst->numSrcRegs(); + src_reg_idx++) + { + PhysRegIndex src_reg = + squashed_inst->renamedSrcRegIdx(src_reg_idx); + + // Only remove it from the dependency graph if it + // was placed there in the first place. + + // Instead of doing a linked list traversal, we + // can just remove these squashed instructions + // either at issue time, or when the register is + // overwritten. The only downside to this is it + // leaves more room for error. + + if (!squashed_inst->isReadySrcRegIdx(src_reg_idx) && + src_reg < numPhysRegs) { + dependGraph.remove(src_reg, squashed_inst); + } + + + ++iqSquashedOperandsExamined; + } + } else { + NonSpecMapIt ns_inst_it = + nonSpecInsts.find(squashed_inst->seqNum); + assert(ns_inst_it != nonSpecInsts.end()); + + (*ns_inst_it).second = NULL; + + nonSpecInsts.erase(ns_inst_it); + + ++iqSquashedNonSpecRemoved; + } + + // Might want to also clear out the head of the dependency graph. + + // Mark it as squashed within the IQ. + squashed_inst->setSquashedInIQ(); + + // @todo: Remove this hack where several statuses are set so the + // inst will flow through the rest of the pipeline. + squashed_inst->setIssued(); + squashed_inst->setCanCommit(); + squashed_inst->removeInIQ(); + + //Update Thread IQ Count + count[squashed_inst->threadNumber]--; + + ++freeEntries; + + DPRINTF(IQ, "[tid:%i]: Instruction [sn:%lli] PC %#x " + "squashed.\n", + tid, squashed_inst->seqNum, squashed_inst->readPC()); + } + + instList[tid].erase(squash_it--); + ++iqSquashedInstsExamined; + } +} + +template <class Impl> +bool +InstructionQueue<Impl>::addToDependents(DynInstPtr &new_inst) +{ + // Loop through the instruction's source registers, adding + // them to the dependency list if they are not ready. + int8_t total_src_regs = new_inst->numSrcRegs(); + bool return_val = false; + + for (int src_reg_idx = 0; + src_reg_idx < total_src_regs; + src_reg_idx++) + { + // Only add it to the dependency graph if it's not ready. + if (!new_inst->isReadySrcRegIdx(src_reg_idx)) { + PhysRegIndex src_reg = new_inst->renamedSrcRegIdx(src_reg_idx); + + // Check the IQ's scoreboard to make sure the register + // hasn't become ready while the instruction was in flight + // between stages. Only if it really isn't ready should + // it be added to the dependency graph. + if (src_reg >= numPhysRegs) { + continue; + } else if (regScoreboard[src_reg] == false) { + DPRINTF(IQ, "Instruction PC %#x has src reg %i that " + "is being added to the dependency chain.\n", + new_inst->readPC(), src_reg); + + dependGraph.insert(src_reg, new_inst); + + // Change the return value to indicate that something + // was added to the dependency graph. + return_val = true; + } else { + DPRINTF(IQ, "Instruction PC %#x has src reg %i that " + "became ready before it reached the IQ.\n", + new_inst->readPC(), src_reg); + // Mark a register ready within the instruction. + new_inst->markSrcRegReady(src_reg_idx); + } + } + } + + return return_val; +} + +template <class Impl> +void +InstructionQueue<Impl>::addToProducers(DynInstPtr &new_inst) +{ + // Nothing really needs to be marked when an instruction becomes + // the producer of a register's value, but for convenience a ptr + // to the producing instruction will be placed in the head node of + // the dependency links. + int8_t total_dest_regs = new_inst->numDestRegs(); + + for (int dest_reg_idx = 0; + dest_reg_idx < total_dest_regs; + dest_reg_idx++) + { + PhysRegIndex dest_reg = new_inst->renamedDestRegIdx(dest_reg_idx); + + // Instructions that use the misc regs will have a reg number + // higher than the normal physical registers. In this case these + // registers are not renamed, and there is no need to track + // dependencies as these instructions must be executed at commit. + if (dest_reg >= numPhysRegs) { + continue; + } + + if (!dependGraph.empty(dest_reg)) { + dependGraph.dump(); + panic("Dependency graph %i not empty!", dest_reg); + } + + dependGraph.setInst(dest_reg, new_inst); + + // Mark the scoreboard to say it's not yet ready. + regScoreboard[dest_reg] = false; + } +} + +template <class Impl> +void +InstructionQueue<Impl>::addIfReady(DynInstPtr &inst) +{ + // If the instruction now has all of its source registers + // available, then add it to the list of ready instructions. + if (inst->readyToIssue()) { + + //Add the instruction to the proper ready list. + if (inst->isMemRef()) { + + DPRINTF(IQ, "Checking if memory instruction can issue.\n"); + + // Message to the mem dependence unit that this instruction has + // its registers ready. + memDepUnit[inst->threadNumber].regsReady(inst); + + return; + } + + OpClass op_class = inst->opClass(); + + DPRINTF(IQ, "Instruction is ready to issue, putting it onto " + "the ready list, PC %#x opclass:%i [sn:%lli].\n", + inst->readPC(), op_class, inst->seqNum); + + readyInsts[op_class].push(inst); + + // Will need to reorder the list if either a queue is not on the list, + // or it has an older instruction than last time. + if (!queueOnList[op_class]) { + addToOrderList(op_class); + } else if (readyInsts[op_class].top()->seqNum < + (*readyIt[op_class]).oldestInst) { + listOrder.erase(readyIt[op_class]); + addToOrderList(op_class); + } + } +} + +template <class Impl> +int +InstructionQueue<Impl>::countInsts() +{ +#if 0 + //ksewell:This works but definitely could use a cleaner write + //with a more intuitive way of counting. Right now it's + //just brute force .... + // Change the #if if you want to use this method. + int total_insts = 0; + + for (int i = 0; i < numThreads; ++i) { + ListIt count_it = instList[i].begin(); + + while (count_it != instList[i].end()) { + if (!(*count_it)->isSquashed() && !(*count_it)->isSquashedInIQ()) { + if (!(*count_it)->isIssued()) { + ++total_insts; + } else if ((*count_it)->isMemRef() && + !(*count_it)->memOpDone) { + // Loads that have not been marked as executed still count + // towards the total instructions. + ++total_insts; + } + } + + ++count_it; + } + } + + return total_insts; +#else + return numEntries - freeEntries; +#endif +} + +template <class Impl> +void +InstructionQueue<Impl>::dumpLists() +{ + for (int i = 0; i < Num_OpClasses; ++i) { + cprintf("Ready list %i size: %i\n", i, readyInsts[i].size()); + + cprintf("\n"); + } + + cprintf("Non speculative list size: %i\n", nonSpecInsts.size()); + + NonSpecMapIt non_spec_it = nonSpecInsts.begin(); + NonSpecMapIt non_spec_end_it = nonSpecInsts.end(); + + cprintf("Non speculative list: "); + + while (non_spec_it != non_spec_end_it) { + cprintf("%#x [sn:%lli]", (*non_spec_it).second->readPC(), + (*non_spec_it).second->seqNum); + ++non_spec_it; + } + + cprintf("\n"); + + ListOrderIt list_order_it = listOrder.begin(); + ListOrderIt list_order_end_it = listOrder.end(); + int i = 1; + + cprintf("List order: "); + + while (list_order_it != list_order_end_it) { + cprintf("%i OpClass:%i [sn:%lli] ", i, (*list_order_it).queueType, + (*list_order_it).oldestInst); + + ++list_order_it; + ++i; + } + + cprintf("\n"); +} + + +template <class Impl> +void +InstructionQueue<Impl>::dumpInsts() +{ + for (int i = 0; i < numThreads; ++i) { + int num = 0; + int valid_num = 0; + ListIt inst_list_it = instList[i].begin(); + + while (inst_list_it != instList[i].end()) + { + cprintf("Instruction:%i\n", + num); + if (!(*inst_list_it)->isSquashed()) { + if (!(*inst_list_it)->isIssued()) { + ++valid_num; + cprintf("Count:%i\n", valid_num); + } else if ((*inst_list_it)->isMemRef() && + !(*inst_list_it)->memOpDone) { + // Loads that have not been marked as executed + // still count towards the total instructions. + ++valid_num; + cprintf("Count:%i\n", valid_num); + } + } + + cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" + "Issued:%i\nSquashed:%i\n", + (*inst_list_it)->readPC(), + (*inst_list_it)->seqNum, + (*inst_list_it)->threadNumber, + (*inst_list_it)->isIssued(), + (*inst_list_it)->isSquashed()); + + if ((*inst_list_it)->isMemRef()) { + cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone); + } + + cprintf("\n"); + + inst_list_it++; + ++num; + } + } + + cprintf("Insts to Execute list:\n"); + + int num = 0; + int valid_num = 0; + ListIt inst_list_it = instsToExecute.begin(); + + while (inst_list_it != instsToExecute.end()) + { + cprintf("Instruction:%i\n", + num); + if (!(*inst_list_it)->isSquashed()) { + if (!(*inst_list_it)->isIssued()) { + ++valid_num; + cprintf("Count:%i\n", valid_num); + } else if ((*inst_list_it)->isMemRef() && + !(*inst_list_it)->memOpDone) { + // Loads that have not been marked as executed + // still count towards the total instructions. + ++valid_num; + cprintf("Count:%i\n", valid_num); + } + } + + cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" + "Issued:%i\nSquashed:%i\n", + (*inst_list_it)->readPC(), + (*inst_list_it)->seqNum, + (*inst_list_it)->threadNumber, + (*inst_list_it)->isIssued(), + (*inst_list_it)->isSquashed()); + + if ((*inst_list_it)->isMemRef()) { + cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone); + } + + cprintf("\n"); + + inst_list_it++; + ++num; + } +} diff --git a/src/cpu/o3/lsq.cc b/src/cpu/o3/lsq.cc new file mode 100644 index 000000000..de0325920 --- /dev/null +++ b/src/cpu/o3/lsq.cc @@ -0,0 +1,38 @@ +/* + * 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 + */ + +#include "cpu/o3/alpha_dyn_inst.hh" +#include "cpu/o3/alpha_cpu.hh" +#include "cpu/o3/alpha_impl.hh" +#include "cpu/o3/lsq_impl.hh" + +// Force the instantiation of LDSTQ for all the implementations we care about. +template class LSQ<AlphaSimpleImpl>; + diff --git a/src/cpu/o3/lsq.hh b/src/cpu/o3/lsq.hh new file mode 100644 index 000000000..bc4154c85 --- /dev/null +++ b/src/cpu/o3/lsq.hh @@ -0,0 +1,318 @@ +/* + * 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: Korey Sewell + */ + +#ifndef __CPU_O3_LSQ_HH__ +#define __CPU_O3_LSQ_HH__ + +#include <map> +#include <queue> + +#include "config/full_system.hh" +#include "cpu/inst_seq.hh" +#include "cpu/o3/lsq_unit.hh" +#include "mem/port.hh" +#include "sim/sim_object.hh" + +template <class Impl> +class LSQ { + public: + typedef typename Impl::Params Params; + typedef typename Impl::FullCPU FullCPU; + typedef typename Impl::DynInstPtr DynInstPtr; + typedef typename Impl::CPUPol::IEW IEW; + typedef typename Impl::CPUPol::LSQUnit LSQUnit; + + /** SMT policy. */ + enum LSQPolicy { + Dynamic, + Partitioned, + Threshold + }; + + /** Constructs an LSQ with the given parameters. */ + LSQ(Params *params); + + /** Returns the name of the LSQ. */ + std::string name() const; + + /** Sets the pointer to the list of active threads. */ + void setActiveThreads(std::list<unsigned> *at_ptr); + /** Sets the CPU pointer. */ + void setCPU(FullCPU *cpu_ptr); + /** Sets the IEW stage pointer. */ + void setIEW(IEW *iew_ptr); + /** Switches out the LSQ. */ + void switchOut(); + /** Takes over execution from another CPU's thread. */ + void takeOverFrom(); + + /** Number of entries needed for the given amount of threads.*/ + int entryAmount(int num_threads); + void removeEntries(unsigned tid); + /** Reset the max entries for each thread. */ + void resetEntries(); + /** Resize the max entries for a thread. */ + void resizeEntries(unsigned size, unsigned tid); + + /** Ticks the LSQ. */ + void tick(); + /** Ticks a specific LSQ Unit. */ + void tick(unsigned tid) + { thread[tid].tick(); } + + /** Inserts a load into the LSQ. */ + void insertLoad(DynInstPtr &load_inst); + /** Inserts a store into the LSQ. */ + void insertStore(DynInstPtr &store_inst); + + /** Executes a load. */ + Fault executeLoad(DynInstPtr &inst); + + /** Executes a store. */ + Fault executeStore(DynInstPtr &inst); + + /** + * Commits loads up until the given sequence number for a specific thread. + */ + void commitLoads(InstSeqNum &youngest_inst, unsigned tid) + { thread[tid].commitLoads(youngest_inst); } + + /** + * Commits stores up until the given sequence number for a specific thread. + */ + void commitStores(InstSeqNum &youngest_inst, unsigned tid) + { thread[tid].commitStores(youngest_inst); } + + /** + * Attempts to write back stores until all cache ports are used or the + * interface becomes blocked. + */ + void writebackStores(); + /** Same as above, but only for one thread. */ + void writebackStores(unsigned tid); + + /** + * Squash instructions from a thread until the specified sequence number. + */ + void squash(const InstSeqNum &squashed_num, unsigned tid) + { thread[tid].squash(squashed_num); } + + /** Returns whether or not there was a memory ordering violation. */ + bool violation(); + /** + * Returns whether or not there was a memory ordering violation for a + * specific thread. + */ + bool violation(unsigned tid) + { return thread[tid].violation(); } + + /** Returns if a load is blocked due to the memory system for a specific + * thread. + */ + bool loadBlocked(unsigned tid) + { return thread[tid].loadBlocked(); } + + bool isLoadBlockedHandled(unsigned tid) + { return thread[tid].isLoadBlockedHandled(); } + + void setLoadBlockedHandled(unsigned tid) + { thread[tid].setLoadBlockedHandled(); } + + /** Gets the instruction that caused the memory ordering violation. */ + DynInstPtr getMemDepViolator(unsigned tid) + { return thread[tid].getMemDepViolator(); } + + /** Returns the head index of the load queue for a specific thread. */ + int getLoadHead(unsigned tid) + { return thread[tid].getLoadHead(); } + + /** Returns the sequence number of the head of the load queue. */ + InstSeqNum getLoadHeadSeqNum(unsigned tid) + { + return thread[tid].getLoadHeadSeqNum(); + } + + /** Returns the head index of the store queue. */ + int getStoreHead(unsigned tid) + { return thread[tid].getStoreHead(); } + + /** Returns the sequence number of the head of the store queue. */ + InstSeqNum getStoreHeadSeqNum(unsigned tid) + { + return thread[tid].getStoreHeadSeqNum(); + } + + /** Returns the number of instructions in all of the queues. */ + int getCount(); + /** Returns the number of instructions in the queues of one thread. */ + int getCount(unsigned tid) + { return thread[tid].getCount(); } + + /** Returns the total number of loads in the load queue. */ + int numLoads(); + /** Returns the total number of loads for a single thread. */ + int numLoads(unsigned tid) + { return thread[tid].numLoads(); } + + /** Returns the total number of stores in the store queue. */ + int numStores(); + /** Returns the total number of stores for a single thread. */ + int numStores(unsigned tid) + { return thread[tid].numStores(); } + + /** Returns the total number of loads that are ready. */ + int numLoadsReady(); + /** Returns the number of loads that are ready for a single thread. */ + int numLoadsReady(unsigned tid) + { return thread[tid].numLoadsReady(); } + + /** Returns the number of free entries. */ + unsigned numFreeEntries(); + /** Returns the number of free entries for a specific thread. */ + unsigned numFreeEntries(unsigned tid); + + /** Returns if the LSQ is full (either LQ or SQ is full). */ + bool isFull(); + /** + * Returns if the LSQ is full for a specific thread (either LQ or SQ is + * full). + */ + bool isFull(unsigned tid); + + /** Returns if any of the LQs are full. */ + bool lqFull(); + /** Returns if the LQ of a given thread is full. */ + bool lqFull(unsigned tid); + + /** Returns if any of the SQs are full. */ + bool sqFull(); + /** Returns if the SQ of a given thread is full. */ + bool sqFull(unsigned tid); + + /** + * Returns if the LSQ is stalled due to a memory operation that must be + * replayed. + */ + bool isStalled(); + /** + * Returns if the LSQ of a specific thread is stalled due to a memory + * operation that must be replayed. + */ + bool isStalled(unsigned tid); + + /** Returns whether or not there are any stores to write back to memory. */ + bool hasStoresToWB(); + + /** Returns whether or not a specific thread has any stores to write back + * to memory. + */ + bool hasStoresToWB(unsigned tid) + { return thread[tid].hasStoresToWB(); } + + /** Returns the number of stores a specific thread has to write back. */ + int numStoresToWB(unsigned tid) + { return thread[tid].numStoresToWB(); } + + /** Returns if the LSQ will write back to memory this cycle. */ + bool willWB(); + /** Returns if the LSQ of a specific thread will write back to memory this + * cycle. + */ + bool willWB(unsigned tid) + { return thread[tid].willWB(); } + + /** Debugging function to print out all instructions. */ + void dumpInsts(); + /** Debugging function to print out instructions from a specific thread. */ + void dumpInsts(unsigned tid) + { thread[tid].dumpInsts(); } + + /** Executes a read operation, using the load specified at the load index. */ + template <class T> + Fault read(RequestPtr req, T &data, int load_idx); + + /** Executes a store operation, using the store specified at the store + * index. + */ + template <class T> + Fault write(RequestPtr req, T &data, int store_idx); + + private: + /** The LSQ policy for SMT mode. */ + LSQPolicy lsqPolicy; + + /** The LSQ units for individual threads. */ + LSQUnit thread[Impl::MaxThreads]; + + /** The CPU pointer. */ + FullCPU *cpu; + + /** The IEW stage pointer. */ + IEW *iewStage; + + /** List of Active Threads in System. */ + std::list<unsigned> *activeThreads; + + /** Total Size of LQ Entries. */ + unsigned LQEntries; + /** Total Size of SQ Entries. */ + unsigned SQEntries; + + /** Max LQ Size - Used to Enforce Sharing Policies. */ + unsigned maxLQEntries; + + /** Max SQ Size - Used to Enforce Sharing Policies. */ + unsigned maxSQEntries; + + /** Number of Threads. */ + unsigned numThreads; +}; + +template <class Impl> +template <class T> +Fault +LSQ<Impl>::read(RequestPtr req, T &data, int load_idx) +{ + unsigned tid = req->getThreadNum(); + + return thread[tid].read(req, data, load_idx); +} + +template <class Impl> +template <class T> +Fault +LSQ<Impl>::write(RequestPtr req, T &data, int store_idx) +{ + unsigned tid = req->getThreadNum(); + + return thread[tid].write(req, data, store_idx); +} + +#endif // __CPU_O3_LSQ_HH__ diff --git a/src/cpu/o3/lsq_impl.hh b/src/cpu/o3/lsq_impl.hh new file mode 100644 index 000000000..27aa0dc3c --- /dev/null +++ b/src/cpu/o3/lsq_impl.hh @@ -0,0 +1,529 @@ +/* + * 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: Korey Sewell + */ + +#include <algorithm> +#include <string> + +#include "cpu/o3/lsq.hh" + +using namespace std; + +template <class Impl> +LSQ<Impl>::LSQ(Params *params) + : LQEntries(params->LQEntries), SQEntries(params->SQEntries), + numThreads(params->numberOfThreads) +{ + DPRINTF(LSQ, "Creating LSQ object.\n"); + + //**********************************************/ + //************ Handle SMT Parameters ***********/ + //**********************************************/ + string policy = params->smtLSQPolicy; + + //Convert string to lowercase + std::transform(policy.begin(), policy.end(), policy.begin(), + (int(*)(int)) tolower); + + //Figure out fetch policy + if (policy == "dynamic") { + lsqPolicy = Dynamic; + + maxLQEntries = LQEntries; + maxSQEntries = SQEntries; + + DPRINTF(LSQ, "LSQ sharing policy set to Dynamic\n"); + + } else if (policy == "partitioned") { + lsqPolicy = Partitioned; + + //@todo:make work if part_amt doesnt divide evenly. + maxLQEntries = LQEntries / numThreads; + maxSQEntries = SQEntries / numThreads; + + DPRINTF(Fetch, "LSQ sharing policy set to Partitioned: " + "%i entries per LQ | %i entries per SQ", + maxLQEntries,maxSQEntries); + + } else if (policy == "threshold") { + lsqPolicy = Threshold; + + assert(params->smtLSQThreshold > LQEntries); + assert(params->smtLSQThreshold > SQEntries); + + //Divide up by threshold amount + //@todo: Should threads check the max and the total + //amount of the LSQ + maxLQEntries = params->smtLSQThreshold; + maxSQEntries = params->smtLSQThreshold; + + DPRINTF(LSQ, "LSQ sharing policy set to Threshold: " + "%i entries per LQ | %i entries per SQ", + maxLQEntries,maxSQEntries); + + } else { + assert(0 && "Invalid LSQ Sharing Policy.Options Are:{Dynamic," + "Partitioned, Threshold}"); + } + + //Initialize LSQs + for (int tid=0; tid < numThreads; tid++) { + thread[tid].init(params, maxLQEntries, maxSQEntries, tid); + } +} + + +template<class Impl> +std::string +LSQ<Impl>::name() const +{ + return iewStage->name() + ".lsq"; +} + +template<class Impl> +void +LSQ<Impl>::setActiveThreads(list<unsigned> *at_ptr) +{ + activeThreads = at_ptr; + assert(activeThreads != 0); +} + +template<class Impl> +void +LSQ<Impl>::setCPU(FullCPU *cpu_ptr) +{ + cpu = cpu_ptr; + + for (int tid=0; tid < numThreads; tid++) { + thread[tid].setCPU(cpu_ptr); + } +} + +template<class Impl> +void +LSQ<Impl>::setIEW(IEW *iew_ptr) +{ + iewStage = iew_ptr; + + for (int tid=0; tid < numThreads; tid++) { + thread[tid].setIEW(iew_ptr); + } +} + +template <class Impl> +void +LSQ<Impl>::switchOut() +{ + for (int tid = 0; tid < numThreads; tid++) { + thread[tid].switchOut(); + } +} + +template <class Impl> +void +LSQ<Impl>::takeOverFrom() +{ + for (int tid = 0; tid < numThreads; tid++) { + thread[tid].takeOverFrom(); + } +} + +template <class Impl> +int +LSQ<Impl>::entryAmount(int num_threads) +{ + if (lsqPolicy == Partitioned) { + return LQEntries / num_threads; + } else { + return 0; + } +} + +template <class Impl> +void +LSQ<Impl>::resetEntries() +{ + if (lsqPolicy != Dynamic || numThreads > 1) { + int active_threads = (*activeThreads).size(); + + list<unsigned>::iterator threads = (*activeThreads).begin(); + list<unsigned>::iterator list_end = (*activeThreads).end(); + + int maxEntries; + + if (lsqPolicy == Partitioned) { + maxEntries = LQEntries / active_threads; + } else if (lsqPolicy == Threshold && active_threads == 1) { + maxEntries = LQEntries; + } else { + maxEntries = LQEntries; + } + + while (threads != list_end) { + resizeEntries(maxEntries,*threads++); + } + } +} + +template<class Impl> +void +LSQ<Impl>::removeEntries(unsigned tid) +{ + thread[tid].clearLQ(); + thread[tid].clearSQ(); +} + +template<class Impl> +void +LSQ<Impl>::resizeEntries(unsigned size,unsigned tid) +{ + thread[tid].resizeLQ(size); + thread[tid].resizeSQ(size); +} + +template<class Impl> +void +LSQ<Impl>::tick() +{ + list<unsigned>::iterator active_threads = (*activeThreads).begin(); + + while (active_threads != (*activeThreads).end()) { + unsigned tid = *active_threads++; + + thread[tid].tick(); + } +} + +template<class Impl> +void +LSQ<Impl>::insertLoad(DynInstPtr &load_inst) +{ + unsigned tid = load_inst->threadNumber; + + thread[tid].insertLoad(load_inst); +} + +template<class Impl> +void +LSQ<Impl>::insertStore(DynInstPtr &store_inst) +{ + unsigned tid = store_inst->threadNumber; + + thread[tid].insertStore(store_inst); +} + +template<class Impl> +Fault +LSQ<Impl>::executeLoad(DynInstPtr &inst) +{ + unsigned tid = inst->threadNumber; + + return thread[tid].executeLoad(inst); +} + +template<class Impl> +Fault +LSQ<Impl>::executeStore(DynInstPtr &inst) +{ + unsigned tid = inst->threadNumber; + + return thread[tid].executeStore(inst); +} + +template<class Impl> +void +LSQ<Impl>::writebackStores() +{ + list<unsigned>::iterator active_threads = (*activeThreads).begin(); + + while (active_threads != (*activeThreads).end()) { + unsigned tid = *active_threads++; + + if (numStoresToWB(tid) > 0) { + DPRINTF(Writeback,"[tid:%i] Writing back stores. %i stores " + "available for Writeback.\n", tid, numStoresToWB(tid)); + } + + thread[tid].writebackStores(); + } +} + +template<class Impl> +bool +LSQ<Impl>::violation() +{ + /* Answers: Does Anybody Have a Violation?*/ + list<unsigned>::iterator active_threads = (*activeThreads).begin(); + + while (active_threads != (*activeThreads).end()) { + unsigned tid = *active_threads++; + if (thread[tid].violation()) + return true; + } + + return false; +} + +template<class Impl> +int +LSQ<Impl>::getCount() +{ + unsigned total = 0; + + list<unsigned>::iterator active_threads = (*activeThreads).begin(); + + while (active_threads != (*activeThreads).end()) { + unsigned tid = *active_threads++; + total += getCount(tid); + } + + return total; +} + +template<class Impl> +int +LSQ<Impl>::numLoads() +{ + unsigned total = 0; + + list<unsigned>::iterator active_threads = (*activeThreads).begin(); + + while (active_threads != (*activeThreads).end()) { + unsigned tid = *active_threads++; + total += numLoads(tid); + } + + return total; +} + +template<class Impl> +int +LSQ<Impl>::numStores() +{ + unsigned total = 0; + + list<unsigned>::iterator active_threads = (*activeThreads).begin(); + + while (active_threads != (*activeThreads).end()) { + unsigned tid = *active_threads++; + total += thread[tid].numStores(); + } + + return total; +} + +template<class Impl> +int +LSQ<Impl>::numLoadsReady() +{ + unsigned total = 0; + + list<unsigned>::iterator active_threads = (*activeThreads).begin(); + + while (active_threads != (*activeThreads).end()) { + unsigned tid = *active_threads++; + total += thread[tid].numLoadsReady(); + } + + return total; +} + +template<class Impl> +unsigned +LSQ<Impl>::numFreeEntries() +{ + unsigned total = 0; + + list<unsigned>::iterator active_threads = (*activeThreads).begin(); + + while (active_threads != (*activeThreads).end()) { + unsigned tid = *active_threads++; + total += thread[tid].numFreeEntries(); + } + + return total; +} + +template<class Impl> +unsigned +LSQ<Impl>::numFreeEntries(unsigned tid) +{ + //if( lsqPolicy == Dynamic ) + //return numFreeEntries(); + //else + return thread[tid].numFreeEntries(); +} + +template<class Impl> +bool +LSQ<Impl>::isFull() +{ + list<unsigned>::iterator active_threads = (*activeThreads).begin(); + + while (active_threads != (*activeThreads).end()) { + unsigned tid = *active_threads++; + if (! (thread[tid].lqFull() || thread[tid].sqFull()) ) + return false; + } + + return true; +} + +template<class Impl> +bool +LSQ<Impl>::isFull(unsigned tid) +{ + //@todo: Change to Calculate All Entries for + //Dynamic Policy + if( lsqPolicy == Dynamic ) + return isFull(); + else + return thread[tid].lqFull() || thread[tid].sqFull(); +} + +template<class Impl> +bool +LSQ<Impl>::lqFull() +{ + list<unsigned>::iterator active_threads = (*activeThreads).begin(); + + while (active_threads != (*activeThreads).end()) { + unsigned tid = *active_threads++; + if (!thread[tid].lqFull()) + return false; + } + + return true; +} + +template<class Impl> +bool +LSQ<Impl>::lqFull(unsigned tid) +{ + //@todo: Change to Calculate All Entries for + //Dynamic Policy + if( lsqPolicy == Dynamic ) + return lqFull(); + else + return thread[tid].lqFull(); +} + +template<class Impl> +bool +LSQ<Impl>::sqFull() +{ + list<unsigned>::iterator active_threads = (*activeThreads).begin(); + + while (active_threads != (*activeThreads).end()) { + unsigned tid = *active_threads++; + if (!sqFull(tid)) + return false; + } + + return true; +} + +template<class Impl> +bool +LSQ<Impl>::sqFull(unsigned tid) +{ + //@todo: Change to Calculate All Entries for + //Dynamic Policy + if( lsqPolicy == Dynamic ) + return sqFull(); + else + return thread[tid].sqFull(); +} + +template<class Impl> +bool +LSQ<Impl>::isStalled() +{ + list<unsigned>::iterator active_threads = (*activeThreads).begin(); + + while (active_threads != (*activeThreads).end()) { + unsigned tid = *active_threads++; + if (!thread[tid].isStalled()) + return false; + } + + return true; +} + +template<class Impl> +bool +LSQ<Impl>::isStalled(unsigned tid) +{ + if( lsqPolicy == Dynamic ) + return isStalled(); + else + return thread[tid].isStalled(); +} + +template<class Impl> +bool +LSQ<Impl>::hasStoresToWB() +{ + list<unsigned>::iterator active_threads = (*activeThreads).begin(); + + while (active_threads != (*activeThreads).end()) { + unsigned tid = *active_threads++; + if (!hasStoresToWB(tid)) + return false; + } + + return true; +} + +template<class Impl> +bool +LSQ<Impl>::willWB() +{ + list<unsigned>::iterator active_threads = (*activeThreads).begin(); + + while (active_threads != (*activeThreads).end()) { + unsigned tid = *active_threads++; + if (!willWB(tid)) + return false; + } + + return true; +} + +template<class Impl> +void +LSQ<Impl>::dumpInsts() +{ + list<unsigned>::iterator active_threads = (*activeThreads).begin(); + + while (active_threads != (*activeThreads).end()) { + unsigned tid = *active_threads++; + thread[tid].dumpInsts(); + } +} diff --git a/src/cpu/o3/lsq_unit.cc b/src/cpu/o3/lsq_unit.cc new file mode 100644 index 000000000..e935ffa5c --- /dev/null +++ b/src/cpu/o3/lsq_unit.cc @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + * Korey Sewell + */ + +#include "cpu/o3/alpha_dyn_inst.hh" +#include "cpu/o3/alpha_cpu.hh" +#include "cpu/o3/alpha_impl.hh" +#include "cpu/o3/lsq_unit_impl.hh" + +// Force the instantiation of LDSTQ for all the implementations we care about. +template class LSQUnit<AlphaSimpleImpl>; + diff --git a/src/cpu/o3/lsq_unit.hh b/src/cpu/o3/lsq_unit.hh new file mode 100644 index 000000000..ce0cdd36f --- /dev/null +++ b/src/cpu/o3/lsq_unit.hh @@ -0,0 +1,711 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + * Korey Sewell + */ + +#ifndef __CPU_O3_LSQ_UNIT_HH__ +#define __CPU_O3_LSQ_UNIT_HH__ + +#include <algorithm> +#include <map> +#include <queue> + +#include "arch/faults.hh" +#include "config/full_system.hh" +#include "base/hashmap.hh" +#include "cpu/inst_seq.hh" +#include "mem/packet.hh" +#include "mem/port.hh" + +/** + * Class that implements the actual LQ and SQ for each specific + * thread. Both are circular queues; load entries are freed upon + * committing, while store entries are freed once they writeback. The + * LSQUnit tracks if there are memory ordering violations, and also + * detects partial load to store forwarding cases (a store only has + * part of a load's data) that requires the load to wait until the + * store writes back. In the former case it holds onto the instruction + * until the dependence unit looks at it, and in the latter it stalls + * the LSQ until the store writes back. At that point the load is + * replayed. + */ +template <class Impl> +class LSQUnit { + protected: + typedef TheISA::IntReg IntReg; + public: + typedef typename Impl::Params Params; + typedef typename Impl::FullCPU FullCPU; + typedef typename Impl::DynInstPtr DynInstPtr; + typedef typename Impl::CPUPol::IEW IEW; + typedef typename Impl::CPUPol::IssueStruct IssueStruct; + + public: + /** Constructs an LSQ unit. init() must be called prior to use. */ + LSQUnit(); + + /** Initializes the LSQ unit with the specified number of entries. */ + void init(Params *params, unsigned maxLQEntries, + unsigned maxSQEntries, unsigned id); + + /** Returns the name of the LSQ unit. */ + std::string name() const; + + /** Sets the CPU pointer. */ + void setCPU(FullCPU *cpu_ptr); + + /** Sets the IEW stage pointer. */ + void setIEW(IEW *iew_ptr) + { iewStage = iew_ptr; } + + /** Switches out LSQ unit. */ + void switchOut(); + + /** Takes over from another CPU's thread. */ + void takeOverFrom(); + + /** Returns if the LSQ is switched out. */ + bool isSwitchedOut() { return switchedOut; } + + /** Ticks the LSQ unit, which in this case only resets the number of + * used cache ports. + * @todo: Move the number of used ports up to the LSQ level so it can + * be shared by all LSQ units. + */ + void tick() { usedPorts = 0; } + + /** Inserts an instruction. */ + void insert(DynInstPtr &inst); + /** Inserts a load instruction. */ + void insertLoad(DynInstPtr &load_inst); + /** Inserts a store instruction. */ + void insertStore(DynInstPtr &store_inst); + + /** Executes a load instruction. */ + Fault executeLoad(DynInstPtr &inst); + + Fault executeLoad(int lq_idx) { panic("Not implemented"); return NoFault; } + /** Executes a store instruction. */ + Fault executeStore(DynInstPtr &inst); + + /** Commits the head load. */ + void commitLoad(); + /** Commits loads older than a specific sequence number. */ + void commitLoads(InstSeqNum &youngest_inst); + + /** Commits stores older than a specific sequence number. */ + void commitStores(InstSeqNum &youngest_inst); + + /** Writes back stores. */ + void writebackStores(); + + void completeDataAccess(PacketPtr pkt); + + // @todo: Include stats in the LSQ unit. + //void regStats(); + + /** Clears all the entries in the LQ. */ + void clearLQ(); + + /** Clears all the entries in the SQ. */ + void clearSQ(); + + /** Resizes the LQ to a given size. */ + void resizeLQ(unsigned size); + + /** Resizes the SQ to a given size. */ + void resizeSQ(unsigned size); + + /** Squashes all instructions younger than a specific sequence number. */ + void squash(const InstSeqNum &squashed_num); + + /** Returns if there is a memory ordering violation. Value is reset upon + * call to getMemDepViolator(). + */ + bool violation() { return memDepViolator; } + + /** Returns the memory ordering violator. */ + DynInstPtr getMemDepViolator(); + + /** Returns if a load became blocked due to the memory system. */ + bool loadBlocked() + { return isLoadBlocked; } + + /** Clears the signal that a load became blocked. */ + void clearLoadBlocked() + { isLoadBlocked = false; } + + /** Returns if the blocked load was handled. */ + bool isLoadBlockedHandled() + { return loadBlockedHandled; } + + /** Records the blocked load as being handled. */ + void setLoadBlockedHandled() + { loadBlockedHandled = true; } + + /** Returns the number of free entries (min of free LQ and SQ entries). */ + unsigned numFreeEntries(); + + /** Returns the number of loads ready to execute. */ + int numLoadsReady(); + + /** Returns the number of loads in the LQ. */ + int numLoads() { return loads; } + + /** Returns the number of stores in the SQ. */ + int numStores() { return stores; } + + /** Returns if either the LQ or SQ is full. */ + bool isFull() { return lqFull() || sqFull(); } + + /** Returns if the LQ is full. */ + bool lqFull() { return loads >= (LQEntries - 1); } + + /** Returns if the SQ is full. */ + bool sqFull() { return stores >= (SQEntries - 1); } + + /** Returns the number of instructions in the LSQ. */ + unsigned getCount() { return loads + stores; } + + /** Returns if there are any stores to writeback. */ + bool hasStoresToWB() { return storesToWB; } + + /** Returns the number of stores to writeback. */ + int numStoresToWB() { return storesToWB; } + + /** Returns if the LSQ unit will writeback on this cycle. */ + bool willWB() { return storeQueue[storeWBIdx].canWB && + !storeQueue[storeWBIdx].completed && + !isStoreBlocked; } + + private: + /** Writes back the instruction, sending it to IEW. */ + void writeback(DynInstPtr &inst, PacketPtr pkt); + + /** Handles completing the send of a store to memory. */ + void storePostSend(Packet *pkt); + + /** Completes the store at the specified index. */ + void completeStore(int store_idx); + + /** Handles doing the retry. */ + void recvRetry(); + + /** Increments the given store index (circular queue). */ + inline void incrStIdx(int &store_idx); + /** Decrements the given store index (circular queue). */ + inline void decrStIdx(int &store_idx); + /** Increments the given load index (circular queue). */ + inline void incrLdIdx(int &load_idx); + /** Decrements the given load index (circular queue). */ + inline void decrLdIdx(int &load_idx); + + public: + /** Debugging function to dump instructions in the LSQ. */ + void dumpInsts(); + + private: + /** Pointer to the CPU. */ + FullCPU *cpu; + + /** Pointer to the IEW stage. */ + IEW *iewStage; + + /** Pointer to memory object. */ + MemObject *mem; + + /** DcachePort class for this LSQ Unit. Handles doing the + * communication with the cache/memory. + * @todo: Needs to be moved to the LSQ level and have some sort + * of arbitration. + */ + class DcachePort : public Port + { + protected: + /** Pointer to CPU. */ + FullCPU *cpu; + /** Pointer to LSQ. */ + LSQUnit *lsq; + + public: + /** Default constructor. */ + DcachePort(FullCPU *_cpu, LSQUnit *_lsq) + : Port(_lsq->name() + "-dport"), cpu(_cpu), lsq(_lsq) + { } + + protected: + /** Atomic version of receive. Panics. */ + virtual Tick recvAtomic(PacketPtr pkt); + + /** Functional version of receive. Panics. */ + virtual void recvFunctional(PacketPtr pkt); + + /** Receives status change. Other than range changing, panics. */ + virtual void recvStatusChange(Status status); + + /** Returns the address ranges of this device. */ + virtual void getDeviceAddressRanges(AddrRangeList &resp, + AddrRangeList &snoop) + { resp.clear(); snoop.clear(); } + + /** Timing version of receive. Handles writing back and + * completing the load or store that has returned from + * memory. */ + virtual bool recvTiming(PacketPtr pkt); + + /** Handles doing a retry of the previous send. */ + virtual void recvRetry(); + }; + + /** Pointer to the D-cache. */ + DcachePort *dcachePort; + + /** Derived class to hold any sender state the LSQ needs. */ + class LSQSenderState : public Packet::SenderState + { + public: + /** Default constructor. */ + LSQSenderState() + : noWB(false) + { } + + /** Instruction who initiated the access to memory. */ + DynInstPtr inst; + /** Whether or not it is a load. */ + bool isLoad; + /** The LQ/SQ index of the instruction. */ + int idx; + /** Whether or not the instruction will need to writeback. */ + bool noWB; + }; + + /** Writeback event, specifically for when stores forward data to loads. */ + class WritebackEvent : public Event { + public: + /** Constructs a writeback event. */ + WritebackEvent(DynInstPtr &_inst, PacketPtr pkt, LSQUnit *lsq_ptr); + + /** Processes the writeback event. */ + void process(); + + /** Returns the description of this event. */ + const char *description(); + + private: + /** Instruction whose results are being written back. */ + DynInstPtr inst; + + /** The packet that would have been sent to memory. */ + PacketPtr pkt; + + /** The pointer to the LSQ unit that issued the store. */ + LSQUnit<Impl> *lsqPtr; + }; + + public: + struct SQEntry { + /** Constructs an empty store queue entry. */ + SQEntry() + : inst(NULL), req(NULL), size(0), data(0), + canWB(0), committed(0), completed(0) + { } + + /** Constructs a store queue entry for a given instruction. */ + SQEntry(DynInstPtr &_inst) + : inst(_inst), req(NULL), size(0), data(0), + canWB(0), committed(0), completed(0) + { } + + /** The store instruction. */ + DynInstPtr inst; + /** The request for the store. */ + RequestPtr req; + /** The size of the store. */ + int size; + /** The store data. */ + IntReg data; + /** Whether or not the store can writeback. */ + bool canWB; + /** Whether or not the store is committed. */ + bool committed; + /** Whether or not the store is completed. */ + bool completed; + }; + + private: + /** The LSQUnit thread id. */ + unsigned lsqID; + + /** The store queue. */ + std::vector<SQEntry> storeQueue; + + /** The load queue. */ + std::vector<DynInstPtr> loadQueue; + + /** The number of LQ entries, plus a sentinel entry (circular queue). + * @todo: Consider having var that records the true number of LQ entries. + */ + unsigned LQEntries; + /** The number of SQ entries, plus a sentinel entry (circular queue). + * @todo: Consider having var that records the true number of SQ entries. + */ + unsigned SQEntries; + + /** The number of load instructions in the LQ. */ + int loads; + /** The number of store instructions in the SQ. */ + int stores; + /** The number of store instructions in the SQ waiting to writeback. */ + int storesToWB; + + /** The index of the head instruction in the LQ. */ + int loadHead; + /** The index of the tail instruction in the LQ. */ + int loadTail; + + /** The index of the head instruction in the SQ. */ + int storeHead; + /** The index of the first instruction that may be ready to be + * written back, and has not yet been written back. + */ + int storeWBIdx; + /** The index of the tail instruction in the SQ. */ + int storeTail; + + /// @todo Consider moving to a more advanced model with write vs read ports + /** The number of cache ports available each cycle. */ + int cachePorts; + + /** The number of used cache ports in this cycle. */ + int usedPorts; + + /** Is the LSQ switched out. */ + bool switchedOut; + + //list<InstSeqNum> mshrSeqNums; + + /** Wire to read information from the issue stage time queue. */ + typename TimeBuffer<IssueStruct>::wire fromIssue; + + /** Whether or not the LSQ is stalled. */ + bool stalled; + /** The store that causes the stall due to partial store to load + * forwarding. + */ + InstSeqNum stallingStoreIsn; + /** The index of the above store. */ + int stallingLoadIdx; + + /** The packet that needs to be retried. */ + PacketPtr retryPkt; + + /** Whehter or not a store is blocked due to the memory system. */ + bool isStoreBlocked; + + /** Whether or not a load is blocked due to the memory system. */ + bool isLoadBlocked; + + /** Has the blocked load been handled. */ + bool loadBlockedHandled; + + /** The sequence number of the blocked load. */ + InstSeqNum blockedLoadSeqNum; + + /** The oldest load that caused a memory ordering violation. */ + DynInstPtr memDepViolator; + + // Will also need how many read/write ports the Dcache has. Or keep track + // of that in stage that is one level up, and only call executeLoad/Store + // the appropriate number of times. +/* + // total number of loads forwaded from LSQ stores + Stats::Vector<> lsq_forw_loads; + + // total number of loads ignored due to invalid addresses + Stats::Vector<> inv_addr_loads; + + // total number of software prefetches ignored due to invalid addresses + Stats::Vector<> inv_addr_swpfs; + + // total non-speculative bogus addresses seen (debug var) + Counter sim_invalid_addrs; + Stats::Vector<> fu_busy; //cumulative fu busy + + // ready loads blocked due to memory disambiguation + Stats::Vector<> lsq_blocked_loads; + + Stats::Scalar<> lsqInversion; +*/ + public: + /** Executes the load at the given index. */ + template <class T> + Fault read(Request *req, T &data, int load_idx); + + /** Executes the store at the given index. */ + template <class T> + Fault write(Request *req, T &data, int store_idx); + + /** Returns the index of the head load instruction. */ + int getLoadHead() { return loadHead; } + /** Returns the sequence number of the head load instruction. */ + InstSeqNum getLoadHeadSeqNum() + { + if (loadQueue[loadHead]) { + return loadQueue[loadHead]->seqNum; + } else { + return 0; + } + + } + + /** Returns the index of the head store instruction. */ + int getStoreHead() { return storeHead; } + /** Returns the sequence number of the head store instruction. */ + InstSeqNum getStoreHeadSeqNum() + { + if (storeQueue[storeHead].inst) { + return storeQueue[storeHead].inst->seqNum; + } else { + return 0; + } + + } + + /** Returns whether or not the LSQ unit is stalled. */ + bool isStalled() { return stalled; } +}; + +template <class Impl> +template <class T> +Fault +LSQUnit<Impl>::read(Request *req, T &data, int load_idx) +{ + DynInstPtr load_inst = loadQueue[load_idx]; + + assert(load_inst); + + assert(!load_inst->isExecuted()); + + // Make sure this isn't an uncacheable access + // A bit of a hackish way to get uncached accesses to work only if they're + // at the head of the LSQ and are ready to commit (at the head of the ROB + // too). + if (req->getFlags() & UNCACHEABLE && + (load_idx != loadHead || !load_inst->reachedCommit)) { + iewStage->rescheduleMemInst(load_inst); + return TheISA::genMachineCheckFault(); + } + + // Check the SQ for any previous stores that might lead to forwarding + int store_idx = load_inst->sqIdx; + + int store_size = 0; + + DPRINTF(LSQUnit, "Read called, load idx: %i, store idx: %i, " + "storeHead: %i addr: %#x\n", + load_idx, store_idx, storeHead, req->getPaddr()); + +#if FULL_SYSTEM + if (req->getFlags() & LOCKED) { + cpu->lockAddr = req->getPaddr(); + cpu->lockFlag = true; + } +#endif + + while (store_idx != -1) { + // End once we've reached the top of the LSQ + if (store_idx == storeWBIdx) { + break; + } + + // Move the index to one younger + if (--store_idx < 0) + store_idx += SQEntries; + + assert(storeQueue[store_idx].inst); + + store_size = storeQueue[store_idx].size; + + if (store_size == 0) + continue; + + // Check if the store data is within the lower and upper bounds of + // addresses that the request needs. + bool store_has_lower_limit = + req->getVaddr() >= storeQueue[store_idx].inst->effAddr; + bool store_has_upper_limit = + (req->getVaddr() + req->getSize()) <= + (storeQueue[store_idx].inst->effAddr + store_size); + bool lower_load_has_store_part = + req->getVaddr() < (storeQueue[store_idx].inst->effAddr + + store_size); + bool upper_load_has_store_part = + (req->getVaddr() + req->getSize()) > + storeQueue[store_idx].inst->effAddr; + + // If the store's data has all of the data needed, we can forward. + if (store_has_lower_limit && store_has_upper_limit) { + // Get shift amount for offset into the store's data. + int shift_amt = req->getVaddr() & (store_size - 1); + // @todo: Magic number, assumes byte addressing + shift_amt = shift_amt << 3; + + // Cast this to type T? + data = storeQueue[store_idx].data >> shift_amt; + + assert(!load_inst->memData); + load_inst->memData = new uint8_t[64]; + + memcpy(load_inst->memData, &data, req->getSize()); + + DPRINTF(LSQUnit, "Forwarding from store idx %i to load to " + "addr %#x, data %#x\n", + store_idx, req->getVaddr(), data); + + PacketPtr data_pkt = new Packet(req, Packet::ReadReq, Packet::Broadcast); + data_pkt->dataStatic(load_inst->memData); + + WritebackEvent *wb = new WritebackEvent(load_inst, data_pkt, this); + + // We'll say this has a 1 cycle load-store forwarding latency + // for now. + // @todo: Need to make this a parameter. + wb->schedule(curTick); + + // Should keep track of stat for forwarded data + return NoFault; + } else if ((store_has_lower_limit && lower_load_has_store_part) || + (store_has_upper_limit && upper_load_has_store_part) || + (lower_load_has_store_part && upper_load_has_store_part)) { + // This is the partial store-load forwarding case where a store + // has only part of the load's data. + + // If it's already been written back, then don't worry about + // stalling on it. + if (storeQueue[store_idx].completed) { + continue; + } + + // Must stall load and force it to retry, so long as it's the oldest + // load that needs to do so. + if (!stalled || + (stalled && + load_inst->seqNum < + loadQueue[stallingLoadIdx]->seqNum)) { + stalled = true; + stallingStoreIsn = storeQueue[store_idx].inst->seqNum; + stallingLoadIdx = load_idx; + } + + // Tell IQ/mem dep unit that this instruction will need to be + // rescheduled eventually + iewStage->rescheduleMemInst(load_inst); + + // Do not generate a writeback event as this instruction is not + // complete. + DPRINTF(LSQUnit, "Load-store forwarding mis-match. " + "Store idx %i to load addr %#x\n", + store_idx, req->getVaddr()); + + return NoFault; + } + } + + // If there's no forwarding case, then go access memory + DPRINTF(LSQUnit, "Doing functional access for inst [sn:%lli] PC %#x\n", + load_inst->seqNum, load_inst->readPC()); + + assert(!load_inst->memData); + load_inst->memData = new uint8_t[64]; + + ++usedPorts; + + DPRINTF(LSQUnit, "Doing timing access for inst PC %#x\n", + load_inst->readPC()); + + PacketPtr data_pkt = new Packet(req, Packet::ReadReq, Packet::Broadcast); + data_pkt->dataStatic(load_inst->memData); + + LSQSenderState *state = new LSQSenderState; + state->isLoad = true; + state->idx = load_idx; + state->inst = load_inst; + data_pkt->senderState = state; + + // if we have a cache, do cache access too + if (!dcachePort->sendTiming(data_pkt)) { + // There's an older load that's already going to squash. + if (isLoadBlocked && blockedLoadSeqNum < load_inst->seqNum) + return NoFault; + + // Record that the load was blocked due to memory. This + // load will squash all instructions after it, be + // refetched, and re-executed. + isLoadBlocked = true; + loadBlockedHandled = false; + blockedLoadSeqNum = load_inst->seqNum; + // No fault occurred, even though the interface is blocked. + return NoFault; + } + + if (data_pkt->result != Packet::Success) { + DPRINTF(LSQUnit, "LSQUnit: D-cache miss!\n"); + DPRINTF(Activity, "Activity: ld accessing mem miss [sn:%lli]\n", + load_inst->seqNum); + } else { + DPRINTF(LSQUnit, "LSQUnit: D-cache hit!\n"); + DPRINTF(Activity, "Activity: ld accessing mem hit [sn:%lli]\n", + load_inst->seqNum); + } + + return NoFault; +} + +template <class Impl> +template <class T> +Fault +LSQUnit<Impl>::write(Request *req, T &data, int store_idx) +{ + assert(storeQueue[store_idx].inst); + + DPRINTF(LSQUnit, "Doing write to store idx %i, addr %#x data %#x" + " | storeHead:%i [sn:%i]\n", + store_idx, req->getPaddr(), data, storeHead, + storeQueue[store_idx].inst->seqNum); + + storeQueue[store_idx].req = req; + storeQueue[store_idx].size = sizeof(T); + storeQueue[store_idx].data = data; + + // This function only writes the data to the store queue, so no fault + // can happen here. + return NoFault; +} + +#endif // __CPU_O3_LSQ_UNIT_HH__ diff --git a/src/cpu/o3/lsq_unit_impl.hh b/src/cpu/o3/lsq_unit_impl.hh new file mode 100644 index 000000000..6f32ec304 --- /dev/null +++ b/src/cpu/o3/lsq_unit_impl.hh @@ -0,0 +1,929 @@ +/* + * 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 + */ + +#include "cpu/checker/cpu.hh" +#include "cpu/o3/lsq_unit.hh" +#include "base/str.hh" +#include "mem/request.hh" + +template<class Impl> +LSQUnit<Impl>::WritebackEvent::WritebackEvent(DynInstPtr &_inst, PacketPtr _pkt, + LSQUnit *lsq_ptr) + : Event(&mainEventQueue), inst(_inst), pkt(_pkt), lsqPtr(lsq_ptr) +{ + this->setFlags(Event::AutoDelete); +} + +template<class Impl> +void +LSQUnit<Impl>::WritebackEvent::process() +{ + if (!lsqPtr->isSwitchedOut()) { + lsqPtr->writeback(inst, pkt); + } + delete pkt; +} + +template<class Impl> +const char * +LSQUnit<Impl>::WritebackEvent::description() +{ + return "Store writeback event"; +} + +template<class Impl> +void +LSQUnit<Impl>::completeDataAccess(PacketPtr pkt) +{ + LSQSenderState *state = dynamic_cast<LSQSenderState *>(pkt->senderState); + DynInstPtr inst = state->inst; + DPRINTF(IEW, "Writeback event [sn:%lli]\n", inst->seqNum); + DPRINTF(Activity, "Activity: Writeback event [sn:%lli]\n", inst->seqNum); + + //iewStage->ldstQueue.removeMSHR(inst->threadNumber,inst->seqNum); + + if (isSwitchedOut() || inst->isSquashed()) { + delete state; + delete pkt; + return; + } else { + if (!state->noWB) { + writeback(inst, pkt); + } + + if (inst->isStore()) { + completeStore(state->idx); + } + } + + delete state; + delete pkt; +} + +template <class Impl> +Tick +LSQUnit<Impl>::DcachePort::recvAtomic(PacketPtr pkt) +{ + panic("O3CPU model does not work with atomic mode!"); + return curTick; +} + +template <class Impl> +void +LSQUnit<Impl>::DcachePort::recvFunctional(PacketPtr pkt) +{ + panic("O3CPU doesn't expect recvFunctional callback!"); +} + +template <class Impl> +void +LSQUnit<Impl>::DcachePort::recvStatusChange(Status status) +{ + if (status == RangeChange) + return; + + panic("O3CPU doesn't expect recvStatusChange callback!"); +} + +template <class Impl> +bool +LSQUnit<Impl>::DcachePort::recvTiming(PacketPtr pkt) +{ + lsq->completeDataAccess(pkt); + return true; +} + +template <class Impl> +void +LSQUnit<Impl>::DcachePort::recvRetry() +{ + lsq->recvRetry(); +} + +template <class Impl> +LSQUnit<Impl>::LSQUnit() + : loads(0), stores(0), storesToWB(0), stalled(false), + isStoreBlocked(false), isLoadBlocked(false), + loadBlockedHandled(false) +{ +} + +template<class Impl> +void +LSQUnit<Impl>::init(Params *params, unsigned maxLQEntries, + unsigned maxSQEntries, unsigned id) +{ + DPRINTF(LSQUnit, "Creating LSQUnit%i object.\n",id); + + switchedOut = false; + + lsqID = id; + + // Add 1 for the sentinel entry (they are circular queues). + LQEntries = maxLQEntries + 1; + SQEntries = maxSQEntries + 1; + + loadQueue.resize(LQEntries); + storeQueue.resize(SQEntries); + + loadHead = loadTail = 0; + + storeHead = storeWBIdx = storeTail = 0; + + usedPorts = 0; + cachePorts = params->cachePorts; + + mem = params->mem; + + memDepViolator = NULL; + + blockedLoadSeqNum = 0; +} + +template<class Impl> +void +LSQUnit<Impl>::setCPU(FullCPU *cpu_ptr) +{ + cpu = cpu_ptr; + dcachePort = new DcachePort(cpu, this); + + Port *mem_dport = mem->getPort(""); + dcachePort->setPeer(mem_dport); + mem_dport->setPeer(dcachePort); + + if (cpu->checker) { + cpu->checker->setDcachePort(dcachePort); + } +} + +template<class Impl> +std::string +LSQUnit<Impl>::name() const +{ + if (Impl::MaxThreads == 1) { + return iewStage->name() + ".lsq"; + } else { + return iewStage->name() + ".lsq.thread." + to_string(lsqID); + } +} + +template<class Impl> +void +LSQUnit<Impl>::clearLQ() +{ + loadQueue.clear(); +} + +template<class Impl> +void +LSQUnit<Impl>::clearSQ() +{ + storeQueue.clear(); +} + +template<class Impl> +void +LSQUnit<Impl>::switchOut() +{ + switchedOut = true; + for (int i = 0; i < loadQueue.size(); ++i) + loadQueue[i] = NULL; + + assert(storesToWB == 0); +} + +template<class Impl> +void +LSQUnit<Impl>::takeOverFrom() +{ + switchedOut = false; + loads = stores = storesToWB = 0; + + loadHead = loadTail = 0; + + storeHead = storeWBIdx = storeTail = 0; + + usedPorts = 0; + + memDepViolator = NULL; + + blockedLoadSeqNum = 0; + + stalled = false; + isLoadBlocked = false; + loadBlockedHandled = false; +} + +template<class Impl> +void +LSQUnit<Impl>::resizeLQ(unsigned size) +{ + unsigned size_plus_sentinel = size + 1; + assert(size_plus_sentinel >= LQEntries); + + if (size_plus_sentinel > LQEntries) { + while (size_plus_sentinel > loadQueue.size()) { + DynInstPtr dummy; + loadQueue.push_back(dummy); + LQEntries++; + } + } else { + LQEntries = size_plus_sentinel; + } + +} + +template<class Impl> +void +LSQUnit<Impl>::resizeSQ(unsigned size) +{ + unsigned size_plus_sentinel = size + 1; + if (size_plus_sentinel > SQEntries) { + while (size_plus_sentinel > storeQueue.size()) { + SQEntry dummy; + storeQueue.push_back(dummy); + SQEntries++; + } + } else { + SQEntries = size_plus_sentinel; + } +} + +template <class Impl> +void +LSQUnit<Impl>::insert(DynInstPtr &inst) +{ + assert(inst->isMemRef()); + + assert(inst->isLoad() || inst->isStore()); + + if (inst->isLoad()) { + insertLoad(inst); + } else { + insertStore(inst); + } + + inst->setInLSQ(); +} + +template <class Impl> +void +LSQUnit<Impl>::insertLoad(DynInstPtr &load_inst) +{ + assert((loadTail + 1) % LQEntries != loadHead); + assert(loads < LQEntries); + + DPRINTF(LSQUnit, "Inserting load PC %#x, idx:%i [sn:%lli]\n", + load_inst->readPC(), loadTail, load_inst->seqNum); + + load_inst->lqIdx = loadTail; + + if (stores == 0) { + load_inst->sqIdx = -1; + } else { + load_inst->sqIdx = storeTail; + } + + loadQueue[loadTail] = load_inst; + + incrLdIdx(loadTail); + + ++loads; +} + +template <class Impl> +void +LSQUnit<Impl>::insertStore(DynInstPtr &store_inst) +{ + // Make sure it is not full before inserting an instruction. + assert((storeTail + 1) % SQEntries != storeHead); + assert(stores < SQEntries); + + DPRINTF(LSQUnit, "Inserting store PC %#x, idx:%i [sn:%lli]\n", + store_inst->readPC(), storeTail, store_inst->seqNum); + + store_inst->sqIdx = storeTail; + store_inst->lqIdx = loadTail; + + storeQueue[storeTail] = SQEntry(store_inst); + + incrStIdx(storeTail); + + ++stores; +} + +template <class Impl> +typename Impl::DynInstPtr +LSQUnit<Impl>::getMemDepViolator() +{ + DynInstPtr temp = memDepViolator; + + memDepViolator = NULL; + + return temp; +} + +template <class Impl> +unsigned +LSQUnit<Impl>::numFreeEntries() +{ + unsigned free_lq_entries = LQEntries - loads; + unsigned free_sq_entries = SQEntries - stores; + + // Both the LQ and SQ entries have an extra dummy entry to differentiate + // empty/full conditions. Subtract 1 from the free entries. + if (free_lq_entries < free_sq_entries) { + return free_lq_entries - 1; + } else { + return free_sq_entries - 1; + } +} + +template <class Impl> +int +LSQUnit<Impl>::numLoadsReady() +{ + int load_idx = loadHead; + int retval = 0; + + while (load_idx != loadTail) { + assert(loadQueue[load_idx]); + + if (loadQueue[load_idx]->readyToIssue()) { + ++retval; + } + } + + return retval; +} + +template <class Impl> +Fault +LSQUnit<Impl>::executeLoad(DynInstPtr &inst) +{ + // Execute a specific load. + Fault load_fault = NoFault; + + DPRINTF(LSQUnit, "Executing load PC %#x, [sn:%lli]\n", + inst->readPC(),inst->seqNum); + + load_fault = inst->initiateAcc(); + + // If the instruction faulted, then we need to send it along to commit + // without the instruction completing. + if (load_fault != NoFault) { + // Send this instruction to commit, also make sure iew stage + // realizes there is activity. + iewStage->instToCommit(inst); + iewStage->activityThisCycle(); + } + + return load_fault; +} + +template <class Impl> +Fault +LSQUnit<Impl>::executeStore(DynInstPtr &store_inst) +{ + using namespace TheISA; + // Make sure that a store exists. + assert(stores != 0); + + int store_idx = store_inst->sqIdx; + + DPRINTF(LSQUnit, "Executing store PC %#x [sn:%lli]\n", + store_inst->readPC(), store_inst->seqNum); + + // Check the recently completed loads to see if any match this store's + // address. If so, then we have a memory ordering violation. + int load_idx = store_inst->lqIdx; + + Fault store_fault = store_inst->initiateAcc(); + + if (storeQueue[store_idx].size == 0) { + DPRINTF(LSQUnit,"Fault on Store PC %#x, [sn:%lli],Size = 0\n", + store_inst->readPC(),store_inst->seqNum); + + return store_fault; + } + + assert(store_fault == NoFault); + + if (store_inst->isStoreConditional()) { + // Store conditionals need to set themselves as able to + // writeback if we haven't had a fault by here. + storeQueue[store_idx].canWB = true; + + ++storesToWB; + } + + if (!memDepViolator) { + while (load_idx != loadTail) { + // Really only need to check loads that have actually executed + // It's safe to check all loads because effAddr is set to + // InvalAddr when the dyn inst is created. + + // @todo: For now this is extra conservative, detecting a + // violation if the addresses match assuming all accesses + // are quad word accesses. + + // @todo: Fix this, magic number being used here + if ((loadQueue[load_idx]->effAddr >> 8) == + (store_inst->effAddr >> 8)) { + // A load incorrectly passed this store. Squash and refetch. + // For now return a fault to show that it was unsuccessful. + memDepViolator = loadQueue[load_idx]; + + return genMachineCheckFault(); + } + + incrLdIdx(load_idx); + } + + // If we've reached this point, there was no violation. + memDepViolator = NULL; + } + + return store_fault; +} + +template <class Impl> +void +LSQUnit<Impl>::commitLoad() +{ + assert(loadQueue[loadHead]); + + DPRINTF(LSQUnit, "Committing head load instruction, PC %#x\n", + loadQueue[loadHead]->readPC()); + + loadQueue[loadHead] = NULL; + + incrLdIdx(loadHead); + + --loads; +} + +template <class Impl> +void +LSQUnit<Impl>::commitLoads(InstSeqNum &youngest_inst) +{ + assert(loads == 0 || loadQueue[loadHead]); + + while (loads != 0 && loadQueue[loadHead]->seqNum <= youngest_inst) { + commitLoad(); + } +} + +template <class Impl> +void +LSQUnit<Impl>::commitStores(InstSeqNum &youngest_inst) +{ + assert(stores == 0 || storeQueue[storeHead].inst); + + int store_idx = storeHead; + + while (store_idx != storeTail) { + assert(storeQueue[store_idx].inst); + // Mark any stores that are now committed and have not yet + // been marked as able to write back. + if (!storeQueue[store_idx].canWB) { + if (storeQueue[store_idx].inst->seqNum > youngest_inst) { + break; + } + DPRINTF(LSQUnit, "Marking store as able to write back, PC " + "%#x [sn:%lli]\n", + storeQueue[store_idx].inst->readPC(), + storeQueue[store_idx].inst->seqNum); + + storeQueue[store_idx].canWB = true; + + ++storesToWB; + } + + incrStIdx(store_idx); + } +} + +template <class Impl> +void +LSQUnit<Impl>::writebackStores() +{ + while (storesToWB > 0 && + storeWBIdx != storeTail && + storeQueue[storeWBIdx].inst && + storeQueue[storeWBIdx].canWB && + usedPorts < cachePorts) { + + if (isStoreBlocked) { + DPRINTF(LSQUnit, "Unable to write back any more stores, cache" + " is blocked!\n"); + break; + } + + // Store didn't write any data so no need to write it back to + // memory. + if (storeQueue[storeWBIdx].size == 0) { + completeStore(storeWBIdx); + + incrStIdx(storeWBIdx); + + continue; + } + + ++usedPorts; + + if (storeQueue[storeWBIdx].inst->isDataPrefetch()) { + incrStIdx(storeWBIdx); + + continue; + } + + assert(storeQueue[storeWBIdx].req); + assert(!storeQueue[storeWBIdx].committed); + + DynInstPtr inst = storeQueue[storeWBIdx].inst; + + Request *req = storeQueue[storeWBIdx].req; + storeQueue[storeWBIdx].committed = true; + + assert(!inst->memData); + inst->memData = new uint8_t[64]; + memcpy(inst->memData, (uint8_t *)&storeQueue[storeWBIdx].data, + req->getSize()); + + PacketPtr data_pkt = new Packet(req, Packet::WriteReq, Packet::Broadcast); + data_pkt->dataStatic(inst->memData); + + LSQSenderState *state = new LSQSenderState; + state->isLoad = false; + state->idx = storeWBIdx; + state->inst = inst; + data_pkt->senderState = state; + + DPRINTF(LSQUnit, "D-Cache: Writing back store idx:%i PC:%#x " + "to Addr:%#x, data:%#x [sn:%lli]\n", + storeWBIdx, storeQueue[storeWBIdx].inst->readPC(), + req->getPaddr(), *(inst->memData), + storeQueue[storeWBIdx].inst->seqNum); + + // @todo: Remove this SC hack once the memory system handles it. + if (req->getFlags() & LOCKED) { + if (req->getFlags() & UNCACHEABLE) { + req->setScResult(2); + } else { + if (cpu->lockFlag) { + req->setScResult(1); + } else { + req->setScResult(0); + // Hack: Instantly complete this store. + completeDataAccess(data_pkt); + incrStIdx(storeWBIdx); + continue; + } + } + } else { + // Non-store conditionals do not need a writeback. + state->noWB = true; + } + + if (!dcachePort->sendTiming(data_pkt)) { + // Need to handle becoming blocked on a store. + isStoreBlocked = true; + + assert(retryPkt == NULL); + retryPkt = data_pkt; + } else { + storePostSend(data_pkt); + } + } + + // Not sure this should set it to 0. + usedPorts = 0; + + assert(stores >= 0 && storesToWB >= 0); +} + +/*template <class Impl> +void +LSQUnit<Impl>::removeMSHR(InstSeqNum seqNum) +{ + list<InstSeqNum>::iterator mshr_it = find(mshrSeqNums.begin(), + mshrSeqNums.end(), + seqNum); + + if (mshr_it != mshrSeqNums.end()) { + mshrSeqNums.erase(mshr_it); + DPRINTF(LSQUnit, "Removing MSHR. count = %i\n",mshrSeqNums.size()); + } +}*/ + +template <class Impl> +void +LSQUnit<Impl>::squash(const InstSeqNum &squashed_num) +{ + DPRINTF(LSQUnit, "Squashing until [sn:%lli]!" + "(Loads:%i Stores:%i)\n", squashed_num, loads, stores); + + int load_idx = loadTail; + decrLdIdx(load_idx); + + while (loads != 0 && loadQueue[load_idx]->seqNum > squashed_num) { + DPRINTF(LSQUnit,"Load Instruction PC %#x squashed, " + "[sn:%lli]\n", + loadQueue[load_idx]->readPC(), + loadQueue[load_idx]->seqNum); + + if (isStalled() && load_idx == stallingLoadIdx) { + stalled = false; + stallingStoreIsn = 0; + stallingLoadIdx = 0; + } + + // Clear the smart pointer to make sure it is decremented. + loadQueue[load_idx]->squashed = true; + loadQueue[load_idx] = NULL; + --loads; + + // Inefficient! + loadTail = load_idx; + + decrLdIdx(load_idx); + } + + if (isLoadBlocked) { + if (squashed_num < blockedLoadSeqNum) { + isLoadBlocked = false; + loadBlockedHandled = false; + blockedLoadSeqNum = 0; + } + } + + int store_idx = storeTail; + decrStIdx(store_idx); + + while (stores != 0 && + storeQueue[store_idx].inst->seqNum > squashed_num) { + // Instructions marked as can WB are already committed. + if (storeQueue[store_idx].canWB) { + break; + } + + DPRINTF(LSQUnit,"Store Instruction PC %#x squashed, " + "idx:%i [sn:%lli]\n", + storeQueue[store_idx].inst->readPC(), + store_idx, storeQueue[store_idx].inst->seqNum); + + // I don't think this can happen. It should have been cleared + // by the stalling load. + if (isStalled() && + storeQueue[store_idx].inst->seqNum == stallingStoreIsn) { + panic("Is stalled should have been cleared by stalling load!\n"); + stalled = false; + stallingStoreIsn = 0; + } + + // Clear the smart pointer to make sure it is decremented. + storeQueue[store_idx].inst->squashed = true; + storeQueue[store_idx].inst = NULL; + storeQueue[store_idx].canWB = 0; + + storeQueue[store_idx].req = NULL; + --stores; + + // Inefficient! + storeTail = store_idx; + + decrStIdx(store_idx); + } +} + +template <class Impl> +void +LSQUnit<Impl>::storePostSend(Packet *pkt) +{ + if (isStalled() && + storeQueue[storeWBIdx].inst->seqNum == stallingStoreIsn) { + DPRINTF(LSQUnit, "Unstalling, stalling store [sn:%lli] " + "load idx:%i\n", + stallingStoreIsn, stallingLoadIdx); + stalled = false; + stallingStoreIsn = 0; + iewStage->replayMemInst(loadQueue[stallingLoadIdx]); + } + + if (!storeQueue[storeWBIdx].inst->isStoreConditional()) { + // The store is basically completed at this time. This + // only works so long as the checker doesn't try to + // verify the value in memory for stores. + storeQueue[storeWBIdx].inst->setCompleted(); + if (cpu->checker) { + cpu->checker->tick(storeQueue[storeWBIdx].inst); + } + } + + if (pkt->result != Packet::Success) { + DPRINTF(LSQUnit,"D-Cache Write Miss on idx:%i!\n", + storeWBIdx); + + DPRINTF(Activity, "Active st accessing mem miss [sn:%lli]\n", + storeQueue[storeWBIdx].inst->seqNum); + + //mshrSeqNums.push_back(storeQueue[storeWBIdx].inst->seqNum); + + //DPRINTF(LSQUnit, "Added MSHR. count = %i\n",mshrSeqNums.size()); + + // @todo: Increment stat here. + } else { + DPRINTF(LSQUnit,"D-Cache: Write Hit on idx:%i !\n", + storeWBIdx); + + DPRINTF(Activity, "Active st accessing mem hit [sn:%lli]\n", + storeQueue[storeWBIdx].inst->seqNum); + } + + incrStIdx(storeWBIdx); +} + +template <class Impl> +void +LSQUnit<Impl>::writeback(DynInstPtr &inst, PacketPtr pkt) +{ + iewStage->wakeCPU(); + + // Squashed instructions do not need to complete their access. + if (inst->isSquashed()) { + assert(!inst->isStore()); + return; + } + + if (!inst->isExecuted()) { + inst->setExecuted(); + + // Complete access to copy data to proper place. + inst->completeAcc(pkt); + } + + // Need to insert instruction into queue to commit + iewStage->instToCommit(inst); + + iewStage->activityThisCycle(); +} + +template <class Impl> +void +LSQUnit<Impl>::completeStore(int store_idx) +{ + assert(storeQueue[store_idx].inst); + storeQueue[store_idx].completed = true; + --storesToWB; + // A bit conservative because a store completion may not free up entries, + // but hopefully avoids two store completions in one cycle from making + // the CPU tick twice. + cpu->activityThisCycle(); + + if (store_idx == storeHead) { + do { + incrStIdx(storeHead); + + --stores; + } while (storeQueue[storeHead].completed && + storeHead != storeTail); + + iewStage->updateLSQNextCycle = true; + } + + DPRINTF(LSQUnit, "Completing store [sn:%lli], idx:%i, store head " + "idx:%i\n", + storeQueue[store_idx].inst->seqNum, store_idx, storeHead); + + if (isStalled() && + storeQueue[store_idx].inst->seqNum == stallingStoreIsn) { + DPRINTF(LSQUnit, "Unstalling, stalling store [sn:%lli] " + "load idx:%i\n", + stallingStoreIsn, stallingLoadIdx); + stalled = false; + stallingStoreIsn = 0; + iewStage->replayMemInst(loadQueue[stallingLoadIdx]); + } + + storeQueue[store_idx].inst->setCompleted(); + + // Tell the checker we've completed this instruction. Some stores + // may get reported twice to the checker, but the checker can + // handle that case. + if (cpu->checker) { + cpu->checker->tick(storeQueue[store_idx].inst); + } +} + +template <class Impl> +void +LSQUnit<Impl>::recvRetry() +{ + if (isStoreBlocked) { + assert(retryPkt != NULL); + + if (dcachePort->sendTiming(retryPkt)) { + storePostSend(retryPkt); + retryPkt = NULL; + isStoreBlocked = false; + } else { + // Still blocked! + } + } else if (isLoadBlocked) { + DPRINTF(LSQUnit, "Loads squash themselves and all younger insts, " + "no need to resend packet.\n"); + } else { + DPRINTF(LSQUnit, "Retry received but LSQ is no longer blocked.\n"); + } +} + +template <class Impl> +inline void +LSQUnit<Impl>::incrStIdx(int &store_idx) +{ + if (++store_idx >= SQEntries) + store_idx = 0; +} + +template <class Impl> +inline void +LSQUnit<Impl>::decrStIdx(int &store_idx) +{ + if (--store_idx < 0) + store_idx += SQEntries; +} + +template <class Impl> +inline void +LSQUnit<Impl>::incrLdIdx(int &load_idx) +{ + if (++load_idx >= LQEntries) + load_idx = 0; +} + +template <class Impl> +inline void +LSQUnit<Impl>::decrLdIdx(int &load_idx) +{ + if (--load_idx < 0) + load_idx += LQEntries; +} + +template <class Impl> +void +LSQUnit<Impl>::dumpInsts() +{ + cprintf("Load store queue: Dumping instructions.\n"); + cprintf("Load queue size: %i\n", loads); + cprintf("Load queue: "); + + int load_idx = loadHead; + + while (load_idx != loadTail && loadQueue[load_idx]) { + cprintf("%#x ", loadQueue[load_idx]->readPC()); + + incrLdIdx(load_idx); + } + + cprintf("Store queue size: %i\n", stores); + cprintf("Store queue: "); + + int store_idx = storeHead; + + while (store_idx != storeTail && storeQueue[store_idx].inst) { + cprintf("%#x ", storeQueue[store_idx].inst->readPC()); + + incrStIdx(store_idx); + } + + cprintf("\n"); +} diff --git a/src/cpu/o3/mem_dep_unit.cc b/src/cpu/o3/mem_dep_unit.cc new file mode 100644 index 000000000..a95103266 --- /dev/null +++ b/src/cpu/o3/mem_dep_unit.cc @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#include "cpu/o3/alpha_dyn_inst.hh" +#include "cpu/o3/alpha_impl.hh" +#include "cpu/o3/store_set.hh" +#include "cpu/o3/mem_dep_unit_impl.hh" + +// Force instantation of memory dependency unit using store sets and +// AlphaSimpleImpl. +template class MemDepUnit<StoreSet, AlphaSimpleImpl>; + +#ifdef DEBUG +template <> +int +MemDepUnit<StoreSet, AlphaSimpleImpl>::MemDepEntry::memdep_count = 0; +template <> +int +MemDepUnit<StoreSet, AlphaSimpleImpl>::MemDepEntry::memdep_insert = 0; +template <> +int +MemDepUnit<StoreSet, AlphaSimpleImpl>::MemDepEntry::memdep_erase = 0; +#endif diff --git a/src/cpu/o3/mem_dep_unit.hh b/src/cpu/o3/mem_dep_unit.hh new file mode 100644 index 000000000..e399f0133 --- /dev/null +++ b/src/cpu/o3/mem_dep_unit.hh @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#ifndef __CPU_O3_MEM_DEP_UNIT_HH__ +#define __CPU_O3_MEM_DEP_UNIT_HH__ + +#include <list> +#include <set> + +#include "base/hashmap.hh" +#include "base/refcnt.hh" +#include "base/statistics.hh" +#include "cpu/inst_seq.hh" + +struct SNHash { + size_t operator() (const InstSeqNum &seq_num) const { + unsigned a = (unsigned)seq_num; + unsigned hash = (((a >> 14) ^ ((a >> 2) & 0xffff))) & 0x7FFFFFFF; + + return hash; + } +}; + +template <class Impl> +class InstructionQueue; + +/** + * Memory dependency unit class. This holds the memory dependence predictor. + * As memory operations are issued to the IQ, they are also issued to this + * unit, which then looks up the prediction as to what they are dependent + * upon. This unit must be checked prior to a memory operation being able + * to issue. Although this is templated, it's somewhat hard to make a generic + * memory dependence unit. This one is mostly for store sets; it will be + * quite limited in what other memory dependence predictions it can also + * utilize. Thus this class should be most likely be rewritten for other + * dependence prediction schemes. + */ +template <class MemDepPred, class Impl> +class MemDepUnit { + public: + typedef typename Impl::Params Params; + typedef typename Impl::DynInstPtr DynInstPtr; + + /** Empty constructor. Must call init() prior to using in this case. */ + MemDepUnit() {} + + /** Constructs a MemDepUnit with given parameters. */ + MemDepUnit(Params *params); + + /** Frees up any memory allocated. */ + ~MemDepUnit(); + + /** Returns the name of the memory dependence unit. */ + std::string name() const; + + /** Initializes the unit with parameters and a thread id. */ + void init(Params *params, int tid); + + /** Registers statistics. */ + void regStats(); + + /** Switches out the memory dependence predictor. */ + void switchOut(); + + /** Takes over from another CPU's thread. */ + void takeOverFrom(); + + /** Sets the pointer to the IQ. */ + void setIQ(InstructionQueue<Impl> *iq_ptr); + + /** Inserts a memory instruction. */ + void insert(DynInstPtr &inst); + + /** Inserts a non-speculative memory instruction. */ + void insertNonSpec(DynInstPtr &inst); + + /** Inserts a barrier instruction. */ + void insertBarrier(DynInstPtr &barr_inst); + + /** Indicate that an instruction has its registers ready. */ + void regsReady(DynInstPtr &inst); + + /** Indicate that a non-speculative instruction is ready. */ + void nonSpecInstReady(DynInstPtr &inst); + + /** Reschedules an instruction to be re-executed. */ + void reschedule(DynInstPtr &inst); + + /** Replays all instructions that have been rescheduled by moving them to + * the ready list. + */ + void replay(DynInstPtr &inst); + + /** Completes a memory instruction. */ + void completed(DynInstPtr &inst); + + /** Completes a barrier instruction. */ + void completeBarrier(DynInstPtr &inst); + + /** Wakes any dependents of a memory instruction. */ + void wakeDependents(DynInstPtr &inst); + + /** Squashes all instructions up until a given sequence number for a + * specific thread. + */ + void squash(const InstSeqNum &squashed_num, unsigned tid); + + /** Indicates an ordering violation between a store and a younger load. */ + void violation(DynInstPtr &store_inst, DynInstPtr &violating_load); + + /** Issues the given instruction */ + void issue(DynInstPtr &inst); + + /** Debugging function to dump the lists of instructions. */ + void dumpLists(); + + private: + typedef typename std::list<DynInstPtr>::iterator ListIt; + + class MemDepEntry; + + typedef RefCountingPtr<MemDepEntry> MemDepEntryPtr; + + /** Memory dependence entries that track memory operations, marking + * when the instruction is ready to execute and what instructions depend + * upon it. + */ + class MemDepEntry : public RefCounted { + public: + /** Constructs a memory dependence entry. */ + MemDepEntry(DynInstPtr &new_inst) + : inst(new_inst), regsReady(false), memDepReady(false), + completed(false), squashed(false) + { +#ifdef DEBUG + ++memdep_count; + + DPRINTF(MemDepUnit, "Memory dependency entry created. " + "memdep_count=%i\n", memdep_count); +#endif + } + + /** Frees any pointers. */ + ~MemDepEntry() + { + for (int i = 0; i < dependInsts.size(); ++i) { + dependInsts[i] = NULL; + } +#ifdef DEBUG + --memdep_count; + + DPRINTF(MemDepUnit, "Memory dependency entry deleted. " + "memdep_count=%i\n", memdep_count); +#endif + } + + /** Returns the name of the memory dependence entry. */ + std::string name() const { return "memdepentry"; } + + /** The instruction being tracked. */ + DynInstPtr inst; + + /** The iterator to the instruction's location inside the list. */ + ListIt listIt; + + /** A vector of any dependent instructions. */ + std::vector<MemDepEntryPtr> dependInsts; + + /** If the registers are ready or not. */ + bool regsReady; + /** If all memory dependencies have been satisfied. */ + bool memDepReady; + /** If the instruction is completed. */ + bool completed; + /** If the instruction is squashed. */ + bool squashed; + + /** For debugging. */ +#ifdef DEBUG + static int memdep_count; + static int memdep_insert; + static int memdep_erase; +#endif + }; + + /** Finds the memory dependence entry in the hash map. */ + inline MemDepEntryPtr &findInHash(const DynInstPtr &inst); + + /** Moves an entry to the ready list. */ + inline void moveToReady(MemDepEntryPtr &ready_inst_entry); + + typedef m5::hash_map<InstSeqNum, MemDepEntryPtr, SNHash> MemDepHash; + + typedef typename MemDepHash::iterator MemDepHashIt; + + /** A hash map of all memory dependence entries. */ + MemDepHash memDepHash; + + /** A list of all instructions in the memory dependence unit. */ + std::list<DynInstPtr> instList[Impl::MaxThreads]; + + /** A list of all instructions that are going to be replayed. */ + std::list<DynInstPtr> instsToReplay; + + /** The memory dependence predictor. It is accessed upon new + * instructions being added to the IQ, and responds by telling + * this unit what instruction the newly added instruction is dependent + * upon. + */ + MemDepPred depPred; + + /** Is there an outstanding load barrier that loads must wait on. */ + bool loadBarrier; + /** The sequence number of the load barrier. */ + InstSeqNum loadBarrierSN; + /** Is there an outstanding store barrier that loads must wait on. */ + bool storeBarrier; + /** The sequence number of the store barrier. */ + InstSeqNum storeBarrierSN; + + /** Pointer to the IQ. */ + InstructionQueue<Impl> *iqPtr; + + /** The thread id of this memory dependence unit. */ + int id; + + /** Stat for number of inserted loads. */ + Stats::Scalar<> insertedLoads; + /** Stat for number of inserted stores. */ + Stats::Scalar<> insertedStores; + /** Stat for number of conflicting loads that had to wait for a store. */ + Stats::Scalar<> conflictingLoads; + /** Stat for number of conflicting stores that had to wait for a store. */ + Stats::Scalar<> conflictingStores; +}; + +#endif // __CPU_O3_MEM_DEP_UNIT_HH__ diff --git a/src/cpu/o3/mem_dep_unit_impl.hh b/src/cpu/o3/mem_dep_unit_impl.hh new file mode 100644 index 000000000..16f67a4e0 --- /dev/null +++ b/src/cpu/o3/mem_dep_unit_impl.hh @@ -0,0 +1,571 @@ +/* + * 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 <map> + +#include "cpu/o3/inst_queue.hh" +#include "cpu/o3/mem_dep_unit.hh" + +template <class MemDepPred, class Impl> +MemDepUnit<MemDepPred, Impl>::MemDepUnit(Params *params) + : depPred(params->SSITSize, params->LFSTSize), loadBarrier(false), + loadBarrierSN(0), storeBarrier(false), storeBarrierSN(0), iqPtr(NULL) +{ + DPRINTF(MemDepUnit, "Creating MemDepUnit object.\n"); +} + +template <class MemDepPred, class Impl> +MemDepUnit<MemDepPred, Impl>::~MemDepUnit() +{ + for (int tid=0; tid < Impl::MaxThreads; tid++) { + + ListIt inst_list_it = instList[tid].begin(); + + MemDepHashIt hash_it; + + while (!instList[tid].empty()) { + hash_it = memDepHash.find((*inst_list_it)->seqNum); + + assert(hash_it != memDepHash.end()); + + memDepHash.erase(hash_it); + + instList[tid].erase(inst_list_it++); + } + } + +#ifdef DEBUG + assert(MemDepEntry::memdep_count == 0); +#endif +} + +template <class MemDepPred, class Impl> +std::string +MemDepUnit<MemDepPred, Impl>::name() const +{ + return "memdepunit"; +} + +template <class MemDepPred, class Impl> +void +MemDepUnit<MemDepPred, Impl>::init(Params *params, int tid) +{ + DPRINTF(MemDepUnit, "Creating MemDepUnit %i object.\n",tid); + + id = tid; + + depPred.init(params->SSITSize, params->LFSTSize); +} + +template <class MemDepPred, class Impl> +void +MemDepUnit<MemDepPred, Impl>::regStats() +{ + insertedLoads + .name(name() + ".memDep.insertedLoads") + .desc("Number of loads inserted to the mem dependence unit."); + + insertedStores + .name(name() + ".memDep.insertedStores") + .desc("Number of stores inserted to the mem dependence unit."); + + conflictingLoads + .name(name() + ".memDep.conflictingLoads") + .desc("Number of conflicting loads."); + + conflictingStores + .name(name() + ".memDep.conflictingStores") + .desc("Number of conflicting stores."); +} + +template <class MemDepPred, class Impl> +void +MemDepUnit<MemDepPred, Impl>::switchOut() +{ + // Clear any state. + for (int i = 0; i < Impl::MaxThreads; ++i) { + instList[i].clear(); + } + instsToReplay.clear(); + memDepHash.clear(); +} + +template <class MemDepPred, class Impl> +void +MemDepUnit<MemDepPred, Impl>::takeOverFrom() +{ + // Be sure to reset all state. + loadBarrier = storeBarrier = false; + loadBarrierSN = storeBarrierSN = 0; + depPred.clear(); +} + +template <class MemDepPred, class Impl> +void +MemDepUnit<MemDepPred, Impl>::setIQ(InstructionQueue<Impl> *iq_ptr) +{ + iqPtr = iq_ptr; +} + +template <class MemDepPred, class Impl> +void +MemDepUnit<MemDepPred, Impl>::insert(DynInstPtr &inst) +{ + unsigned tid = inst->threadNumber; + + MemDepEntryPtr inst_entry = new MemDepEntry(inst); + + // Add the MemDepEntry to the hash. + memDepHash.insert( + std::pair<InstSeqNum, MemDepEntryPtr>(inst->seqNum, inst_entry)); +#ifdef DEBUG + MemDepEntry::memdep_insert++; +#endif + + instList[tid].push_back(inst); + + inst_entry->listIt = --(instList[tid].end()); + + // Check any barriers and the dependence predictor for any + // producing memrefs/stores. + InstSeqNum producing_store; + if (inst->isLoad() && loadBarrier) { + producing_store = loadBarrierSN; + } else if (inst->isStore() && storeBarrier) { + producing_store = storeBarrierSN; + } else { + producing_store = depPred.checkInst(inst->readPC()); + } + + MemDepEntryPtr store_entry = NULL; + + // If there is a producing store, try to find the entry. + if (producing_store != 0) { + MemDepHashIt hash_it = memDepHash.find(producing_store); + + if (hash_it != memDepHash.end()) { + store_entry = (*hash_it).second; + } + } + + // If no store entry, then instruction can issue as soon as the registers + // are ready. + if (!store_entry) { + DPRINTF(MemDepUnit, "No dependency for inst PC " + "%#x [sn:%lli].\n", inst->readPC(), inst->seqNum); + + inst_entry->memDepReady = true; + + if (inst->readyToIssue()) { + inst_entry->regsReady = true; + + moveToReady(inst_entry); + } + } else { + // Otherwise make the instruction dependent on the store/barrier. + DPRINTF(MemDepUnit, "Adding to dependency list; " + "inst PC %#x is dependent on [sn:%lli].\n", + inst->readPC(), producing_store); + + if (inst->readyToIssue()) { + inst_entry->regsReady = true; + } + + // Add this instruction to the list of dependents. + store_entry->dependInsts.push_back(inst_entry); + + if (inst->isLoad()) { + ++conflictingLoads; + } else { + ++conflictingStores; + } + } + + if (inst->isStore()) { + DPRINTF(MemDepUnit, "Inserting store PC %#x [sn:%lli].\n", + inst->readPC(), inst->seqNum); + + depPred.insertStore(inst->readPC(), inst->seqNum, inst->threadNumber); + + ++insertedStores; + } else if (inst->isLoad()) { + ++insertedLoads; + } else { + panic("Unknown type! (most likely a barrier)."); + } +} + +template <class MemDepPred, class Impl> +void +MemDepUnit<MemDepPred, Impl>::insertNonSpec(DynInstPtr &inst) +{ + unsigned tid = inst->threadNumber; + + MemDepEntryPtr inst_entry = new MemDepEntry(inst); + + // Insert the MemDepEntry into the hash. + memDepHash.insert( + std::pair<InstSeqNum, MemDepEntryPtr>(inst->seqNum, inst_entry)); +#ifdef DEBUG + MemDepEntry::memdep_insert++; +#endif + + // Add the instruction to the list. + instList[tid].push_back(inst); + + inst_entry->listIt = --(instList[tid].end()); + + // Might want to turn this part into an inline function or something. + // It's shared between both insert functions. + if (inst->isStore()) { + DPRINTF(MemDepUnit, "Inserting store PC %#x [sn:%lli].\n", + inst->readPC(), inst->seqNum); + + depPred.insertStore(inst->readPC(), inst->seqNum, inst->threadNumber); + + ++insertedStores; + } else if (inst->isLoad()) { + ++insertedLoads; + } else { + panic("Unknown type! (most likely a barrier)."); + } +} + +template <class MemDepPred, class Impl> +void +MemDepUnit<MemDepPred, Impl>::insertBarrier(DynInstPtr &barr_inst) +{ + InstSeqNum barr_sn = barr_inst->seqNum; + // Memory barriers block loads and stores, write barriers only stores. + if (barr_inst->isMemBarrier()) { + loadBarrier = true; + loadBarrierSN = barr_sn; + storeBarrier = true; + storeBarrierSN = barr_sn; + DPRINTF(MemDepUnit, "Inserted a memory barrier\n"); + } else if (barr_inst->isWriteBarrier()) { + storeBarrier = true; + storeBarrierSN = barr_sn; + DPRINTF(MemDepUnit, "Inserted a write barrier\n"); + } + + unsigned tid = barr_inst->threadNumber; + + MemDepEntryPtr inst_entry = new MemDepEntry(barr_inst); + + // Add the MemDepEntry to the hash. + memDepHash.insert( + std::pair<InstSeqNum, MemDepEntryPtr>(barr_sn, inst_entry)); +#ifdef DEBUG + MemDepEntry::memdep_insert++; +#endif + + // Add the instruction to the instruction list. + instList[tid].push_back(barr_inst); + + inst_entry->listIt = --(instList[tid].end()); +} + +template <class MemDepPred, class Impl> +void +MemDepUnit<MemDepPred, Impl>::regsReady(DynInstPtr &inst) +{ + DPRINTF(MemDepUnit, "Marking registers as ready for " + "instruction PC %#x [sn:%lli].\n", + inst->readPC(), inst->seqNum); + + MemDepEntryPtr inst_entry = findInHash(inst); + + inst_entry->regsReady = true; + + if (inst_entry->memDepReady) { + DPRINTF(MemDepUnit, "Instruction has its memory " + "dependencies resolved, adding it to the ready list.\n"); + + moveToReady(inst_entry); + } else { + DPRINTF(MemDepUnit, "Instruction still waiting on " + "memory dependency.\n"); + } +} + +template <class MemDepPred, class Impl> +void +MemDepUnit<MemDepPred, Impl>::nonSpecInstReady(DynInstPtr &inst) +{ + DPRINTF(MemDepUnit, "Marking non speculative " + "instruction PC %#x as ready [sn:%lli].\n", + inst->readPC(), inst->seqNum); + + MemDepEntryPtr inst_entry = findInHash(inst); + + moveToReady(inst_entry); +} + +template <class MemDepPred, class Impl> +void +MemDepUnit<MemDepPred, Impl>::reschedule(DynInstPtr &inst) +{ + instsToReplay.push_back(inst); +} + +template <class MemDepPred, class Impl> +void +MemDepUnit<MemDepPred, Impl>::replay(DynInstPtr &inst) +{ + DynInstPtr temp_inst; + bool found_inst = false; + + // For now this replay function replays all waiting memory ops. + while (!instsToReplay.empty()) { + temp_inst = instsToReplay.front(); + + MemDepEntryPtr inst_entry = findInHash(temp_inst); + + DPRINTF(MemDepUnit, "Replaying mem instruction PC %#x " + "[sn:%lli].\n", + temp_inst->readPC(), temp_inst->seqNum); + + moveToReady(inst_entry); + + if (temp_inst == inst) { + found_inst = true; + } + + instsToReplay.pop_front(); + } + + assert(found_inst); +} + +template <class MemDepPred, class Impl> +void +MemDepUnit<MemDepPred, Impl>::completed(DynInstPtr &inst) +{ + DPRINTF(MemDepUnit, "Completed mem instruction PC %#x " + "[sn:%lli].\n", + inst->readPC(), inst->seqNum); + + unsigned tid = inst->threadNumber; + + // Remove the instruction from the hash and the list. + MemDepHashIt hash_it = memDepHash.find(inst->seqNum); + + assert(hash_it != memDepHash.end()); + + instList[tid].erase((*hash_it).second->listIt); + + (*hash_it).second = NULL; + + memDepHash.erase(hash_it); +#ifdef DEBUG + MemDepEntry::memdep_erase++; +#endif +} + +template <class MemDepPred, class Impl> +void +MemDepUnit<MemDepPred, Impl>::completeBarrier(DynInstPtr &inst) +{ + wakeDependents(inst); + completed(inst); + + InstSeqNum barr_sn = inst->seqNum; + + if (inst->isMemBarrier()) { + assert(loadBarrier && storeBarrier); + if (loadBarrierSN == barr_sn) + loadBarrier = false; + if (storeBarrierSN == barr_sn) + storeBarrier = false; + } else if (inst->isWriteBarrier()) { + assert(storeBarrier); + if (storeBarrierSN == barr_sn) + storeBarrier = false; + } +} + +template <class MemDepPred, class Impl> +void +MemDepUnit<MemDepPred, Impl>::wakeDependents(DynInstPtr &inst) +{ + // Only stores and barriers have dependents. + if (!inst->isStore() && !inst->isMemBarrier() && !inst->isWriteBarrier()) { + return; + } + + MemDepEntryPtr inst_entry = findInHash(inst); + + for (int i = 0; i < inst_entry->dependInsts.size(); ++i ) { + MemDepEntryPtr woken_inst = inst_entry->dependInsts[i]; + + if (!woken_inst->inst) { + // Potentially removed mem dep entries could be on this list + continue; + } + + DPRINTF(MemDepUnit, "Waking up a dependent inst, " + "[sn:%lli].\n", + woken_inst->inst->seqNum); + + if (woken_inst->regsReady && !woken_inst->squashed) { + moveToReady(woken_inst); + } else { + woken_inst->memDepReady = true; + } + } + + inst_entry->dependInsts.clear(); +} + +template <class MemDepPred, class Impl> +void +MemDepUnit<MemDepPred, Impl>::squash(const InstSeqNum &squashed_num, + unsigned tid) +{ + if (!instsToReplay.empty()) { + ListIt replay_it = instsToReplay.begin(); + while (replay_it != instsToReplay.end()) { + if ((*replay_it)->threadNumber == tid && + (*replay_it)->seqNum > squashed_num) { + instsToReplay.erase(replay_it++); + } else { + ++replay_it; + } + } + } + + ListIt squash_it = instList[tid].end(); + --squash_it; + + MemDepHashIt hash_it; + + while (!instList[tid].empty() && + (*squash_it)->seqNum > squashed_num) { + + DPRINTF(MemDepUnit, "Squashing inst [sn:%lli]\n", + (*squash_it)->seqNum); + + hash_it = memDepHash.find((*squash_it)->seqNum); + + assert(hash_it != memDepHash.end()); + + (*hash_it).second->squashed = true; + + (*hash_it).second = NULL; + + memDepHash.erase(hash_it); +#ifdef DEBUG + MemDepEntry::memdep_erase++; +#endif + + instList[tid].erase(squash_it--); + } + + // Tell the dependency predictor to squash as well. + depPred.squash(squashed_num, tid); +} + +template <class MemDepPred, class Impl> +void +MemDepUnit<MemDepPred, Impl>::violation(DynInstPtr &store_inst, + DynInstPtr &violating_load) +{ + DPRINTF(MemDepUnit, "Passing violating PCs to store sets," + " load: %#x, store: %#x\n", violating_load->readPC(), + store_inst->readPC()); + // Tell the memory dependence unit of the violation. + depPred.violation(violating_load->readPC(), store_inst->readPC()); +} + +template <class MemDepPred, class Impl> +void +MemDepUnit<MemDepPred, Impl>::issue(DynInstPtr &inst) +{ + DPRINTF(MemDepUnit, "Issuing instruction PC %#x [sn:%lli].\n", + inst->readPC(), inst->seqNum); + + depPred.issued(inst->readPC(), inst->seqNum, inst->isStore()); +} + +template <class MemDepPred, class Impl> +inline typename MemDepUnit<MemDepPred,Impl>::MemDepEntryPtr & +MemDepUnit<MemDepPred, Impl>::findInHash(const DynInstPtr &inst) +{ + MemDepHashIt hash_it = memDepHash.find(inst->seqNum); + + assert(hash_it != memDepHash.end()); + + return (*hash_it).second; +} + +template <class MemDepPred, class Impl> +inline void +MemDepUnit<MemDepPred, Impl>::moveToReady(MemDepEntryPtr &woken_inst_entry) +{ + DPRINTF(MemDepUnit, "Adding instruction [sn:%lli] " + "to the ready list.\n", woken_inst_entry->inst->seqNum); + + assert(!woken_inst_entry->squashed); + + iqPtr->addReadyMemInst(woken_inst_entry->inst); +} + + +template <class MemDepPred, class Impl> +void +MemDepUnit<MemDepPred, Impl>::dumpLists() +{ + for (unsigned tid=0; tid < Impl::MaxThreads; tid++) { + cprintf("Instruction list %i size: %i\n", + tid, instList[tid].size()); + + ListIt inst_list_it = instList[tid].begin(); + int num = 0; + + while (inst_list_it != instList[tid].end()) { + cprintf("Instruction:%i\nPC:%#x\n[sn:%i]\n[tid:%i]\nIssued:%i\n" + "Squashed:%i\n\n", + num, (*inst_list_it)->readPC(), + (*inst_list_it)->seqNum, + (*inst_list_it)->threadNumber, + (*inst_list_it)->isIssued(), + (*inst_list_it)->isSquashed()); + inst_list_it++; + ++num; + } + } + + cprintf("Memory dependence hash size: %i\n", memDepHash.size()); + +#ifdef DEBUG + cprintf("Memory dependence entries: %i\n", MemDepEntry::memdep_count); +#endif +} diff --git a/src/cpu/o3/ras.cc b/src/cpu/o3/ras.cc new file mode 100644 index 000000000..f9939259a --- /dev/null +++ b/src/cpu/o3/ras.cc @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#include "cpu/o3/ras.hh" + +void +ReturnAddrStack::init(unsigned _numEntries) +{ + numEntries = _numEntries; + usedEntries = 0; + tos = 0; + + addrStack.resize(numEntries); + + for (int i = 0; i < numEntries; ++i) + addrStack[i] = 0; +} + +void +ReturnAddrStack::reset() +{ + usedEntries = 0; + tos = 0; + for (int i = 0; i < numEntries; ++i) + addrStack[i] = 0; +} + +void +ReturnAddrStack::push(const Addr &return_addr) +{ + incrTos(); + + addrStack[tos] = return_addr; + + if (usedEntries != numEntries) { + ++usedEntries; + } +} + +void +ReturnAddrStack::pop() +{ + if (usedEntries > 0) { + --usedEntries; + } + + decrTos(); +} + +void +ReturnAddrStack::restore(unsigned top_entry_idx, + const Addr &restored_target) +{ + tos = top_entry_idx; + + addrStack[tos] = restored_target; +} diff --git a/src/cpu/o3/ras.hh b/src/cpu/o3/ras.hh new file mode 100644 index 000000000..5c8a93285 --- /dev/null +++ b/src/cpu/o3/ras.hh @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#ifndef __CPU_O3_RAS_HH__ +#define __CPU_O3_RAS_HH__ + +// For Addr type. +#include "arch/isa_traits.hh" +#include <vector> + +/** Return address stack class, implements a simple RAS. */ +class ReturnAddrStack +{ + public: + /** Creates a return address stack, but init() must be called prior to + * use. + */ + ReturnAddrStack() {} + + /** Initializes RAS with a specified number of entries. + * @param numEntries Number of entries in the RAS. + */ + void init(unsigned numEntries); + + void reset(); + + /** Returns the top address on the RAS. */ + Addr top() + { return addrStack[tos]; } + + /** Returns the index of the top of the RAS. */ + unsigned topIdx() + { return tos; } + + /** Pushes an address onto the RAS. */ + void push(const Addr &return_addr); + + /** Pops the top address from the RAS. */ + void pop(); + + /** Changes index to the top of the RAS, and replaces the top address with + * a new target. + * @param top_entry_idx The index of the RAS that will now be the top. + * @param restored_target The new target address of the new top of the RAS. + */ + void restore(unsigned top_entry_idx, const Addr &restored_target); + + private: + /** Increments the top of stack index. */ + inline void incrTos() + { if (++tos == numEntries) tos = 0; } + + /** Decrements the top of stack index. */ + inline void decrTos() + { tos = (tos == 0 ? numEntries - 1 : tos - 1); } + + /** The RAS itself. */ + std::vector<Addr> addrStack; + + /** The number of entries in the RAS. */ + unsigned numEntries; + + /** The number of used entries in the RAS. */ + unsigned usedEntries; + + /** The top of stack index. */ + unsigned tos; +}; + +#endif // __CPU_O3_RAS_HH__ diff --git a/src/cpu/o3/regfile.hh b/src/cpu/o3/regfile.hh new file mode 100644 index 000000000..ade5e4e56 --- /dev/null +++ b/src/cpu/o3/regfile.hh @@ -0,0 +1,310 @@ +/* + * 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 + * Gabe Black + */ + +#ifndef __CPU_O3_REGFILE_HH__ +#define __CPU_O3_REGFILE_HH__ + +#include "arch/isa_traits.hh" +#include "arch/faults.hh" +#include "arch/types.hh" +#include "base/trace.hh" +#include "config/full_system.hh" +#include "cpu/o3/comm.hh" + +#if FULL_SYSTEM +#include "kern/kernel_stats.hh" + +#endif + +#include <vector> + +/** + * Simple physical register file class. + * Right now this is specific to Alpha until we decide if/how to make things + * generic enough to support other ISAs. + */ +template <class Impl> +class PhysRegFile +{ + protected: + typedef TheISA::IntReg IntReg; + typedef TheISA::FloatReg FloatReg; + typedef TheISA::FloatRegBits FloatRegBits; + typedef TheISA::MiscRegFile MiscRegFile; + typedef TheISA::MiscReg MiscReg; + + typedef union { + FloatReg d; + FloatRegBits q; + } PhysFloatReg; + + // Note that most of the definitions of the IntReg, FloatReg, etc. exist + // within the Impl/ISA class and not within this PhysRegFile class. + + // Will make these registers public for now, but they probably should + // be private eventually with some accessor functions. + public: + typedef typename Impl::FullCPU FullCPU; + + /** + * Constructs a physical register file with the specified amount of + * integer and floating point registers. + */ + PhysRegFile(unsigned _numPhysicalIntRegs, + unsigned _numPhysicalFloatRegs); + + //Everything below should be pretty well identical to the normal + //register file that exists within AlphaISA class. + //The duplication is unfortunate but it's better than having + //different ways to access certain registers. + + //Add these in later when everything else is in place +// void serialize(std::ostream &os); +// void unserialize(Checkpoint *cp, const std::string §ion); + + /** Reads an integer register. */ + uint64_t readIntReg(PhysRegIndex reg_idx) + { + assert(reg_idx < numPhysicalIntRegs); + + DPRINTF(IEW, "RegFile: Access to int register %i, has data " + "%#x\n", int(reg_idx), intRegFile[reg_idx]); + return intRegFile[reg_idx]; + } + + FloatReg readFloatReg(PhysRegIndex reg_idx, int width) + { + // Remove the base Float reg dependency. + reg_idx = reg_idx - numPhysicalIntRegs; + + assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); + + FloatReg floatReg = floatRegFile[reg_idx].d; + + DPRINTF(IEW, "RegFile: Access to %d byte float register %i, has " + "data %#x\n", int(reg_idx), floatRegFile[reg_idx].q); + + return floatReg; + } + + /** Reads a floating point register (double precision). */ + FloatReg readFloatReg(PhysRegIndex reg_idx) + { + // Remove the base Float reg dependency. + reg_idx = reg_idx - numPhysicalIntRegs; + + assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); + + FloatReg floatReg = floatRegFile[reg_idx].d; + + DPRINTF(IEW, "RegFile: Access to float register %i, has " + "data %#x\n", int(reg_idx), floatRegFile[reg_idx].q); + + return floatReg; + } + + /** Reads a floating point register as an integer. */ + FloatRegBits readFloatRegBits(PhysRegIndex reg_idx, int width) + { + // Remove the base Float reg dependency. + reg_idx = reg_idx - numPhysicalIntRegs; + + assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); + + FloatRegBits floatRegBits = floatRegFile[reg_idx].q; + + DPRINTF(IEW, "RegFile: Access to float register %i as int, " + "has data %#x\n", int(reg_idx), (uint64_t)floatRegBits); + + return floatRegBits; + } + + FloatRegBits readFloatRegBits(PhysRegIndex reg_idx) + { + // Remove the base Float reg dependency. + reg_idx = reg_idx - numPhysicalIntRegs; + + assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); + + FloatRegBits floatRegBits = floatRegFile[reg_idx].q; + + DPRINTF(IEW, "RegFile: Access to float register %i as int, " + "has data %#x\n", int(reg_idx), (uint64_t)floatRegBits); + + return floatRegBits; + } + + /** Sets an integer register to the given value. */ + void setIntReg(PhysRegIndex reg_idx, uint64_t val) + { + assert(reg_idx < numPhysicalIntRegs); + + DPRINTF(IEW, "RegFile: Setting int register %i to %#x\n", + int(reg_idx), val); + + if (reg_idx != TheISA::ZeroReg) + intRegFile[reg_idx] = val; + } + + /** Sets a single precision floating point register to the given value. */ + void setFloatReg(PhysRegIndex reg_idx, FloatReg val, int width) + { + // Remove the base Float reg dependency. + reg_idx = reg_idx - numPhysicalIntRegs; + + assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); + + DPRINTF(IEW, "RegFile: Setting float register %i to %#x\n", + int(reg_idx), (uint64_t)val); + + if (reg_idx != TheISA::ZeroReg) + floatRegFile[reg_idx].d = val; + } + + /** Sets a double precision floating point register to the given value. */ + void setFloatReg(PhysRegIndex reg_idx, FloatReg val) + { + // Remove the base Float reg dependency. + reg_idx = reg_idx - numPhysicalIntRegs; + + assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); + + DPRINTF(IEW, "RegFile: Setting float register %i to %#x\n", + int(reg_idx), (uint64_t)val); + + if (reg_idx != TheISA::ZeroReg) + floatRegFile[reg_idx].d = val; + } + + /** Sets a floating point register to the given integer value. */ + void setFloatRegBits(PhysRegIndex reg_idx, FloatRegBits val, int width) + { + // Remove the base Float reg dependency. + reg_idx = reg_idx - numPhysicalIntRegs; + + assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); + + DPRINTF(IEW, "RegFile: Setting float register %i to %#x\n", + int(reg_idx), (uint64_t)val); + + floatRegFile[reg_idx].q = val; + } + + void setFloatRegBits(PhysRegIndex reg_idx, FloatRegBits val) + { + // Remove the base Float reg dependency. + reg_idx = reg_idx - numPhysicalIntRegs; + + assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); + + DPRINTF(IEW, "RegFile: Setting float register %i to %#x\n", + int(reg_idx), (uint64_t)val); + + floatRegFile[reg_idx].q = val; + } + + MiscReg readMiscReg(int misc_reg, unsigned thread_id) + { + return miscRegs[thread_id].readReg(misc_reg); + } + + MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault, + unsigned thread_id) + { + return miscRegs[thread_id].readRegWithEffect(misc_reg, fault, + cpu->tcBase(thread_id)); + } + + Fault setMiscReg(int misc_reg, const MiscReg &val, unsigned thread_id) + { + return miscRegs[thread_id].setReg(misc_reg, val); + } + + Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val, + unsigned thread_id) + { + return miscRegs[thread_id].setRegWithEffect(misc_reg, val, + cpu->tcBase(thread_id)); + } + +#if FULL_SYSTEM + int readIntrFlag() { return intrflag; } + /** Sets an interrupt flag. */ + void setIntrFlag(int val) { intrflag = val; } +#endif + + public: + /** (signed) integer register file. */ + IntReg *intRegFile; + + /** Floating point register file. */ + PhysFloatReg *floatRegFile; + + /** Miscellaneous register file. */ + MiscRegFile miscRegs[Impl::MaxThreads]; + +#if FULL_SYSTEM + private: + int intrflag; // interrupt flag +#endif + + private: + /** CPU pointer. */ + FullCPU *cpu; + + public: + /** Sets the CPU pointer. */ + void setCPU(FullCPU *cpu_ptr) { cpu = cpu_ptr; } + + /** Number of physical integer registers. */ + unsigned numPhysicalIntRegs; + /** Number of physical floating point registers. */ + unsigned numPhysicalFloatRegs; +}; + +template <class Impl> +PhysRegFile<Impl>::PhysRegFile(unsigned _numPhysicalIntRegs, + unsigned _numPhysicalFloatRegs) + : numPhysicalIntRegs(_numPhysicalIntRegs), + numPhysicalFloatRegs(_numPhysicalFloatRegs) +{ + intRegFile = new IntReg[numPhysicalIntRegs]; + floatRegFile = new PhysFloatReg[numPhysicalFloatRegs]; + + for (int i = 0; i < Impl::MaxThreads; ++i) { + miscRegs[i].clear(); + } + + memset(intRegFile, 0, sizeof(IntReg) * numPhysicalIntRegs); + memset(floatRegFile, 0, sizeof(PhysFloatReg) * numPhysicalFloatRegs); +} + +#endif diff --git a/src/cpu/o3/rename.cc b/src/cpu/o3/rename.cc new file mode 100644 index 000000000..9ca8e82c6 --- /dev/null +++ b/src/cpu/o3/rename.cc @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#include "cpu/o3/alpha_dyn_inst.hh" +#include "cpu/o3/alpha_impl.hh" +#include "cpu/o3/rename_impl.hh" + +template class DefaultRename<AlphaSimpleImpl>; diff --git a/src/cpu/o3/rename.hh b/src/cpu/o3/rename.hh new file mode 100644 index 000000000..42fdf6bf5 --- /dev/null +++ b/src/cpu/o3/rename.hh @@ -0,0 +1,472 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#ifndef __CPU_O3_RENAME_HH__ +#define __CPU_O3_RENAME_HH__ + +#include <list> + +#include "base/statistics.hh" +#include "base/timebuf.hh" + +/** + * DefaultRename handles both single threaded and SMT rename. Its + * width is specified by the parameters; each cycle it tries to rename + * that many instructions. It holds onto the rename history of all + * instructions with destination registers, storing the + * arch. register, the new physical register, and the old physical + * register, to allow for undoing of mappings if squashing happens, or + * freeing up registers upon commit. Rename handles blocking if the + * ROB, IQ, or LSQ is going to be full. Rename also handles barriers, + * and does so by stalling on the instruction until the ROB is empty + * and there are no instructions in flight to the ROB. + */ +template<class Impl> +class DefaultRename +{ + public: + // Typedefs from the Impl. + typedef typename Impl::CPUPol CPUPol; + typedef typename Impl::DynInstPtr DynInstPtr; + typedef typename Impl::FullCPU FullCPU; + typedef typename Impl::Params Params; + + // Typedefs from the CPUPol + typedef typename CPUPol::DecodeStruct DecodeStruct; + typedef typename CPUPol::RenameStruct RenameStruct; + typedef typename CPUPol::TimeStruct TimeStruct; + typedef typename CPUPol::FreeList FreeList; + typedef typename CPUPol::RenameMap RenameMap; + // These are used only for initialization. + typedef typename CPUPol::IEW IEW; + typedef typename CPUPol::Commit Commit; + + // Typedefs from the ISA. + typedef TheISA::RegIndex RegIndex; + + // A list is used to queue the instructions. Barrier insts must + // be added to the front of the list, which is the only reason for + // using a list instead of a queue. (Most other stages use a + // queue) + typedef std::list<DynInstPtr> InstQueue; + + public: + /** Overall rename status. Used to determine if the CPU can + * deschedule itself due to a lack of activity. + */ + enum RenameStatus { + Active, + Inactive + }; + + /** Individual thread status. */ + enum ThreadStatus { + Running, + Idle, + StartSquash, + Squashing, + Blocked, + Unblocking, + SerializeStall + }; + + private: + /** Rename status. */ + RenameStatus _status; + + /** Per-thread status. */ + ThreadStatus renameStatus[Impl::MaxThreads]; + + public: + /** DefaultRename constructor. */ + DefaultRename(Params *params); + + /** Returns the name of rename. */ + std::string name() const; + + /** Registers statistics. */ + void regStats(); + + /** Sets CPU pointer. */ + void setCPU(FullCPU *cpu_ptr); + + /** Sets the main backwards communication time buffer pointer. */ + void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr); + + /** Sets pointer to time buffer used to communicate to the next stage. */ + void setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr); + + /** Sets pointer to time buffer coming from decode. */ + void setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr); + + /** Sets pointer to IEW stage. Used only for initialization. */ + void setIEWStage(IEW *iew_stage) + { iew_ptr = iew_stage; } + + /** Sets pointer to commit stage. Used only for initialization. */ + void setCommitStage(Commit *commit_stage) + { commit_ptr = commit_stage; } + + private: + /** Pointer to IEW stage. Used only for initialization. */ + IEW *iew_ptr; + + /** Pointer to commit stage. Used only for initialization. */ + Commit *commit_ptr; + + public: + /** Initializes variables for the stage. */ + void initStage(); + + /** Sets pointer to list of active threads. */ + void setActiveThreads(std::list<unsigned> *at_ptr); + + /** Sets pointer to rename maps (per-thread structures). */ + void setRenameMap(RenameMap rm_ptr[Impl::MaxThreads]); + + /** Sets pointer to the free list. */ + void setFreeList(FreeList *fl_ptr); + + /** Sets pointer to the scoreboard. */ + void setScoreboard(Scoreboard *_scoreboard); + + /** Switches out the rename stage. */ + void switchOut(); + + /** Completes the switch out. */ + void doSwitchOut(); + + /** Takes over from another CPU's thread. */ + void takeOverFrom(); + + /** Squashes all instructions in a thread. */ + void squash(unsigned tid); + + /** Ticks rename, which processes all input signals and attempts to rename + * as many instructions as possible. + */ + void tick(); + + /** Debugging function used to dump history buffer of renamings. */ + void dumpHistory(); + + private: + /** Determines what to do based on rename's current status. + * @param status_change rename() sets this variable if there was a status + * change (ie switching from blocking to unblocking). + * @param tid Thread id to rename instructions from. + */ + void rename(bool &status_change, unsigned tid); + + /** Renames instructions for the given thread. Also handles serializing + * instructions. + */ + void renameInsts(unsigned tid); + + /** Inserts unused instructions from a given thread into the skid buffer, + * to be renamed once rename unblocks. + */ + void skidInsert(unsigned tid); + + /** Separates instructions from decode into individual lists of instructions + * sorted by thread. + */ + void sortInsts(); + + /** Returns if all of the skid buffers are empty. */ + bool skidsEmpty(); + + /** Updates overall rename status based on all of the threads' statuses. */ + void updateStatus(); + + /** Switches rename to blocking, and signals back that rename has become + * blocked. + * @return Returns true if there is a status change. + */ + bool block(unsigned tid); + + /** Switches rename to unblocking if the skid buffer is empty, and signals + * back that rename has unblocked. + * @return Returns true if there is a status change. + */ + bool unblock(unsigned tid); + + /** Executes actual squash, removing squashed instructions. */ + void doSquash(unsigned tid); + + /** Removes a committed instruction's rename history. */ + void removeFromHistory(InstSeqNum inst_seq_num, unsigned tid); + + /** Renames the source registers of an instruction. */ + inline void renameSrcRegs(DynInstPtr &inst, unsigned tid); + + /** Renames the destination registers of an instruction. */ + inline void renameDestRegs(DynInstPtr &inst, unsigned tid); + + /** Calculates the number of free ROB entries for a specific thread. */ + inline int calcFreeROBEntries(unsigned tid); + + /** Calculates the number of free IQ entries for a specific thread. */ + inline int calcFreeIQEntries(unsigned tid); + + /** Calculates the number of free LSQ entries for a specific thread. */ + inline int calcFreeLSQEntries(unsigned tid); + + /** Returns the number of valid instructions coming from decode. */ + unsigned validInsts(); + + /** Reads signals telling rename to block/unblock. */ + void readStallSignals(unsigned tid); + + /** Checks if any stages are telling rename to block. */ + bool checkStall(unsigned tid); + + /** Gets the number of free entries for a specific thread. */ + void readFreeEntries(unsigned tid); + + /** Checks the signals and updates the status. */ + bool checkSignalsAndUpdate(unsigned tid); + + /** Either serializes on the next instruction available in the InstQueue, + * or records that it must serialize on the next instruction to enter + * rename. + * @param inst_list The list of younger, unprocessed instructions for the + * thread that has the serializeAfter instruction. + * @param tid The thread id. + */ + void serializeAfter(InstQueue &inst_list, unsigned tid); + + /** Holds the information for each destination register rename. It holds + * the instruction's sequence number, the arch register, the old physical + * register for that arch. register, and the new physical register. + */ + struct RenameHistory { + RenameHistory(InstSeqNum _instSeqNum, RegIndex _archReg, + PhysRegIndex _newPhysReg, PhysRegIndex _prevPhysReg) + : instSeqNum(_instSeqNum), archReg(_archReg), + newPhysReg(_newPhysReg), prevPhysReg(_prevPhysReg) + { + } + + /** The sequence number of the instruction that renamed. */ + InstSeqNum instSeqNum; + /** The architectural register index that was renamed. */ + RegIndex archReg; + /** The new physical register that the arch. register is renamed to. */ + PhysRegIndex newPhysReg; + /** The old physical register that the arch. register was renamed to. */ + PhysRegIndex prevPhysReg; + }; + + /** A per-thread list of all destination register renames, used to either + * undo rename mappings or free old physical registers. + */ + std::list<RenameHistory> historyBuffer[Impl::MaxThreads]; + + /** Pointer to CPU. */ + FullCPU *cpu; + + /** Pointer to main time buffer used for backwards communication. */ + TimeBuffer<TimeStruct> *timeBuffer; + + /** Wire to get IEW's output from backwards time buffer. */ + typename TimeBuffer<TimeStruct>::wire fromIEW; + + /** Wire to get commit's output from backwards time buffer. */ + typename TimeBuffer<TimeStruct>::wire fromCommit; + + /** Wire to write infromation heading to previous stages. */ + typename TimeBuffer<TimeStruct>::wire toDecode; + + /** Rename instruction queue. */ + TimeBuffer<RenameStruct> *renameQueue; + + /** Wire to write any information heading to IEW. */ + typename TimeBuffer<RenameStruct>::wire toIEW; + + /** Decode instruction queue interface. */ + TimeBuffer<DecodeStruct> *decodeQueue; + + /** Wire to get decode's output from decode queue. */ + typename TimeBuffer<DecodeStruct>::wire fromDecode; + + /** Queue of all instructions coming from decode this cycle. */ + InstQueue insts[Impl::MaxThreads]; + + /** Skid buffer between rename and decode. */ + InstQueue skidBuffer[Impl::MaxThreads]; + + /** Rename map interface. */ + RenameMap *renameMap[Impl::MaxThreads]; + + /** Free list interface. */ + FreeList *freeList; + + /** Pointer to the list of active threads. */ + std::list<unsigned> *activeThreads; + + /** Pointer to the scoreboard. */ + Scoreboard *scoreboard; + + /** Count of instructions in progress that have been sent off to the IQ + * and ROB, but are not yet included in their occupancy counts. + */ + int instsInProgress[Impl::MaxThreads]; + + /** Variable that tracks if decode has written to the time buffer this + * cycle. Used to tell CPU if there is activity this cycle. + */ + bool wroteToTimeBuffer; + + /** Structures whose free entries impact the amount of instructions that + * can be renamed. + */ + struct FreeEntries { + unsigned iqEntries; + unsigned lsqEntries; + unsigned robEntries; + }; + + /** Per-thread tracking of the number of free entries of back-end + * structures. + */ + FreeEntries freeEntries[Impl::MaxThreads]; + + /** Records if the ROB is empty. In SMT mode the ROB may be dynamically + * partitioned between threads, so the ROB must tell rename when it is + * empty. + */ + bool emptyROB[Impl::MaxThreads]; + + /** Source of possible stalls. */ + struct Stalls { + bool iew; + bool commit; + }; + + /** Tracks which stages are telling decode to stall. */ + Stalls stalls[Impl::MaxThreads]; + + /** The serialize instruction that rename has stalled on. */ + DynInstPtr serializeInst[Impl::MaxThreads]; + + /** Records if rename needs to serialize on the next instruction for any + * thread. + */ + bool serializeOnNextInst[Impl::MaxThreads]; + + /** Delay between iew and rename, in ticks. */ + int iewToRenameDelay; + + /** Delay between decode and rename, in ticks. */ + int decodeToRenameDelay; + + /** Delay between commit and rename, in ticks. */ + unsigned commitToRenameDelay; + + /** Rename width, in instructions. */ + unsigned renameWidth; + + /** Commit width, in instructions. Used so rename knows how many + * instructions might have freed registers in the previous cycle. + */ + unsigned commitWidth; + + /** The index of the instruction in the time buffer to IEW that rename is + * currently using. + */ + unsigned toIEWIndex; + + /** Whether or not rename needs to block this cycle. */ + bool blockThisCycle; + + /** The number of threads active in rename. */ + unsigned numThreads; + + /** The maximum skid buffer size. */ + unsigned skidBufferMax; + + /** Enum to record the source of a structure full stall. Can come from + * either ROB, IQ, LSQ, and it is priortized in that order. + */ + enum FullSource { + ROB, + IQ, + LSQ, + NONE + }; + + /** Function used to increment the stat that corresponds to the source of + * the stall. + */ + inline void incrFullStat(const FullSource &source); + + /** Stat for total number of cycles spent squashing. */ + Stats::Scalar<> renameSquashCycles; + /** Stat for total number of cycles spent idle. */ + Stats::Scalar<> renameIdleCycles; + /** Stat for total number of cycles spent blocking. */ + Stats::Scalar<> renameBlockCycles; + /** Stat for total number of cycles spent stalling for a serializing inst. */ + Stats::Scalar<> renameSerializeStallCycles; + /** Stat for total number of cycles spent running normally. */ + Stats::Scalar<> renameRunCycles; + /** Stat for total number of cycles spent unblocking. */ + Stats::Scalar<> renameUnblockCycles; + /** Stat for total number of renamed instructions. */ + Stats::Scalar<> renameRenamedInsts; + /** Stat for total number of squashed instructions that rename discards. */ + Stats::Scalar<> renameSquashedInsts; + /** Stat for total number of times that the ROB starts a stall in rename. */ + Stats::Scalar<> renameROBFullEvents; + /** Stat for total number of times that the IQ starts a stall in rename. */ + Stats::Scalar<> renameIQFullEvents; + /** Stat for total number of times that the LSQ starts a stall in rename. */ + Stats::Scalar<> renameLSQFullEvents; + /** Stat for total number of times that rename runs out of free registers + * to use to rename. */ + Stats::Scalar<> renameFullRegistersEvents; + /** Stat for total number of renamed destination registers. */ + Stats::Scalar<> renameRenamedOperands; + /** Stat for total number of source register rename lookups. */ + Stats::Scalar<> renameRenameLookups; + /** Stat for total number of committed renaming mappings. */ + Stats::Scalar<> renameCommittedMaps; + /** Stat for total number of mappings that were undone due to a squash. */ + Stats::Scalar<> renameUndoneMaps; + /** Number of serialize instructions handled. */ + Stats::Scalar<> renamedSerializing; + /** Number of instructions marked as temporarily serializing. */ + Stats::Scalar<> renamedTempSerializing; + /** Number of instructions inserted into skid buffers. */ + Stats::Scalar<> renameSkidInsts; +}; + +#endif // __CPU_O3_RENAME_HH__ diff --git a/src/cpu/o3/rename_impl.hh b/src/cpu/o3/rename_impl.hh new file mode 100644 index 000000000..df33b98ee --- /dev/null +++ b/src/cpu/o3/rename_impl.hh @@ -0,0 +1,1274 @@ +/* + * 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 <list> + +#include "config/full_system.hh" +#include "cpu/o3/rename.hh" + +using namespace std; + +template <class Impl> +DefaultRename<Impl>::DefaultRename(Params *params) + : iewToRenameDelay(params->iewToRenameDelay), + decodeToRenameDelay(params->decodeToRenameDelay), + commitToRenameDelay(params->commitToRenameDelay), + renameWidth(params->renameWidth), + commitWidth(params->commitWidth), + numThreads(params->numberOfThreads) +{ + _status = Inactive; + + for (int i=0; i< numThreads; i++) { + renameStatus[i] = Idle; + + freeEntries[i].iqEntries = 0; + freeEntries[i].lsqEntries = 0; + freeEntries[i].robEntries = 0; + + stalls[i].iew = false; + stalls[i].commit = false; + serializeInst[i] = NULL; + + instsInProgress[i] = 0; + + emptyROB[i] = true; + + serializeOnNextInst[i] = false; + } + + // @todo: Make into a parameter. + skidBufferMax = (2 * (iewToRenameDelay * params->decodeWidth)) + renameWidth; +} + +template <class Impl> +std::string +DefaultRename<Impl>::name() const +{ + return cpu->name() + ".rename"; +} + +template <class Impl> +void +DefaultRename<Impl>::regStats() +{ + renameSquashCycles + .name(name() + ".RENAME:SquashCycles") + .desc("Number of cycles rename is squashing") + .prereq(renameSquashCycles); + renameIdleCycles + .name(name() + ".RENAME:IdleCycles") + .desc("Number of cycles rename is idle") + .prereq(renameIdleCycles); + renameBlockCycles + .name(name() + ".RENAME:BlockCycles") + .desc("Number of cycles rename is blocking") + .prereq(renameBlockCycles); + renameSerializeStallCycles + .name(name() + ".RENAME:serializeStallCycles") + .desc("count of cycles rename stalled for serializing inst") + .flags(Stats::total); + renameRunCycles + .name(name() + ".RENAME:RunCycles") + .desc("Number of cycles rename is running") + .prereq(renameIdleCycles); + renameUnblockCycles + .name(name() + ".RENAME:UnblockCycles") + .desc("Number of cycles rename is unblocking") + .prereq(renameUnblockCycles); + renameRenamedInsts + .name(name() + ".RENAME:RenamedInsts") + .desc("Number of instructions processed by rename") + .prereq(renameRenamedInsts); + renameSquashedInsts + .name(name() + ".RENAME:SquashedInsts") + .desc("Number of squashed instructions processed by rename") + .prereq(renameSquashedInsts); + renameROBFullEvents + .name(name() + ".RENAME:ROBFullEvents") + .desc("Number of times rename has blocked due to ROB full") + .prereq(renameROBFullEvents); + renameIQFullEvents + .name(name() + ".RENAME:IQFullEvents") + .desc("Number of times rename has blocked due to IQ full") + .prereq(renameIQFullEvents); + renameLSQFullEvents + .name(name() + ".RENAME:LSQFullEvents") + .desc("Number of times rename has blocked due to LSQ full") + .prereq(renameLSQFullEvents); + renameFullRegistersEvents + .name(name() + ".RENAME:FullRegisterEvents") + .desc("Number of times there has been no free registers") + .prereq(renameFullRegistersEvents); + renameRenamedOperands + .name(name() + ".RENAME:RenamedOperands") + .desc("Number of destination operands rename has renamed") + .prereq(renameRenamedOperands); + renameRenameLookups + .name(name() + ".RENAME:RenameLookups") + .desc("Number of register rename lookups that rename has made") + .prereq(renameRenameLookups); + renameCommittedMaps + .name(name() + ".RENAME:CommittedMaps") + .desc("Number of HB maps that are committed") + .prereq(renameCommittedMaps); + renameUndoneMaps + .name(name() + ".RENAME:UndoneMaps") + .desc("Number of HB maps that are undone due to squashing") + .prereq(renameUndoneMaps); + renamedSerializing + .name(name() + ".RENAME:serializingInsts") + .desc("count of serializing insts renamed") + .flags(Stats::total) + ; + renamedTempSerializing + .name(name() + ".RENAME:tempSerializingInsts") + .desc("count of temporary serializing insts renamed") + .flags(Stats::total) + ; + renameSkidInsts + .name(name() + ".RENAME:skidInsts") + .desc("count of insts added to the skid buffer") + .flags(Stats::total) + ; +} + +template <class Impl> +void +DefaultRename<Impl>::setCPU(FullCPU *cpu_ptr) +{ + DPRINTF(Rename, "Setting CPU pointer.\n"); + cpu = cpu_ptr; +} + +template <class Impl> +void +DefaultRename<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) +{ + DPRINTF(Rename, "Setting time buffer pointer.\n"); + timeBuffer = tb_ptr; + + // Setup wire to read information from time buffer, from IEW stage. + fromIEW = timeBuffer->getWire(-iewToRenameDelay); + + // Setup wire to read infromation from time buffer, from commit stage. + fromCommit = timeBuffer->getWire(-commitToRenameDelay); + + // Setup wire to write information to previous stages. + toDecode = timeBuffer->getWire(0); +} + +template <class Impl> +void +DefaultRename<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr) +{ + DPRINTF(Rename, "Setting rename queue pointer.\n"); + renameQueue = rq_ptr; + + // Setup wire to write information to future stages. + toIEW = renameQueue->getWire(0); +} + +template <class Impl> +void +DefaultRename<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr) +{ + DPRINTF(Rename, "Setting decode queue pointer.\n"); + decodeQueue = dq_ptr; + + // Setup wire to get information from decode. + fromDecode = decodeQueue->getWire(-decodeToRenameDelay); +} + +template <class Impl> +void +DefaultRename<Impl>::initStage() +{ + // Grab the number of free entries directly from the stages. + for (int tid=0; tid < numThreads; tid++) { + freeEntries[tid].iqEntries = iew_ptr->instQueue.numFreeEntries(tid); + freeEntries[tid].lsqEntries = iew_ptr->ldstQueue.numFreeEntries(tid); + freeEntries[tid].robEntries = commit_ptr->numROBFreeEntries(tid); + emptyROB[tid] = true; + } +} + +template<class Impl> +void +DefaultRename<Impl>::setActiveThreads(list<unsigned> *at_ptr) +{ + DPRINTF(Rename, "Setting active threads list pointer.\n"); + activeThreads = at_ptr; +} + + +template <class Impl> +void +DefaultRename<Impl>::setRenameMap(RenameMap rm_ptr[]) +{ + DPRINTF(Rename, "Setting rename map pointers.\n"); + + for (int i=0; i<numThreads; i++) { + renameMap[i] = &rm_ptr[i]; + } +} + +template <class Impl> +void +DefaultRename<Impl>::setFreeList(FreeList *fl_ptr) +{ + DPRINTF(Rename, "Setting free list pointer.\n"); + freeList = fl_ptr; +} + +template<class Impl> +void +DefaultRename<Impl>::setScoreboard(Scoreboard *_scoreboard) +{ + DPRINTF(Rename, "Setting scoreboard pointer.\n"); + scoreboard = _scoreboard; +} + +template <class Impl> +void +DefaultRename<Impl>::switchOut() +{ + // Rename is ready to switch out at any time. + cpu->signalSwitched(); +} + +template <class Impl> +void +DefaultRename<Impl>::doSwitchOut() +{ + // Clear any state, fix up the rename map. + for (int i = 0; i < numThreads; i++) { + typename list<RenameHistory>::iterator hb_it = historyBuffer[i].begin(); + + while (!historyBuffer[i].empty()) { + assert(hb_it != historyBuffer[i].end()); + + DPRINTF(Rename, "[tid:%u]: Removing history entry with sequence " + "number %i.\n", i, (*hb_it).instSeqNum); + + // Tell the rename map to set the architected register to the + // previous physical register that it was renamed to. + renameMap[i]->setEntry(hb_it->archReg, hb_it->prevPhysReg); + + // Put the renamed physical register back on the free list. + freeList->addReg(hb_it->newPhysReg); + + historyBuffer[i].erase(hb_it++); + } + insts[i].clear(); + skidBuffer[i].clear(); + } +} + +template <class Impl> +void +DefaultRename<Impl>::takeOverFrom() +{ + _status = Inactive; + initStage(); + + // Reset all state prior to taking over from the other CPU. + for (int i=0; i< numThreads; i++) { + renameStatus[i] = Idle; + + stalls[i].iew = false; + stalls[i].commit = false; + serializeInst[i] = NULL; + + instsInProgress[i] = 0; + + emptyROB[i] = true; + + serializeOnNextInst[i] = false; + } +} + +template <class Impl> +void +DefaultRename<Impl>::squash(unsigned tid) +{ + DPRINTF(Rename, "[tid:%u]: Squashing instructions.\n",tid); + + // Clear the stall signal if rename was blocked or unblocking before. + // If it still needs to block, the blocking should happen the next + // cycle and there should be space to hold everything due to the squash. + if (renameStatus[tid] == Blocked || + renameStatus[tid] == Unblocking || + renameStatus[tid] == SerializeStall) { + + toDecode->renameUnblock[tid] = 1; + + serializeInst[tid] = NULL; + } + + // Set the status to Squashing. + renameStatus[tid] = Squashing; + + // Squash any instructions from decode. + unsigned squashCount = 0; + + for (int i=0; i<fromDecode->size; i++) { + if (fromDecode->insts[i]->threadNumber == tid) { + fromDecode->insts[i]->squashed = true; + wroteToTimeBuffer = true; + squashCount++; + } + } + + insts[tid].clear(); + + // Clear the skid buffer in case it has any data in it. + skidBuffer[tid].clear(); + + doSquash(tid); +} + +template <class Impl> +void +DefaultRename<Impl>::tick() +{ + wroteToTimeBuffer = false; + + blockThisCycle = false; + + bool status_change = false; + + toIEWIndex = 0; + + sortInsts(); + + list<unsigned>::iterator threads = (*activeThreads).begin(); + + // Check stall and squash signals. + while (threads != (*activeThreads).end()) { + unsigned tid = *threads++; + + DPRINTF(Rename, "Processing [tid:%i]\n", tid); + + status_change = checkSignalsAndUpdate(tid) || status_change; + + rename(status_change, tid); + } + + if (status_change) { + updateStatus(); + } + + if (wroteToTimeBuffer) { + DPRINTF(Activity, "Activity this cycle.\n"); + cpu->activityThisCycle(); + } + + threads = (*activeThreads).begin(); + + while (threads != (*activeThreads).end()) { + unsigned tid = *threads++; + + // If we committed this cycle then doneSeqNum will be > 0 + if (fromCommit->commitInfo[tid].doneSeqNum != 0 && + !fromCommit->commitInfo[tid].squash && + renameStatus[tid] != Squashing) { + + removeFromHistory(fromCommit->commitInfo[tid].doneSeqNum, + tid); + } + } + + // @todo: make into updateProgress function + for (int tid=0; tid < numThreads; tid++) { + instsInProgress[tid] -= fromIEW->iewInfo[tid].dispatched; + + assert(instsInProgress[tid] >=0); + } + +} + +template<class Impl> +void +DefaultRename<Impl>::rename(bool &status_change, unsigned tid) +{ + // If status is Running or idle, + // call renameInsts() + // If status is Unblocking, + // buffer any instructions coming from decode + // continue trying to empty skid buffer + // check if stall conditions have passed + + if (renameStatus[tid] == Blocked) { + ++renameBlockCycles; + } else if (renameStatus[tid] == Squashing) { + ++renameSquashCycles; + } else if (renameStatus[tid] == SerializeStall) { + ++renameSerializeStallCycles; + } + + if (renameStatus[tid] == Running || + renameStatus[tid] == Idle) { + DPRINTF(Rename, "[tid:%u]: Not blocked, so attempting to run " + "stage.\n", tid); + + renameInsts(tid); + } else if (renameStatus[tid] == Unblocking) { + renameInsts(tid); + + if (validInsts()) { + // Add the current inputs to the skid buffer so they can be + // reprocessed when this stage unblocks. + skidInsert(tid); + } + + // If we switched over to blocking, then there's a potential for + // an overall status change. + status_change = unblock(tid) || status_change || blockThisCycle; + } +} + +template <class Impl> +void +DefaultRename<Impl>::renameInsts(unsigned tid) +{ + // Instructions can be either in the skid buffer or the queue of + // instructions coming from decode, depending on the status. + int insts_available = renameStatus[tid] == Unblocking ? + skidBuffer[tid].size() : insts[tid].size(); + + // Check the decode queue to see if instructions are available. + // If there are no available instructions to rename, then do nothing. + if (insts_available == 0) { + DPRINTF(Rename, "[tid:%u]: Nothing to do, breaking out early.\n", + tid); + // Should I change status to idle? + ++renameIdleCycles; + return; + } else if (renameStatus[tid] == Unblocking) { + ++renameUnblockCycles; + } else if (renameStatus[tid] == Running) { + ++renameRunCycles; + } + + DynInstPtr inst; + + // Will have to do a different calculation for the number of free + // entries. + int free_rob_entries = calcFreeROBEntries(tid); + int free_iq_entries = calcFreeIQEntries(tid); + int free_lsq_entries = calcFreeLSQEntries(tid); + int min_free_entries = free_rob_entries; + + FullSource source = ROB; + + if (free_iq_entries < min_free_entries) { + min_free_entries = free_iq_entries; + source = IQ; + } + + if (free_lsq_entries < min_free_entries) { + min_free_entries = free_lsq_entries; + source = LSQ; + } + + // Check if there's any space left. + if (min_free_entries <= 0) { + DPRINTF(Rename, "[tid:%u]: Blocking due to no free ROB/IQ/LSQ " + "entries.\n" + "ROB has %i free entries.\n" + "IQ has %i free entries.\n" + "LSQ has %i free entries.\n", + tid, + free_rob_entries, + free_iq_entries, + free_lsq_entries); + + blockThisCycle = true; + + block(tid); + + incrFullStat(source); + + return; + } else if (min_free_entries < insts_available) { + DPRINTF(Rename, "[tid:%u]: Will have to block this cycle." + "%i insts available, but only %i insts can be " + "renamed due to ROB/IQ/LSQ limits.\n", + tid, insts_available, min_free_entries); + + insts_available = min_free_entries; + + blockThisCycle = true; + + incrFullStat(source); + } + + InstQueue &insts_to_rename = renameStatus[tid] == Unblocking ? + skidBuffer[tid] : insts[tid]; + + DPRINTF(Rename, "[tid:%u]: %i available instructions to " + "send iew.\n", tid, insts_available); + + DPRINTF(Rename, "[tid:%u]: %i insts pipelining from Rename | %i insts " + "dispatched to IQ last cycle.\n", + tid, instsInProgress[tid], fromIEW->iewInfo[tid].dispatched); + + // Handle serializing the next instruction if necessary. + if (serializeOnNextInst[tid]) { + if (emptyROB[tid] && instsInProgress[tid] == 0) { + // ROB already empty; no need to serialize. + serializeOnNextInst[tid] = false; + } else if (!insts_to_rename.empty()) { + insts_to_rename.front()->setSerializeBefore(); + } + } + + int renamed_insts = 0; + + while (insts_available > 0 && toIEWIndex < renameWidth) { + DPRINTF(Rename, "[tid:%u]: Sending instructions to IEW.\n", tid); + + assert(!insts_to_rename.empty()); + + inst = insts_to_rename.front(); + + insts_to_rename.pop_front(); + + if (renameStatus[tid] == Unblocking) { + DPRINTF(Rename,"[tid:%u]: Removing [sn:%lli] PC:%#x from rename " + "skidBuffer\n", + tid, inst->seqNum, inst->readPC()); + } + + if (inst->isSquashed()) { + DPRINTF(Rename, "[tid:%u]: instruction %i with PC %#x is " + "squashed, skipping.\n", + tid, inst->seqNum, inst->threadNumber,inst->readPC()); + + ++renameSquashedInsts; + + // Decrement how many instructions are available. + --insts_available; + + continue; + } + + DPRINTF(Rename, "[tid:%u]: Processing instruction [sn:%lli] with " + "PC %#x.\n", + tid, inst->seqNum, inst->readPC()); + + // Handle serializeAfter/serializeBefore instructions. + // serializeAfter marks the next instruction as serializeBefore. + // serializeBefore makes the instruction wait in rename until the ROB + // is empty. + + // In this model, IPR accesses are serialize before + // instructions, and store conditionals are serialize after + // instructions. This is mainly due to lack of support for + // out-of-order operations of either of those classes of + // instructions. + if ((inst->isIprAccess() || inst->isSerializeBefore()) && + !inst->isSerializeHandled()) { + DPRINTF(Rename, "Serialize before instruction encountered.\n"); + + if (!inst->isTempSerializeBefore()) { + renamedSerializing++; + inst->setSerializeHandled(); + } else { + renamedTempSerializing++; + } + + // Change status over to SerializeStall so that other stages know + // what this is blocked on. + renameStatus[tid] = SerializeStall; + + serializeInst[tid] = inst; + + blockThisCycle = true; + + break; + } else if ((inst->isStoreConditional() || inst->isSerializeAfter()) && + !inst->isSerializeHandled()) { + DPRINTF(Rename, "Serialize after instruction encountered.\n"); + + renamedSerializing++; + + inst->setSerializeHandled(); + + serializeAfter(insts_to_rename, tid); + } + + // Check here to make sure there are enough destination registers + // to rename to. Otherwise block. + if (renameMap[tid]->numFreeEntries() < inst->numDestRegs()) { + DPRINTF(Rename, "Blocking due to lack of free " + "physical registers to rename to.\n"); + blockThisCycle = true; + + ++renameFullRegistersEvents; + + break; + } + + renameSrcRegs(inst, inst->threadNumber); + + renameDestRegs(inst, inst->threadNumber); + + ++renamed_insts; + + // Put instruction in rename queue. + toIEW->insts[toIEWIndex] = inst; + ++(toIEW->size); + + // Increment which instruction we're on. + ++toIEWIndex; + + // Decrement how many instructions are available. + --insts_available; + } + + instsInProgress[tid] += renamed_insts; + renameRenamedInsts += renamed_insts; + + // If we wrote to the time buffer, record this. + if (toIEWIndex) { + wroteToTimeBuffer = true; + } + + // Check if there's any instructions left that haven't yet been renamed. + // If so then block. + if (insts_available) { + blockThisCycle = true; + } + + if (blockThisCycle) { + block(tid); + toDecode->renameUnblock[tid] = false; + } +} + +template<class Impl> +void +DefaultRename<Impl>::skidInsert(unsigned tid) +{ + DynInstPtr inst = NULL; + + while (!insts[tid].empty()) { + inst = insts[tid].front(); + + insts[tid].pop_front(); + + assert(tid == inst->threadNumber); + + DPRINTF(Rename, "[tid:%u]: Inserting [sn:%lli] PC:%#x into Rename " + "skidBuffer\n", tid, inst->seqNum, inst->readPC()); + + ++renameSkidInsts; + + skidBuffer[tid].push_back(inst); + } + + if (skidBuffer[tid].size() > skidBufferMax) + panic("Skidbuffer Exceeded Max Size"); +} + +template <class Impl> +void +DefaultRename<Impl>::sortInsts() +{ + int insts_from_decode = fromDecode->size; +#ifdef DEBUG + for (int i=0; i < numThreads; i++) + assert(insts[i].empty()); +#endif + for (int i = 0; i < insts_from_decode; ++i) { + DynInstPtr inst = fromDecode->insts[i]; + insts[inst->threadNumber].push_back(inst); + } +} + +template<class Impl> +bool +DefaultRename<Impl>::skidsEmpty() +{ + list<unsigned>::iterator threads = (*activeThreads).begin(); + + while (threads != (*activeThreads).end()) { + if (!skidBuffer[*threads++].empty()) + return false; + } + + return true; +} + +template<class Impl> +void +DefaultRename<Impl>::updateStatus() +{ + bool any_unblocking = false; + + list<unsigned>::iterator threads = (*activeThreads).begin(); + + threads = (*activeThreads).begin(); + + while (threads != (*activeThreads).end()) { + unsigned tid = *threads++; + + if (renameStatus[tid] == Unblocking) { + any_unblocking = true; + break; + } + } + + // Rename will have activity if it's unblocking. + if (any_unblocking) { + if (_status == Inactive) { + _status = Active; + + DPRINTF(Activity, "Activating stage.\n"); + + cpu->activateStage(FullCPU::RenameIdx); + } + } else { + // If it's not unblocking, then rename will not have any internal + // activity. Switch it to inactive. + if (_status == Active) { + _status = Inactive; + DPRINTF(Activity, "Deactivating stage.\n"); + + cpu->deactivateStage(FullCPU::RenameIdx); + } + } +} + +template <class Impl> +bool +DefaultRename<Impl>::block(unsigned tid) +{ + DPRINTF(Rename, "[tid:%u]: Blocking.\n", tid); + + // Add the current inputs onto the skid buffer, so they can be + // reprocessed when this stage unblocks. + skidInsert(tid); + + // Only signal backwards to block if the previous stages do not think + // rename is already blocked. + if (renameStatus[tid] != Blocked) { + if (renameStatus[tid] != Unblocking) { + toDecode->renameBlock[tid] = true; + toDecode->renameUnblock[tid] = false; + wroteToTimeBuffer = true; + } + + // Rename can not go from SerializeStall to Blocked, otherwise + // it would not know to complete the serialize stall. + if (renameStatus[tid] != SerializeStall) { + // Set status to Blocked. + renameStatus[tid] = Blocked; + return true; + } + } + + return false; +} + +template <class Impl> +bool +DefaultRename<Impl>::unblock(unsigned tid) +{ + DPRINTF(Rename, "[tid:%u]: Trying to unblock.\n", tid); + + // Rename is done unblocking if the skid buffer is empty. + if (skidBuffer[tid].empty() && renameStatus[tid] != SerializeStall) { + + DPRINTF(Rename, "[tid:%u]: Done unblocking.\n", tid); + + toDecode->renameUnblock[tid] = true; + wroteToTimeBuffer = true; + + renameStatus[tid] = Running; + return true; + } + + return false; +} + +template <class Impl> +void +DefaultRename<Impl>::doSquash(unsigned tid) +{ + typename list<RenameHistory>::iterator hb_it = historyBuffer[tid].begin(); + + InstSeqNum squashed_seq_num = fromCommit->commitInfo[tid].doneSeqNum; + + // After a syscall squashes everything, the history buffer may be empty + // but the ROB may still be squashing instructions. + if (historyBuffer[tid].empty()) { + return; + } + + // Go through the most recent instructions, undoing the mappings + // they did and freeing up the registers. + while (!historyBuffer[tid].empty() && + (*hb_it).instSeqNum > squashed_seq_num) { + assert(hb_it != historyBuffer[tid].end()); + + DPRINTF(Rename, "[tid:%u]: Removing history entry with sequence " + "number %i.\n", tid, (*hb_it).instSeqNum); + + // Tell the rename map to set the architected register to the + // previous physical register that it was renamed to. + renameMap[tid]->setEntry(hb_it->archReg, hb_it->prevPhysReg); + + // Put the renamed physical register back on the free list. + freeList->addReg(hb_it->newPhysReg); + + historyBuffer[tid].erase(hb_it++); + + ++renameUndoneMaps; + } +} + +template<class Impl> +void +DefaultRename<Impl>::removeFromHistory(InstSeqNum inst_seq_num, unsigned tid) +{ + DPRINTF(Rename, "[tid:%u]: Removing a committed instruction from the " + "history buffer %u (size=%i), until [sn:%lli].\n", + tid, tid, historyBuffer[tid].size(), inst_seq_num); + + typename list<RenameHistory>::iterator hb_it = historyBuffer[tid].end(); + + --hb_it; + + if (historyBuffer[tid].empty()) { + DPRINTF(Rename, "[tid:%u]: History buffer is empty.\n", tid); + return; + } else if (hb_it->instSeqNum > inst_seq_num) { + DPRINTF(Rename, "[tid:%u]: Old sequence number encountered. Ensure " + "that a syscall happened recently.\n", tid); + return; + } + + // Commit all the renames up until (and including) the committed sequence + // number. Some or even all of the committed instructions may not have + // rename histories if they did not have destination registers that were + // renamed. + while (!historyBuffer[tid].empty() && + hb_it != historyBuffer[tid].end() && + (*hb_it).instSeqNum <= inst_seq_num) { + + DPRINTF(Rename, "[tid:%u]: Freeing up older rename of reg %i, " + "[sn:%lli].\n", + tid, (*hb_it).prevPhysReg, (*hb_it).instSeqNum); + + freeList->addReg((*hb_it).prevPhysReg); + ++renameCommittedMaps; + + historyBuffer[tid].erase(hb_it--); + } +} + +template <class Impl> +inline void +DefaultRename<Impl>::renameSrcRegs(DynInstPtr &inst,unsigned tid) +{ + assert(renameMap[tid] != 0); + + unsigned num_src_regs = inst->numSrcRegs(); + + // Get the architectual register numbers from the source and + // destination operands, and redirect them to the right register. + // Will need to mark dependencies though. + for (int src_idx = 0; src_idx < num_src_regs; src_idx++) { + RegIndex src_reg = inst->srcRegIdx(src_idx); + + // Look up the source registers to get the phys. register they've + // been renamed to, and set the sources to those registers. + PhysRegIndex renamed_reg = renameMap[tid]->lookup(src_reg); + + DPRINTF(Rename, "[tid:%u]: Looking up arch reg %i, got " + "physical reg %i.\n", tid, (int)src_reg, + (int)renamed_reg); + + inst->renameSrcReg(src_idx, renamed_reg); + + // See if the register is ready or not. + if (scoreboard->getReg(renamed_reg) == true) { + DPRINTF(Rename, "[tid:%u]: Register is ready.\n", tid); + + inst->markSrcRegReady(src_idx); + } + + ++renameRenameLookups; + } +} + +template <class Impl> +inline void +DefaultRename<Impl>::renameDestRegs(DynInstPtr &inst,unsigned tid) +{ + typename RenameMap::RenameInfo rename_result; + + unsigned num_dest_regs = inst->numDestRegs(); + + // Rename the destination registers. + for (int dest_idx = 0; dest_idx < num_dest_regs; dest_idx++) { + RegIndex dest_reg = inst->destRegIdx(dest_idx); + + // Get the physical register that the destination will be + // renamed to. + rename_result = renameMap[tid]->rename(dest_reg); + + //Mark Scoreboard entry as not ready + scoreboard->unsetReg(rename_result.first); + + DPRINTF(Rename, "[tid:%u]: Renaming arch reg %i to physical " + "reg %i.\n", tid, (int)dest_reg, + (int)rename_result.first); + + // Record the rename information so that a history can be kept. + RenameHistory hb_entry(inst->seqNum, dest_reg, + rename_result.first, + rename_result.second); + + historyBuffer[tid].push_front(hb_entry); + + DPRINTF(Rename, "[tid:%u]: Adding instruction to history buffer, " + "[sn:%lli].\n",tid, + (*historyBuffer[tid].begin()).instSeqNum); + + // Tell the instruction to rename the appropriate destination + // register (dest_idx) to the new physical register + // (rename_result.first), and record the previous physical + // register that the same logical register was renamed to + // (rename_result.second). + inst->renameDestReg(dest_idx, + rename_result.first, + rename_result.second); + + ++renameRenamedOperands; + } +} + +template <class Impl> +inline int +DefaultRename<Impl>::calcFreeROBEntries(unsigned tid) +{ + int num_free = freeEntries[tid].robEntries - + (instsInProgress[tid] - fromIEW->iewInfo[tid].dispatched); + + //DPRINTF(Rename,"[tid:%i]: %i rob free\n",tid,num_free); + + return num_free; +} + +template <class Impl> +inline int +DefaultRename<Impl>::calcFreeIQEntries(unsigned tid) +{ + int num_free = freeEntries[tid].iqEntries - + (instsInProgress[tid] - fromIEW->iewInfo[tid].dispatched); + + //DPRINTF(Rename,"[tid:%i]: %i iq free\n",tid,num_free); + + return num_free; +} + +template <class Impl> +inline int +DefaultRename<Impl>::calcFreeLSQEntries(unsigned tid) +{ + int num_free = freeEntries[tid].lsqEntries - + (instsInProgress[tid] - fromIEW->iewInfo[tid].dispatchedToLSQ); + + //DPRINTF(Rename,"[tid:%i]: %i lsq free\n",tid,num_free); + + return num_free; +} + +template <class Impl> +unsigned +DefaultRename<Impl>::validInsts() +{ + unsigned inst_count = 0; + + for (int i=0; i<fromDecode->size; i++) { + if (!fromDecode->insts[i]->squashed) + inst_count++; + } + + return inst_count; +} + +template <class Impl> +void +DefaultRename<Impl>::readStallSignals(unsigned tid) +{ + if (fromIEW->iewBlock[tid]) { + stalls[tid].iew = true; + } + + if (fromIEW->iewUnblock[tid]) { + assert(stalls[tid].iew); + stalls[tid].iew = false; + } + + if (fromCommit->commitBlock[tid]) { + stalls[tid].commit = true; + } + + if (fromCommit->commitUnblock[tid]) { + assert(stalls[tid].commit); + stalls[tid].commit = false; + } +} + +template <class Impl> +bool +DefaultRename<Impl>::checkStall(unsigned tid) +{ + bool ret_val = false; + + if (stalls[tid].iew) { + DPRINTF(Rename,"[tid:%i]: Stall from IEW stage detected.\n", tid); + ret_val = true; + } else if (stalls[tid].commit) { + DPRINTF(Rename,"[tid:%i]: Stall from Commit stage detected.\n", tid); + ret_val = true; + } else if (calcFreeROBEntries(tid) <= 0) { + DPRINTF(Rename,"[tid:%i]: Stall: ROB has 0 free entries.\n", tid); + ret_val = true; + } else if (calcFreeIQEntries(tid) <= 0) { + DPRINTF(Rename,"[tid:%i]: Stall: IQ has 0 free entries.\n", tid); + ret_val = true; + } else if (calcFreeLSQEntries(tid) <= 0) { + DPRINTF(Rename,"[tid:%i]: Stall: LSQ has 0 free entries.\n", tid); + ret_val = true; + } else if (renameMap[tid]->numFreeEntries() <= 0) { + DPRINTF(Rename,"[tid:%i]: Stall: RenameMap has 0 free entries.\n", tid); + ret_val = true; + } else if (renameStatus[tid] == SerializeStall && + (!emptyROB[tid] || instsInProgress[tid])) { + DPRINTF(Rename,"[tid:%i]: Stall: Serialize stall and ROB is not " + "empty.\n", + tid); + ret_val = true; + } + + return ret_val; +} + +template <class Impl> +void +DefaultRename<Impl>::readFreeEntries(unsigned tid) +{ + bool updated = false; + if (fromIEW->iewInfo[tid].usedIQ) { + freeEntries[tid].iqEntries = + fromIEW->iewInfo[tid].freeIQEntries; + updated = true; + } + + if (fromIEW->iewInfo[tid].usedLSQ) { + freeEntries[tid].lsqEntries = + fromIEW->iewInfo[tid].freeLSQEntries; + updated = true; + } + + if (fromCommit->commitInfo[tid].usedROB) { + freeEntries[tid].robEntries = + fromCommit->commitInfo[tid].freeROBEntries; + emptyROB[tid] = fromCommit->commitInfo[tid].emptyROB; + updated = true; + } + + DPRINTF(Rename, "[tid:%i]: Free IQ: %i, Free ROB: %i, Free LSQ: %i\n", + tid, + freeEntries[tid].iqEntries, + freeEntries[tid].robEntries, + freeEntries[tid].lsqEntries); + + DPRINTF(Rename, "[tid:%i]: %i instructions not yet in ROB\n", + tid, instsInProgress[tid]); +} + +template <class Impl> +bool +DefaultRename<Impl>::checkSignalsAndUpdate(unsigned tid) +{ + // Check if there's a squash signal, squash if there is + // Check stall signals, block if necessary. + // If status was blocked + // check if stall conditions have passed + // if so then go to unblocking + // If status was Squashing + // check if squashing is not high. Switch to running this cycle. + // If status was serialize stall + // check if ROB is empty and no insts are in flight to the ROB + + readFreeEntries(tid); + readStallSignals(tid); + + if (fromCommit->commitInfo[tid].squash) { + DPRINTF(Rename, "[tid:%u]: Squashing instructions due to squash from " + "commit.\n", tid); + + squash(tid); + + return true; + } + + if (fromCommit->commitInfo[tid].robSquashing) { + DPRINTF(Rename, "[tid:%u]: ROB is still squashing.\n", tid); + + renameStatus[tid] = Squashing; + + return true; + } + + if (checkStall(tid)) { + return block(tid); + } + + if (renameStatus[tid] == Blocked) { + DPRINTF(Rename, "[tid:%u]: Done blocking, switching to unblocking.\n", + tid); + + renameStatus[tid] = Unblocking; + + unblock(tid); + + return true; + } + + if (renameStatus[tid] == Squashing) { + // Switch status to running if rename isn't being told to block or + // squash this cycle. + DPRINTF(Rename, "[tid:%u]: Done squashing, switching to running.\n", + tid); + + renameStatus[tid] = Running; + + return false; + } + + if (renameStatus[tid] == SerializeStall) { + // Stall ends once the ROB is free. + DPRINTF(Rename, "[tid:%u]: Done with serialize stall, switching to " + "unblocking.\n", tid); + + DynInstPtr serial_inst = serializeInst[tid]; + + renameStatus[tid] = Unblocking; + + unblock(tid); + + DPRINTF(Rename, "[tid:%u]: Processing instruction [%lli] with " + "PC %#x.\n", + tid, serial_inst->seqNum, serial_inst->readPC()); + + // Put instruction into queue here. + serial_inst->clearSerializeBefore(); + + if (!skidBuffer[tid].empty()) { + skidBuffer[tid].push_front(serial_inst); + } else { + insts[tid].push_front(serial_inst); + } + + DPRINTF(Rename, "[tid:%u]: Instruction must be processed by rename." + " Adding to front of list.", tid); + + serializeInst[tid] = NULL; + + return true; + } + + // If we've reached this point, we have not gotten any signals that + // cause rename to change its status. Rename remains the same as before. + return false; +} + +template<class Impl> +void +DefaultRename<Impl>::serializeAfter(InstQueue &inst_list, + unsigned tid) +{ + if (inst_list.empty()) { + // Mark a bit to say that I must serialize on the next instruction. + serializeOnNextInst[tid] = true; + return; + } + + // Set the next instruction as serializing. + inst_list.front()->setSerializeBefore(); +} + +template <class Impl> +inline void +DefaultRename<Impl>::incrFullStat(const FullSource &source) +{ + switch (source) { + case ROB: + ++renameROBFullEvents; + break; + case IQ: + ++renameIQFullEvents; + break; + case LSQ: + ++renameLSQFullEvents; + break; + default: + panic("Rename full stall stat should be incremented for a reason!"); + break; + } +} + +template <class Impl> +void +DefaultRename<Impl>::dumpHistory() +{ + typename list<RenameHistory>::iterator buf_it; + + for (int i = 0; i < numThreads; i++) { + + buf_it = historyBuffer[i].begin(); + + while (buf_it != historyBuffer[i].end()) { + cprintf("Seq num: %i\nArch reg: %i New phys reg: %i Old phys " + "reg: %i\n", (*buf_it).instSeqNum, (int)(*buf_it).archReg, + (int)(*buf_it).newPhysReg, (int)(*buf_it).prevPhysReg); + + buf_it++; + } + } +} diff --git a/src/cpu/o3/rename_map.cc b/src/cpu/o3/rename_map.cc new file mode 100644 index 000000000..befbc3e8a --- /dev/null +++ b/src/cpu/o3/rename_map.cc @@ -0,0 +1,247 @@ +/* + * 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 <vector> + +#include "cpu/o3/rename_map.hh" + +using namespace std; + +// @todo: Consider making inline bool functions that determine if the +// register is a logical int, logical fp, physical int, physical fp, +// etc. + +SimpleRenameMap::~SimpleRenameMap() +{ +} + +void +SimpleRenameMap::init(unsigned _numLogicalIntRegs, + unsigned _numPhysicalIntRegs, + PhysRegIndex &ireg_idx, + + unsigned _numLogicalFloatRegs, + unsigned _numPhysicalFloatRegs, + PhysRegIndex &freg_idx, + + unsigned _numMiscRegs, + + RegIndex _intZeroReg, + RegIndex _floatZeroReg, + + int map_id, + bool bindRegs) +{ + id = map_id; + + numLogicalIntRegs = _numLogicalIntRegs; + + numLogicalFloatRegs = _numLogicalFloatRegs; + + numPhysicalIntRegs = _numPhysicalIntRegs; + + numPhysicalFloatRegs = _numPhysicalFloatRegs; + + numMiscRegs = _numMiscRegs; + + intZeroReg = _intZeroReg; + floatZeroReg = _floatZeroReg; + + DPRINTF(Rename, "Creating rename map %i. Phys: %i / %i, Float: " + "%i / %i.\n", id, numLogicalIntRegs, numPhysicalIntRegs, + numLogicalFloatRegs, numPhysicalFloatRegs); + + numLogicalRegs = numLogicalIntRegs + numLogicalFloatRegs; + + numPhysicalRegs = numPhysicalIntRegs + numPhysicalFloatRegs; + + //Create the rename maps + intRenameMap.resize(numLogicalIntRegs); + floatRenameMap.resize(numLogicalRegs); + + if (bindRegs) { + DPRINTF(Rename, "Binding registers into rename map %i",id); + + // Initialize the entries in the integer rename map to point to the + // physical registers of the same index + for (RegIndex index = 0; index < numLogicalIntRegs; ++index) + { + intRenameMap[index].physical_reg = ireg_idx++; + } + + // Initialize the entries in the floating point rename map to point to + // the physical registers of the same index + // Although the index refers purely to architected registers, because + // the floating reg indices come after the integer reg indices, they + // may exceed the size of a normal RegIndex (short). + for (PhysRegIndex index = numLogicalIntRegs; + index < numLogicalRegs; ++index) + { + floatRenameMap[index].physical_reg = freg_idx++; + } + } else { + DPRINTF(Rename, "Binding registers into rename map %i",id); + + PhysRegIndex temp_ireg = ireg_idx; + + for (RegIndex index = 0; index < numLogicalIntRegs; ++index) + { + intRenameMap[index].physical_reg = temp_ireg++; + } + + PhysRegIndex temp_freg = freg_idx; + + for (PhysRegIndex index = numLogicalIntRegs; + index < numLogicalRegs; ++index) + { + floatRenameMap[index].physical_reg = temp_freg++; + } + } +} + +void +SimpleRenameMap::setFreeList(SimpleFreeList *fl_ptr) +{ + freeList = fl_ptr; +} + + +SimpleRenameMap::RenameInfo +SimpleRenameMap::rename(RegIndex arch_reg) +{ + PhysRegIndex renamed_reg; + PhysRegIndex prev_reg; + + if (arch_reg < numLogicalIntRegs) { + + // Record the current physical register that is renamed to the + // requested architected register. + prev_reg = intRenameMap[arch_reg].physical_reg; + + // If it's not referencing the zero register, then rename the + // register. + if (arch_reg != intZeroReg) { + renamed_reg = freeList->getIntReg(); + + intRenameMap[arch_reg].physical_reg = renamed_reg; + + assert(renamed_reg >= 0 && renamed_reg < numPhysicalIntRegs); + + } else { + // Otherwise return the zero register so nothing bad happens. + renamed_reg = intZeroReg; + } + } else if (arch_reg < numLogicalRegs) { + // Record the current physical register that is renamed to the + // requested architected register. + prev_reg = floatRenameMap[arch_reg].physical_reg; + + // If it's not referencing the zero register, then rename the + // register. + if (arch_reg != floatZeroReg) { + renamed_reg = freeList->getFloatReg(); + + floatRenameMap[arch_reg].physical_reg = renamed_reg; + + assert(renamed_reg < numPhysicalRegs && + renamed_reg >= numPhysicalIntRegs); + } else { + // Otherwise return the zero register so nothing bad happens. + renamed_reg = floatZeroReg; + } + } else { + // Subtract off the base offset for miscellaneous registers. + arch_reg = arch_reg - numLogicalRegs; + + // No renaming happens to the misc. registers. They are + // simply the registers that come after all the physical + // registers; thus take the base architected register and add + // the physical registers to it. + renamed_reg = arch_reg + numPhysicalRegs; + + // Set the previous register to the same register; mainly it must be + // known that the prev reg was outside the range of normal registers + // so the free list can avoid adding it. + prev_reg = renamed_reg; + + assert(renamed_reg < numPhysicalRegs + numMiscRegs); + } + + return RenameInfo(renamed_reg, prev_reg); +} + +PhysRegIndex +SimpleRenameMap::lookup(RegIndex arch_reg) +{ + if (arch_reg < numLogicalIntRegs) { + return intRenameMap[arch_reg].physical_reg; + } else if (arch_reg < numLogicalRegs) { + return floatRenameMap[arch_reg].physical_reg; + } else { + // Subtract off the misc registers offset. + arch_reg = arch_reg - numLogicalRegs; + + // Misc. regs don't rename, so simply add the base arch reg to + // the number of physical registers. + return numPhysicalRegs + arch_reg; + } +} + +void +SimpleRenameMap::setEntry(RegIndex arch_reg, PhysRegIndex renamed_reg) +{ + // In this implementation the miscellaneous registers do not + // actually rename, so this function does not allow you to try to + // change their mappings. + if (arch_reg < numLogicalIntRegs) { + DPRINTF(Rename, "Rename Map: Integer register %i being set to %i.\n", + (int)arch_reg, renamed_reg); + + intRenameMap[arch_reg].physical_reg = renamed_reg; + } else if (arch_reg < numLogicalIntRegs + numLogicalFloatRegs) { + DPRINTF(Rename, "Rename Map: Float register %i being set to %i.\n", + (int)arch_reg - numLogicalIntRegs, renamed_reg); + + floatRenameMap[arch_reg].physical_reg = renamed_reg; + } +} + +int +SimpleRenameMap::numFreeEntries() +{ + int free_int_regs = freeList->numFreeIntRegs(); + int free_float_regs = freeList->numFreeFloatRegs(); + + if (free_int_regs < free_float_regs) { + return free_int_regs; + } else { + return free_float_regs; + } +} diff --git a/src/cpu/o3/rename_map.hh b/src/cpu/o3/rename_map.hh new file mode 100644 index 000000000..c4c90c99a --- /dev/null +++ b/src/cpu/o3/rename_map.hh @@ -0,0 +1,168 @@ +/* + * 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 + */ + +// Todo: Create destructor. +// Have it so that there's a more meaningful name given to the variable +// that marks the beginning of the FP registers. + +#ifndef __CPU_O3_RENAME_MAP_HH__ +#define __CPU_O3_RENAME_MAP_HH__ + +#include <iostream> +#include <utility> +#include <vector> + +#include "cpu/o3/free_list.hh" +//For RegIndex +#include "arch/isa_traits.hh" + +class SimpleRenameMap +{ + protected: + typedef TheISA::RegIndex RegIndex; + public: + /** + * Pair of a logical register and a physical register. Tells the + * previous mapping of a logical register to a physical register. + * Used to roll back the rename map to a previous state. + */ + typedef std::pair<RegIndex, PhysRegIndex> UnmapInfo; + + /** + * Pair of a physical register and a physical register. Used to + * return the physical register that a logical register has been + * renamed to, and the previous physical register that the same + * logical register was previously mapped to. + */ + typedef std::pair<PhysRegIndex, PhysRegIndex> RenameInfo; + + public: + /** Default constructor. init() must be called prior to use. */ + SimpleRenameMap() {}; + + /** Destructor. */ + ~SimpleRenameMap(); + + /** Initializes rename map with given parameters. */ + void init(unsigned _numLogicalIntRegs, + unsigned _numPhysicalIntRegs, + PhysRegIndex &_int_reg_start, + + unsigned _numLogicalFloatRegs, + unsigned _numPhysicalFloatRegs, + PhysRegIndex &_float_reg_start, + + unsigned _numMiscRegs, + + RegIndex _intZeroReg, + RegIndex _floatZeroReg, + + int id, + bool bindRegs); + + /** Sets the free list used with this rename map. */ + void setFreeList(SimpleFreeList *fl_ptr); + + //Tell rename map to get a free physical register for a given + //architected register. Not sure it should have a return value, + //but perhaps it should have some sort of fault in case there are + //no free registers. + RenameInfo rename(RegIndex arch_reg); + + PhysRegIndex lookup(RegIndex phys_reg); + + /** + * Marks the given register as ready, meaning that its value has been + * calculated and written to the register file. + * @param ready_reg The index of the physical register that is now ready. + */ + void setEntry(RegIndex arch_reg, PhysRegIndex renamed_reg); + + int numFreeEntries(); + + private: + /** Rename Map ID */ + int id; + + /** Number of logical integer registers. */ + int numLogicalIntRegs; + + /** Number of physical integer registers. */ + int numPhysicalIntRegs; + + /** Number of logical floating point registers. */ + int numLogicalFloatRegs; + + /** Number of physical floating point registers. */ + int numPhysicalFloatRegs; + + /** Number of miscellaneous registers. */ + int numMiscRegs; + + /** Number of logical integer + float registers. */ + int numLogicalRegs; + + /** Number of physical integer + float registers. */ + int numPhysicalRegs; + + /** The integer zero register. This implementation assumes it is always + * zero and never can be anything else. + */ + RegIndex intZeroReg; + + /** The floating point zero register. This implementation assumes it is + * always zero and never can be anything else. + */ + RegIndex floatZeroReg; + + class RenameEntry + { + public: + PhysRegIndex physical_reg; + bool valid; + + RenameEntry() + : physical_reg(0), valid(false) + { } + }; + + private: + /** Integer rename map. */ + std::vector<RenameEntry> intRenameMap; + + /** Floating point rename map. */ + std::vector<RenameEntry> floatRenameMap; + + private: + /** Free list interface. */ + SimpleFreeList *freeList; +}; + +#endif //__CPU_O3_RENAME_MAP_HH__ diff --git a/src/cpu/o3/rob.cc b/src/cpu/o3/rob.cc new file mode 100644 index 000000000..f99e5ccfd --- /dev/null +++ b/src/cpu/o3/rob.cc @@ -0,0 +1,37 @@ +/* + * 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 + * Nathan Binkert + */ + +#include "cpu/o3/alpha_dyn_inst.hh" +#include "cpu/o3/alpha_impl.hh" +#include "cpu/o3/rob_impl.hh" + +// Force instantiation of InstructionQueue. +template class ROB<AlphaSimpleImpl>; diff --git a/src/cpu/o3/rob.hh b/src/cpu/o3/rob.hh new file mode 100644 index 000000000..6d1402531 --- /dev/null +++ b/src/cpu/o3/rob.hh @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#ifndef __CPU_O3_ROB_HH__ +#define __CPU_O3_ROB_HH__ + +#include <string> +#include <utility> +#include <vector> + +/** + * ROB class. The ROB is largely what drives squashing. + */ +template <class Impl> +class ROB +{ + protected: + typedef TheISA::RegIndex RegIndex; + public: + //Typedefs from the Impl. + typedef typename Impl::FullCPU FullCPU; + typedef typename Impl::DynInstPtr DynInstPtr; + + typedef std::pair<RegIndex, PhysRegIndex> UnmapInfo; + typedef typename std::list<DynInstPtr>::iterator InstIt; + + /** Possible ROB statuses. */ + enum Status { + Running, + Idle, + ROBSquashing + }; + + /** SMT ROB Sharing Policy */ + enum ROBPolicy{ + Dynamic, + Partitioned, + Threshold + }; + + private: + /** Per-thread ROB status. */ + Status robStatus[Impl::MaxThreads]; + + /** ROB resource sharing policy for SMT mode. */ + ROBPolicy robPolicy; + + public: + /** ROB constructor. + * @param _numEntries Number of entries in ROB. + * @param _squashWidth Number of instructions that can be squashed in a + * single cycle. + * @param _smtROBPolicy ROB Partitioning Scheme for SMT. + * @param _smtROBThreshold Max Resources(by %) a thread can have in the ROB. + * @param _numThreads The number of active threads. + */ + ROB(unsigned _numEntries, unsigned _squashWidth, std::string smtROBPolicy, + unsigned _smtROBThreshold, unsigned _numThreads); + + std::string name() const; + + /** Function to set the CPU pointer, necessary due to which object the ROB + * is created within. + * @param cpu_ptr Pointer to the implementation specific full CPU object. + */ + void setCPU(FullCPU *cpu_ptr); + + /** Sets pointer to the list of active threads. + * @param at_ptr Pointer to the list of active threads. + */ + void setActiveThreads(std::list<unsigned>* at_ptr); + + /** Switches out the ROB. */ + void switchOut(); + + /** Takes over another CPU's thread. */ + void takeOverFrom(); + + /** Function to insert an instruction into the ROB. Note that whatever + * calls this function must ensure that there is enough space within the + * ROB for the new instruction. + * @param inst The instruction being inserted into the ROB. + */ + void insertInst(DynInstPtr &inst); + + /** Returns pointer to the head instruction within the ROB. There is + * no guarantee as to the return value if the ROB is empty. + * @retval Pointer to the DynInst that is at the head of the ROB. + */ +// DynInstPtr readHeadInst(); + + /** Returns a pointer to the head instruction of a specific thread within + * the ROB. + * @return Pointer to the DynInst that is at the head of the ROB. + */ + DynInstPtr readHeadInst(unsigned tid); + + /** Returns pointer to the tail instruction within the ROB. There is + * no guarantee as to the return value if the ROB is empty. + * @retval Pointer to the DynInst that is at the tail of the ROB. + */ +// DynInstPtr readTailInst(); + + /** Returns a pointer to the tail instruction of a specific thread within + * the ROB. + * @return Pointer to the DynInst that is at the tail of the ROB. + */ + DynInstPtr readTailInst(unsigned tid); + + /** Retires the head instruction, removing it from the ROB. */ +// void retireHead(); + + /** Retires the head instruction of a specific thread, removing it from the + * ROB. + */ + void retireHead(unsigned tid); + + /** Is the oldest instruction across all threads ready. */ +// bool isHeadReady(); + + /** Is the oldest instruction across a particular thread ready. */ + bool isHeadReady(unsigned tid); + + /** Is there any commitable head instruction across all threads ready. */ + bool canCommit(); + + /** Re-adjust ROB partitioning. */ + void resetEntries(); + + /** Number of entries needed For 'num_threads' amount of threads. */ + int entryAmount(int num_threads); + + /** Returns the number of total free entries in the ROB. */ + unsigned numFreeEntries(); + + /** Returns the number of free entries in a specific ROB paritition. */ + unsigned numFreeEntries(unsigned tid); + + /** Returns the maximum number of entries for a specific thread. */ + unsigned getMaxEntries(unsigned tid) + { return maxEntries[tid]; } + + /** Returns the number of entries being used by a specific thread. */ + unsigned getThreadEntries(unsigned tid) + { return threadEntries[tid]; } + + /** Returns if the ROB is full. */ + bool isFull() + { return numInstsInROB == numEntries; } + + /** Returns if a specific thread's partition is full. */ + bool isFull(unsigned tid) + { return threadEntries[tid] == numEntries; } + + /** Returns if the ROB is empty. */ + bool isEmpty() + { return numInstsInROB == 0; } + + /** Returns if a specific thread's partition is empty. */ + bool isEmpty(unsigned tid) + { return threadEntries[tid] == 0; } + + /** Executes the squash, marking squashed instructions. */ + void doSquash(unsigned tid); + + /** Squashes all instructions younger than the given sequence number for + * the specific thread. + */ + void squash(InstSeqNum squash_num, unsigned tid); + + /** Updates the head instruction with the new oldest instruction. */ + void updateHead(); + + /** Updates the tail instruction with the new youngest instruction. */ + void updateTail(); + + /** Reads the PC of the oldest head instruction. */ +// uint64_t readHeadPC(); + + /** Reads the PC of the head instruction of a specific thread. */ +// uint64_t readHeadPC(unsigned tid); + + /** Reads the next PC of the oldest head instruction. */ +// uint64_t readHeadNextPC(); + + /** Reads the next PC of the head instruction of a specific thread. */ +// uint64_t readHeadNextPC(unsigned tid); + + /** Reads the sequence number of the oldest head instruction. */ +// InstSeqNum readHeadSeqNum(); + + /** Reads the sequence number of the head instruction of a specific thread. + */ +// InstSeqNum readHeadSeqNum(unsigned tid); + + /** Reads the PC of the youngest tail instruction. */ +// uint64_t readTailPC(); + + /** Reads the PC of the tail instruction of a specific thread. */ +// uint64_t readTailPC(unsigned tid); + + /** Reads the sequence number of the youngest tail instruction. */ +// InstSeqNum readTailSeqNum(); + + /** Reads the sequence number of tail instruction of a specific thread. */ +// InstSeqNum readTailSeqNum(unsigned tid); + + /** Checks if the ROB is still in the process of squashing instructions. + * @retval Whether or not the ROB is done squashing. + */ + bool isDoneSquashing(unsigned tid) const + { return doneSquashing[tid]; } + + /** Checks if the ROB is still in the process of squashing instructions for + * any thread. + */ + bool isDoneSquashing(); + + /** This is more of a debugging function than anything. Use + * numInstsInROB to get the instructions in the ROB unless you are + * double checking that variable. + */ + int countInsts(); + + /** This is more of a debugging function than anything. Use + * threadEntries to get the instructions in the ROB unless you are + * double checking that variable. + */ + int countInsts(unsigned tid); + + private: + /** Pointer to the CPU. */ + FullCPU *cpu; + + /** Active Threads in CPU */ + std::list<unsigned>* activeThreads; + + /** Number of instructions in the ROB. */ + unsigned numEntries; + + /** Entries Per Thread */ + unsigned threadEntries[Impl::MaxThreads]; + + /** Max Insts a Thread Can Have in the ROB */ + unsigned maxEntries[Impl::MaxThreads]; + + /** ROB List of Instructions */ + std::list<DynInstPtr> instList[Impl::MaxThreads]; + + /** Number of instructions that can be squashed in a single cycle. */ + unsigned squashWidth; + + public: + /** Iterator pointing to the instruction which is the last instruction + * in the ROB. This may at times be invalid (ie when the ROB is empty), + * however it should never be incorrect. + */ + InstIt tail; + + /** Iterator pointing to the instruction which is the first instruction in + * in the ROB*/ + InstIt head; + + private: + /** Iterator used for walking through the list of instructions when + * squashing. Used so that there is persistent state between cycles; + * when squashing, the instructions are marked as squashed but not + * immediately removed, meaning the tail iterator remains the same before + * and after a squash. + * This will always be set to cpu->instList.end() if it is invalid. + */ + InstIt squashIt[Impl::MaxThreads]; + + public: + /** Number of instructions in the ROB. */ + int numInstsInROB; + + /** Dummy instruction returned if there are no insts left. */ + DynInstPtr dummyInst; + + private: + /** The sequence number of the squashed instruction. */ + InstSeqNum squashedSeqNum; + + /** Is the ROB done squashing. */ + bool doneSquashing[Impl::MaxThreads]; + + /** Number of active threads. */ + unsigned numThreads; +}; + +#endif //__CPU_O3_ROB_HH__ diff --git a/src/cpu/o3/rob_impl.hh b/src/cpu/o3/rob_impl.hh new file mode 100644 index 000000000..97694e371 --- /dev/null +++ b/src/cpu/o3/rob_impl.hh @@ -0,0 +1,693 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#include "config/full_system.hh" +#include "cpu/o3/rob.hh" + +using namespace std; + +template <class Impl> +ROB<Impl>::ROB(unsigned _numEntries, unsigned _squashWidth, + string _smtROBPolicy, unsigned _smtROBThreshold, + unsigned _numThreads) + : numEntries(_numEntries), + squashWidth(_squashWidth), + numInstsInROB(0), + squashedSeqNum(0), + numThreads(_numThreads) +{ + for (int tid=0; tid < numThreads; tid++) { + doneSquashing[tid] = true; + threadEntries[tid] = 0; + } + + string policy = _smtROBPolicy; + + //Convert string to lowercase + std::transform(policy.begin(), policy.end(), policy.begin(), + (int(*)(int)) tolower); + + //Figure out rob policy + if (policy == "dynamic") { + robPolicy = Dynamic; + + //Set Max Entries to Total ROB Capacity + for (int i = 0; i < numThreads; i++) { + maxEntries[i]=numEntries; + } + + } else if (policy == "partitioned") { + robPolicy = Partitioned; + DPRINTF(Fetch, "ROB sharing policy set to Partitioned\n"); + + //@todo:make work if part_amt doesnt divide evenly. + int part_amt = numEntries / numThreads; + + //Divide ROB up evenly + for (int i = 0; i < numThreads; i++) { + maxEntries[i]=part_amt; + } + + } else if (policy == "threshold") { + robPolicy = Threshold; + DPRINTF(Fetch, "ROB sharing policy set to Threshold\n"); + + int threshold = _smtROBThreshold;; + + //Divide up by threshold amount + for (int i = 0; i < numThreads; i++) { + maxEntries[i]=threshold; + } + } else { + assert(0 && "Invalid ROB Sharing Policy.Options Are:{Dynamic," + "Partitioned, Threshold}"); + } +} + +template <class Impl> +std::string +ROB<Impl>::name() const +{ + return cpu->name() + ".rob"; +} + +template <class Impl> +void +ROB<Impl>::setCPU(FullCPU *cpu_ptr) +{ + cpu = cpu_ptr; + + // Set the per-thread iterators to the end of the instruction list. + for (int i=0; i < numThreads;i++) { + squashIt[i] = instList[i].end(); + } + + // Initialize the "universal" ROB head & tail point to invalid + // pointers + head = instList[0].end(); + tail = instList[0].end(); +} + +template <class Impl> +void +ROB<Impl>::setActiveThreads(list<unsigned> *at_ptr) +{ + DPRINTF(ROB, "Setting active threads list pointer.\n"); + activeThreads = at_ptr; +} + +template <class Impl> +void +ROB<Impl>::switchOut() +{ + for (int tid = 0; tid < numThreads; tid++) { + instList[tid].clear(); + } +} + +template <class Impl> +void +ROB<Impl>::takeOverFrom() +{ + for (int tid=0; tid < numThreads; tid++) { + doneSquashing[tid] = true; + threadEntries[tid] = 0; + squashIt[tid] = instList[tid].end(); + } + numInstsInROB = 0; + + // Initialize the "universal" ROB head & tail point to invalid + // pointers + head = instList[0].end(); + tail = instList[0].end(); +} + +template <class Impl> +void +ROB<Impl>::resetEntries() +{ + if (robPolicy != Dynamic || numThreads > 1) { + int active_threads = (*activeThreads).size(); + + list<unsigned>::iterator threads = (*activeThreads).begin(); + list<unsigned>::iterator list_end = (*activeThreads).end(); + + while (threads != list_end) { + if (robPolicy == Partitioned) { + maxEntries[*threads++] = numEntries / active_threads; + } else if (robPolicy == Threshold && active_threads == 1) { + maxEntries[*threads++] = numEntries; + } + } + } +} + +template <class Impl> +int +ROB<Impl>::entryAmount(int num_threads) +{ + if (robPolicy == Partitioned) { + return numEntries / num_threads; + } else { + return 0; + } +} + +template <class Impl> +int +ROB<Impl>::countInsts() +{ + int total=0; + + for (int i=0;i < numThreads;i++) + total += countInsts(i); + + return total; +} + +template <class Impl> +int +ROB<Impl>::countInsts(unsigned tid) +{ + return instList[tid].size(); +} + +template <class Impl> +void +ROB<Impl>::insertInst(DynInstPtr &inst) +{ + //assert(numInstsInROB == countInsts()); + assert(inst); + + DPRINTF(ROB, "Adding inst PC %#x to the ROB.\n", inst->readPC()); + + assert(numInstsInROB != numEntries); + + int tid = inst->threadNumber; + + instList[tid].push_back(inst); + + //Set Up head iterator if this is the 1st instruction in the ROB + if (numInstsInROB == 0) { + head = instList[tid].begin(); + assert((*head) == inst); + } + + //Must Decrement for iterator to actually be valid since __.end() + //actually points to 1 after the last inst + tail = instList[tid].end(); + tail--; + + inst->setInROB(); + + ++numInstsInROB; + ++threadEntries[tid]; + + assert((*tail) == inst); + + DPRINTF(ROB, "[tid:%i] Now has %d instructions.\n", tid, threadEntries[tid]); +} + +// Whatever calls this function needs to ensure that it properly frees up +// registers prior to this function. +/* +template <class Impl> +void +ROB<Impl>::retireHead() +{ + //assert(numInstsInROB == countInsts()); + assert(numInstsInROB > 0); + + int tid = (*head)->threadNumber; + + retireHead(tid); + + if (numInstsInROB == 0) { + tail = instList[tid].end(); + } +} +*/ + +template <class Impl> +void +ROB<Impl>::retireHead(unsigned tid) +{ + //assert(numInstsInROB == countInsts()); + assert(numInstsInROB > 0); + + // Get the head ROB instruction. + InstIt head_it = instList[tid].begin(); + + DynInstPtr head_inst = (*head_it); + + assert(head_inst->readyToCommit()); + + DPRINTF(ROB, "[tid:%u]: Retiring head instruction, " + "instruction PC %#x,[sn:%lli]\n", tid, head_inst->readPC(), + head_inst->seqNum); + + --numInstsInROB; + --threadEntries[tid]; + + head_inst->removeInROB(); + head_inst->setCommitted(); + + instList[tid].erase(head_it); + + //Update "Global" Head of ROB + updateHead(); + + // @todo: A special case is needed if the instruction being + // retired is the only instruction in the ROB; otherwise the tail + // iterator will become invalidated. + cpu->removeFrontInst(head_inst); +} +/* +template <class Impl> +bool +ROB<Impl>::isHeadReady() +{ + if (numInstsInROB != 0) { + return (*head)->readyToCommit(); + } + + return false; +} +*/ +template <class Impl> +bool +ROB<Impl>::isHeadReady(unsigned tid) +{ + if (threadEntries[tid] != 0) { + return instList[tid].front()->readyToCommit(); + } + + return false; +} + +template <class Impl> +bool +ROB<Impl>::canCommit() +{ + //@todo: set ActiveThreads through ROB or CPU + list<unsigned>::iterator threads = (*activeThreads).begin(); + + while (threads != (*activeThreads).end()) { + unsigned tid = *threads++; + + if (isHeadReady(tid)) { + return true; + } + } + + return false; +} + +template <class Impl> +unsigned +ROB<Impl>::numFreeEntries() +{ + //assert(numInstsInROB == countInsts()); + + return numEntries - numInstsInROB; +} + +template <class Impl> +unsigned +ROB<Impl>::numFreeEntries(unsigned tid) +{ + return maxEntries[tid] - threadEntries[tid]; +} + +template <class Impl> +void +ROB<Impl>::doSquash(unsigned tid) +{ + DPRINTF(ROB, "[tid:%u]: Squashing instructions until [sn:%i].\n", + tid, squashedSeqNum); + + assert(squashIt[tid] != instList[tid].end()); + + if ((*squashIt[tid])->seqNum < squashedSeqNum) { + DPRINTF(ROB, "[tid:%u]: Done squashing instructions.\n", + tid); + + squashIt[tid] = instList[tid].end(); + + doneSquashing[tid] = true; + return; + } + + bool robTailUpdate = false; + + for (int numSquashed = 0; + numSquashed < squashWidth && + squashIt[tid] != instList[tid].end() && + (*squashIt[tid])->seqNum > squashedSeqNum; + ++numSquashed) + { + DPRINTF(ROB, "[tid:%u]: Squashing instruction PC %#x, seq num %i.\n", + (*squashIt[tid])->threadNumber, + (*squashIt[tid])->readPC(), + (*squashIt[tid])->seqNum); + + // Mark the instruction as squashed, and ready to commit so that + // it can drain out of the pipeline. + (*squashIt[tid])->setSquashed(); + + (*squashIt[tid])->setCanCommit(); + + + if (squashIt[tid] == instList[tid].begin()) { + DPRINTF(ROB, "Reached head of instruction list while " + "squashing.\n"); + + squashIt[tid] = instList[tid].end(); + + doneSquashing[tid] = true; + + return; + } + + InstIt tail_thread = instList[tid].end(); + tail_thread--; + + if ((*squashIt[tid]) == (*tail_thread)) + robTailUpdate = true; + + squashIt[tid]--; + } + + + // Check if ROB is done squashing. + if ((*squashIt[tid])->seqNum <= squashedSeqNum) { + DPRINTF(ROB, "[tid:%u]: Done squashing instructions.\n", + tid); + + squashIt[tid] = instList[tid].end(); + + doneSquashing[tid] = true; + } + + if (robTailUpdate) { + updateTail(); + } +} + + +template <class Impl> +void +ROB<Impl>::updateHead() +{ + DynInstPtr head_inst; + InstSeqNum lowest_num = 0; + bool first_valid = true; + + // @todo: set ActiveThreads through ROB or CPU + list<unsigned>::iterator threads = (*activeThreads).begin(); + + while (threads != (*activeThreads).end()) { + unsigned thread_num = *threads++; + + if (instList[thread_num].empty()) + continue; + + if (first_valid) { + head = instList[thread_num].begin(); + lowest_num = (*head)->seqNum; + first_valid = false; + continue; + } + + InstIt head_thread = instList[thread_num].begin(); + + DynInstPtr head_inst = (*head_thread); + + assert(head_inst != 0); + + if (head_inst->seqNum < lowest_num) { + head = head_thread; + lowest_num = head_inst->seqNum; + } + } + + if (first_valid) { + head = instList[0].end(); + } + +} + +template <class Impl> +void +ROB<Impl>::updateTail() +{ + tail = instList[0].end(); + bool first_valid = true; + + list<unsigned>::iterator threads = (*activeThreads).begin(); + + while (threads != (*activeThreads).end()) { + unsigned tid = *threads++; + + if (instList[tid].empty()) { + continue; + } + + // If this is the first valid then assign w/out + // comparison + if (first_valid) { + tail = instList[tid].end(); + tail--; + first_valid = false; + continue; + } + + // Assign new tail if this thread's tail is younger + // than our current "tail high" + InstIt tail_thread = instList[tid].end(); + tail_thread--; + + if ((*tail_thread)->seqNum > (*tail)->seqNum) { + tail = tail_thread; + } + } +} + + +template <class Impl> +void +ROB<Impl>::squash(InstSeqNum squash_num,unsigned tid) +{ + if (isEmpty()) { + DPRINTF(ROB, "Does not need to squash due to being empty " + "[sn:%i]\n", + squash_num); + + return; + } + + DPRINTF(ROB, "Starting to squash within the ROB.\n"); + + robStatus[tid] = ROBSquashing; + + doneSquashing[tid] = false; + + squashedSeqNum = squash_num; + + if (!instList[tid].empty()) { + InstIt tail_thread = instList[tid].end(); + tail_thread--; + + squashIt[tid] = tail_thread; + + doSquash(tid); + } +} +/* +template <class Impl> +typename Impl::DynInstPtr +ROB<Impl>::readHeadInst() +{ + if (numInstsInROB != 0) { + assert((*head)->isInROB()==true); + return *head; + } else { + return dummyInst; + } +} +*/ +template <class Impl> +typename Impl::DynInstPtr +ROB<Impl>::readHeadInst(unsigned tid) +{ + if (threadEntries[tid] != 0) { + InstIt head_thread = instList[tid].begin(); + + assert((*head_thread)->isInROB()==true); + + return *head_thread; + } else { + return dummyInst; + } +} +/* +template <class Impl> +uint64_t +ROB<Impl>::readHeadPC() +{ + //assert(numInstsInROB == countInsts()); + + DynInstPtr head_inst = *head; + + return head_inst->readPC(); +} + +template <class Impl> +uint64_t +ROB<Impl>::readHeadPC(unsigned tid) +{ + //assert(numInstsInROB == countInsts()); + InstIt head_thread = instList[tid].begin(); + + return (*head_thread)->readPC(); +} + + +template <class Impl> +uint64_t +ROB<Impl>::readHeadNextPC() +{ + //assert(numInstsInROB == countInsts()); + + DynInstPtr head_inst = *head; + + return head_inst->readNextPC(); +} + +template <class Impl> +uint64_t +ROB<Impl>::readHeadNextPC(unsigned tid) +{ + //assert(numInstsInROB == countInsts()); + InstIt head_thread = instList[tid].begin(); + + return (*head_thread)->readNextPC(); +} + +template <class Impl> +InstSeqNum +ROB<Impl>::readHeadSeqNum() +{ + //assert(numInstsInROB == countInsts()); + DynInstPtr head_inst = *head; + + return head_inst->seqNum; +} + +template <class Impl> +InstSeqNum +ROB<Impl>::readHeadSeqNum(unsigned tid) +{ + InstIt head_thread = instList[tid].begin(); + + return ((*head_thread)->seqNum); +} + +template <class Impl> +typename Impl::DynInstPtr +ROB<Impl>::readTailInst() +{ + //assert(numInstsInROB == countInsts()); + //assert(tail != instList[0].end()); + + return (*tail); +} +*/ +template <class Impl> +typename Impl::DynInstPtr +ROB<Impl>::readTailInst(unsigned tid) +{ + //assert(tail_thread[tid] != instList[tid].end()); + + InstIt tail_thread = instList[tid].end(); + tail_thread--; + + return *tail_thread; +} + +/* +template <class Impl> +uint64_t +ROB<Impl>::readTailPC() +{ + //assert(numInstsInROB == countInsts()); + + //assert(tail != instList[0].end()); + + return (*tail)->readPC(); +} + +template <class Impl> +uint64_t +ROB<Impl>::readTailPC(unsigned tid) +{ + //assert(tail_thread[tid] != instList[tid].end()); + + InstIt tail_thread = instList[tid].end(); + tail_thread--; + + return (*tail_thread)->readPC(); +} + +template <class Impl> +InstSeqNum +ROB<Impl>::readTailSeqNum() +{ + // Return the last sequence number that has not been squashed. Other + // stages can use it to squash any instructions younger than the current + // tail. + return (*tail)->seqNum; +} + +template <class Impl> +InstSeqNum +ROB<Impl>::readTailSeqNum(unsigned tid) +{ + // Return the last sequence number that has not been squashed. Other + // stages can use it to squash any instructions younger than the current + // tail. + // assert(tail_thread[tid] != instList[tid].end()); + + InstIt tail_thread = instList[tid].end(); + tail_thread--; + + return (*tail_thread)->seqNum; +} +*/ diff --git a/src/cpu/o3/sat_counter.cc b/src/cpu/o3/sat_counter.cc new file mode 100644 index 000000000..68d3ef627 --- /dev/null +++ b/src/cpu/o3/sat_counter.cc @@ -0,0 +1,57 @@ +/* + * Copyright (c) 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 "base/misc.hh" +#include "cpu/o3/sat_counter.hh" + +SatCounter::SatCounter() + : initialVal(0), counter(0) +{ +} + +SatCounter::SatCounter(unsigned bits) + : initialVal(0), maxVal((1 << bits) - 1), counter(0) +{ +} + +SatCounter::SatCounter(unsigned bits, uint8_t initial_val) + : initialVal(initialVal), maxVal((1 << bits) - 1), counter(initial_val) +{ + // Check to make sure initial value doesn't exceed the max counter value. + if (initial_val > maxVal) { + fatal("BP: Initial counter value exceeds max size."); + } +} + +void +SatCounter::setBits(unsigned bits) +{ + maxVal = (1 << bits) - 1; +} diff --git a/src/cpu/o3/sat_counter.hh b/src/cpu/o3/sat_counter.hh new file mode 100644 index 000000000..7e15119b0 --- /dev/null +++ b/src/cpu/o3/sat_counter.hh @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2005-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#ifndef __CPU_O3_SAT_COUNTER_HH__ +#define __CPU_O3_SAT_COUNTER_HH__ + +#include "base/misc.hh" +#include "sim/host.hh" + +/** + * Private counter class for the internal saturating counters. + * Implements an n bit saturating counter and provides methods to + * increment, decrement, and read it. + * @todo Consider making this something that more closely mimics a + * built in class so you can use ++ or --. + */ +class SatCounter +{ + public: + /** + * Constructor for the counter. + */ + SatCounter() + : initialVal(0), counter(0) + { } + + /** + * Constructor for the counter. + * @param bits How many bits the counter will have. + */ + SatCounter(unsigned bits) + : initialVal(0), maxVal((1 << bits) - 1), counter(0) + { } + + /** + * Constructor for the counter. + * @param bits How many bits the counter will have. + * @param initial_val Starting value for each counter. + */ + SatCounter(unsigned bits, uint8_t initial_val) + : initialVal(initialVal), maxVal((1 << bits) - 1), counter(initial_val) + { + // Check to make sure initial value doesn't exceed the max + // counter value. + if (initial_val > maxVal) { + fatal("BP: Initial counter value exceeds max size."); + } + } + + /** + * Sets the number of bits. + */ + void setBits(unsigned bits) { maxVal = (1 << bits) - 1; } + + void reset() { counter = initialVal; } + + /** + * Increments the counter's current value. + */ + void increment() + { + if (counter < maxVal) { + ++counter; + } + } + + /** + * Decrements the counter's current value. + */ + void decrement() + { + if (counter > 0) { + --counter; + } + } + + /** + * Read the counter's value. + */ + const uint8_t read() const + { return counter; } + + private: + uint8_t initialVal; + uint8_t maxVal; + uint8_t counter; +}; + +#endif // __CPU_O3_SAT_COUNTER_HH__ diff --git a/src/cpu/o3/scoreboard.cc b/src/cpu/o3/scoreboard.cc new file mode 100644 index 000000000..1859b35a4 --- /dev/null +++ b/src/cpu/o3/scoreboard.cc @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2005-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: Korey Sewell + * Kevin Lim + */ + +#include "cpu/o3/scoreboard.hh" + +Scoreboard::Scoreboard(unsigned activeThreads, + unsigned _numLogicalIntRegs, + unsigned _numPhysicalIntRegs, + unsigned _numLogicalFloatRegs, + unsigned _numPhysicalFloatRegs, + unsigned _numMiscRegs, + unsigned _zeroRegIdx) + : numLogicalIntRegs(_numLogicalIntRegs), + numPhysicalIntRegs(_numPhysicalIntRegs), + numLogicalFloatRegs(_numLogicalFloatRegs), + numPhysicalFloatRegs(_numPhysicalFloatRegs), + numMiscRegs(_numMiscRegs), + zeroRegIdx(_zeroRegIdx) +{ + //Get Register Sizes + numLogicalRegs = numLogicalIntRegs + numLogicalFloatRegs; + numPhysicalRegs = numPhysicalIntRegs + numPhysicalFloatRegs; + + //Resize scoreboard appropriately + regScoreBoard.resize(numPhysicalRegs + (numMiscRegs * activeThreads)); + + //Initialize values + for (int i=0; i < numLogicalIntRegs * activeThreads; i++) { + regScoreBoard[i] = 1; + } + + for (int i= numPhysicalIntRegs; + i < numPhysicalIntRegs + (numLogicalFloatRegs * activeThreads); + i++) { + regScoreBoard[i] = 1; + } + + for (int i = numPhysicalRegs; + i < numPhysicalRegs + (numMiscRegs * activeThreads); + i++) { + regScoreBoard[i] = 1; + } +} + +std::string +Scoreboard::name() const +{ + return "cpu.scoreboard"; +} + +bool +Scoreboard::getReg(PhysRegIndex phys_reg) +{ + // Always ready if int or fp zero reg. + if (phys_reg == zeroRegIdx || + phys_reg == (zeroRegIdx + numPhysicalIntRegs)) { + return 1; + } + + return regScoreBoard[phys_reg]; +} + +void +Scoreboard::setReg(PhysRegIndex phys_reg) +{ + DPRINTF(Scoreboard, "Setting reg %i as ready\n", phys_reg); + + regScoreBoard[phys_reg] = 1; +} + +void +Scoreboard::unsetReg(PhysRegIndex ready_reg) +{ + if (ready_reg == zeroRegIdx || + ready_reg == (zeroRegIdx + numPhysicalIntRegs)) { + // Don't do anything if int or fp zero reg. + return; + } + + regScoreBoard[ready_reg] = 0; +} diff --git a/src/cpu/o3/scoreboard.hh b/src/cpu/o3/scoreboard.hh new file mode 100644 index 000000000..f8e4df3b7 --- /dev/null +++ b/src/cpu/o3/scoreboard.hh @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2005-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: Korey Sewell + * Kevin Lim + */ + +#ifndef __CPU_O3_SCOREBOARD_HH__ +#define __CPU_O3_SCOREBOARD_HH__ + +#include <iostream> +#include <utility> +#include <vector> +#include "arch/alpha/isa_traits.hh" +#include "base/trace.hh" +#include "base/traceflags.hh" +#include "cpu/o3/comm.hh" + +/** + * Implements a simple scoreboard to track which registers are ready. + * This class assumes that the fp registers start, index wise, right after + * the integer registers. The misc. registers start, index wise, right after + * the fp registers. + * @todo: Fix up handling of the zero register in case the decoder does not + * automatically make insts that write the zero register into nops. + */ +class Scoreboard +{ + public: + /** Constructs a scoreboard. + * @param activeThreads The number of active threads. + * @param _numLogicalIntRegs Number of logical integer registers. + * @param _numPhysicalIntRegs Number of physical integer registers. + * @param _numLogicalFloatRegs Number of logical fp registers. + * @param _numPhysicalFloatRegs Number of physical fp registers. + * @param _numMiscRegs Number of miscellaneous registers. + * @param _zeroRegIdx Index of the zero register. + */ + Scoreboard(unsigned activeThreads, + unsigned _numLogicalIntRegs, + unsigned _numPhysicalIntRegs, + unsigned _numLogicalFloatRegs, + unsigned _numPhysicalFloatRegs, + unsigned _numMiscRegs, + unsigned _zeroRegIdx); + + /** Destructor. */ + ~Scoreboard() {} + + /** Returns the name of the scoreboard. */ + std::string name() const; + + /** Checks if the register is ready. */ + bool getReg(PhysRegIndex ready_reg); + + /** Sets the register as ready. */ + void setReg(PhysRegIndex phys_reg); + + /** Sets the register as not ready. */ + void unsetReg(PhysRegIndex ready_reg); + + private: + /** Scoreboard of physical integer registers, saying whether or not they + * are ready. + */ + std::vector<bool> regScoreBoard; + + /** Number of logical integer registers. */ + int numLogicalIntRegs; + + /** Number of physical integer registers. */ + int numPhysicalIntRegs; + + /** Number of logical floating point registers. */ + int numLogicalFloatRegs; + + /** Number of physical floating point registers. */ + int numPhysicalFloatRegs; + + /** Number of miscellaneous registers. */ + int numMiscRegs; + + /** Number of logical integer + float registers. */ + int numLogicalRegs; + + /** Number of physical integer + float registers. */ + int numPhysicalRegs; + + /** The logical index of the zero register. */ + int zeroRegIdx; +}; + +#endif diff --git a/src/cpu/o3/store_set.cc b/src/cpu/o3/store_set.cc new file mode 100644 index 000000000..2d28b617f --- /dev/null +++ b/src/cpu/o3/store_set.cc @@ -0,0 +1,348 @@ +/* + * 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 "base/intmath.hh" +#include "base/misc.hh" +#include "base/trace.hh" +#include "cpu/o3/store_set.hh" + +StoreSet::StoreSet(int _SSIT_size, int _LFST_size) + : SSITSize(_SSIT_size), LFSTSize(_LFST_size) +{ + DPRINTF(StoreSet, "StoreSet: Creating store set object.\n"); + DPRINTF(StoreSet, "StoreSet: SSIT size: %i, LFST size: %i.\n", + SSITSize, LFSTSize); + + if (!isPowerOf2(SSITSize)) { + fatal("Invalid SSIT size!\n"); + } + + SSIT.resize(SSITSize); + + validSSIT.resize(SSITSize); + + for (int i = 0; i < SSITSize; ++i) + validSSIT[i] = false; + + if (!isPowerOf2(LFSTSize)) { + fatal("Invalid LFST size!\n"); + } + + LFST.resize(LFSTSize); + + validLFST.resize(LFSTSize); + + for (int i = 0; i < LFSTSize; ++i) { + validLFST[i] = false; + LFST[i] = 0; + } + + indexMask = SSITSize - 1; + + offsetBits = 2; +} + +StoreSet::~StoreSet() +{ +} + +void +StoreSet::init(int _SSIT_size, int _LFST_size) +{ + SSITSize = _SSIT_size; + LFSTSize = _LFST_size; + + DPRINTF(StoreSet, "StoreSet: Creating store set object.\n"); + DPRINTF(StoreSet, "StoreSet: SSIT size: %i, LFST size: %i.\n", + SSITSize, LFSTSize); + + SSIT.resize(SSITSize); + + validSSIT.resize(SSITSize); + + for (int i = 0; i < SSITSize; ++i) + validSSIT[i] = false; + + LFST.resize(LFSTSize); + + validLFST.resize(LFSTSize); + + for (int i = 0; i < LFSTSize; ++i) { + validLFST[i] = false; + LFST[i] = 0; + } + + indexMask = SSITSize - 1; + + offsetBits = 2; +} + + +void +StoreSet::violation(Addr store_PC, Addr load_PC) +{ + int load_index = calcIndex(load_PC); + int store_index = calcIndex(store_PC); + + assert(load_index < SSITSize && store_index < SSITSize); + + bool valid_load_SSID = validSSIT[load_index]; + bool valid_store_SSID = validSSIT[store_index]; + + if (!valid_load_SSID && !valid_store_SSID) { + // Calculate a new SSID here. + SSID new_set = calcSSID(load_PC); + + validSSIT[load_index] = true; + + SSIT[load_index] = new_set; + + validSSIT[store_index] = true; + + SSIT[store_index] = new_set; + + assert(new_set < LFSTSize); + + DPRINTF(StoreSet, "StoreSet: Neither load nor store had a valid " + "storeset, creating a new one: %i for load %#x, store %#x\n", + new_set, load_PC, store_PC); + } else if (valid_load_SSID && !valid_store_SSID) { + SSID load_SSID = SSIT[load_index]; + + validSSIT[store_index] = true; + + SSIT[store_index] = load_SSID; + + assert(load_SSID < LFSTSize); + + DPRINTF(StoreSet, "StoreSet: Load had a valid store set. Adding " + "store to that set: %i for load %#x, store %#x\n", + load_SSID, load_PC, store_PC); + } else if (!valid_load_SSID && valid_store_SSID) { + SSID store_SSID = SSIT[store_index]; + + validSSIT[load_index] = true; + + SSIT[load_index] = store_SSID; + + DPRINTF(StoreSet, "StoreSet: Store had a valid store set: %i for " + "load %#x, store %#x\n", + store_SSID, load_PC, store_PC); + } else { + SSID load_SSID = SSIT[load_index]; + SSID store_SSID = SSIT[store_index]; + + assert(load_SSID < LFSTSize && store_SSID < LFSTSize); + + // The store set with the lower number wins + if (store_SSID > load_SSID) { + SSIT[store_index] = load_SSID; + + DPRINTF(StoreSet, "StoreSet: Load had smaller store set: %i; " + "for load %#x, store %#x\n", + load_SSID, load_PC, store_PC); + } else { + SSIT[load_index] = store_SSID; + + DPRINTF(StoreSet, "StoreSet: Store had smaller store set: %i; " + "for load %#x, store %#x\n", + store_SSID, load_PC, store_PC); + } + } +} + +void +StoreSet::insertLoad(Addr load_PC, InstSeqNum load_seq_num) +{ + // Does nothing. + return; +} + +void +StoreSet::insertStore(Addr store_PC, InstSeqNum store_seq_num, + unsigned tid) +{ + int index = calcIndex(store_PC); + + int store_SSID; + + assert(index < SSITSize); + + if (!validSSIT[index]) { + // Do nothing if there's no valid entry. + return; + } else { + store_SSID = SSIT[index]; + + assert(store_SSID < LFSTSize); + + // Update the last store that was fetched with the current one. + LFST[store_SSID] = store_seq_num; + + validLFST[store_SSID] = 1; + + storeList[store_seq_num] = store_SSID; + + DPRINTF(StoreSet, "Store %#x updated the LFST, SSID: %i\n", + store_PC, store_SSID); + } +} + +InstSeqNum +StoreSet::checkInst(Addr PC) +{ + int index = calcIndex(PC); + + int inst_SSID; + + assert(index < SSITSize); + + if (!validSSIT[index]) { + DPRINTF(StoreSet, "Inst %#x with index %i had no SSID\n", + PC, index); + + // Return 0 if there's no valid entry. + return 0; + } else { + inst_SSID = SSIT[index]; + + assert(inst_SSID < LFSTSize); + + if (!validLFST[inst_SSID]) { + + DPRINTF(StoreSet, "Inst %#x with index %i and SSID %i had no " + "dependency\n", PC, index, inst_SSID); + + return 0; + } else { + DPRINTF(StoreSet, "Inst %#x with index %i and SSID %i had LFST " + "inum of %i\n", PC, index, inst_SSID, LFST[inst_SSID]); + + return LFST[inst_SSID]; + } + } +} + +void +StoreSet::issued(Addr issued_PC, InstSeqNum issued_seq_num, bool is_store) +{ + // This only is updated upon a store being issued. + if (!is_store) { + return; + } + + int index = calcIndex(issued_PC); + + int store_SSID; + + assert(index < SSITSize); + + SeqNumMapIt store_list_it = storeList.find(issued_seq_num); + + if (store_list_it != storeList.end()) { + storeList.erase(store_list_it); + } + + // Make sure the SSIT still has a valid entry for the issued store. + if (!validSSIT[index]) { + return; + } + + store_SSID = SSIT[index]; + + assert(store_SSID < LFSTSize); + + // If the last fetched store in the store set refers to the store that + // was just issued, then invalidate the entry. + if (validLFST[store_SSID] && LFST[store_SSID] == issued_seq_num) { + DPRINTF(StoreSet, "StoreSet: store invalidated itself in LFST.\n"); + validLFST[store_SSID] = false; + } +} + +void +StoreSet::squash(InstSeqNum squashed_num, unsigned tid) +{ + DPRINTF(StoreSet, "StoreSet: Squashing until inum %i\n", + squashed_num); + + int idx; + SeqNumMapIt store_list_it = storeList.begin(); + + //@todo:Fix to only delete from correct thread + while (!storeList.empty()) { + idx = (*store_list_it).second; + + if ((*store_list_it).first <= squashed_num) { + break; + } + + bool younger = LFST[idx] > squashed_num; + + if (validLFST[idx] && younger) { + DPRINTF(StoreSet, "Squashed [sn:%lli]\n", LFST[idx]); + validLFST[idx] = false; + + storeList.erase(store_list_it++); + } else if (!validLFST[idx] && younger) { + storeList.erase(store_list_it++); + } + } +} + +void +StoreSet::clear() +{ + for (int i = 0; i < SSITSize; ++i) { + validSSIT[i] = false; + } + + for (int i = 0; i < LFSTSize; ++i) { + validLFST[i] = false; + } + + storeList.clear(); +} + +void +StoreSet::dump() +{ + cprintf("storeList.size(): %i\n", storeList.size()); + SeqNumMapIt store_list_it = storeList.begin(); + + int num = 0; + + while (store_list_it != storeList.end()) { + cprintf("%i: [sn:%lli] SSID:%i\n", + num, (*store_list_it).first, (*store_list_it).second); + num++; + store_list_it++; + } +} diff --git a/src/cpu/o3/store_set.hh b/src/cpu/o3/store_set.hh new file mode 100644 index 000000000..f5a44a1ac --- /dev/null +++ b/src/cpu/o3/store_set.hh @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#ifndef __CPU_O3_STORE_SET_HH__ +#define __CPU_O3_STORE_SET_HH__ + +#include <list> +#include <map> +#include <utility> +#include <vector> + +#include "arch/isa_traits.hh" +#include "cpu/inst_seq.hh" + +struct ltseqnum { + bool operator()(const InstSeqNum &lhs, const InstSeqNum &rhs) const + { + return lhs > rhs; + } +}; + +/** + * Implements a store set predictor for determining if memory + * instructions are dependent upon each other. See paper "Memory + * Dependence Prediction using Store Sets" by Chrysos and Emer. SSID + * stands for Store Set ID, SSIT stands for Store Set ID Table, and + * LFST is Last Fetched Store Table. + */ +class StoreSet +{ + public: + typedef unsigned SSID; + + public: + /** Default constructor. init() must be called prior to use. */ + StoreSet() { }; + + /** Creates store set predictor with given table sizes. */ + StoreSet(int SSIT_size, int LFST_size); + + /** Default destructor. */ + ~StoreSet(); + + /** Initializes the store set predictor with the given table sizes. */ + void init(int SSIT_size, int LFST_size); + + /** Records a memory ordering violation between the younger load + * and the older store. */ + void violation(Addr store_PC, Addr load_PC); + + /** Inserts a load into the store set predictor. This does nothing but + * is included in case other predictors require a similar function. + */ + void insertLoad(Addr load_PC, InstSeqNum load_seq_num); + + /** Inserts a store into the store set predictor. Updates the + * LFST if the store has a valid SSID. */ + void insertStore(Addr store_PC, InstSeqNum store_seq_num, + unsigned tid); + + /** Checks if the instruction with the given PC is dependent upon + * any store. @return Returns the sequence number of the store + * instruction this PC is dependent upon. Returns 0 if none. + */ + InstSeqNum checkInst(Addr PC); + + /** Records this PC/sequence number as issued. */ + void issued(Addr issued_PC, InstSeqNum issued_seq_num, bool is_store); + + /** Squashes for a specific thread until the given sequence number. */ + void squash(InstSeqNum squashed_num, unsigned tid); + + /** Resets all tables. */ + void clear(); + + /** Debug function to dump the contents of the store list. */ + void dump(); + + private: + /** Calculates the index into the SSIT based on the PC. */ + inline int calcIndex(Addr PC) + { return (PC >> offsetBits) & indexMask; } + + /** Calculates a Store Set ID based on the PC. */ + inline SSID calcSSID(Addr PC) + { return ((PC ^ (PC >> 10)) % LFSTSize); } + + /** The Store Set ID Table. */ + std::vector<SSID> SSIT; + + /** Bit vector to tell if the SSIT has a valid entry. */ + std::vector<bool> validSSIT; + + /** Last Fetched Store Table. */ + std::vector<InstSeqNum> LFST; + + /** Bit vector to tell if the LFST has a valid entry. */ + std::vector<bool> validLFST; + + /** Map of stores that have been inserted into the store set, but + * not yet issued or squashed. + */ + std::map<InstSeqNum, int, ltseqnum> storeList; + + typedef std::map<InstSeqNum, int, ltseqnum>::iterator SeqNumMapIt; + + /** Store Set ID Table size, in entries. */ + int SSITSize; + + /** Last Fetched Store Table size, in entries. */ + int LFSTSize; + + /** Mask to obtain the index. */ + int indexMask; + + // HACK: Hardcoded for now. + int offsetBits; +}; + +#endif // __CPU_O3_STORE_SET_HH__ diff --git a/src/cpu/o3/thread_state.hh b/src/cpu/o3/thread_state.hh new file mode 100644 index 000000000..b6535baa1 --- /dev/null +++ b/src/cpu/o3/thread_state.hh @@ -0,0 +1,102 @@ +/* + * 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_O3_THREAD_STATE_HH__ +#define __CPU_O3_THREAD_STATE_HH__ + +#include "arch/faults.hh" +#include "arch/isa_traits.hh" +#include "cpu/thread_context.hh" +#include "cpu/thread_state.hh" + +class Event; +class Process; + +#if FULL_SYSTEM +class EndQuiesceEvent; +class FunctionProfile; +class ProfileNode; +#else +class FunctionalMemory; +class Process; +#endif + +/** + * 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. + */ +template <class Impl> +struct O3ThreadState : public ThreadState { + typedef ThreadContext::Status Status; + typedef typename Impl::FullCPU FullCPU; + + private: + /** Pointer to the CPU. */ + FullCPU *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; + +#if FULL_SYSTEM + O3ThreadState(FullCPU *_cpu, int _thread_num) + : ThreadState(-1, _thread_num), + inSyscall(0), trapPending(0) + { } +#else + O3ThreadState(FullCPU *_cpu, int _thread_num, Process *_process, int _asid, + MemObject *mem) + : ThreadState(-1, _thread_num, mem, _process, _asid), + cpu(_cpu), inSyscall(0), trapPending(0) + { } +#endif + + /** Pointer to the ThreadContext of this thread. */ + ThreadContext *tc; + + /** Returns a pointer to the TC of this thread. */ + ThreadContext *getTC() { return tc; } + +#if !FULL_SYSTEM + /** Handles the syscall. */ + void syscall(int64_t callnum) { process->syscall(callnum, tc); } +#endif +}; + +#endif // __CPU_O3_THREAD_STATE_HH__ diff --git a/src/cpu/o3/tournament_pred.cc b/src/cpu/o3/tournament_pred.cc new file mode 100644 index 000000000..7cf78dcb1 --- /dev/null +++ b/src/cpu/o3/tournament_pred.cc @@ -0,0 +1,293 @@ +/* + * 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 "base/intmath.hh" +#include "cpu/o3/tournament_pred.hh" + +TournamentBP::TournamentBP(unsigned _localPredictorSize, + unsigned _localCtrBits, + unsigned _localHistoryTableSize, + unsigned _localHistoryBits, + unsigned _globalPredictorSize, + unsigned _globalCtrBits, + unsigned _globalHistoryBits, + unsigned _choicePredictorSize, + unsigned _choiceCtrBits, + unsigned _instShiftAmt) + : localPredictorSize(_localPredictorSize), + localCtrBits(_localCtrBits), + localHistoryTableSize(_localHistoryTableSize), + localHistoryBits(_localHistoryBits), + globalPredictorSize(_globalPredictorSize), + globalCtrBits(_globalCtrBits), + globalHistoryBits(_globalHistoryBits), + choicePredictorSize(_globalPredictorSize), + choiceCtrBits(_choiceCtrBits), + instShiftAmt(_instShiftAmt) +{ + if (!isPowerOf2(localPredictorSize)) { + fatal("Invalid local predictor size!\n"); + } + + //Setup the array of counters for the local predictor + localCtrs.resize(localPredictorSize); + + for (int i = 0; i < localPredictorSize; ++i) + localCtrs[i].setBits(localCtrBits); + + if (!isPowerOf2(localHistoryTableSize)) { + fatal("Invalid local history table size!\n"); + } + + //Setup the history table for the local table + localHistoryTable.resize(localHistoryTableSize); + + for (int i = 0; i < localHistoryTableSize; ++i) + localHistoryTable[i] = 0; + + // Setup the local history mask + localHistoryMask = (1 << localHistoryBits) - 1; + + if (!isPowerOf2(globalPredictorSize)) { + fatal("Invalid global predictor size!\n"); + } + + //Setup the array of counters for the global predictor + globalCtrs.resize(globalPredictorSize); + + for (int i = 0; i < globalPredictorSize; ++i) + globalCtrs[i].setBits(globalCtrBits); + + //Clear the global history + globalHistory = 0; + // Setup the global history mask + globalHistoryMask = (1 << globalHistoryBits) - 1; + + if (!isPowerOf2(choicePredictorSize)) { + fatal("Invalid choice predictor size!\n"); + } + + //Setup the array of counters for the choice predictor + choiceCtrs.resize(choicePredictorSize); + + for (int i = 0; i < choicePredictorSize; ++i) + choiceCtrs[i].setBits(choiceCtrBits); + + // @todo: Allow for different thresholds between the predictors. + threshold = (1 << (localCtrBits - 1)) - 1; + threshold = threshold / 2; +} + +inline +unsigned +TournamentBP::calcLocHistIdx(Addr &branch_addr) +{ + // Get low order bits after removing instruction offset. + return (branch_addr >> instShiftAmt) & (localHistoryTableSize - 1); +} + +inline +void +TournamentBP::updateGlobalHistTaken() +{ + globalHistory = (globalHistory << 1) | 1; + globalHistory = globalHistory & globalHistoryMask; +} + +inline +void +TournamentBP::updateGlobalHistNotTaken() +{ + globalHistory = (globalHistory << 1); + globalHistory = globalHistory & globalHistoryMask; +} + +inline +void +TournamentBP::updateLocalHistTaken(unsigned local_history_idx) +{ + localHistoryTable[local_history_idx] = + (localHistoryTable[local_history_idx] << 1) | 1; +} + +inline +void +TournamentBP::updateLocalHistNotTaken(unsigned local_history_idx) +{ + localHistoryTable[local_history_idx] = + (localHistoryTable[local_history_idx] << 1); +} + +bool +TournamentBP::lookup(Addr &branch_addr, void * &bp_history) +{ + bool local_prediction; + unsigned local_history_idx; + unsigned local_predictor_idx; + + bool global_prediction; + bool choice_prediction; + + //Lookup in the local predictor to get its branch prediction + local_history_idx = calcLocHistIdx(branch_addr); + local_predictor_idx = localHistoryTable[local_history_idx] + & localHistoryMask; + local_prediction = localCtrs[local_predictor_idx].read() > threshold; + + //Lookup in the global predictor to get its branch prediction + global_prediction = globalCtrs[globalHistory].read() > threshold; + + //Lookup in the choice predictor to see which one to use + choice_prediction = choiceCtrs[globalHistory].read() > threshold; + + // Create BPHistory and pass it back to be recorded. + BPHistory *history = new BPHistory; + history->globalHistory = globalHistory; + history->localPredTaken = local_prediction; + history->globalPredTaken = global_prediction; + history->globalUsed = choice_prediction; + bp_history = (void *)history; + + assert(globalHistory < globalPredictorSize && + local_history_idx < localPredictorSize); + + // Commented code is for doing speculative update of counters and + // all histories. + if (choice_prediction) { + if (global_prediction) { +// updateHistoriesTaken(local_history_idx); +// globalCtrs[globalHistory].increment(); +// localCtrs[local_history_idx].increment(); + updateGlobalHistTaken(); + return true; + } else { +// updateHistoriesNotTaken(local_history_idx); +// globalCtrs[globalHistory].decrement(); +// localCtrs[local_history_idx].decrement(); + updateGlobalHistNotTaken(); + return false; + } + } else { + if (local_prediction) { +// updateHistoriesTaken(local_history_idx); +// globalCtrs[globalHistory].increment(); +// localCtrs[local_history_idx].increment(); + updateGlobalHistTaken(); + return true; + } else { +// updateHistoriesNotTaken(local_history_idx); +// globalCtrs[globalHistory].decrement(); +// localCtrs[local_history_idx].decrement(); + updateGlobalHistNotTaken(); + return false; + } + } +} + +void +TournamentBP::uncondBr(void * &bp_history) +{ + // Create BPHistory and pass it back to be recorded. + BPHistory *history = new BPHistory; + history->globalHistory = globalHistory; + history->localPredTaken = true; + history->globalPredTaken = true; + bp_history = static_cast<void *>(history); + + updateGlobalHistTaken(); +} + +void +TournamentBP::update(Addr &branch_addr, bool taken, void *bp_history) +{ + unsigned local_history_idx; + unsigned local_predictor_idx; + unsigned local_predictor_hist; + + // Get the local predictor's current prediction + local_history_idx = calcLocHistIdx(branch_addr); + local_predictor_hist = localHistoryTable[local_history_idx]; + local_predictor_idx = local_predictor_hist & localHistoryMask; + + // Update the choice predictor to tell it which one was correct if + // there was a prediction. + if (bp_history) { + BPHistory *history = static_cast<BPHistory *>(bp_history); + if (history->localPredTaken != history->globalPredTaken) { + // If the local prediction matches the actual outcome, + // decerement the counter. Otherwise increment the + // counter. + if (history->localPredTaken == taken) { + choiceCtrs[globalHistory].decrement(); + } else if (history->globalPredTaken == taken){ + choiceCtrs[globalHistory].increment(); + } + } + + // We're done with this history, now delete it. + delete history; + } + + assert(globalHistory < globalPredictorSize && + local_predictor_idx < localPredictorSize); + + // Update the counters and local history with the proper + // resolution of the branch. Global history is updated + // speculatively and restored upon squash() calls, so it does not + // need to be updated. + if (taken) { + localCtrs[local_predictor_idx].increment(); + globalCtrs[globalHistory].increment(); + + updateLocalHistTaken(local_history_idx); + } else { + localCtrs[local_predictor_idx].decrement(); + globalCtrs[globalHistory].decrement(); + + updateLocalHistNotTaken(local_history_idx); + } +} + +void +TournamentBP::squash(void *bp_history) +{ + BPHistory *history = static_cast<BPHistory *>(bp_history); + + // Restore global history to state prior to this branch. + globalHistory = history->globalHistory; + + // Delete this BPHistory now that we're done with it. + delete history; +} + +#ifdef DEBUG +int +TournamentBP::BPHistory::newCount = 0; +#endif diff --git a/src/cpu/o3/tournament_pred.hh b/src/cpu/o3/tournament_pred.hh new file mode 100644 index 000000000..92402adc6 --- /dev/null +++ b/src/cpu/o3/tournament_pred.hh @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#ifndef __CPU_O3_TOURNAMENT_PRED_HH__ +#define __CPU_O3_TOURNAMENT_PRED_HH__ + +// For Addr type. +#include "arch/isa_traits.hh" +#include "cpu/o3/sat_counter.hh" +#include <vector> + +/** + * Implements a tournament branch predictor, hopefully identical to the one + * used in the 21264. It has a local predictor, which uses a local history + * table to index into a table of counters, and a global predictor, which + * uses a global history to index into a table of counters. A choice + * predictor chooses between the two. Only the global history register + * is speculatively updated, the rest are updated upon branches committing + * or misspeculating. + */ +class TournamentBP +{ + public: + /** + * Default branch predictor constructor. + */ + TournamentBP(unsigned localPredictorSize, + unsigned localCtrBits, + unsigned localHistoryTableSize, + unsigned localHistoryBits, + unsigned globalPredictorSize, + unsigned globalHistoryBits, + unsigned globalCtrBits, + unsigned choicePredictorSize, + unsigned choiceCtrBits, + unsigned instShiftAmt); + + /** + * Looks up the given address in the branch predictor and returns + * a true/false value as to whether it is taken. Also creates a + * BPHistory object to store any state it will need on squash/update. + * @param branch_addr The address of the branch to look up. + * @param bp_history Pointer that will be set to the BPHistory object. + * @return Whether or not the branch is taken. + */ + bool lookup(Addr &branch_addr, void * &bp_history); + + /** + * Records that there was an unconditional branch, and modifies + * the bp history to point to an object that has the previous + * global history stored in it. + * @param bp_history Pointer that will be set to the BPHistory object. + */ + void uncondBr(void * &bp_history); + + /** + * Updates the branch predictor with the actual result of a branch. + * @param branch_addr The address of the branch to update. + * @param taken Whether or not the branch was taken. + * @param bp_history Pointer to the BPHistory object that was created + * when the branch was predicted. + */ + void update(Addr &branch_addr, bool taken, void *bp_history); + + /** + * Restores the global branch history on a squash. + * @param bp_history Pointer to the BPHistory object that has the + * previous global branch history in it. + */ + void squash(void *bp_history); + + /** Returns the global history. */ + inline unsigned readGlobalHist() { return globalHistory; } + + private: + /** + * Returns if the branch should be taken or not, given a counter + * value. + * @param count The counter value. + */ + inline bool getPrediction(uint8_t &count); + + /** + * Returns the local history index, given a branch address. + * @param branch_addr The branch's PC address. + */ + inline unsigned calcLocHistIdx(Addr &branch_addr); + + /** Updates global history as taken. */ + inline void updateGlobalHistTaken(); + + /** Updates global history as not taken. */ + inline void updateGlobalHistNotTaken(); + + /** + * Updates local histories as taken. + * @param local_history_idx The local history table entry that + * will be updated. + */ + inline void updateLocalHistTaken(unsigned local_history_idx); + + /** + * Updates local histories as not taken. + * @param local_history_idx The local history table entry that + * will be updated. + */ + inline void updateLocalHistNotTaken(unsigned local_history_idx); + + /** + * The branch history information that is created upon predicting + * a branch. It will be passed back upon updating and squashing, + * when the BP can use this information to update/restore its + * state properly. + */ + struct BPHistory { +#ifdef DEBUG + BPHistory() + { newCount++; } + ~BPHistory() + { newCount--; } + + static int newCount; +#endif + unsigned globalHistory; + bool localPredTaken; + bool globalPredTaken; + bool globalUsed; + }; + + /** Local counters. */ + std::vector<SatCounter> localCtrs; + + /** Size of the local predictor. */ + unsigned localPredictorSize; + + /** Number of bits of the local predictor's counters. */ + unsigned localCtrBits; + + /** Array of local history table entries. */ + std::vector<unsigned> localHistoryTable; + + /** Size of the local history table. */ + unsigned localHistoryTableSize; + + /** Number of bits for each entry of the local history table. + * @todo Doesn't this come from the size of the local predictor? + */ + unsigned localHistoryBits; + + /** Mask to get the proper local history. */ + unsigned localHistoryMask; + + /** Array of counters that make up the global predictor. */ + std::vector<SatCounter> globalCtrs; + + /** Size of the global predictor. */ + unsigned globalPredictorSize; + + /** Number of bits of the global predictor's counters. */ + unsigned globalCtrBits; + + /** Global history register. */ + unsigned globalHistory; + + /** Number of bits for the global history. */ + unsigned globalHistoryBits; + + /** Mask to get the proper global history. */ + unsigned globalHistoryMask; + + /** Array of counters that make up the choice predictor. */ + std::vector<SatCounter> choiceCtrs; + + /** Size of the choice predictor (identical to the global predictor). */ + unsigned choicePredictorSize; + + /** Number of bits of the choice predictor's counters. */ + unsigned choiceCtrBits; + + /** Number of bits to shift the instruction over to get rid of the word + * offset. + */ + unsigned instShiftAmt; + + /** Threshold for the counter value; above the threshold is taken, + * equal to or below the threshold is not taken. + */ + unsigned threshold; +}; + +#endif // __CPU_O3_TOURNAMENT_PRED_HH__ diff --git a/src/cpu/op_class.cc b/src/cpu/op_class.cc new file mode 100644 index 000000000..f7ef49c0f --- /dev/null +++ b/src/cpu/op_class.cc @@ -0,0 +1,52 @@ +/* + * Copyright (c) 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 Reinhardt + */ + +#include "cpu/op_class.hh" + +/** OpClass enum -> description string */ +const char * +opClassStrings[Num_OpClasses] = +{ + "(null)", + "IntAlu", + "IntMult", + "IntDiv", + "FloatAdd", + "FloatCmp", + "FloatCvt", + "FloatMult", + "FloatDiv", + "FloatSqrt", + "MemRead", + "MemWrite", + "IprAccess", + "InstPrefetch" +}; + diff --git a/src/cpu/op_class.hh b/src/cpu/op_class.hh new file mode 100644 index 000000000..71819c904 --- /dev/null +++ b/src/cpu/op_class.hh @@ -0,0 +1,67 @@ +/* + * Copyright (c) 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 Reinhardt + * Nathan Binkert + */ + +#ifndef __CPU__OP_CLASS_HH__ +#define __CPU__OP_CLASS_HH__ + +/** + * @file + * Definition of operation classes. + */ + +/** + * Instruction operation classes. These classes are used for + * assigning instructions to functional units. + */ +enum OpClass { + No_OpClass = 0, ///< Instruction does not use a functional unit + IntAluOp, ///< Integer ALU operaton (add/sub/logical) + IntMultOp, ///< Integer multiply + IntDivOp, ///< Integer divide + FloatAddOp, ///< Floating point add/subtract + FloatCmpOp, ///< Floating point comparison + FloatCvtOp, ///< Floating point<->integer conversion + FloatMultOp, ///< Floating point multiply + FloatDivOp, ///< Floating point divide + FloatSqrtOp, ///< Floating point square root + MemReadOp, ///< Memory read port + MemWriteOp, ///< Memory write port + IprAccessOp, ///< Internal Processor Register read/write port + InstPrefetchOp, ///< Instruction prefetch port (on I-cache) + Num_OpClasses ///< Total number of operation classes +}; + +/** + * Array mapping OpClass enum values to strings. Defined in op_class.cc. + */ +extern const char *opClassStrings[Num_OpClasses]; + +#endif // __CPU__OP_CLASS_HH__ diff --git a/src/cpu/ozone/back_end.cc b/src/cpu/ozone/back_end.cc new file mode 100644 index 000000000..a61a00c84 --- /dev/null +++ b/src/cpu/ozone/back_end.cc @@ -0,0 +1,34 @@ +/* + * 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 "cpu/ozone/back_end_impl.hh" +#include "cpu/ozone/ozone_impl.hh" + +//template class BackEnd<OzoneImpl>; diff --git a/src/cpu/ozone/back_end.hh b/src/cpu/ozone/back_end.hh new file mode 100644 index 000000000..9bab6a964 --- /dev/null +++ b/src/cpu/ozone/back_end.hh @@ -0,0 +1,543 @@ +/* + * 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_OZONE_BACK_END_HH__ +#define __CPU_OZONE_BACK_END_HH__ + +#include <list> +#include <queue> +#include <string> + +#include "arch/faults.hh" +#include "base/timebuf.hh" +#include "cpu/inst_seq.hh" +#include "cpu/ozone/rename_table.hh" +#include "cpu/ozone/thread_state.hh" +#include "mem/request.hh" +#include "sim/eventq.hh" + +class ThreadContext; + +template <class Impl> +class OzoneThreadState; + +template <class Impl> +class BackEnd +{ + public: + typedef OzoneThreadState<Impl> Thread; + + typedef typename Impl::Params Params; + typedef typename Impl::DynInst DynInst; + typedef typename Impl::DynInstPtr DynInstPtr; + typedef typename Impl::FullCPU FullCPU; + typedef typename Impl::FrontEnd FrontEnd; + typedef typename Impl::FullCPU::CommStruct CommStruct; + + struct SizeStruct { + int size; + }; + + typedef SizeStruct DispatchToIssue; + typedef SizeStruct IssueToExec; + typedef SizeStruct ExecToCommit; + typedef SizeStruct Writeback; + + TimeBuffer<DispatchToIssue> d2i; + typename TimeBuffer<DispatchToIssue>::wire instsToDispatch; + TimeBuffer<IssueToExec> i2e; + typename TimeBuffer<IssueToExec>::wire instsToExecute; + TimeBuffer<ExecToCommit> e2c; + TimeBuffer<Writeback> numInstsToWB; + + TimeBuffer<CommStruct> *comm; + typename TimeBuffer<CommStruct>::wire toIEW; + typename TimeBuffer<CommStruct>::wire fromCommit; + + class InstQueue { + enum queue { + NonSpec, + IQ, + ToBeScheduled, + ReadyList, + ReplayList + }; + struct pqCompare { + bool operator() (const DynInstPtr &lhs, const DynInstPtr &rhs) const + { + return lhs->seqNum > rhs->seqNum; + } + }; + public: + InstQueue(Params *params); + + std::string name() const; + + void regStats(); + + void setIssueExecQueue(TimeBuffer<IssueToExec> *i2e_queue); + + void setBE(BackEnd *_be) { be = _be; } + + void insert(DynInstPtr &inst); + + void scheduleReadyInsts(); + + void scheduleNonSpec(const InstSeqNum &sn); + + DynInstPtr getReadyInst(); + + void commit(const InstSeqNum &sn) {} + + void squash(const InstSeqNum &sn); + + int wakeDependents(DynInstPtr &inst); + + /** Tells memory dependence unit that a memory instruction needs to be + * rescheduled. It will re-execute once replayMemInst() is called. + */ + void rescheduleMemInst(DynInstPtr &inst); + + /** Re-executes all rescheduled memory instructions. */ + void replayMemInst(DynInstPtr &inst); + + /** Completes memory instruction. */ + void completeMemInst(DynInstPtr &inst); + + void violation(DynInstPtr &inst, DynInstPtr &violation) { } + + bool isFull() { return numInsts >= size; } + + void dumpInsts(); + + private: + bool find(queue q, typename std::list<DynInstPtr>::iterator it); + BackEnd *be; + TimeBuffer<IssueToExec> *i2e; + typename TimeBuffer<IssueToExec>::wire numIssued; + typedef typename std::list<DynInstPtr> InstList; + typedef typename std::list<DynInstPtr>::iterator InstListIt; + typedef typename std::priority_queue<DynInstPtr, std::vector<DynInstPtr>, pqCompare> ReadyInstQueue; + // Not sure I need the IQ list; it just needs to be a count. + InstList iq; + InstList toBeScheduled; + InstList readyList; + InstList nonSpec; + InstList replayList; + ReadyInstQueue readyQueue; + public: + int size; + int numInsts; + int width; + + Stats::VectorDistribution<> occ_dist; + + Stats::Vector<> inst_count; + Stats::Vector<> peak_inst_count; + Stats::Scalar<> empty_count; + Stats::Scalar<> current_count; + Stats::Scalar<> fullCount; + + Stats::Formula occ_rate; + Stats::Formula avg_residency; + Stats::Formula empty_rate; + Stats::Formula full_rate; + }; + + /** LdWriteback event for a load completion. */ + class LdWritebackEvent : public Event { + private: + /** Instruction that is writing back data to the register file. */ + DynInstPtr inst; + /** Pointer to IEW stage. */ + BackEnd *be; + + public: + /** Constructs a load writeback event. */ + LdWritebackEvent(DynInstPtr &_inst, BackEnd *be); + + /** Processes writeback event. */ + virtual void process(); + /** Returns the description of the writeback event. */ + virtual const char *description(); + }; + + BackEnd(Params *params); + + std::string name() const; + + void regStats(); + + void setCPU(FullCPU *cpu_ptr) + { cpu = cpu_ptr; } + + void setFrontEnd(FrontEnd *front_end_ptr) + { frontEnd = front_end_ptr; } + + void setTC(ThreadContext *tc_ptr) + { tc = tc_ptr; } + + void setThreadState(Thread *thread_ptr) + { thread = thread_ptr; } + + void setCommBuffer(TimeBuffer<CommStruct> *_comm); + + void tick(); + void squash(); + void squashFromTC(); + bool tcSquash; + + template <class T> + Fault read(RequestPtr req, T &data, int load_idx); + + template <class T> + Fault write(RequestPtr req, T &data, int store_idx); + + Addr readCommitPC() { return commitPC; } + + Addr commitPC; + + bool robEmpty() { return instList.empty(); } + + bool isFull() { return numInsts >= numROBEntries; } + bool isBlocked() { return status == Blocked || dispatchStatus == Blocked; } + + /** Tells memory dependence unit that a memory instruction needs to be + * rescheduled. It will re-execute once replayMemInst() is called. + */ + void rescheduleMemInst(DynInstPtr &inst) + { IQ.rescheduleMemInst(inst); } + + /** Re-executes all rescheduled memory instructions. */ + void replayMemInst(DynInstPtr &inst) + { IQ.replayMemInst(inst); } + + /** Completes memory instruction. */ + void completeMemInst(DynInstPtr &inst) + { IQ.completeMemInst(inst); } + + void fetchFault(Fault &fault); + + private: + void updateStructures(); + void dispatchInsts(); + void dispatchStall(); + void checkDispatchStatus(); + void scheduleReadyInsts(); + void executeInsts(); + void commitInsts(); + void addToIQ(DynInstPtr &inst); + void addToLSQ(DynInstPtr &inst); + void instToCommit(DynInstPtr &inst); + void writebackInsts(); + bool commitInst(int inst_num); + void squash(const InstSeqNum &sn); + void squashDueToBranch(DynInstPtr &inst); + void squashDueToMemBlocked(DynInstPtr &inst); + void updateExeInstStats(DynInstPtr &inst); + void updateComInstStats(DynInstPtr &inst); + + public: + FullCPU *cpu; + + FrontEnd *frontEnd; + + ThreadContext *tc; + + Thread *thread; + + enum Status { + Running, + Idle, + DcacheMissStall, + DcacheMissComplete, + Blocked + }; + + Status status; + + Status dispatchStatus; + + Counter funcExeInst; + + private: +// typedef typename Impl::InstQueue InstQueue; + + InstQueue IQ; + + typedef typename Impl::LdstQueue LdstQueue; + + LdstQueue LSQ; + public: + RenameTable<Impl> commitRenameTable; + + RenameTable<Impl> renameTable; + private: + class DCacheCompletionEvent : public Event + { + private: + BackEnd *be; + + public: + DCacheCompletionEvent(BackEnd *_be); + + virtual void process(); + virtual const char *description(); + }; + + friend class DCacheCompletionEvent; + + DCacheCompletionEvent cacheCompletionEvent; + + MemInterface *dcacheInterface; + + Request *memReq; + + // General back end width. Used if the more specific isn't given. + int width; + + // Dispatch width. + int dispatchWidth; + int numDispatchEntries; + int dispatchSize; + + int issueWidth; + + // Writeback width + int wbWidth; + + // Commit width + int commitWidth; + + /** Index into queue of instructions being written back. */ + unsigned wbNumInst; + + /** Cycle number within the queue of instructions being written + * back. Used in case there are too many instructions writing + * back at the current cycle and writesbacks need to be scheduled + * for the future. See comments in instToCommit(). + */ + unsigned wbCycle; + + int numROBEntries; + int numInsts; + + bool squashPending; + InstSeqNum squashSeqNum; + Addr squashNextPC; + + Fault faultFromFetch; + + private: + typedef typename std::list<DynInstPtr>::iterator InstListIt; + + std::list<DynInstPtr> instList; + std::list<DynInstPtr> dispatch; + std::list<DynInstPtr> writeback; + + int latency; + + int squashLatency; + + bool exactFullStall; + + bool fetchRedirect[Impl::MaxThreads]; + + // number of cycles stalled for D-cache misses +/* Stats::Scalar<> dcacheStallCycles; + Counter lastDcacheStall; +*/ + Stats::Vector<> rob_cap_events; + Stats::Vector<> rob_cap_inst_count; + Stats::Vector<> iq_cap_events; + Stats::Vector<> iq_cap_inst_count; + // total number of instructions executed + Stats::Vector<> exe_inst; + Stats::Vector<> exe_swp; + Stats::Vector<> exe_nop; + Stats::Vector<> exe_refs; + Stats::Vector<> exe_loads; + Stats::Vector<> exe_branches; + + Stats::Vector<> issued_ops; + + // total number of loads forwaded from LSQ stores + Stats::Vector<> lsq_forw_loads; + + // total number of loads ignored due to invalid addresses + Stats::Vector<> inv_addr_loads; + + // total number of software prefetches ignored due to invalid addresses + Stats::Vector<> inv_addr_swpfs; + // ready loads blocked due to memory disambiguation + Stats::Vector<> lsq_blocked_loads; + + Stats::Scalar<> lsqInversion; + + Stats::Vector<> n_issued_dist; + Stats::VectorDistribution<> issue_delay_dist; + + Stats::VectorDistribution<> queue_res_dist; +/* + Stats::Vector<> stat_fu_busy; + Stats::Vector2d<> stat_fuBusy; + Stats::Vector<> dist_unissued; + Stats::Vector2d<> stat_issued_inst_type; + + Stats::Formula misspec_cnt; + Stats::Formula misspec_ipc; + Stats::Formula issue_rate; + Stats::Formula issue_stores; + Stats::Formula issue_op_rate; + Stats::Formula fu_busy_rate; + Stats::Formula commit_stores; + Stats::Formula commit_ipc; + Stats::Formula commit_ipb; + Stats::Formula lsq_inv_rate; +*/ + Stats::Vector<> writeback_count; + Stats::Vector<> producer_inst; + Stats::Vector<> consumer_inst; + Stats::Vector<> wb_penalized; + + Stats::Formula wb_rate; + Stats::Formula wb_fanout; + Stats::Formula wb_penalized_rate; + + // total number of instructions committed + Stats::Vector<> stat_com_inst; + Stats::Vector<> stat_com_swp; + Stats::Vector<> stat_com_refs; + Stats::Vector<> stat_com_loads; + Stats::Vector<> stat_com_membars; + Stats::Vector<> stat_com_branches; + + Stats::Distribution<> n_committed_dist; + + Stats::Scalar<> commit_eligible_samples; + Stats::Vector<> commit_eligible; + + Stats::Scalar<> ROB_fcount; + Stats::Formula ROB_full_rate; + + Stats::Vector<> ROB_count; // cumulative ROB occupancy + Stats::Formula ROB_occ_rate; + Stats::VectorDistribution<> ROB_occ_dist; + public: + void dumpInsts(); +}; + +template <class Impl> +template <class T> +Fault +BackEnd<Impl>::read(RequestPtr req, T &data, int load_idx) +{ +/* memReq->reset(addr, sizeof(T), flags); + + // translate to physical address + Fault fault = cpu->translateDataReadReq(memReq); + + // if we have a cache, do cache access too + if (fault == NoFault && dcacheInterface) { + memReq->cmd = Read; + memReq->completionEvent = NULL; + memReq->time = curTick; + memReq->flags &= ~INST_READ; + MemAccessResult result = dcacheInterface->access(memReq); + + // Ugly hack to get an event scheduled *only* if the access is + // a miss. We really should add first-class support for this + // at some point. + if (result != MA_HIT && dcacheInterface->doEvents()) { + // Fix this hack for keeping funcExeInst correct with loads that + // are executed twice. + --funcExeInst; + + memReq->completionEvent = &cacheCompletionEvent; + lastDcacheStall = curTick; +// unscheduleTickEvent(); +// status = DcacheMissStall; + DPRINTF(OzoneCPU, "Dcache miss stall!\n"); + } else { + // do functional access + fault = thread->mem->read(memReq, data); + + } + } +*/ +/* + if (!dcacheInterface && (memReq->flags & UNCACHEABLE)) + recordEvent("Uncached Read"); +*/ + return LSQ.read(req, data, load_idx); +} + +template <class Impl> +template <class T> +Fault +BackEnd<Impl>::write(RequestPtr req, T &data, int store_idx) +{ +/* + memReq->reset(addr, sizeof(T), flags); + + // translate to physical address + Fault fault = cpu->translateDataWriteReq(memReq); + + if (fault == NoFault && dcacheInterface) { + memReq->cmd = Write; + memcpy(memReq->data,(uint8_t *)&data,memReq->size); + memReq->completionEvent = NULL; + memReq->time = curTick; + memReq->flags &= ~INST_READ; + MemAccessResult result = dcacheInterface->access(memReq); + + // Ugly hack to get an event scheduled *only* if the access is + // a miss. We really should add first-class support for this + // at some point. + if (result != MA_HIT && dcacheInterface->doEvents()) { + memReq->completionEvent = &cacheCompletionEvent; + lastDcacheStall = curTick; +// unscheduleTickEvent(); +// status = DcacheMissStall; + DPRINTF(OzoneCPU, "Dcache miss stall!\n"); + } + } + + if (res && (fault == NoFault)) + *res = memReq->result; + */ +/* + if (!dcacheInterface && (memReq->flags & UNCACHEABLE)) + recordEvent("Uncached Write"); +*/ + return LSQ.write(req, data, store_idx); +} + +#endif // __CPU_OZONE_BACK_END_HH__ diff --git a/src/cpu/ozone/back_end_impl.hh b/src/cpu/ozone/back_end_impl.hh new file mode 100644 index 000000000..ac3218c02 --- /dev/null +++ b/src/cpu/ozone/back_end_impl.hh @@ -0,0 +1,1933 @@ +/* + * 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 "encumbered/cpu/full/op_class.hh" +#include "cpu/ozone/back_end.hh" + +template <class Impl> +BackEnd<Impl>::InstQueue::InstQueue(Params *params) + : size(params->numIQEntries), numInsts(0), width(params->issueWidth) +{ +} + +template <class Impl> +std::string +BackEnd<Impl>::InstQueue::name() const +{ + return be->name() + ".iq"; +} + +template <class Impl> +void +BackEnd<Impl>::InstQueue::regStats() +{ + using namespace Stats; + + occ_dist + .init(1, 0, size, 2) + .name(name() + "occ_dist") + .desc("IQ Occupancy per cycle") + .flags(total | cdf) + ; + + inst_count + .init(1) + .name(name() + "cum_num_insts") + .desc("Total occupancy") + .flags(total) + ; + + peak_inst_count + .init(1) + .name(name() + "peak_occupancy") + .desc("Peak IQ occupancy") + .flags(total) + ; + + current_count + .name(name() + "current_count") + .desc("Occupancy this cycle") + ; + + empty_count + .name(name() + "empty_count") + .desc("Number of empty cycles") + ; + + fullCount + .name(name() + "full_count") + .desc("Number of full cycles") + ; + + + occ_rate + .name(name() + "occ_rate") + .desc("Average occupancy") + .flags(total) + ; + occ_rate = inst_count / be->cpu->numCycles; + + avg_residency + .name(name() + "avg_residency") + .desc("Average IQ residency") + .flags(total) + ; + avg_residency = occ_rate / be->cpu->numCycles; + + empty_rate + .name(name() + "empty_rate") + .desc("Fraction of cycles empty") + ; + empty_rate = 100 * empty_count / be->cpu->numCycles; + + full_rate + .name(name() + "full_rate") + .desc("Fraction of cycles full") + ; + full_rate = 100 * fullCount / be->cpu->numCycles; +} + +template <class Impl> +void +BackEnd<Impl>::InstQueue::setIssueExecQueue(TimeBuffer<IssueToExec> *i2e_queue) +{ + i2e = i2e_queue; + numIssued = i2e->getWire(0); +} + +template <class Impl> +void +BackEnd<Impl>::InstQueue::insert(DynInstPtr &inst) +{ + numInsts++; + inst_count[0]++; + if (!inst->isNonSpeculative()) { + DPRINTF(BE, "Instruction [sn:%lli] added to IQ\n", inst->seqNum); + if (inst->readyToIssue()) { + toBeScheduled.push_front(inst); + inst->iqIt = toBeScheduled.begin(); + inst->iqItValid = true; + } else { + iq.push_front(inst); + inst->iqIt = iq.begin(); + inst->iqItValid = true; + } + } else { + DPRINTF(BE, "Nonspeculative instruction [sn:%lli] added to IQ\n", inst->seqNum); + nonSpec.push_front(inst); + inst->iqIt = nonSpec.begin(); + inst->iqItValid = true; + } +} + +template <class Impl> +void +BackEnd<Impl>::InstQueue::scheduleReadyInsts() +{ + int scheduled = numIssued->size; + InstListIt iq_it = --toBeScheduled.end(); + InstListIt iq_end_it = toBeScheduled.end(); + + while (iq_it != iq_end_it && scheduled < width) { +// if ((*iq_it)->readyToIssue()) { + DPRINTF(BE, "Instruction [sn:%lli] PC:%#x is ready\n", + (*iq_it)->seqNum, (*iq_it)->readPC()); + readyQueue.push(*iq_it); + readyList.push_front(*iq_it); + + (*iq_it)->iqIt = readyList.begin(); + + toBeScheduled.erase(iq_it--); + + ++scheduled; +// } else { +// iq_it++; +// } + } + + numIssued->size+= scheduled; +} + +template <class Impl> +void +BackEnd<Impl>::InstQueue::scheduleNonSpec(const InstSeqNum &sn) +{ +/* + InstListIt non_spec_it = nonSpec.begin(); + InstListIt non_spec_end_it = nonSpec.end(); + + while ((*non_spec_it)->seqNum != sn) { + non_spec_it++; + assert(non_spec_it != non_spec_end_it); + } +*/ + DynInstPtr inst = nonSpec.back(); + + DPRINTF(BE, "Nonspeculative instruction [sn:%lli] scheduled\n", inst->seqNum); + + assert(inst->seqNum == sn); + + assert(find(NonSpec, inst->iqIt)); + nonSpec.erase(inst->iqIt); + readyList.push_front(inst); + inst->iqIt = readyList.begin(); + readyQueue.push(inst); + numIssued->size++; +} + +template <class Impl> +typename Impl::DynInstPtr +BackEnd<Impl>::InstQueue::getReadyInst() +{ + assert(!readyList.empty()); + + DynInstPtr inst = readyQueue.top(); + readyQueue.pop(); + assert(find(ReadyList, inst->iqIt)); + readyList.erase(inst->iqIt); + inst->iqItValid = false; +// if (!inst->isMemRef()) + --numInsts; + return inst; +} + +template <class Impl> +void +BackEnd<Impl>::InstQueue::squash(const InstSeqNum &sn) +{ + InstListIt iq_it = iq.begin(); + InstListIt iq_end_it = iq.end(); + + while (iq_it != iq_end_it && (*iq_it)->seqNum > sn) { + DPRINTF(BE, "Instruction [sn:%lli] removed from IQ\n", (*iq_it)->seqNum); + (*iq_it)->iqItValid = false; + iq.erase(iq_it++); + --numInsts; + } + + iq_it = nonSpec.begin(); + iq_end_it = nonSpec.end(); + + while (iq_it != iq_end_it && (*iq_it)->seqNum > sn) { + DPRINTF(BE, "Instruction [sn:%lli] removed from IQ\n", (*iq_it)->seqNum); + (*iq_it)->iqItValid = false; + nonSpec.erase(iq_it++); + --numInsts; + } + + iq_it = replayList.begin(); + iq_end_it = replayList.end(); + + while (iq_it != iq_end_it) { + if ((*iq_it)->seqNum > sn) { + DPRINTF(BE, "Instruction [sn:%lli] removed from IQ\n", (*iq_it)->seqNum); + (*iq_it)->iqItValid = false; + replayList.erase(iq_it++); + --numInsts; + } else { + iq_it++; + } + } + + assert(numInsts >= 0); +/* + InstListIt ready_it = readyList.begin(); + InstListIt ready_end_it = readyList.end(); + + while (ready_it != ready_end_it) { + if ((*ready_it)->seqNum > sn) { + readyList.erase(ready_it++); + } else { + ready_it++; + } + } +*/ +} + +template <class Impl> +int +BackEnd<Impl>::InstQueue::wakeDependents(DynInstPtr &inst) +{ + assert(!inst->isSquashed()); + std::vector<DynInstPtr> &dependents = inst->getDependents(); + int num_outputs = dependents.size(); + + DPRINTF(BE, "Waking instruction [sn:%lli] dependents in IQ\n", inst->seqNum); + + for (int i = 0; i < num_outputs; i++) { + DynInstPtr dep_inst = dependents[i]; + dep_inst->markSrcRegReady(); + DPRINTF(BE, "Marking source reg ready [sn:%lli] in IQ\n", dep_inst->seqNum); + + if (dep_inst->readyToIssue() && dep_inst->iqItValid) { + if (dep_inst->isNonSpeculative()) { + assert(find(NonSpec, dep_inst->iqIt)); + nonSpec.erase(dep_inst->iqIt); + } else { + assert(find(IQ, dep_inst->iqIt)); + iq.erase(dep_inst->iqIt); + } + + toBeScheduled.push_front(dep_inst); + dep_inst->iqIt = toBeScheduled.begin(); + } + } + return num_outputs; +} + +template <class Impl> +void +BackEnd<Impl>::InstQueue::rescheduleMemInst(DynInstPtr &inst) +{ + DPRINTF(BE, "Rescheduling memory instruction [sn:%lli]\n", inst->seqNum); + assert(!inst->iqItValid); + replayList.push_front(inst); + inst->iqIt = replayList.begin(); + inst->iqItValid = true; + ++numInsts; +} + +template <class Impl> +void +BackEnd<Impl>::InstQueue::replayMemInst(DynInstPtr &inst) +{ + DPRINTF(BE, "Replaying memory instruction [sn:%lli]\n", inst->seqNum); + assert(find(ReplayList, inst->iqIt)); + InstListIt iq_it = --replayList.end(); + InstListIt iq_end_it = replayList.end(); + while (iq_it != iq_end_it) { + DynInstPtr rescheduled_inst = (*iq_it); + + DPRINTF(BE, "Memory instruction [sn:%lli] also replayed\n", inst->seqNum); + replayList.erase(iq_it--); + toBeScheduled.push_front(rescheduled_inst); + rescheduled_inst->iqIt = toBeScheduled.begin(); + } +} + +template <class Impl> +void +BackEnd<Impl>::InstQueue::completeMemInst(DynInstPtr &inst) +{ + panic("Not implemented."); +} + +template <class Impl> +bool +BackEnd<Impl>::InstQueue::find(queue q, InstListIt it) +{ + InstListIt iq_it, iq_end_it; + switch(q) { + case NonSpec: + iq_it = nonSpec.begin(); + iq_end_it = nonSpec.end(); + break; + case IQ: + iq_it = iq.begin(); + iq_end_it = iq.end(); + break; + case ToBeScheduled: + iq_it = toBeScheduled.begin(); + iq_end_it = toBeScheduled.end(); + break; + case ReadyList: + iq_it = readyList.begin(); + iq_end_it = readyList.end(); + break; + case ReplayList: + iq_it = replayList.begin(); + iq_end_it = replayList.end(); + } + + while (iq_it != it && iq_it != iq_end_it) { + iq_it++; + } + if (iq_it == it) { + return true; + } else { + return false; + } +} + +template <class Impl> +void +BackEnd<Impl>::InstQueue::dumpInsts() +{ + cprintf("IQ size: %i\n", iq.size()); + + InstListIt inst_list_it = --iq.end(); + + int num = 0; + int valid_num = 0; + while (inst_list_it != iq.end()) + { + cprintf("Instruction:%i\n", + num); + if (!(*inst_list_it)->isSquashed()) { + if (!(*inst_list_it)->isIssued()) { + ++valid_num; + cprintf("Count:%i\n", valid_num); + } else if ((*inst_list_it)->isMemRef() && + !(*inst_list_it)->memOpDone) { + // Loads that have not been marked as executed still count + // towards the total instructions. + ++valid_num; + cprintf("Count:%i\n", valid_num); + } + } + + cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" + "Issued:%i\nSquashed:%i\n", + (*inst_list_it)->readPC(), + (*inst_list_it)->seqNum, + (*inst_list_it)->threadNumber, + (*inst_list_it)->isIssued(), + (*inst_list_it)->isSquashed()); + + if ((*inst_list_it)->isMemRef()) { + cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone); + } + + cprintf("\n"); + + inst_list_it--; + ++num; + } + + cprintf("nonSpec size: %i\n", nonSpec.size()); + + inst_list_it = --nonSpec.end(); + + while (inst_list_it != nonSpec.end()) + { + cprintf("Instruction:%i\n", + num); + if (!(*inst_list_it)->isSquashed()) { + if (!(*inst_list_it)->isIssued()) { + ++valid_num; + cprintf("Count:%i\n", valid_num); + } else if ((*inst_list_it)->isMemRef() && + !(*inst_list_it)->memOpDone) { + // Loads that have not been marked as executed still count + // towards the total instructions. + ++valid_num; + cprintf("Count:%i\n", valid_num); + } + } + + cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" + "Issued:%i\nSquashed:%i\n", + (*inst_list_it)->readPC(), + (*inst_list_it)->seqNum, + (*inst_list_it)->threadNumber, + (*inst_list_it)->isIssued(), + (*inst_list_it)->isSquashed()); + + if ((*inst_list_it)->isMemRef()) { + cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone); + } + + cprintf("\n"); + + inst_list_it--; + ++num; + } + + cprintf("toBeScheduled size: %i\n", toBeScheduled.size()); + + inst_list_it = --toBeScheduled.end(); + + while (inst_list_it != toBeScheduled.end()) + { + cprintf("Instruction:%i\n", + num); + if (!(*inst_list_it)->isSquashed()) { + if (!(*inst_list_it)->isIssued()) { + ++valid_num; + cprintf("Count:%i\n", valid_num); + } else if ((*inst_list_it)->isMemRef() && + !(*inst_list_it)->memOpDone) { + // Loads that have not been marked as executed still count + // towards the total instructions. + ++valid_num; + cprintf("Count:%i\n", valid_num); + } + } + + cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" + "Issued:%i\nSquashed:%i\n", + (*inst_list_it)->readPC(), + (*inst_list_it)->seqNum, + (*inst_list_it)->threadNumber, + (*inst_list_it)->isIssued(), + (*inst_list_it)->isSquashed()); + + if ((*inst_list_it)->isMemRef()) { + cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone); + } + + cprintf("\n"); + + inst_list_it--; + ++num; + } + + cprintf("readyList size: %i\n", readyList.size()); + + inst_list_it = --readyList.end(); + + while (inst_list_it != readyList.end()) + { + cprintf("Instruction:%i\n", + num); + if (!(*inst_list_it)->isSquashed()) { + if (!(*inst_list_it)->isIssued()) { + ++valid_num; + cprintf("Count:%i\n", valid_num); + } else if ((*inst_list_it)->isMemRef() && + !(*inst_list_it)->memOpDone) { + // Loads that have not been marked as executed still count + // towards the total instructions. + ++valid_num; + cprintf("Count:%i\n", valid_num); + } + } + + cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" + "Issued:%i\nSquashed:%i\n", + (*inst_list_it)->readPC(), + (*inst_list_it)->seqNum, + (*inst_list_it)->threadNumber, + (*inst_list_it)->isIssued(), + (*inst_list_it)->isSquashed()); + + if ((*inst_list_it)->isMemRef()) { + cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone); + } + + cprintf("\n"); + + inst_list_it--; + ++num; + } +} + +template<class Impl> +BackEnd<Impl>::LdWritebackEvent::LdWritebackEvent(DynInstPtr &_inst, + BackEnd<Impl> *_be) + : Event(&mainEventQueue), inst(_inst), be(_be) +{ + this->setFlags(Event::AutoDelete); +} + +template<class Impl> +void +BackEnd<Impl>::LdWritebackEvent::process() +{ + DPRINTF(BE, "Load writeback event [sn:%lli]\n", inst->seqNum); +// DPRINTF(Activity, "Activity: Ld Writeback event [sn:%lli]\n", inst->seqNum); + + //iewStage->ldstQueue.removeMSHR(inst->threadNumber,inst->seqNum); + +// iewStage->wakeCPU(); + + if (inst->isSquashed()) { + inst = NULL; + return; + } + + if (!inst->isExecuted()) { + inst->setExecuted(); + + // Execute again to copy data to proper place. + inst->completeAcc(); + } + + // Need to insert instruction into queue to commit + be->instToCommit(inst); + + //wroteToTimeBuffer = true; +// iewStage->activityThisCycle(); + + inst = NULL; +} + +template<class Impl> +const char * +BackEnd<Impl>::LdWritebackEvent::description() +{ + return "Load writeback event"; +} + + +template <class Impl> +BackEnd<Impl>::DCacheCompletionEvent::DCacheCompletionEvent(BackEnd *_be) + : Event(&mainEventQueue, CPU_Tick_Pri), be(_be) +{ +} + +template <class Impl> +void +BackEnd<Impl>::DCacheCompletionEvent::process() +{ +} + +template <class Impl> +const char * +BackEnd<Impl>::DCacheCompletionEvent::description() +{ + return "Cache completion event"; +} + +template <class Impl> +BackEnd<Impl>::BackEnd(Params *params) + : d2i(5, 5), i2e(5, 5), e2c(5, 5), numInstsToWB(5, 5), + xcSquash(false), IQ(params), + cacheCompletionEvent(this), width(params->backEndWidth), + exactFullStall(true) +{ + numROBEntries = params->numROBEntries; + numInsts = 0; + numDispatchEntries = 32; + IQ.setBE(this); + LSQ.setBE(this); + + // Setup IQ and LSQ with their parameters here. + instsToDispatch = d2i.getWire(-1); + + instsToExecute = i2e.getWire(-1); + + IQ.setIssueExecQueue(&i2e); + + dispatchWidth = params->dispatchWidth ? params->dispatchWidth : width; + issueWidth = params->issueWidth ? params->issueWidth : width; + wbWidth = params->wbWidth ? params->wbWidth : width; + commitWidth = params->commitWidth ? params->commitWidth : width; + + LSQ.init(params, params->LQEntries, params->SQEntries, 0); + + dispatchStatus = Running; +} + +template <class Impl> +std::string +BackEnd<Impl>::name() const +{ + return cpu->name() + ".backend"; +} + +template <class Impl> +void +BackEnd<Impl>::regStats() +{ + using namespace Stats; + rob_cap_events + .init(cpu->number_of_threads) + .name(name() + ".ROB:cap_events") + .desc("number of cycles where ROB cap was active") + .flags(total) + ; + + rob_cap_inst_count + .init(cpu->number_of_threads) + .name(name() + ".ROB:cap_inst") + .desc("number of instructions held up by ROB cap") + .flags(total) + ; + + iq_cap_events + .init(cpu->number_of_threads) + .name(name() +".IQ:cap_events" ) + .desc("number of cycles where IQ cap was active") + .flags(total) + ; + + iq_cap_inst_count + .init(cpu->number_of_threads) + .name(name() + ".IQ:cap_inst") + .desc("number of instructions held up by IQ cap") + .flags(total) + ; + + + exe_inst + .init(cpu->number_of_threads) + .name(name() + ".ISSUE:count") + .desc("number of insts issued") + .flags(total) + ; + + exe_swp + .init(cpu->number_of_threads) + .name(name() + ".ISSUE:swp") + .desc("number of swp insts issued") + .flags(total) + ; + + exe_nop + .init(cpu->number_of_threads) + .name(name() + ".ISSUE:nop") + .desc("number of nop insts issued") + .flags(total) + ; + + exe_refs + .init(cpu->number_of_threads) + .name(name() + ".ISSUE:refs") + .desc("number of memory reference insts issued") + .flags(total) + ; + + exe_loads + .init(cpu->number_of_threads) + .name(name() + ".ISSUE:loads") + .desc("number of load insts issued") + .flags(total) + ; + + exe_branches + .init(cpu->number_of_threads) + .name(name() + ".ISSUE:branches") + .desc("Number of branches issued") + .flags(total) + ; + + issued_ops + .init(cpu->number_of_threads) + .name(name() + ".ISSUE:op_count") + .desc("number of insts issued") + .flags(total) + ; + +/* + for (int i=0; i<Num_OpClasses; ++i) { + stringstream subname; + subname << opClassStrings[i] << "_delay"; + issue_delay_dist.subname(i, subname.str()); + } +*/ + // + // Other stats + // + lsq_forw_loads + .init(cpu->number_of_threads) + .name(name() + ".LSQ:forw_loads") + .desc("number of loads forwarded via LSQ") + .flags(total) + ; + + inv_addr_loads + .init(cpu->number_of_threads) + .name(name() + ".ISSUE:addr_loads") + .desc("number of invalid-address loads") + .flags(total) + ; + + inv_addr_swpfs + .init(cpu->number_of_threads) + .name(name() + ".ISSUE:addr_swpfs") + .desc("number of invalid-address SW prefetches") + .flags(total) + ; + + lsq_blocked_loads + .init(cpu->number_of_threads) + .name(name() + ".LSQ:blocked_loads") + .desc("number of ready loads not issued due to memory disambiguation") + .flags(total) + ; + + lsqInversion + .name(name() + ".ISSUE:lsq_invert") + .desc("Number of times LSQ instruction issued early") + ; + + n_issued_dist + .init(issueWidth + 1) + .name(name() + ".ISSUE:issued_per_cycle") + .desc("Number of insts issued each cycle") + .flags(total | pdf | dist) + ; + issue_delay_dist + .init(Num_OpClasses,0,99,2) + .name(name() + ".ISSUE:") + .desc("cycles from operands ready to issue") + .flags(pdf | cdf) + ; + + queue_res_dist + .init(Num_OpClasses, 0, 99, 2) + .name(name() + ".IQ:residence:") + .desc("cycles from dispatch to issue") + .flags(total | pdf | cdf ) + ; + for (int i = 0; i < Num_OpClasses; ++i) { + queue_res_dist.subname(i, opClassStrings[i]); + } + + writeback_count + .init(cpu->number_of_threads) + .name(name() + ".WB:count") + .desc("cumulative count of insts written-back") + .flags(total) + ; + + producer_inst + .init(cpu->number_of_threads) + .name(name() + ".WB:producers") + .desc("num instructions producing a value") + .flags(total) + ; + + consumer_inst + .init(cpu->number_of_threads) + .name(name() + ".WB:consumers") + .desc("num instructions consuming a value") + .flags(total) + ; + + wb_penalized + .init(cpu->number_of_threads) + .name(name() + ".WB:penalized") + .desc("number of instrctions required to write to 'other' IQ") + .flags(total) + ; + + + wb_penalized_rate + .name(name() + ".WB:penalized_rate") + .desc ("fraction of instructions written-back that wrote to 'other' IQ") + .flags(total) + ; + + wb_penalized_rate = wb_penalized / writeback_count; + + wb_fanout + .name(name() + ".WB:fanout") + .desc("average fanout of values written-back") + .flags(total) + ; + + wb_fanout = producer_inst / consumer_inst; + + wb_rate + .name(name() + ".WB:rate") + .desc("insts written-back per cycle") + .flags(total) + ; + wb_rate = writeback_count / cpu->numCycles; + + stat_com_inst + .init(cpu->number_of_threads) + .name(name() + ".COM:count") + .desc("Number of instructions committed") + .flags(total) + ; + + stat_com_swp + .init(cpu->number_of_threads) + .name(name() + ".COM:swp_count") + .desc("Number of s/w prefetches committed") + .flags(total) + ; + + stat_com_refs + .init(cpu->number_of_threads) + .name(name() + ".COM:refs") + .desc("Number of memory references committed") + .flags(total) + ; + + stat_com_loads + .init(cpu->number_of_threads) + .name(name() + ".COM:loads") + .desc("Number of loads committed") + .flags(total) + ; + + stat_com_membars + .init(cpu->number_of_threads) + .name(name() + ".COM:membars") + .desc("Number of memory barriers committed") + .flags(total) + ; + + stat_com_branches + .init(cpu->number_of_threads) + .name(name() + ".COM:branches") + .desc("Number of branches committed") + .flags(total) + ; + n_committed_dist + .init(0,commitWidth,1) + .name(name() + ".COM:committed_per_cycle") + .desc("Number of insts commited each cycle") + .flags(pdf) + ; + + // + // Commit-Eligible instructions... + // + // -> The number of instructions eligible to commit in those + // cycles where we reached our commit BW limit (less the number + // actually committed) + // + // -> The average value is computed over ALL CYCLES... not just + // the BW limited cycles + // + // -> The standard deviation is computed only over cycles where + // we reached the BW limit + // + commit_eligible + .init(cpu->number_of_threads) + .name(name() + ".COM:bw_limited") + .desc("number of insts not committed due to BW limits") + .flags(total) + ; + + commit_eligible_samples + .name(name() + ".COM:bw_lim_events") + .desc("number cycles where commit BW limit reached") + ; + + ROB_fcount + .name(name() + ".ROB:full_count") + .desc("number of cycles where ROB was full") + ; + + ROB_count + .init(cpu->number_of_threads) + .name(name() + ".ROB:occupancy") + .desc(name() + ".ROB occupancy (cumulative)") + .flags(total) + ; + + ROB_full_rate + .name(name() + ".ROB:full_rate") + .desc("ROB full per cycle") + ; + ROB_full_rate = ROB_fcount / cpu->numCycles; + + ROB_occ_rate + .name(name() + ".ROB:occ_rate") + .desc("ROB occupancy rate") + .flags(total) + ; + ROB_occ_rate = ROB_count / cpu->numCycles; + + ROB_occ_dist + .init(cpu->number_of_threads,0,numROBEntries,2) + .name(name() + ".ROB:occ_dist") + .desc("ROB Occupancy per cycle") + .flags(total | cdf) + ; + + IQ.regStats(); +} + +template <class Impl> +void +BackEnd<Impl>::setCommBuffer(TimeBuffer<CommStruct> *_comm) +{ + comm = _comm; + toIEW = comm->getWire(0); + fromCommit = comm->getWire(-1); +} + +template <class Impl> +void +BackEnd<Impl>::tick() +{ + DPRINTF(BE, "Ticking back end\n"); + + ROB_count[0]+= numInsts; + + wbCycle = 0; + + if (xcSquash) { + squashFromXC(); + } + + // Read in any done instruction information and update the IQ or LSQ. + updateStructures(); + + if (dispatchStatus != Blocked) { + d2i.advance(); + dispatchInsts(); + } else { + checkDispatchStatus(); + } + + i2e.advance(); + scheduleReadyInsts(); + + e2c.advance(); + executeInsts(); + + numInstsToWB.advance(); + writebackInsts(); + + commitInsts(); + + DPRINTF(BE, "IQ entries in use: %i, ROB entries in use: %i, LSQ loads: %i, LSQ stores: %i\n", + IQ.numInsts, numInsts, LSQ.numLoads(), LSQ.numStores()); + + assert(numInsts == instList.size()); +} + +template <class Impl> +void +BackEnd<Impl>::updateStructures() +{ + if (fromCommit->doneSeqNum) { + IQ.commit(fromCommit->doneSeqNum); + LSQ.commitLoads(fromCommit->doneSeqNum); + LSQ.commitStores(fromCommit->doneSeqNum); + } + + if (fromCommit->nonSpecSeqNum) { + if (fromCommit->uncached) { + LSQ.executeLoad(fromCommit->lqIdx); + } else { + IQ.scheduleNonSpec( + fromCommit->nonSpecSeqNum); + } + } +} + +template <class Impl> +void +BackEnd<Impl>::addToIQ(DynInstPtr &inst) +{ + // Do anything IQ specific here? + IQ.insert(inst); +} + +template <class Impl> +void +BackEnd<Impl>::addToLSQ(DynInstPtr &inst) +{ + // Do anything LSQ specific here? + LSQ.insert(inst); +} + +template <class Impl> +void +BackEnd<Impl>::dispatchInsts() +{ + DPRINTF(BE, "Trying to dispatch instructions.\n"); + + // Pull instructions out of the front end. + int disp_width = dispatchWidth ? dispatchWidth : width; + + // Could model dispatching time, but in general 1 cycle is probably + // good enough. + + if (dispatchSize < numDispatchEntries) { + for (int i = 0; i < disp_width; i++) { + // Get instructions + DynInstPtr inst = frontEnd->getInst(); + + if (!inst) { + // No more instructions to get + break; + } + + DPRINTF(BE, "Processing instruction [sn:%lli] PC:%#x\n", + inst->seqNum, inst->readPC()); + + for (int i = 0; i < inst->numDestRegs(); ++i) + renameTable[inst->destRegIdx(i)] = inst; + + // Add to queue to be dispatched. + dispatch.push_back(inst); + + d2i[0].size++; + ++dispatchSize; + } + } + + assert(dispatch.size() < 64); + + for (int i = 0; i < instsToDispatch->size; ++i) { + assert(!dispatch.empty()); + // Get instruction from front of time buffer + DynInstPtr inst = dispatch.front(); + dispatch.pop_front(); + --dispatchSize; + + if (inst->isSquashed()) + continue; + + ++numInsts; + instList.push_back(inst); + + DPRINTF(BE, "Dispatching instruction [sn:%lli] PC:%#x\n", + inst->seqNum, inst->readPC()); + + addToIQ(inst); + + if (inst->isMemRef()) { + addToLSQ(inst); + } + + if (inst->isNonSpeculative()) { + inst->setCanCommit(); + } + + // Check if IQ or LSQ is full. If so we'll need to break and stop + // removing instructions. Also update the number of insts to remove + // from the queue. + if (exactFullStall) { + bool stall = false; + if (IQ.isFull()) { + DPRINTF(BE, "IQ is full!\n"); + stall = true; + } else if (LSQ.isFull()) { + DPRINTF(BE, "LSQ is full!\n"); + stall = true; + } else if (isFull()) { + DPRINTF(BE, "ROB is full!\n"); + stall = true; + ROB_fcount++; + } + if (stall) { + instsToDispatch->size-= i+1; + dispatchStall(); + return; + } + } + } + + // Check if IQ or LSQ is full. If so we'll need to break and stop + // removing instructions. Also update the number of insts to remove + // from the queue. Check here if we don't care about exact stall + // conditions. + + bool stall = false; + if (IQ.isFull()) { + DPRINTF(BE, "IQ is full!\n"); + stall = true; + } else if (LSQ.isFull()) { + DPRINTF(BE, "LSQ is full!\n"); + stall = true; + } else if (isFull()) { + DPRINTF(BE, "ROB is full!\n"); + stall = true; + ROB_fcount++; + } + if (stall) { + d2i.advance(); + dispatchStall(); + return; + } +} + +template <class Impl> +void +BackEnd<Impl>::dispatchStall() +{ + dispatchStatus = Blocked; + if (!cpu->decoupledFrontEnd) { + // Tell front end to stall here through a timebuffer, or just tell + // it directly. + } +} + +template <class Impl> +void +BackEnd<Impl>::checkDispatchStatus() +{ + DPRINTF(BE, "Checking dispatch status\n"); + assert(dispatchStatus == Blocked); + if (!IQ.isFull() && !LSQ.isFull() && !isFull()) { + DPRINTF(BE, "Dispatch no longer blocked\n"); + dispatchStatus = Running; + dispatchInsts(); + } +} + +template <class Impl> +void +BackEnd<Impl>::scheduleReadyInsts() +{ + // Tell IQ to put any ready instructions into the instruction list. + // Probably want to have a list of DynInstPtrs returned here. Then I + // can choose to either put them into a time buffer to simulate + // IQ scheduling time, or hand them directly off to the next stage. + // Do you ever want to directly hand it off to the next stage? + DPRINTF(BE, "Trying to schedule ready instructions\n"); + IQ.scheduleReadyInsts(); +} + +template <class Impl> +void +BackEnd<Impl>::executeInsts() +{ + int insts_to_execute = instsToExecute->size; + + issued_ops[0]+= insts_to_execute; + n_issued_dist[insts_to_execute]++; + + DPRINTF(BE, "Trying to execute %i instructions\n", insts_to_execute); + + fetchRedirect[0] = false; + + while (insts_to_execute > 0) { + // Get ready instruction from the IQ (or queue coming out of IQ) + // Execute the ready instruction. + // Wakeup any dependents if it's done. + DynInstPtr inst = IQ.getReadyInst(); + + DPRINTF(BE, "Executing inst [sn:%lli] PC: %#x\n", + inst->seqNum, inst->readPC()); + + ++funcExeInst; + + // Check if the instruction is squashed; if so then skip it + // and don't count it towards the FU usage. + if (inst->isSquashed()) { + DPRINTF(BE, "Execute: Instruction was squashed.\n"); + + // Not sure how to handle this plus the method of sending # of + // instructions to use. Probably will just have to count it + // towards the bandwidth usage, but not the FU usage. + --insts_to_execute; + + // Consider this instruction executed so that commit can go + // ahead and retire the instruction. + inst->setExecuted(); + + // Not sure if I should set this here or just let commit try to + // commit any squashed instructions. I like the latter a bit more. + inst->setCanCommit(); + +// ++iewExecSquashedInsts; + + continue; + } + + Fault fault = NoFault; + + // Execute instruction. + // Note that if the instruction faults, it will be handled + // at the commit stage. + if (inst->isMemRef() && + (!inst->isDataPrefetch() && !inst->isInstPrefetch())) { + DPRINTF(BE, "Execute: Initiating access for memory " + "reference.\n"); + + // Tell the LDSTQ to execute this instruction (if it is a load). + if (inst->isLoad()) { + // Loads will mark themselves as executed, and their writeback + // event adds the instruction to the queue to commit + fault = LSQ.executeLoad(inst); + +// ++iewExecLoadInsts; + } else if (inst->isStore()) { + LSQ.executeStore(inst); + +// ++iewExecStoreInsts; + + if (!(inst->req->flags & LOCKED)) { + inst->setExecuted(); + + instToCommit(inst); + } + // Store conditionals will mark themselves as executed, and + // their writeback event will add the instruction to the queue + // to commit. + } else { + panic("Unexpected memory type!\n"); + } + + } else { + inst->execute(); + +// ++iewExecutedInsts; + + inst->setExecuted(); + + instToCommit(inst); + } + + updateExeInstStats(inst); + + // Probably should have some sort of function for this. + // More general question of how to handle squashes? Have some sort of + // squash unit that controls it? Probably... + // Check if branch was correct. This check happens after the + // instruction is added to the queue because even if the branch + // is mispredicted, the branch instruction itself is still valid. + // Only handle this if there hasn't already been something that + // redirects fetch in this group of instructions. + + // This probably needs to prioritize the redirects if a different + // scheduler is used. Currently the scheduler schedules the oldest + // instruction first, so the branch resolution order will be correct. + unsigned tid = inst->threadNumber; + + if (!fetchRedirect[tid]) { + + if (inst->mispredicted()) { + fetchRedirect[tid] = true; + + DPRINTF(BE, "Execute: Branch mispredict detected.\n"); + DPRINTF(BE, "Execute: Redirecting fetch to PC: %#x.\n", + inst->nextPC); + + // If incorrect, then signal the ROB that it must be squashed. + squashDueToBranch(inst); + + if (inst->predTaken()) { +// predictedTakenIncorrect++; + } else { +// predictedNotTakenIncorrect++; + } + } else if (LSQ.violation()) { + fetchRedirect[tid] = true; + + // Get the DynInst that caused the violation. Note that this + // clears the violation signal. + DynInstPtr violator; + violator = LSQ.getMemDepViolator(); + + DPRINTF(BE, "LDSTQ detected a violation. Violator PC: " + "%#x, inst PC: %#x. Addr is: %#x.\n", + violator->readPC(), inst->readPC(), inst->physEffAddr); + + // Tell the instruction queue that a violation has occured. +// IQ.violation(inst, violator); + + // Squash. +// squashDueToMemOrder(inst,tid); + squashDueToBranch(inst); + +// ++memOrderViolationEvents; + } else if (LSQ.loadBlocked()) { + fetchRedirect[tid] = true; + + DPRINTF(BE, "Load operation couldn't execute because the " + "memory system is blocked. PC: %#x [sn:%lli]\n", + inst->readPC(), inst->seqNum); + + squashDueToMemBlocked(inst); + } + } + +// instList.pop_front(); + + --insts_to_execute; + + // keep an instruction count + thread->numInst++; + thread->numInsts++; + } + + assert(insts_to_execute >= 0); +} + +template<class Impl> +void +BackEnd<Impl>::instToCommit(DynInstPtr &inst) +{ + int wb_width = wbWidth; + // First check the time slot that this instruction will write + // to. If there are free write ports at the time, then go ahead + // and write the instruction to that time. If there are not, + // keep looking back to see where's the first time there's a + // free slot. What happens if you run out of free spaces? + // For now naively assume that all instructions take one cycle. + // Otherwise would have to look into the time buffer based on the + // latency of the instruction. + + DPRINTF(BE, "Sending instructions to commit [sn:%lli] PC %#x.\n", + inst->seqNum, inst->readPC()); + + while (numInstsToWB[wbCycle].size >= wb_width) { + ++wbCycle; + + assert(wbCycle < 5); + } + + // Add finished instruction to queue to commit. + writeback.push_back(inst); + numInstsToWB[wbCycle].size++; + + if (wbCycle) + wb_penalized[0]++; +} + +template <class Impl> +void +BackEnd<Impl>::writebackInsts() +{ + int wb_width = wbWidth; + // Using this method I'm not quite sure how to prevent an + // instruction from waking its own dependents multiple times, + // without the guarantee that commit always has enough bandwidth + // to accept all instructions being written back. This guarantee + // might not be too unrealistic. + InstListIt wb_inst_it = writeback.begin(); + InstListIt wb_end_it = writeback.end(); + int inst_num = 0; + int consumer_insts = 0; + + for (; inst_num < wb_width && + wb_inst_it != wb_end_it; inst_num++) { + DynInstPtr inst = (*wb_inst_it); + + // Some instructions will be sent to commit without having + // executed because they need commit to handle them. + // E.g. Uncached loads have not actually executed when they + // are first sent to commit. Instead commit must tell the LSQ + // when it's ready to execute the uncached load. + if (!inst->isSquashed()) { + DPRINTF(BE, "Writing back instruction [sn:%lli] PC %#x.\n", + inst->seqNum, inst->readPC()); + + inst->setCanCommit(); + inst->setResultReady(); + + if (inst->isExecuted()) { + int dependents = IQ.wakeDependents(inst); + if (dependents) { + producer_inst[0]++; + consumer_insts+= dependents; + } + } + } + + writeback.erase(wb_inst_it++); + } + LSQ.writebackStores(); + consumer_inst[0]+= consumer_insts; + writeback_count[0]+= inst_num; +} + +template <class Impl> +bool +BackEnd<Impl>::commitInst(int inst_num) +{ + // Read instruction from the head of the ROB + DynInstPtr inst = instList.front(); + + // Make sure instruction is valid + assert(inst); + + if (!inst->readyToCommit()) + return false; + + DPRINTF(BE, "Trying to commit instruction [sn:%lli] PC:%#x\n", + inst->seqNum, inst->readPC()); + + // If the instruction is not executed yet, then it is a non-speculative + // or store inst. Signal backwards that it should be executed. + if (!inst->isExecuted()) { + // Keep this number correct. We have not yet actually executed + // and committed this instruction. +// thread->funcExeInst--; + + if (inst->isNonSpeculative()) { +#if !FULL_SYSTEM + // Hack to make sure syscalls aren't executed until all stores + // write back their data. This direct communication shouldn't + // be used for anything other than this. + if (inst_num > 0 || LSQ.hasStoresToWB()) { + DPRINTF(BE, "Waiting for all stores to writeback.\n"); + return false; + } +#endif + + DPRINTF(BE, "Encountered a store or non-speculative " + "instruction at the head of the ROB, PC %#x.\n", + inst->readPC()); + + // Send back the non-speculative instruction's sequence number. + toIEW->nonSpecSeqNum = inst->seqNum; + + // Change the instruction so it won't try to commit again until + // it is executed. + inst->clearCanCommit(); + +// ++commitNonSpecStalls; + + return false; + } else if (inst->isLoad()) { + DPRINTF(BE, "[sn:%lli]: Uncached load, PC %#x.\n", + inst->seqNum, inst->readPC()); + + // Send back the non-speculative instruction's sequence + // number. Maybe just tell the lsq to re-execute the load. + toIEW->nonSpecSeqNum = inst->seqNum; + toIEW->uncached = true; + toIEW->lqIdx = inst->lqIdx; + + inst->clearCanCommit(); + + return false; + } else { + panic("Trying to commit un-executed instruction " + "of unknown type!\n"); + } + } + + // Now check if it's one of the special trap or barrier or + // serializing instructions. + if (inst->isThreadSync()) + { + // Not handled for now. + panic("Barrier instructions are not handled yet.\n"); + } + + // Check if the instruction caused a fault. If so, trap. + Fault inst_fault = inst->getFault(); + + if (inst_fault != NoFault) { + if (!inst->isNop()) { +#if FULL_SYSTEM + DPRINTF(BE, "Inst [sn:%lli] PC %#x has a fault\n", + inst->seqNum, inst->readPC()); + +// assert(!thread->inSyscall); + +// thread->inSyscall = true; + + // Consider holding onto the trap and waiting until the trap event + // happens for this to be executed. + inst_fault->invoke(thread->getXCProxy()); + + // Exit state update mode to avoid accidental updating. +// thread->inSyscall = false; + +// commitStatus = TrapPending; + + // Generate trap squash event. +// generateTrapEvent(); + + return false; +#else // !FULL_SYSTEM + panic("fault (%d) detected @ PC %08p", inst_fault, + inst->PC); +#endif // FULL_SYSTEM + } + } + + if (inst->isControl()) { +// ++commitCommittedBranches; + } + + int freed_regs = 0; + + for (int i = 0; i < inst->numDestRegs(); ++i) { + DPRINTF(BE, "Commit rename map setting register %i to [sn:%lli]\n", + (int)inst->destRegIdx(i), inst->seqNum); + thread->renameTable[inst->destRegIdx(i)] = inst; + ++freed_regs; + } + + if (inst->traceData) { + inst->traceData->finalize(); + inst->traceData = NULL; + } + + inst->clearDependents(); + + frontEnd->addFreeRegs(freed_regs); + + instList.pop_front(); + + --numInsts; + cpu->numInst++; + thread->numInsts++; + ++thread->funcExeInst; + thread->PC = inst->readNextPC(); + updateComInstStats(inst); + + // Write the done sequence number here. + toIEW->doneSeqNum = inst->seqNum; + +#if FULL_SYSTEM + int count = 0; + Addr oldpc; + do { + if (count == 0) + assert(!thread->inSyscall && !thread->trapPending); + oldpc = thread->readPC(); + cpu->system->pcEventQueue.service( + thread->getXCProxy()); + count++; + } while (oldpc != thread->readPC()); + if (count > 1) { + DPRINTF(BE, "PC skip function event, stopping commit\n"); +// completed_last_inst = false; +// squashPending = true; + return false; + } +#endif + return true; +} + +template <class Impl> +void +BackEnd<Impl>::commitInsts() +{ + int commit_width = commitWidth ? commitWidth : width; + + // Not sure this should be a loop or not. + int inst_num = 0; + while (!instList.empty() && inst_num < commit_width) { + if (instList.front()->isSquashed()) { + panic("No squashed insts should still be on the list!"); + instList.front()->clearDependents(); + instList.pop_front(); + continue; + } + + if (!commitInst(inst_num++)) { + break; + } + } + n_committed_dist.sample(inst_num); +} + +template <class Impl> +void +BackEnd<Impl>::squash(const InstSeqNum &sn) +{ + IQ.squash(sn); + LSQ.squash(sn); + + int freed_regs = 0; + InstListIt dispatch_end = dispatch.end(); + InstListIt insts_it = dispatch.end(); + insts_it--; + + while (insts_it != dispatch_end && (*insts_it)->seqNum > sn) + { + if ((*insts_it)->isSquashed()) { + --insts_it; + continue; + } + DPRINTF(BE, "Squashing instruction on dispatch list PC %#x, [sn:%lli].\n", + (*insts_it)->readPC(), + (*insts_it)->seqNum); + + // Mark the instruction as squashed, and ready to commit so that + // it can drain out of the pipeline. + (*insts_it)->setSquashed(); + + (*insts_it)->setCanCommit(); + + // Be careful with IPRs and such here + for (int i = 0; i < (*insts_it)->numDestRegs(); ++i) { + DynInstPtr prev_dest = (*insts_it)->getPrevDestInst(i); + DPRINTF(BE, "Commit rename map setting register %i to [sn:%lli]\n", + (int)(*insts_it)->destRegIdx(i), prev_dest); + renameTable[(*insts_it)->destRegIdx(i)] = prev_dest; + ++freed_regs; + } + + (*insts_it)->clearDependents(); + + --insts_it; + } + + insts_it = instList.end(); + insts_it--; + + while (!instList.empty() && (*insts_it)->seqNum > sn) + { + if ((*insts_it)->isSquashed()) { + --insts_it; + continue; + } + DPRINTF(BE, "Squashing instruction on inst list PC %#x, [sn:%lli].\n", + (*insts_it)->readPC(), + (*insts_it)->seqNum); + + // Mark the instruction as squashed, and ready to commit so that + // it can drain out of the pipeline. + (*insts_it)->setSquashed(); + + (*insts_it)->setCanCommit(); + + for (int i = 0; i < (*insts_it)->numDestRegs(); ++i) { + DynInstPtr prev_dest = (*insts_it)->getPrevDestInst(i); + DPRINTF(BE, "Commit rename map setting register %i to [sn:%lli]\n", + (int)(*insts_it)->destRegIdx(i), prev_dest); + renameTable[(*insts_it)->destRegIdx(i)] = prev_dest; + ++freed_regs; + } + + (*insts_it)->clearDependents(); + + instList.erase(insts_it--); + --numInsts; + } + + frontEnd->addFreeRegs(freed_regs); +} + +template <class Impl> +void +BackEnd<Impl>::squashFromXC() +{ + xcSquash = true; +} + +template <class Impl> +void +BackEnd<Impl>::squashDueToBranch(DynInstPtr &inst) +{ + // Update the branch predictor state I guess + squash(inst->seqNum); + frontEnd->squash(inst->seqNum, inst->readNextPC(), + true, inst->mispredicted()); +} + +template <class Impl> +void +BackEnd<Impl>::squashDueToMemBlocked(DynInstPtr &inst) +{ + DPRINTF(IEW, "Memory blocked, squashing load and younger insts, " + "PC: %#x [sn:%i].\n", inst->readPC(), inst->seqNum); + + squash(inst->seqNum - 1); + frontEnd->squash(inst->seqNum - 1, inst->readPC()); +} + +template <class Impl> +void +BackEnd<Impl>::fetchFault(Fault &fault) +{ + faultFromFetch = fault; +} + +template <class Impl> +void +BackEnd<Impl>::updateExeInstStats(DynInstPtr &inst) +{ + int thread_number = inst->threadNumber; + + // + // Pick off the software prefetches + // +#ifdef TARGET_ALPHA + if (inst->isDataPrefetch()) + exe_swp[thread_number]++; + else + exe_inst[thread_number]++; +#else + exe_inst[thread_number]++; +#endif + + // + // Control operations + // + if (inst->isControl()) + exe_branches[thread_number]++; + + // + // Memory operations + // + if (inst->isMemRef()) { + exe_refs[thread_number]++; + + if (inst->isLoad()) + exe_loads[thread_number]++; + } +} + +template <class Impl> +void +BackEnd<Impl>::updateComInstStats(DynInstPtr &inst) +{ + unsigned thread = inst->threadNumber; + + // + // Pick off the software prefetches + // +#ifdef TARGET_ALPHA + if (inst->isDataPrefetch()) { + stat_com_swp[thread]++; + } else { + stat_com_inst[thread]++; + } +#else + stat_com_inst[thread]++; +#endif + + // + // Control Instructions + // + if (inst->isControl()) + stat_com_branches[thread]++; + + // + // Memory references + // + if (inst->isMemRef()) { + stat_com_refs[thread]++; + + if (inst->isLoad()) { + stat_com_loads[thread]++; + } + } + + if (inst->isMemBarrier()) { + stat_com_membars[thread]++; + } +} + +template <class Impl> +void +BackEnd<Impl>::dumpInsts() +{ + int num = 0; + int valid_num = 0; + + InstListIt inst_list_it = instList.begin(); + + cprintf("Inst list size: %i\n", instList.size()); + + while (inst_list_it != instList.end()) + { + cprintf("Instruction:%i\n", + num); + if (!(*inst_list_it)->isSquashed()) { + if (!(*inst_list_it)->isIssued()) { + ++valid_num; + cprintf("Count:%i\n", valid_num); + } else if ((*inst_list_it)->isMemRef() && + !(*inst_list_it)->memOpDone) { + // Loads that have not been marked as executed still count + // towards the total instructions. + ++valid_num; + cprintf("Count:%i\n", valid_num); + } + } + + cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" + "Issued:%i\nSquashed:%i\n", + (*inst_list_it)->readPC(), + (*inst_list_it)->seqNum, + (*inst_list_it)->threadNumber, + (*inst_list_it)->isIssued(), + (*inst_list_it)->isSquashed()); + + if ((*inst_list_it)->isMemRef()) { + cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone); + } + + cprintf("\n"); + + inst_list_it++; + ++num; + } + + cprintf("Dispatch list size: %i\n", dispatch.size()); + + inst_list_it = dispatch.begin(); + + while (inst_list_it != dispatch.end()) + { + cprintf("Instruction:%i\n", + num); + if (!(*inst_list_it)->isSquashed()) { + if (!(*inst_list_it)->isIssued()) { + ++valid_num; + cprintf("Count:%i\n", valid_num); + } else if ((*inst_list_it)->isMemRef() && + !(*inst_list_it)->memOpDone) { + // Loads that have not been marked as executed still count + // towards the total instructions. + ++valid_num; + cprintf("Count:%i\n", valid_num); + } + } + + cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" + "Issued:%i\nSquashed:%i\n", + (*inst_list_it)->readPC(), + (*inst_list_it)->seqNum, + (*inst_list_it)->threadNumber, + (*inst_list_it)->isIssued(), + (*inst_list_it)->isSquashed()); + + if ((*inst_list_it)->isMemRef()) { + cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone); + } + + cprintf("\n"); + + inst_list_it++; + ++num; + } + + cprintf("Writeback list size: %i\n", writeback.size()); + + inst_list_it = writeback.begin(); + + while (inst_list_it != writeback.end()) + { + cprintf("Instruction:%i\n", + num); + if (!(*inst_list_it)->isSquashed()) { + if (!(*inst_list_it)->isIssued()) { + ++valid_num; + cprintf("Count:%i\n", valid_num); + } else if ((*inst_list_it)->isMemRef() && + !(*inst_list_it)->memOpDone) { + // Loads that have not been marked as executed still count + // towards the total instructions. + ++valid_num; + cprintf("Count:%i\n", valid_num); + } + } + + cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" + "Issued:%i\nSquashed:%i\n", + (*inst_list_it)->readPC(), + (*inst_list_it)->seqNum, + (*inst_list_it)->threadNumber, + (*inst_list_it)->isIssued(), + (*inst_list_it)->isSquashed()); + + if ((*inst_list_it)->isMemRef()) { + cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone); + } + + cprintf("\n"); + + inst_list_it++; + ++num; + } +} diff --git a/src/cpu/ozone/cpu.cc b/src/cpu/ozone/cpu.cc new file mode 100644 index 000000000..303c78eea --- /dev/null +++ b/src/cpu/ozone/cpu.cc @@ -0,0 +1,37 @@ +/* + * Copyright (c) 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 + * Nathan Binkert + */ + +#include "cpu/ozone/cpu_impl.hh" +#include "cpu/ozone/ozone_impl.hh" +#include "cpu/ozone/simple_impl.hh" + +template class OzoneCPU<SimpleImpl>; +template class OzoneCPU<OzoneImpl>; diff --git a/src/cpu/ozone/cpu.hh b/src/cpu/ozone/cpu.hh new file mode 100644 index 000000000..e9550c39b --- /dev/null +++ b/src/cpu/ozone/cpu.hh @@ -0,0 +1,633 @@ +/* + * Copyright (c) 2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#ifndef __CPU_OZONE_CPU_HH__ +#define __CPU_OZONE_CPU_HH__ + +#include <set> + +#include "base/statistics.hh" +#include "base/timebuf.hh" +#include "config/full_system.hh" +#include "cpu/base.hh" +#include "cpu/thread_context.hh" +#include "cpu/inst_seq.hh" +#include "cpu/ozone/rename_table.hh" +#include "cpu/ozone/thread_state.hh" +#include "cpu/pc_event.hh" +#include "cpu/static_inst.hh" +#include "sim/eventq.hh" + +// forward declarations +#if FULL_SYSTEM +#include "arch/alpha/tlb.hh" + +class AlphaITB; +class AlphaDTB; +class PhysicalMemory; +class MemoryController; + +class Sampler; +class RemoteGDB; +class GDBListener; + +namespace Kernel { + class Statistics; +}; + +#else + +class Process; + +#endif // FULL_SYSTEM + +class Checkpoint; +class EndQuiesceEvent; +class Request; + +namespace Trace { + class InstRecord; +} + +template <class> +class Checker; + +/** + * Declaration of Out-of-Order CPU class. Basically it is a SimpleCPU with + * simple out-of-order capabilities added to it. It is still a 1 CPI machine + * (?), but is capable of handling cache misses. Basically it models having + * a ROB/IQ by only allowing a certain amount of instructions to execute while + * the cache miss is outstanding. + */ + +template <class Impl> +class OzoneCPU : public BaseCPU +{ + private: + typedef typename Impl::FrontEnd FrontEnd; + typedef typename Impl::BackEnd BackEnd; + typedef typename Impl::DynInst DynInst; + typedef typename Impl::DynInstPtr DynInstPtr; + + typedef TheISA::FloatReg FloatReg; + typedef TheISA::FloatRegBits FloatRegBits; + typedef TheISA::MiscReg MiscReg; + + public: + class OzoneTC : public ThreadContext { + public: + OzoneCPU<Impl> *cpu; + + OzoneThreadState<Impl> *thread; + + BaseCPU *getCpuPtr(); + + void setCpuId(int id); + + int readCpuId() { return thread->cpuId; } + +#if FULL_SYSTEM + System *getSystemPtr() { return cpu->system; } + + PhysicalMemory *getPhysMemPtr() { return cpu->physmem; } + + AlphaITB *getITBPtr() { return cpu->itb; } + + AlphaDTB * getDTBPtr() { return cpu->dtb; } + + Kernel::Statistics *getKernelStats() { return thread->kernelStats; } + + FunctionalPort *getPhysPort() { return thread->getPhysPort(); } + + VirtualPort *getVirtPort(ThreadContext *tc = NULL) + { return thread->getVirtPort(tc); } + + void delVirtPort(VirtualPort *vp) + { thread->delVirtPort(vp); } +#else + TranslatingPort *getMemPort() { return thread->port; } + + Process *getProcessPtr() { return thread->process; } +#endif + + Status status() const { return thread->_status; } + + void setStatus(Status 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(); + + /// Set the status to Unallocated. + void deallocate(); + + /// Set the status to Halted. + void halt(); + +#if FULL_SYSTEM + void dumpFuncProfile(); +#endif + + void takeOverFrom(ThreadContext *old_context); + + void regStats(const std::string &name); + + void serialize(std::ostream &os); + void unserialize(Checkpoint *cp, const std::string §ion); + +#if FULL_SYSTEM + EndQuiesceEvent *getQuiesceEvent(); + + Tick readLastActivate(); + Tick readLastSuspend(); + + void profileClear(); + void profileSample(); +#endif + + int getThreadNum(); + + // Also somewhat obnoxious. Really only used for the TLB fault. + TheISA::MachInst getInst(); + + void copyArchRegs(ThreadContext *tc); + + void clearArchRegs(); + + uint64_t readIntReg(int reg_idx); + + FloatReg readFloatReg(int reg_idx, int width); + + FloatReg readFloatReg(int reg_idx); + + FloatRegBits readFloatRegBits(int reg_idx, int width); + + FloatRegBits readFloatRegBits(int reg_idx); + + void setIntReg(int reg_idx, uint64_t val); + + void setFloatReg(int reg_idx, FloatReg val, int width); + + void setFloatReg(int reg_idx, FloatReg val); + + void setFloatRegBits(int reg_idx, FloatRegBits val, int width); + + void setFloatRegBits(int reg_idx, FloatRegBits val); + + uint64_t readPC() { return thread->PC; } + void setPC(Addr val); + + uint64_t readNextPC() { return thread->nextPC; } + void setNextPC(Addr val); + + uint64_t readNextNPC() + { + panic("Alpha has no NextNPC!"); + return 0; + } + + void setNextNPC(uint64_t val) + { panic("Alpha has no NextNPC!"); } + + public: + // ISA stuff: + MiscReg readMiscReg(int misc_reg); + + MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault); + + Fault setMiscReg(int misc_reg, const MiscReg &val); + + Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val); + + unsigned readStCondFailures() + { return thread->storeCondFailures; } + + void setStCondFailures(unsigned sc_failures) + { thread->storeCondFailures = sc_failures; } + +#if FULL_SYSTEM + bool inPalMode() { return cpu->inPalMode(); } +#endif + + bool misspeculating() { return false; } + +#if !FULL_SYSTEM + TheISA::IntReg getSyscallArg(int i) + { return thread->renameTable[TheISA::ArgumentReg0 + i]->readIntResult(); } + + // used to shift args for indirect syscall + void setSyscallArg(int i, TheISA::IntReg val) + { thread->renameTable[TheISA::ArgumentReg0 + i]->setIntResult(i); } + + void setSyscallReturn(SyscallReturn return_value) + { cpu->setSyscallReturn(return_value, thread->tid); } + + Counter readFuncExeInst() { return thread->funcExeInst; } + + void setFuncExeInst(Counter new_val) + { thread->funcExeInst = new_val; } +#endif + void changeRegFileContext(TheISA::RegFile::ContextParam param, + TheISA::RegFile::ContextVal val) + { panic("Not supported on Alpha!"); } + }; + + // Ozone specific thread context + OzoneTC ozoneTC; + // Thread context to be used + ThreadContext *tc; + // Checker thread context; will wrap the OzoneTC if a checker is + // being used. + ThreadContext *checkerTC; + + typedef OzoneThreadState<Impl> ImplState; + + private: + OzoneThreadState<Impl> thread; + + public: + // main simulation loop (one cycle) + void tick(); + + std::set<InstSeqNum> snList; + std::set<Addr> lockAddrList; + private: + struct TickEvent : public Event + { + OzoneCPU *cpu; + int width; + + TickEvent(OzoneCPU *c, int w); + void process(); + const char *description(); + }; + + TickEvent tickEvent; + + /// Schedule tick event, regardless of its current state. + void scheduleTickEvent(int delay) + { + if (tickEvent.squashed()) + tickEvent.reschedule(curTick + cycles(delay)); + else if (!tickEvent.scheduled()) + tickEvent.schedule(curTick + cycles(delay)); + } + + /// Unschedule tick event, regardless of its current state. + void unscheduleTickEvent() + { + if (tickEvent.scheduled()) + tickEvent.squash(); + } + + private: + Trace::InstRecord *traceData; + + template<typename T> + void trace_data(T data); + + public: + enum Status { + Running, + Idle, + SwitchedOut + }; + + Status _status; + + public: + bool checkInterrupts; + + void post_interrupt(int int_num, int index); + + void zero_fill_64(Addr addr) { + static int warned = 0; + if (!warned) { + warn ("WH64 is not implemented"); + warned = 1; + } + }; + + typedef typename Impl::Params Params; + + OzoneCPU(Params *params); + + virtual ~OzoneCPU(); + + void init(); + + public: + BaseCPU *getCpuPtr() { return this; } + + void setCpuId(int id) { cpuId = id; } + + int readCpuId() { return cpuId; } + + int cpuId; + + void switchOut(Sampler *sampler); + void signalSwitched(); + void takeOverFrom(BaseCPU *oldCPU); + + Sampler *sampler; + + int switchCount; + +#if FULL_SYSTEM + Addr dbg_vtophys(Addr addr); + + bool interval_stats; + + AlphaITB *itb; + AlphaDTB *dtb; + System *system; + PhysicalMemory *physmem; +#endif + + FrontEnd *frontEnd; + + BackEnd *backEnd; + private: + Status status() const { return _status; } + void setStatus(Status new_status) { _status = new_status; } + + virtual void activateContext(int thread_num, int delay); + virtual void suspendContext(int thread_num); + virtual void deallocateContext(int thread_num); + virtual void haltContext(int thread_num); + + // statistics + virtual void regStats(); + virtual void resetStats(); + + // number of simulated instructions + public: + Counter numInst; + Counter startNumInst; + + virtual Counter totalInstructions() const + { + return numInst - startNumInst; + } + + private: + // number of simulated loads + Counter numLoad; + Counter startNumLoad; + + // number of idle cycles + Stats::Average<> notIdleFraction; + Stats::Formula idleFraction; + public: + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + + +#if FULL_SYSTEM + bool validInstAddr(Addr addr) { return true; } + bool validDataAddr(Addr addr) { return true; } + + Fault translateInstReq(Request *req) + { + return itb->translate(req, tc); + } + + Fault translateDataReadReq(Request *req) + { + return dtb->translate(req, tc, false); + } + + Fault translateDataWriteReq(Request *req) + { + return dtb->translate(req, tc, true); + } + +#else + bool validInstAddr(Addr addr) + { return true; } + + bool validDataAddr(Addr addr) + { return true; } + + int getInstAsid() { return thread.asid; } + int getDataAsid() { return thread.asid; } + + /** Translates instruction requestion in syscall emulation mode. */ + Fault translateInstReq(Request *req) + { + return thread.translateInstReq(req); + } + + /** Translates data read request in syscall emulation mode. */ + Fault translateDataReadReq(Request *req) + { + return thread.translateDataReadReq(req); + } + + /** Translates data write request in syscall emulation mode. */ + Fault translateDataWriteReq(Request *req) + { + return thread.translateDataWriteReq(req); + } +#endif + + /** Old CPU read from memory function. No longer used. */ + template <class T> + Fault read(Request *req, T &data) + { +#if 0 +#if FULL_SYSTEM && defined(TARGET_ALPHA) + if (req->flags & LOCKED) { + req->xc->setMiscReg(TheISA::Lock_Addr_DepTag, req->paddr); + req->xc->setMiscReg(TheISA::Lock_Flag_DepTag, true); + } +#endif + if (req->flags & LOCKED) { + lockAddrList.insert(req->paddr); + lockFlag = true; + } +#endif + Fault error; + + error = this->mem->read(req, data); + data = gtoh(data); + return error; + } + + + /** CPU read function, forwards read to LSQ. */ + template <class T> + Fault read(Request *req, T &data, int load_idx) + { + return backEnd->read(req, data, load_idx); + } + + /** Old CPU write to memory function. No longer used. */ + template <class T> + Fault write(Request *req, T &data) + { +#if 0 +#if FULL_SYSTEM && defined(TARGET_ALPHA) + ExecContext *xc; + + // If this is a store conditional, act appropriately + if (req->flags & LOCKED) { + xc = req->xc; + + if (req->flags & UNCACHEABLE) { + // Don't update result register (see stq_c in isa_desc) + req->result = 2; + xc->setStCondFailures(0);//Needed? [RGD] + } else { + bool lock_flag = xc->readMiscReg(TheISA::Lock_Flag_DepTag); + Addr lock_addr = xc->readMiscReg(TheISA::Lock_Addr_DepTag); + req->result = lock_flag; + if (!lock_flag || + ((lock_addr & ~0xf) != (req->paddr & ~0xf))) { + xc->setMiscReg(TheISA::Lock_Flag_DepTag, false); + xc->setStCondFailures(xc->readStCondFailures() + 1); + if (((xc->readStCondFailures()) % 100000) == 0) { + std::cerr << "Warning: " + << xc->readStCondFailures() + << " consecutive store conditional failures " + << "on cpu " << req->xc->readCpuId() + << std::endl; + } + return NoFault; + } + else xc->setStCondFailures(0); + } + } + + // Need to clear any locked flags on other proccessors for + // this address. Only do this for succsful Store Conditionals + // and all other stores (WH64?). Unsuccessful Store + // Conditionals would have returned above, and wouldn't fall + // through. + for (int i = 0; i < this->system->threadContexts.size(); i++){ + xc = this->system->threadContexts[i]; + if ((xc->readMiscReg(TheISA::Lock_Addr_DepTag) & ~0xf) == + (req->paddr & ~0xf)) { + xc->setMiscReg(TheISA::Lock_Flag_DepTag, false); + } + } + +#endif + + if (req->flags & LOCKED) { + if (req->flags & UNCACHEABLE) { + req->result = 2; + } else { + if (this->lockFlag) { + if (lockAddrList.find(req->paddr) != + lockAddrList.end()) { + req->result = 1; + } else { + req->result = 0; + return NoFault; + } + } else { + req->result = 0; + return NoFault; + } + } + } +#endif + + return this->mem->write(req, (T)htog(data)); + } + + /** CPU write function, forwards write to LSQ. */ + template <class T> + Fault write(Request *req, T &data, int store_idx) + { + return backEnd->write(req, data, store_idx); + } + + void prefetch(Addr addr, unsigned flags) + { + // need to do this... + } + + void writeHint(Addr addr, int size, unsigned flags) + { + // need to do this... + } + + Fault copySrcTranslate(Addr src); + + Fault copy(Addr dest); + + InstSeqNum globalSeqNum; + + public: + void squashFromTC(); + + // @todo: This can be a useful debug function. Implement it. + void dumpInsts() { frontEnd->dumpInsts(); } + +#if FULL_SYSTEM + Fault hwrei(); + int readIntrFlag() { return thread.regs.intrflag; } + void setIntrFlag(int val) { thread.regs.intrflag = val; } + bool inPalMode() { return AlphaISA::PcPAL(thread.PC); } + bool inPalMode(Addr pc) { return AlphaISA::PcPAL(pc); } + bool simPalCheck(int palFunc); + void processInterrupts(); +#else + void syscall(); + void setSyscallReturn(SyscallReturn return_value, int tid); +#endif + + ThreadContext *tcBase() { return tc; } + + bool decoupledFrontEnd; + struct CommStruct { + InstSeqNum doneSeqNum; + InstSeqNum nonSpecSeqNum; + bool uncached; + unsigned lqIdx; + + bool stall; + }; + TimeBuffer<CommStruct> comm; + + bool lockFlag; + + Stats::Scalar<> quiesceCycles; + + Checker<DynInstPtr> *checker; +}; + +#endif // __CPU_OZONE_CPU_HH__ diff --git a/src/cpu/ozone/cpu_builder.cc b/src/cpu/ozone/cpu_builder.cc new file mode 100644 index 000000000..18f257a25 --- /dev/null +++ b/src/cpu/ozone/cpu_builder.cc @@ -0,0 +1,863 @@ +/* + * 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/checker/cpu.hh" +#include "cpu/inst_seq.hh" +#include "cpu/ozone/cpu.hh" +#include "cpu/ozone/ozone_impl.hh" +#include "cpu/ozone/simple_impl.hh" +#include "cpu/ozone/simple_params.hh" +#include "mem/cache/base_cache.hh" +#include "sim/builder.hh" +#include "sim/process.hh" +#include "sim/sim_object.hh" + +class DerivOzoneCPU : public OzoneCPU<OzoneImpl> +{ + public: + DerivOzoneCPU(SimpleParams *p) + : OzoneCPU<OzoneImpl>(p) + { } +}; + +class SimpleOzoneCPU : public OzoneCPU<SimpleImpl> +{ + public: + SimpleOzoneCPU(SimpleParams *p) + : OzoneCPU<SimpleImpl>(p) + { } +}; + + +//////////////////////////////////////////////////////////////////////// +// +// OzoneCPU Simulation Object +// + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(DerivOzoneCPU) + + Param<int> clock; + Param<int> numThreads; + +#if FULL_SYSTEM +SimObjectParam<System *> system; +Param<int> cpu_id; +SimObjectParam<AlphaITB *> itb; +SimObjectParam<AlphaDTB *> dtb; +#else +SimObjectVectorParam<Process *> workload; +//SimObjectParam<PageTable *> page_table; +#endif // FULL_SYSTEM + +SimObjectParam<FunctionalMemory *> mem; + +SimObjectParam<BaseCPU *> checker; + +Param<Counter> max_insts_any_thread; +Param<Counter> max_insts_all_threads; +Param<Counter> max_loads_any_thread; +Param<Counter> max_loads_all_threads; + +SimObjectParam<BaseCache *> icache; +SimObjectParam<BaseCache *> dcache; + +Param<unsigned> cachePorts; +Param<unsigned> width; +Param<unsigned> frontEndWidth; +Param<unsigned> backEndWidth; +Param<unsigned> backEndSquashLatency; +Param<unsigned> backEndLatency; +Param<unsigned> maxInstBufferSize; +Param<unsigned> numPhysicalRegs; +Param<unsigned> maxOutstandingMemOps; + +Param<unsigned> decodeToFetchDelay; +Param<unsigned> renameToFetchDelay; +Param<unsigned> iewToFetchDelay; +Param<unsigned> commitToFetchDelay; +Param<unsigned> fetchWidth; + +Param<unsigned> renameToDecodeDelay; +Param<unsigned> iewToDecodeDelay; +Param<unsigned> commitToDecodeDelay; +Param<unsigned> fetchToDecodeDelay; +Param<unsigned> decodeWidth; + +Param<unsigned> iewToRenameDelay; +Param<unsigned> commitToRenameDelay; +Param<unsigned> decodeToRenameDelay; +Param<unsigned> renameWidth; + +Param<unsigned> commitToIEWDelay; +Param<unsigned> renameToIEWDelay; +Param<unsigned> issueToExecuteDelay; +Param<unsigned> issueWidth; +Param<unsigned> executeWidth; +Param<unsigned> executeIntWidth; +Param<unsigned> executeFloatWidth; +Param<unsigned> executeBranchWidth; +Param<unsigned> executeMemoryWidth; + +Param<unsigned> iewToCommitDelay; +Param<unsigned> renameToROBDelay; +Param<unsigned> commitWidth; +Param<unsigned> squashWidth; + +Param<std::string> predType; +Param<unsigned> localPredictorSize; +Param<unsigned> localCtrBits; +Param<unsigned> localHistoryTableSize; +Param<unsigned> localHistoryBits; +Param<unsigned> globalPredictorSize; +Param<unsigned> globalCtrBits; +Param<unsigned> globalHistoryBits; +Param<unsigned> choicePredictorSize; +Param<unsigned> choiceCtrBits; + +Param<unsigned> BTBEntries; +Param<unsigned> BTBTagSize; + +Param<unsigned> RASSize; + +Param<unsigned> LQEntries; +Param<unsigned> SQEntries; +Param<unsigned> LFSTSize; +Param<unsigned> SSITSize; + +Param<unsigned> numPhysIntRegs; +Param<unsigned> numPhysFloatRegs; +Param<unsigned> numIQEntries; +Param<unsigned> numROBEntries; + +Param<bool> decoupledFrontEnd; +Param<int> dispatchWidth; +Param<int> wbWidth; + +Param<unsigned> smtNumFetchingThreads; +Param<std::string> smtFetchPolicy; +Param<std::string> smtLSQPolicy; +Param<unsigned> smtLSQThreshold; +Param<std::string> smtIQPolicy; +Param<unsigned> smtIQThreshold; +Param<std::string> smtROBPolicy; +Param<unsigned> smtROBThreshold; +Param<std::string> smtCommitPolicy; + +Param<unsigned> instShiftAmt; + +Param<bool> defer_registration; + +Param<bool> function_trace; +Param<Tick> function_trace_start; + +END_DECLARE_SIM_OBJECT_PARAMS(DerivOzoneCPU) + +BEGIN_INIT_SIM_OBJECT_PARAMS(DerivOzoneCPU) + + INIT_PARAM(clock, "clock speed"), + INIT_PARAM(numThreads, "number of HW thread contexts"), + +#if FULL_SYSTEM + INIT_PARAM(system, "System object"), + INIT_PARAM(cpu_id, "processor ID"), + INIT_PARAM(itb, "Instruction translation buffer"), + INIT_PARAM(dtb, "Data translation buffer"), +#else + INIT_PARAM(workload, "Processes to run"), +// INIT_PARAM(page_table, "Page table"), +#endif // FULL_SYSTEM + + INIT_PARAM_DFLT(mem, "Memory", NULL), + + INIT_PARAM_DFLT(checker, "Checker CPU", NULL), + + INIT_PARAM_DFLT(max_insts_any_thread, + "Terminate when any thread reaches this inst count", + 0), + INIT_PARAM_DFLT(max_insts_all_threads, + "Terminate when all threads have reached" + "this inst count", + 0), + INIT_PARAM_DFLT(max_loads_any_thread, + "Terminate when any thread reaches this load count", + 0), + INIT_PARAM_DFLT(max_loads_all_threads, + "Terminate when all threads have reached this load" + "count", + 0), + + INIT_PARAM_DFLT(icache, "L1 instruction cache", NULL), + INIT_PARAM_DFLT(dcache, "L1 data cache", NULL), + + INIT_PARAM_DFLT(cachePorts, "Cache Ports", 200), + INIT_PARAM_DFLT(width, "Width", 1), + INIT_PARAM_DFLT(frontEndWidth, "Front end width", 1), + INIT_PARAM_DFLT(backEndWidth, "Back end width", 1), + INIT_PARAM_DFLT(backEndSquashLatency, "Back end squash latency", 1), + INIT_PARAM_DFLT(backEndLatency, "Back end latency", 1), + INIT_PARAM_DFLT(maxInstBufferSize, "Maximum instruction buffer size", 16), + INIT_PARAM(numPhysicalRegs, "Number of physical registers"), + INIT_PARAM_DFLT(maxOutstandingMemOps, "Maximum outstanding memory operations", 4), + + INIT_PARAM(decodeToFetchDelay, "Decode to fetch delay"), + INIT_PARAM(renameToFetchDelay, "Rename to fetch delay"), + INIT_PARAM(iewToFetchDelay, "Issue/Execute/Writeback to fetch" + "delay"), + INIT_PARAM(commitToFetchDelay, "Commit to fetch delay"), + INIT_PARAM(fetchWidth, "Fetch width"), + INIT_PARAM(renameToDecodeDelay, "Rename to decode delay"), + INIT_PARAM(iewToDecodeDelay, "Issue/Execute/Writeback to decode" + "delay"), + INIT_PARAM(commitToDecodeDelay, "Commit to decode delay"), + INIT_PARAM(fetchToDecodeDelay, "Fetch to decode delay"), + INIT_PARAM(decodeWidth, "Decode width"), + + INIT_PARAM(iewToRenameDelay, "Issue/Execute/Writeback to rename" + "delay"), + INIT_PARAM(commitToRenameDelay, "Commit to rename delay"), + INIT_PARAM(decodeToRenameDelay, "Decode to rename delay"), + INIT_PARAM(renameWidth, "Rename width"), + + INIT_PARAM(commitToIEWDelay, "Commit to " + "Issue/Execute/Writeback delay"), + INIT_PARAM(renameToIEWDelay, "Rename to " + "Issue/Execute/Writeback delay"), + INIT_PARAM(issueToExecuteDelay, "Issue to execute delay (internal" + "to the IEW stage)"), + INIT_PARAM(issueWidth, "Issue width"), + INIT_PARAM(executeWidth, "Execute width"), + INIT_PARAM(executeIntWidth, "Integer execute width"), + INIT_PARAM(executeFloatWidth, "Floating point execute width"), + INIT_PARAM(executeBranchWidth, "Branch execute width"), + INIT_PARAM(executeMemoryWidth, "Memory execute width"), + + INIT_PARAM(iewToCommitDelay, "Issue/Execute/Writeback to commit " + "delay"), + INIT_PARAM(renameToROBDelay, "Rename to reorder buffer delay"), + INIT_PARAM(commitWidth, "Commit width"), + INIT_PARAM(squashWidth, "Squash width"), + + INIT_PARAM(predType, "Type of branch predictor ('local', 'tournament')"), + INIT_PARAM(localPredictorSize, "Size of local predictor"), + INIT_PARAM(localCtrBits, "Bits per counter"), + INIT_PARAM(localHistoryTableSize, "Size of local history table"), + INIT_PARAM(localHistoryBits, "Bits for the local history"), + INIT_PARAM(globalPredictorSize, "Size of global predictor"), + INIT_PARAM(globalCtrBits, "Bits per counter"), + INIT_PARAM(globalHistoryBits, "Bits of history"), + INIT_PARAM(choicePredictorSize, "Size of choice predictor"), + INIT_PARAM(choiceCtrBits, "Bits of choice counters"), + + INIT_PARAM(BTBEntries, "Number of BTB entries"), + INIT_PARAM(BTBTagSize, "Size of the BTB tags, in bits"), + + INIT_PARAM(RASSize, "RAS size"), + + INIT_PARAM(LQEntries, "Number of load queue entries"), + INIT_PARAM(SQEntries, "Number of store queue entries"), + INIT_PARAM(LFSTSize, "Last fetched store table size"), + INIT_PARAM(SSITSize, "Store set ID table size"), + + INIT_PARAM(numPhysIntRegs, "Number of physical integer registers"), + INIT_PARAM(numPhysFloatRegs, "Number of physical floating point " + "registers"), + INIT_PARAM(numIQEntries, "Number of instruction queue entries"), + INIT_PARAM(numROBEntries, "Number of reorder buffer entries"), + + INIT_PARAM_DFLT(decoupledFrontEnd, "Decoupled front end", true), + INIT_PARAM_DFLT(dispatchWidth, "Dispatch width", 0), + INIT_PARAM_DFLT(wbWidth, "Writeback width", 0), + + INIT_PARAM_DFLT(smtNumFetchingThreads, "SMT Number of Fetching Threads", 1), + INIT_PARAM_DFLT(smtFetchPolicy, "SMT Fetch Policy", "SingleThread"), + INIT_PARAM_DFLT(smtLSQPolicy, "SMT LSQ Sharing Policy", "Partitioned"), + INIT_PARAM_DFLT(smtLSQThreshold,"SMT LSQ Threshold", 100), + INIT_PARAM_DFLT(smtIQPolicy, "SMT IQ Policy", "Partitioned"), + INIT_PARAM_DFLT(smtIQThreshold, "SMT IQ Threshold", 100), + INIT_PARAM_DFLT(smtROBPolicy, "SMT ROB Sharing Policy", "Partitioned"), + INIT_PARAM_DFLT(smtROBThreshold,"SMT ROB Threshold", 100), + INIT_PARAM_DFLT(smtCommitPolicy,"SMT Commit Fetch Policy", "RoundRobin"), + + INIT_PARAM(instShiftAmt, "Number of bits to shift instructions by"), + INIT_PARAM(defer_registration, "defer system registration (for sampling)"), + + INIT_PARAM(function_trace, "Enable function trace"), + INIT_PARAM(function_trace_start, "Cycle to start function trace") + +END_INIT_SIM_OBJECT_PARAMS(DerivOzoneCPU) + +CREATE_SIM_OBJECT(DerivOzoneCPU) +{ + DerivOzoneCPU *cpu; + +#if FULL_SYSTEM + // Full-system only supports a single thread for the moment. + int actual_num_threads = 1; +#else + // In non-full-system mode, we infer the number of threads from + // the workload if it's not explicitly specified. + int actual_num_threads = + numThreads.isValid() ? numThreads : workload.size(); + + if (workload.size() == 0) { + fatal("Must specify at least one workload!"); + } + +#endif + + SimpleParams *params = new SimpleParams; + + params->clock = clock; + + params->name = getInstanceName(); + params->numberOfThreads = actual_num_threads; + +#if FULL_SYSTEM + params->system = system; + params->cpu_id = cpu_id; + params->itb = itb; + params->dtb = dtb; +#else + params->workload = workload; +// params->pTable = page_table; +#endif // FULL_SYSTEM + + params->mem = mem; + params->checker = checker; + params->max_insts_any_thread = max_insts_any_thread; + params->max_insts_all_threads = max_insts_all_threads; + params->max_loads_any_thread = max_loads_any_thread; + params->max_loads_all_threads = max_loads_all_threads; + + // + // Caches + // + params->icacheInterface = icache ? icache->getInterface() : NULL; + params->dcacheInterface = dcache ? dcache->getInterface() : NULL; + params->cachePorts = cachePorts; + + params->width = width; + params->frontEndWidth = frontEndWidth; + params->backEndWidth = backEndWidth; + params->backEndSquashLatency = backEndSquashLatency; + params->backEndLatency = backEndLatency; + params->maxInstBufferSize = maxInstBufferSize; + params->numPhysicalRegs = numPhysIntRegs + numPhysFloatRegs; + params->maxOutstandingMemOps = maxOutstandingMemOps; + + params->decodeToFetchDelay = decodeToFetchDelay; + params->renameToFetchDelay = renameToFetchDelay; + params->iewToFetchDelay = iewToFetchDelay; + params->commitToFetchDelay = commitToFetchDelay; + params->fetchWidth = fetchWidth; + + params->renameToDecodeDelay = renameToDecodeDelay; + params->iewToDecodeDelay = iewToDecodeDelay; + params->commitToDecodeDelay = commitToDecodeDelay; + params->fetchToDecodeDelay = fetchToDecodeDelay; + params->decodeWidth = decodeWidth; + + params->iewToRenameDelay = iewToRenameDelay; + params->commitToRenameDelay = commitToRenameDelay; + params->decodeToRenameDelay = decodeToRenameDelay; + params->renameWidth = renameWidth; + + params->commitToIEWDelay = commitToIEWDelay; + params->renameToIEWDelay = renameToIEWDelay; + params->issueToExecuteDelay = issueToExecuteDelay; + params->issueWidth = issueWidth; + params->executeWidth = executeWidth; + params->executeIntWidth = executeIntWidth; + params->executeFloatWidth = executeFloatWidth; + params->executeBranchWidth = executeBranchWidth; + params->executeMemoryWidth = executeMemoryWidth; + + params->iewToCommitDelay = iewToCommitDelay; + params->renameToROBDelay = renameToROBDelay; + params->commitWidth = commitWidth; + params->squashWidth = squashWidth; + + params->predType = predType; + params->localPredictorSize = localPredictorSize; + params->localCtrBits = localCtrBits; + params->localHistoryTableSize = localHistoryTableSize; + params->localHistoryBits = localHistoryBits; + params->globalPredictorSize = globalPredictorSize; + params->globalCtrBits = globalCtrBits; + params->globalHistoryBits = globalHistoryBits; + params->choicePredictorSize = choicePredictorSize; + params->choiceCtrBits = choiceCtrBits; + + params->BTBEntries = BTBEntries; + params->BTBTagSize = BTBTagSize; + + params->RASSize = RASSize; + + params->LQEntries = LQEntries; + params->SQEntries = SQEntries; + + params->SSITSize = SSITSize; + params->LFSTSize = LFSTSize; + + params->numPhysIntRegs = numPhysIntRegs; + params->numPhysFloatRegs = numPhysFloatRegs; + params->numIQEntries = numIQEntries; + params->numROBEntries = numROBEntries; + + params->decoupledFrontEnd = decoupledFrontEnd; + params->dispatchWidth = dispatchWidth; + params->wbWidth = wbWidth; + + params->smtNumFetchingThreads = smtNumFetchingThreads; + params->smtFetchPolicy = smtFetchPolicy; + params->smtIQPolicy = smtIQPolicy; + params->smtLSQPolicy = smtLSQPolicy; + params->smtLSQThreshold = smtLSQThreshold; + params->smtROBPolicy = smtROBPolicy; + params->smtROBThreshold = smtROBThreshold; + params->smtCommitPolicy = smtCommitPolicy; + + params->instShiftAmt = 2; + + params->deferRegistration = defer_registration; + + params->functionTrace = function_trace; + params->functionTraceStart = function_trace_start; + + cpu = new DerivOzoneCPU(params); + + return cpu; +} + +REGISTER_SIM_OBJECT("DerivOzoneCPU", DerivOzoneCPU) + + + +//////////////////////////////////////////////////////////////////////// +// +// OzoneCPU Simulation Object +// + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleOzoneCPU) + + Param<int> clock; + Param<int> numThreads; + +#if FULL_SYSTEM +SimObjectParam<System *> system; +Param<int> cpu_id; +SimObjectParam<AlphaITB *> itb; +SimObjectParam<AlphaDTB *> dtb; +#else +SimObjectVectorParam<Process *> workload; +//SimObjectParam<PageTable *> page_table; +#endif // FULL_SYSTEM + +SimObjectParam<FunctionalMemory *> mem; + +SimObjectParam<BaseCPU *> checker; + +Param<Counter> max_insts_any_thread; +Param<Counter> max_insts_all_threads; +Param<Counter> max_loads_any_thread; +Param<Counter> max_loads_all_threads; + +SimObjectParam<BaseCache *> icache; +SimObjectParam<BaseCache *> dcache; + +Param<unsigned> cachePorts; +Param<unsigned> width; +Param<unsigned> frontEndWidth; +Param<unsigned> backEndWidth; +Param<unsigned> backEndSquashLatency; +Param<unsigned> backEndLatency; +Param<unsigned> maxInstBufferSize; +Param<unsigned> numPhysicalRegs; + +Param<unsigned> decodeToFetchDelay; +Param<unsigned> renameToFetchDelay; +Param<unsigned> iewToFetchDelay; +Param<unsigned> commitToFetchDelay; +Param<unsigned> fetchWidth; + +Param<unsigned> renameToDecodeDelay; +Param<unsigned> iewToDecodeDelay; +Param<unsigned> commitToDecodeDelay; +Param<unsigned> fetchToDecodeDelay; +Param<unsigned> decodeWidth; + +Param<unsigned> iewToRenameDelay; +Param<unsigned> commitToRenameDelay; +Param<unsigned> decodeToRenameDelay; +Param<unsigned> renameWidth; + +Param<unsigned> commitToIEWDelay; +Param<unsigned> renameToIEWDelay; +Param<unsigned> issueToExecuteDelay; +Param<unsigned> issueWidth; +Param<unsigned> executeWidth; +Param<unsigned> executeIntWidth; +Param<unsigned> executeFloatWidth; +Param<unsigned> executeBranchWidth; +Param<unsigned> executeMemoryWidth; + +Param<unsigned> iewToCommitDelay; +Param<unsigned> renameToROBDelay; +Param<unsigned> commitWidth; +Param<unsigned> squashWidth; + +Param<std::string> predType; +Param<unsigned> localPredictorSize; +Param<unsigned> localCtrBits; +Param<unsigned> localHistoryTableSize; +Param<unsigned> localHistoryBits; +Param<unsigned> globalPredictorSize; +Param<unsigned> globalCtrBits; +Param<unsigned> globalHistoryBits; +Param<unsigned> choicePredictorSize; +Param<unsigned> choiceCtrBits; + +Param<unsigned> BTBEntries; +Param<unsigned> BTBTagSize; + +Param<unsigned> RASSize; + +Param<unsigned> LQEntries; +Param<unsigned> SQEntries; +Param<unsigned> LFSTSize; +Param<unsigned> SSITSize; + +Param<unsigned> numPhysIntRegs; +Param<unsigned> numPhysFloatRegs; +Param<unsigned> numIQEntries; +Param<unsigned> numROBEntries; + +Param<bool> decoupledFrontEnd; +Param<int> dispatchWidth; +Param<int> wbWidth; + +Param<unsigned> smtNumFetchingThreads; +Param<std::string> smtFetchPolicy; +Param<std::string> smtLSQPolicy; +Param<unsigned> smtLSQThreshold; +Param<std::string> smtIQPolicy; +Param<unsigned> smtIQThreshold; +Param<std::string> smtROBPolicy; +Param<unsigned> smtROBThreshold; +Param<std::string> smtCommitPolicy; + +Param<unsigned> instShiftAmt; + +Param<bool> defer_registration; + +Param<bool> function_trace; +Param<Tick> function_trace_start; + +END_DECLARE_SIM_OBJECT_PARAMS(SimpleOzoneCPU) + +BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleOzoneCPU) + + INIT_PARAM(clock, "clock speed"), + INIT_PARAM(numThreads, "number of HW thread contexts"), + +#if FULL_SYSTEM + INIT_PARAM(system, "System object"), + INIT_PARAM(cpu_id, "processor ID"), + INIT_PARAM(itb, "Instruction translation buffer"), + INIT_PARAM(dtb, "Data translation buffer"), +#else + INIT_PARAM(workload, "Processes to run"), +// INIT_PARAM(page_table, "Page table"), +#endif // FULL_SYSTEM + + INIT_PARAM_DFLT(mem, "Memory", NULL), + + INIT_PARAM_DFLT(checker, "Checker CPU", NULL), + + INIT_PARAM_DFLT(max_insts_any_thread, + "Terminate when any thread reaches this inst count", + 0), + INIT_PARAM_DFLT(max_insts_all_threads, + "Terminate when all threads have reached" + "this inst count", + 0), + INIT_PARAM_DFLT(max_loads_any_thread, + "Terminate when any thread reaches this load count", + 0), + INIT_PARAM_DFLT(max_loads_all_threads, + "Terminate when all threads have reached this load" + "count", + 0), + + INIT_PARAM_DFLT(icache, "L1 instruction cache", NULL), + INIT_PARAM_DFLT(dcache, "L1 data cache", NULL), + + INIT_PARAM_DFLT(cachePorts, "Cache Ports", 200), + INIT_PARAM_DFLT(width, "Width", 1), + INIT_PARAM_DFLT(frontEndWidth, "Front end width", 1), + INIT_PARAM_DFLT(backEndWidth, "Back end width", 1), + INIT_PARAM_DFLT(backEndSquashLatency, "Back end squash latency", 1), + INIT_PARAM_DFLT(backEndLatency, "Back end latency", 1), + INIT_PARAM_DFLT(maxInstBufferSize, "Maximum instruction buffer size", 16), + INIT_PARAM(numPhysicalRegs, "Number of physical registers"), + + INIT_PARAM(decodeToFetchDelay, "Decode to fetch delay"), + INIT_PARAM(renameToFetchDelay, "Rename to fetch delay"), + INIT_PARAM(iewToFetchDelay, "Issue/Execute/Writeback to fetch" + "delay"), + INIT_PARAM(commitToFetchDelay, "Commit to fetch delay"), + INIT_PARAM(fetchWidth, "Fetch width"), + INIT_PARAM(renameToDecodeDelay, "Rename to decode delay"), + INIT_PARAM(iewToDecodeDelay, "Issue/Execute/Writeback to decode" + "delay"), + INIT_PARAM(commitToDecodeDelay, "Commit to decode delay"), + INIT_PARAM(fetchToDecodeDelay, "Fetch to decode delay"), + INIT_PARAM(decodeWidth, "Decode width"), + + INIT_PARAM(iewToRenameDelay, "Issue/Execute/Writeback to rename" + "delay"), + INIT_PARAM(commitToRenameDelay, "Commit to rename delay"), + INIT_PARAM(decodeToRenameDelay, "Decode to rename delay"), + INIT_PARAM(renameWidth, "Rename width"), + + INIT_PARAM(commitToIEWDelay, "Commit to " + "Issue/Execute/Writeback delay"), + INIT_PARAM(renameToIEWDelay, "Rename to " + "Issue/Execute/Writeback delay"), + INIT_PARAM(issueToExecuteDelay, "Issue to execute delay (internal" + "to the IEW stage)"), + INIT_PARAM(issueWidth, "Issue width"), + INIT_PARAM(executeWidth, "Execute width"), + INIT_PARAM(executeIntWidth, "Integer execute width"), + INIT_PARAM(executeFloatWidth, "Floating point execute width"), + INIT_PARAM(executeBranchWidth, "Branch execute width"), + INIT_PARAM(executeMemoryWidth, "Memory execute width"), + + INIT_PARAM(iewToCommitDelay, "Issue/Execute/Writeback to commit " + "delay"), + INIT_PARAM(renameToROBDelay, "Rename to reorder buffer delay"), + INIT_PARAM(commitWidth, "Commit width"), + INIT_PARAM(squashWidth, "Squash width"), + + INIT_PARAM(predType, "Type of branch predictor ('local', 'tournament')"), + INIT_PARAM(localPredictorSize, "Size of local predictor"), + INIT_PARAM(localCtrBits, "Bits per counter"), + INIT_PARAM(localHistoryTableSize, "Size of local history table"), + INIT_PARAM(localHistoryBits, "Bits for the local history"), + INIT_PARAM(globalPredictorSize, "Size of global predictor"), + INIT_PARAM(globalCtrBits, "Bits per counter"), + INIT_PARAM(globalHistoryBits, "Bits of history"), + INIT_PARAM(choicePredictorSize, "Size of choice predictor"), + INIT_PARAM(choiceCtrBits, "Bits of choice counters"), + + INIT_PARAM(BTBEntries, "Number of BTB entries"), + INIT_PARAM(BTBTagSize, "Size of the BTB tags, in bits"), + + INIT_PARAM(RASSize, "RAS size"), + + INIT_PARAM(LQEntries, "Number of load queue entries"), + INIT_PARAM(SQEntries, "Number of store queue entries"), + INIT_PARAM(LFSTSize, "Last fetched store table size"), + INIT_PARAM(SSITSize, "Store set ID table size"), + + INIT_PARAM(numPhysIntRegs, "Number of physical integer registers"), + INIT_PARAM(numPhysFloatRegs, "Number of physical floating point " + "registers"), + INIT_PARAM(numIQEntries, "Number of instruction queue entries"), + INIT_PARAM(numROBEntries, "Number of reorder buffer entries"), + + INIT_PARAM_DFLT(decoupledFrontEnd, "Decoupled front end", true), + INIT_PARAM_DFLT(dispatchWidth, "Dispatch width", 0), + INIT_PARAM_DFLT(wbWidth, "Writeback width", 0), + + INIT_PARAM_DFLT(smtNumFetchingThreads, "SMT Number of Fetching Threads", 1), + INIT_PARAM_DFLT(smtFetchPolicy, "SMT Fetch Policy", "SingleThread"), + INIT_PARAM_DFLT(smtLSQPolicy, "SMT LSQ Sharing Policy", "Partitioned"), + INIT_PARAM_DFLT(smtLSQThreshold,"SMT LSQ Threshold", 100), + INIT_PARAM_DFLT(smtIQPolicy, "SMT IQ Policy", "Partitioned"), + INIT_PARAM_DFLT(smtIQThreshold, "SMT IQ Threshold", 100), + INIT_PARAM_DFLT(smtROBPolicy, "SMT ROB Sharing Policy", "Partitioned"), + INIT_PARAM_DFLT(smtROBThreshold,"SMT ROB Threshold", 100), + INIT_PARAM_DFLT(smtCommitPolicy,"SMT Commit Fetch Policy", "RoundRobin"), + + INIT_PARAM(instShiftAmt, "Number of bits to shift instructions by"), + INIT_PARAM(defer_registration, "defer system registration (for sampling)"), + + INIT_PARAM(function_trace, "Enable function trace"), + INIT_PARAM(function_trace_start, "Cycle to start function trace") + +END_INIT_SIM_OBJECT_PARAMS(SimpleOzoneCPU) + +CREATE_SIM_OBJECT(SimpleOzoneCPU) +{ + SimpleOzoneCPU *cpu; + +#if FULL_SYSTEM + // Full-system only supports a single thread for the moment. + int actual_num_threads = 1; +#else + // In non-full-system mode, we infer the number of threads from + // the workload if it's not explicitly specified. + int actual_num_threads = + numThreads.isValid() ? numThreads : workload.size(); + + if (workload.size() == 0) { + fatal("Must specify at least one workload!"); + } + +#endif + + SimpleParams *params = new SimpleParams; + + params->clock = clock; + + params->name = getInstanceName(); + params->numberOfThreads = actual_num_threads; + +#if FULL_SYSTEM + params->system = system; + params->cpu_id = cpu_id; + params->itb = itb; + params->dtb = dtb; +#else + params->workload = workload; +// params->pTable = page_table; +#endif // FULL_SYSTEM + + params->mem = mem; + params->checker = checker; + params->max_insts_any_thread = max_insts_any_thread; + params->max_insts_all_threads = max_insts_all_threads; + params->max_loads_any_thread = max_loads_any_thread; + params->max_loads_all_threads = max_loads_all_threads; + + // + // Caches + // + params->icacheInterface = icache ? icache->getInterface() : NULL; + params->dcacheInterface = dcache ? dcache->getInterface() : NULL; + params->cachePorts = cachePorts; + + params->width = width; + params->frontEndWidth = frontEndWidth; + params->backEndWidth = backEndWidth; + params->backEndSquashLatency = backEndSquashLatency; + params->backEndLatency = backEndLatency; + params->maxInstBufferSize = maxInstBufferSize; + params->numPhysicalRegs = numPhysIntRegs + numPhysFloatRegs; + + params->decodeToFetchDelay = decodeToFetchDelay; + params->renameToFetchDelay = renameToFetchDelay; + params->iewToFetchDelay = iewToFetchDelay; + params->commitToFetchDelay = commitToFetchDelay; + params->fetchWidth = fetchWidth; + + params->renameToDecodeDelay = renameToDecodeDelay; + params->iewToDecodeDelay = iewToDecodeDelay; + params->commitToDecodeDelay = commitToDecodeDelay; + params->fetchToDecodeDelay = fetchToDecodeDelay; + params->decodeWidth = decodeWidth; + + params->iewToRenameDelay = iewToRenameDelay; + params->commitToRenameDelay = commitToRenameDelay; + params->decodeToRenameDelay = decodeToRenameDelay; + params->renameWidth = renameWidth; + + params->commitToIEWDelay = commitToIEWDelay; + params->renameToIEWDelay = renameToIEWDelay; + params->issueToExecuteDelay = issueToExecuteDelay; + params->issueWidth = issueWidth; + params->executeWidth = executeWidth; + params->executeIntWidth = executeIntWidth; + params->executeFloatWidth = executeFloatWidth; + params->executeBranchWidth = executeBranchWidth; + params->executeMemoryWidth = executeMemoryWidth; + + params->iewToCommitDelay = iewToCommitDelay; + params->renameToROBDelay = renameToROBDelay; + params->commitWidth = commitWidth; + params->squashWidth = squashWidth; + + params->predType = predType; + params->localPredictorSize = localPredictorSize; + params->localCtrBits = localCtrBits; + params->localHistoryTableSize = localHistoryTableSize; + params->localHistoryBits = localHistoryBits; + params->globalPredictorSize = globalPredictorSize; + params->globalCtrBits = globalCtrBits; + params->globalHistoryBits = globalHistoryBits; + params->choicePredictorSize = choicePredictorSize; + params->choiceCtrBits = choiceCtrBits; + + params->BTBEntries = BTBEntries; + params->BTBTagSize = BTBTagSize; + + params->RASSize = RASSize; + + params->LQEntries = LQEntries; + params->SQEntries = SQEntries; + + params->SSITSize = SSITSize; + params->LFSTSize = LFSTSize; + + params->numPhysIntRegs = numPhysIntRegs; + params->numPhysFloatRegs = numPhysFloatRegs; + params->numIQEntries = numIQEntries; + params->numROBEntries = numROBEntries; + + params->decoupledFrontEnd = decoupledFrontEnd; + params->dispatchWidth = dispatchWidth; + params->wbWidth = wbWidth; + + params->smtNumFetchingThreads = smtNumFetchingThreads; + params->smtFetchPolicy = smtFetchPolicy; + params->smtIQPolicy = smtIQPolicy; + params->smtLSQPolicy = smtLSQPolicy; + params->smtLSQThreshold = smtLSQThreshold; + params->smtROBPolicy = smtROBPolicy; + params->smtROBThreshold = smtROBThreshold; + params->smtCommitPolicy = smtCommitPolicy; + + params->instShiftAmt = 2; + + params->deferRegistration = defer_registration; + + params->functionTrace = function_trace; + params->functionTraceStart = function_trace_start; + + cpu = new SimpleOzoneCPU(params); + + return cpu; +} + +REGISTER_SIM_OBJECT("SimpleOzoneCPU", SimpleOzoneCPU) + diff --git a/src/cpu/ozone/cpu_impl.hh b/src/cpu/ozone/cpu_impl.hh new file mode 100644 index 000000000..76e2318aa --- /dev/null +++ b/src/cpu/ozone/cpu_impl.hh @@ -0,0 +1,1090 @@ +/* + * 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 + * Nathan Binkert + */ + +//#include <cstdio> +//#include <cstdlib> + +#include "arch/isa_traits.hh" // For MachInst +#include "base/trace.hh" +#include "config/full_system.hh" +#include "cpu/base.hh" +#include "cpu/checker/thread_context.hh" +#include "cpu/thread_context.hh" +#include "cpu/exetrace.hh" +#include "cpu/ozone/cpu.hh" +#include "cpu/quiesce_event.hh" +#include "cpu/static_inst.hh" +//#include "mem/base_mem.hh" +#include "mem/mem_interface.hh" +#include "sim/sim_object.hh" +#include "sim/stats.hh" + +#if FULL_SYSTEM +#include "arch/faults.hh" +#include "arch/alpha/osfpal.hh" +#include "arch/alpha/tlb.hh" +#include "arch/vtophys.hh" +#include "base/callback.hh" +//#include "base/remote_gdb.hh" +#include "cpu/profile.hh" +#include "kern/kernel_stats.hh" +#include "mem/functional/memory_control.hh" +#include "mem/functional/physical.hh" +#include "sim/faults.hh" +#include "sim/sim_events.hh" +#include "sim/sim_exit.hh" +#include "sim/system.hh" +#else // !FULL_SYSTEM +#include "mem/functional/functional.hh" +#include "sim/process.hh" +#endif // FULL_SYSTEM + +using namespace TheISA; + +template <class Impl> +template<typename T> +void +OzoneCPU<Impl>::trace_data(T data) { + if (traceData) { + traceData->setData(data); + } +} + +template <class Impl> +OzoneCPU<Impl>::TickEvent::TickEvent(OzoneCPU *c, int w) + : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c), width(w) +{ +} + +template <class Impl> +void +OzoneCPU<Impl>::TickEvent::process() +{ + cpu->tick(); +} + +template <class Impl> +const char * +OzoneCPU<Impl>::TickEvent::description() +{ + return "OzoneCPU tick event"; +} + +template <class Impl> +OzoneCPU<Impl>::OzoneCPU(Params *p) +#if FULL_SYSTEM + : BaseCPU(p), thread(this, 0, p->mem), tickEvent(this, p->width), + mem(p->mem), +#else + : BaseCPU(p), thread(this, 0, p->workload[0], 0), tickEvent(this, p->width), + mem(p->workload[0]->getMemory()), +#endif + comm(5, 5) +{ + frontEnd = new FrontEnd(p); + backEnd = new BackEnd(p); + + _status = Idle; + + if (p->checker) { + BaseCPU *temp_checker = p->checker; + checker = dynamic_cast<Checker<DynInstPtr> *>(temp_checker); + checker->setMemory(mem); +#if FULL_SYSTEM + checker->setSystem(p->system); +#endif + checkerTC = new CheckerThreadContext<OzoneTC>(&ozoneTC, checker); + thread.tc = checkerTC; + tc = checkerXC; + } else { + checker = NULL; + thread.tc = &ozoneTC; + tc = &ozoneTC; + } + + ozoneTC.cpu = this; + ozoneTC.thread = &thread; + + thread.inSyscall = false; + + thread.setStatus(ThreadContext::Suspended); +#if FULL_SYSTEM + /***** All thread state stuff *****/ + thread.cpu = this; + thread.tid = 0; + thread.mem = p->mem; + + thread.quiesceEvent = new EndQuiesceEvent(tc); + + system = p->system; + itb = p->itb; + dtb = p->dtb; + memctrl = p->system->memctrl; + physmem = p->system->physmem; + + if (p->profile) { + thread.profile = new FunctionProfile(p->system->kernelSymtab); + // @todo: This might be better as an ThreadContext instead of OzoneTC + Callback *cb = + new MakeCallback<OzoneTC, + &OzoneTC::dumpFuncProfile>(&ozoneTC); + registerExitCallback(cb); + } + + // let's fill with a dummy node for now so we don't get a segfault + // on the first cycle when there's no node available. + static ProfileNode dummyNode; + thread.profileNode = &dummyNode; + thread.profilePC = 3; +#else + thread.cpu = this; + thread.tid = 0; + thread.process = p->workload[0]; + thread.asid = 0; +#endif // !FULL_SYSTEM + + numInst = 0; + startNumInst = 0; + + threadContexts.push_back(tc); + + frontEnd->setCPU(this); + backEnd->setCPU(this); + + frontEnd->setTC(tc); + backEnd->setTC(tc); + + frontEnd->setThreadState(&thread); + backEnd->setThreadState(&thread); + + frontEnd->setCommBuffer(&comm); + backEnd->setCommBuffer(&comm); + + frontEnd->setBackEnd(backEnd); + backEnd->setFrontEnd(frontEnd); + + decoupledFrontEnd = p->decoupledFrontEnd; + + globalSeqNum = 1; + + checkInterrupts = false; + + for (int i = 0; i < TheISA::TotalNumRegs; ++i) { + thread.renameTable[i] = new DynInst(this); + thread.renameTable[i]->setResultReady(); + } + + frontEnd->renameTable.copyFrom(thread.renameTable); + backEnd->renameTable.copyFrom(thread.renameTable); + +#if !FULL_SYSTEM +// pTable = p->pTable; +#endif + + lockFlag = 0; + + DPRINTF(OzoneCPU, "OzoneCPU: Created Ozone cpu object.\n"); +} + +template <class Impl> +OzoneCPU<Impl>::~OzoneCPU() +{ +} + +template <class Impl> +void +OzoneCPU<Impl>::switchOut(Sampler *_sampler) +{ + sampler = _sampler; + switchCount = 0; + // Front end needs state from back end, so switch out the back end first. + backEnd->switchOut(); + frontEnd->switchOut(); +} + +template <class Impl> +void +OzoneCPU<Impl>::signalSwitched() +{ + if (++switchCount == 2) { + backEnd->doSwitchOut(); + frontEnd->doSwitchOut(); + if (checker) + checker->switchOut(sampler); + _status = SwitchedOut; + if (tickEvent.scheduled()) + tickEvent.squash(); + sampler->signalSwitched(); + } + assert(switchCount <= 2); +} + +template <class Impl> +void +OzoneCPU<Impl>::takeOverFrom(BaseCPU *oldCPU) +{ + BaseCPU::takeOverFrom(oldCPU); + + backEnd->takeOverFrom(); + frontEnd->takeOverFrom(); + assert(!tickEvent.scheduled()); + + // @todo: Fix hardcoded number + // Clear out any old information in time buffer. + for (int i = 0; i < 6; ++i) { + comm.advance(); + } + + // if any of this CPU's ThreadContexts are active, mark the CPU as + // running and schedule its tick event. + for (int i = 0; i < threadContexts.size(); ++i) { + ThreadContext *tc = threadContexts[i]; + if (tc->status() == ThreadContext::Active && + _status != Running) { + _status = Running; + tickEvent.schedule(curTick); + } + } + // Nothing running, change status to reflect that we're no longer + // switched out. + if (_status == SwitchedOut) { + _status = Idle; + } +} + +template <class Impl> +void +OzoneCPU<Impl>::activateContext(int thread_num, int delay) +{ + // Eventually change this in SMT. + assert(thread_num == 0); + + assert(_status == Idle); + notIdleFraction++; + scheduleTickEvent(delay); + _status = Running; + thread._status = ThreadContext::Active; + frontEnd->wakeFromQuiesce(); +} + +template <class Impl> +void +OzoneCPU<Impl>::suspendContext(int thread_num) +{ + // Eventually change this in SMT. + assert(thread_num == 0); + // @todo: Figure out how to initially set the status properly so + // this is running. +// assert(_status == Running); + notIdleFraction--; + unscheduleTickEvent(); + _status = Idle; +} + +template <class Impl> +void +OzoneCPU<Impl>::deallocateContext(int thread_num) +{ + // for now, these are equivalent + suspendContext(thread_num); +} + +template <class Impl> +void +OzoneCPU<Impl>::haltContext(int thread_num) +{ + // for now, these are equivalent + suspendContext(thread_num); +} + +template <class Impl> +void +OzoneCPU<Impl>::regStats() +{ + using namespace Stats; + + BaseCPU::regStats(); + + thread.numInsts + .name(name() + ".num_insts") + .desc("Number of instructions executed") + ; + + thread.numMemRefs + .name(name() + ".num_refs") + .desc("Number of memory references") + ; + + notIdleFraction + .name(name() + ".not_idle_fraction") + .desc("Percentage of non-idle cycles") + ; + + idleFraction + .name(name() + ".idle_fraction") + .desc("Percentage of idle cycles") + ; + + quiesceCycles + .name(name() + ".quiesce_cycles") + .desc("Number of cycles spent in quiesce") + ; + + idleFraction = constant(1.0) - notIdleFraction; + + frontEnd->regStats(); + backEnd->regStats(); +} + +template <class Impl> +void +OzoneCPU<Impl>::resetStats() +{ + startNumInst = numInst; + notIdleFraction = (_status != Idle); +} + +template <class Impl> +void +OzoneCPU<Impl>::init() +{ + BaseCPU::init(); + + // Mark this as in syscall so it won't need to squash + thread.inSyscall = true; +#if FULL_SYSTEM + for (int i = 0; i < threadContexts.size(); ++i) { + ThreadContext *tc = threadContexts[i]; + + // initialize CPU, including PC + TheISA::initCPU(tc, tc->readCpuId()); + } +#endif + frontEnd->renameTable.copyFrom(thread.renameTable); + backEnd->renameTable.copyFrom(thread.renameTable); + + thread.inSyscall = false; +} + +template <class Impl> +void +OzoneCPU<Impl>::serialize(std::ostream &os) +{ + BaseCPU::serialize(os); + SERIALIZE_ENUM(_status); + nameOut(os, csprintf("%s.tc", name())); + ozoneTC.serialize(os); + nameOut(os, csprintf("%s.tickEvent", name())); + tickEvent.serialize(os); +} + +template <class Impl> +void +OzoneCPU<Impl>::unserialize(Checkpoint *cp, const std::string §ion) +{ + BaseCPU::unserialize(cp, section); + UNSERIALIZE_ENUM(_status); + ozoneTC.unserialize(cp, csprintf("%s.tc", section)); + tickEvent.unserialize(cp, csprintf("%s.tickEvent", section)); +} + +template <class Impl> +Fault +OzoneCPU<Impl>::copySrcTranslate(Addr src) +{ + panic("Copy not implemented!\n"); + return NoFault; +#if 0 + static bool no_warn = true; + int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; + // Only support block sizes of 64 atm. + assert(blk_size == 64); + int offset = src & (blk_size - 1); + + // Make sure block doesn't span page + if (no_warn && + (src & TheISA::PageMask) != ((src + blk_size) & TheISA::PageMask) && + (src >> 40) != 0xfffffc) { + warn("Copied block source spans pages %x.", src); + no_warn = false; + } + + memReq->reset(src & ~(blk_size - 1), blk_size); + + // translate to physical address + Fault fault = tc->translateDataReadReq(memReq); + + assert(fault != Alignment_Fault); + + if (fault == NoFault) { + tc->copySrcAddr = src; + tc->copySrcPhysAddr = memReq->paddr + offset; + } else { + tc->copySrcAddr = 0; + tc->copySrcPhysAddr = 0; + } + return fault; +#endif +} + +template <class Impl> +Fault +OzoneCPU<Impl>::copy(Addr dest) +{ + panic("Copy not implemented!\n"); + return NoFault; +#if 0 + static bool no_warn = true; + int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; + // Only support block sizes of 64 atm. + assert(blk_size == 64); + uint8_t data[blk_size]; + //assert(tc->copySrcAddr); + int offset = dest & (blk_size - 1); + + // Make sure block doesn't span page + if (no_warn && + (dest & TheISA::PageMask) != ((dest + blk_size) & TheISA::PageMask) && + (dest >> 40) != 0xfffffc) { + no_warn = false; + warn("Copied block destination spans pages %x. ", dest); + } + + memReq->reset(dest & ~(blk_size -1), blk_size); + // translate to physical address + Fault fault = tc->translateDataWriteReq(memReq); + + assert(fault != Alignment_Fault); + + if (fault == NoFault) { + Addr dest_addr = memReq->paddr + offset; + // Need to read straight from memory since we have more than 8 bytes. + memReq->paddr = tc->copySrcPhysAddr; + tc->mem->read(memReq, data); + memReq->paddr = dest_addr; + tc->mem->write(memReq, data); + if (dcacheInterface) { + memReq->cmd = Copy; + memReq->completionEvent = NULL; + memReq->paddr = tc->copySrcPhysAddr; + memReq->dest = dest_addr; + memReq->size = 64; + memReq->time = curTick; + dcacheInterface->access(memReq); + } + } + return fault; +#endif +} + +#if FULL_SYSTEM +template <class Impl> +Addr +OzoneCPU<Impl>::dbg_vtophys(Addr addr) +{ + return vtophys(tcProxy, addr); +} +#endif // FULL_SYSTEM + +#if FULL_SYSTEM +template <class Impl> +void +OzoneCPU<Impl>::post_interrupt(int int_num, int index) +{ + BaseCPU::post_interrupt(int_num, index); + + if (_status == Idle) { + DPRINTF(IPI,"Suspended Processor awoke\n"); +// thread.activate(); + // Hack for now. Otherwise might have to go through the tc, or + // I need to figure out what's the right thing to call. + activateContext(thread.tid, 1); + } +} +#endif // FULL_SYSTEM + +/* start simulation, program loaded, processor precise state initialized */ +template <class Impl> +void +OzoneCPU<Impl>::tick() +{ + DPRINTF(OzoneCPU, "\n\nOzoneCPU: Ticking cpu.\n"); + + _status = Running; + thread.renameTable[ZeroReg]->setIntResult(0); + thread.renameTable[ZeroReg+TheISA::FP_Base_DepTag]-> + setDoubleResult(0.0); + + comm.advance(); + frontEnd->tick(); + backEnd->tick(); + + // check for instruction-count-based events + comInstEventQueue[0]->serviceEvents(numInst); + + if (!tickEvent.scheduled() && _status == Running) + tickEvent.schedule(curTick + cycles(1)); +} + +template <class Impl> +void +OzoneCPU<Impl>::squashFromTC() +{ + thread.inSyscall = true; + backEnd->generateTCEvent(); +} + +#if !FULL_SYSTEM +template <class Impl> +void +OzoneCPU<Impl>::syscall() +{ + // Not sure this copy is needed, depending on how the TC proxy is made. + thread.renameTable.copyFrom(backEnd->renameTable); + + thread.inSyscall = true; + + thread.funcExeInst++; + + DPRINTF(OzoneCPU, "FuncExeInst: %i\n", thread.funcExeInst); + + thread.process->syscall(yc); + + thread.funcExeInst--; + + thread.inSyscall = false; + + frontEnd->renameTable.copyFrom(thread.renameTable); + backEnd->renameTable.copyFrom(thread.renameTable); +} + +template <class Impl> +void +OzoneCPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid) +{ + // check for error condition. Alpha syscall convention is to + // indicate success/failure in reg a3 (r19) and put the + // return value itself in the standard return value reg (v0). + if (return_value.successful()) { + // no error + thread.renameTable[SyscallSuccessReg]->setIntResult(0); + thread.renameTable[ReturnValueReg]->setIntResult( + return_value.value()); + } else { + // got an error, return details + thread.renameTable[SyscallSuccessReg]->setIntResult((IntReg) -1); + thread.renameTable[ReturnValueReg]->setIntResult( + -return_value.value()); + } +} +#else +template <class Impl> +Fault +OzoneCPU<Impl>::hwrei() +{ + // Need to move this to ISA code + // May also need to make this per thread + + lockFlag = false; + lockAddrList.clear(); + thread.kernelStats->hwrei(); + + checkInterrupts = true; + + // FIXME: XXX check for interrupts? XXX + return NoFault; +} + +template <class Impl> +void +OzoneCPU<Impl>::processInterrupts() +{ + // Check for interrupts here. For now can copy the code that + // exists within isa_fullsys_traits.hh. Also assume that thread 0 + // is the one that handles the interrupts. + + // Check if there are any outstanding interrupts + //Handle the interrupts + int ipl = 0; + int summary = 0; + + checkInterrupts = false; + + if (thread.readMiscReg(IPR_ASTRR)) + panic("asynchronous traps not implemented\n"); + + if (thread.readMiscReg(IPR_SIRR)) { + for (int i = INTLEVEL_SOFTWARE_MIN; + i < INTLEVEL_SOFTWARE_MAX; i++) { + if (thread.readMiscReg(IPR_SIRR) & (ULL(1) << i)) { + // See table 4-19 of the 21164 hardware reference + ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1; + summary |= (ULL(1) << i); + } + } + } + + uint64_t interrupts = intr_status(); + + if (interrupts) { + for (int i = INTLEVEL_EXTERNAL_MIN; + i < INTLEVEL_EXTERNAL_MAX; i++) { + if (interrupts & (ULL(1) << i)) { + // See table 4-19 of the 21164 hardware reference + ipl = i; + summary |= (ULL(1) << i); + } + } + } + + if (ipl && ipl > thread.readMiscReg(IPR_IPLR)) { + thread.setMiscReg(IPR_ISR, summary); + thread.setMiscReg(IPR_INTID, ipl); + // @todo: Make this more transparent + if (checker) { + checker->threadBase()->setMiscReg(IPR_ISR, summary); + checker->threadBase()->setMiscReg(IPR_INTID, ipl); + } + Fault fault = new InterruptFault; + fault->invoke(thread.getTC()); + DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", + thread.readMiscReg(IPR_IPLR), ipl, summary); + } +} + +template <class Impl> +bool +OzoneCPU<Impl>::simPalCheck(int palFunc) +{ + // Need to move this to ISA code + // May also need to make this per thread + thread.kernelStats->callpal(palFunc, tc); + + switch (palFunc) { + case PAL::halt: + haltContext(thread.tid); + if (--System::numSystemsRunning == 0) + new SimExitEvent("all cpus halted"); + break; + + case PAL::bpt: + case PAL::bugchk: + if (system->breakpoint()) + return false; + break; + } + + return true; +} +#endif + +template <class Impl> +BaseCPU * +OzoneCPU<Impl>::OzoneTC::getCpuPtr() +{ + return cpu; +} + +template <class Impl> +void +OzoneCPU<Impl>::OzoneTC::setCpuId(int id) +{ + cpu->cpuId = id; + thread->cpuId = id; +} + +template <class Impl> +void +OzoneCPU<Impl>::OzoneTC::setStatus(Status new_status) +{ + thread->_status = new_status; +} + +template <class Impl> +void +OzoneCPU<Impl>::OzoneTC::activate(int delay) +{ + cpu->activateContext(thread->tid, delay); +} + +/// Set the status to Suspended. +template <class Impl> +void +OzoneCPU<Impl>::OzoneTC::suspend() +{ + cpu->suspendContext(thread->tid); +} + +/// Set the status to Unallocated. +template <class Impl> +void +OzoneCPU<Impl>::OzoneTC::deallocate() +{ + cpu->deallocateContext(thread->tid); +} + +/// Set the status to Halted. +template <class Impl> +void +OzoneCPU<Impl>::OzoneTC::halt() +{ + cpu->haltContext(thread->tid); +} + +#if FULL_SYSTEM +template <class Impl> +void +OzoneCPU<Impl>::OzoneTC::dumpFuncProfile() +{ } +#endif + +template <class Impl> +void +OzoneCPU<Impl>::OzoneTC::takeOverFrom(ThreadContext *old_context) +{ + // some things should already be set up + assert(getMemPtr() == old_context->getMemPtr()); +#if FULL_SYSTEM + assert(getSystemPtr() == old_context->getSystemPtr()); +#else + assert(getProcessPtr() == old_context->getProcessPtr()); +#endif + + // copy over functional state + setStatus(old_context->status()); + copyArchRegs(old_context); + setCpuId(old_context->readCpuId()); + +#if !FULL_SYSTEM + setFuncExeInst(old_context->readFuncExeInst()); +#else + EndQuiesceEvent *other_quiesce = old_context->getQuiesceEvent(); + if (other_quiesce) { + // Point the quiesce event's TC at this TC so that it wakes up + // the proper CPU. + other_quiesce->tc = this; + } + if (thread->quiesceEvent) { + thread->quiesceEvent->tc = this; + } + + thread->kernelStats = old_context->getKernelStats(); +// storeCondFailures = 0; + cpu->lockFlag = false; +#endif + + old_context->setStatus(ThreadContext::Unallocated); +} + +template <class Impl> +void +OzoneCPU<Impl>::OzoneTC::regStats(const std::string &name) +{ +#if FULL_SYSTEM + thread->kernelStats = new Kernel::Statistics(cpu->system); + thread->kernelStats->regStats(name + ".kern"); +#endif +} + +template <class Impl> +void +OzoneCPU<Impl>::OzoneTC::serialize(std::ostream &os) +{ } + +template <class Impl> +void +OzoneCPU<Impl>::OzoneTC::unserialize(Checkpoint *cp, const std::string §ion) +{ } + +#if FULL_SYSTEM +template <class Impl> +EndQuiesceEvent * +OzoneCPU<Impl>::OzoneTC::getQuiesceEvent() +{ + return thread->quiesceEvent; +} + +template <class Impl> +Tick +OzoneCPU<Impl>::OzoneTC::readLastActivate() +{ + return thread->lastActivate; +} + +template <class Impl> +Tick +OzoneCPU<Impl>::OzoneTC::readLastSuspend() +{ + return thread->lastSuspend; +} + +template <class Impl> +void +OzoneCPU<Impl>::OzoneTC::profileClear() +{ + if (thread->profile) + thread->profile->clear(); +} + +template <class Impl> +void +OzoneCPU<Impl>::OzoneTC::profileSample() +{ + if (thread->profile) + thread->profile->sample(thread->profileNode, thread->profilePC); +} +#endif + +template <class Impl> +int +OzoneCPU<Impl>::OzoneTC::getThreadNum() +{ + return thread->tid; +} + +// Also somewhat obnoxious. Really only used for the TLB fault. +template <class Impl> +TheISA::MachInst +OzoneCPU<Impl>::OzoneTC::getInst() +{ + return thread->inst; +} + +template <class Impl> +void +OzoneCPU<Impl>::OzoneTC::copyArchRegs(ThreadContext *tc) +{ + thread->PC = tc->readPC(); + thread->nextPC = tc->readNextPC(); + + cpu->frontEnd->setPC(thread->PC); + cpu->frontEnd->setNextPC(thread->nextPC); + + for (int i = 0; i < TheISA::TotalNumRegs; ++i) { + if (i < TheISA::FP_Base_DepTag) { + thread->renameTable[i]->setIntResult(tc->readIntReg(i)); + } else if (i < (TheISA::FP_Base_DepTag + TheISA::NumFloatRegs)) { + int fp_idx = i - TheISA::FP_Base_DepTag; + thread->renameTable[i]->setDoubleResult( + tc->readFloatRegDouble(fp_idx)); + } + } + +#if !FULL_SYSTEM + thread->funcExeInst = tc->readFuncExeInst(); +#endif + + // Need to copy the TC values into the current rename table, + // copy the misc regs. + thread->regs.miscRegs.copyMiscRegs(tc); +} + +template <class Impl> +void +OzoneCPU<Impl>::OzoneTC::clearArchRegs() +{ + panic("Unimplemented!"); +} + +template <class Impl> +uint64_t +OzoneCPU<Impl>::OzoneTC::readIntReg(int reg_idx) +{ + return thread->renameTable[reg_idx]->readIntResult(); +} + +template <class Impl> +float +OzoneCPU<Impl>::OzoneTC::readFloatReg(int reg_idx, int width) +{ + int idx = reg_idx + TheISA::FP_Base_DepTag; + switch(width) { + case 32: + return thread->renameTable[idx]->readFloatResult(); + case 64: + return thread->renameTable[idx]->readDoubleResult(); + default: + panic("Unsupported width!"); + return 0; + } +} + +template <class Impl> +double +OzoneCPU<Impl>::OzoneTC::readFloatReg(int reg_idx) +{ + int idx = reg_idx + TheISA::FP_Base_DepTag; + return thread->renameTable[idx]->readFloatResult(); +} + +template <class Impl> +uint64_t +OzoneCPU<Impl>::OzoneTC::readFloatRegBits(int reg_idx, int width) +{ + int idx = reg_idx + TheISA::FP_Base_DepTag; + return thread->renameTable[idx]->readIntResult(); +} + +template <class Impl> +uint64_t +OzoneCPU<Impl>::OzoneTC::readFloatRegBits(int reg_idx) +{ + int idx = reg_idx + TheISA::FP_Base_DepTag; + return thread->renameTable[idx]->readIntResult(); +} + +template <class Impl> +void +OzoneCPU<Impl>::OzoneTC::setIntReg(int reg_idx, uint64_t val) +{ + thread->renameTable[reg_idx]->setIntResult(val); + + if (!thread->inSyscall) { + cpu->squashFromTC(); + } +} + +template <class Impl> +void +OzoneCPU<Impl>::OzoneTC::setFloatReg(int reg_idx, FloatReg val, int width) +{ + int idx = reg_idx + TheISA::FP_Base_DepTag; + switch(width) { + case 32: + panic("Unimplemented!"); + break; + case 64: + thread->renameTable[idx]->setDoubleResult(val); + break; + default: + panic("Unsupported width!"); + } + + if (!thread->inSyscall) { + cpu->squashFromTC(); + } +} + +template <class Impl> +void +OzoneCPU<Impl>::OzoneTC::setFloatReg(int reg_idx, FloatReg val) +{ + int idx = reg_idx + TheISA::FP_Base_DepTag; + + thread->renameTable[idx]->setDoubleResult(val); + + if (!thread->inSyscall) { + cpu->squashFromTC(); + } +} + +template <class Impl> +void +OzoneCPU<Impl>::OzoneTC::setFloatRegBits(int reg_idx, FloatRegBits val, + int width) +{ + panic("Unimplemented!"); +} + +template <class Impl> +void +OzoneCPU<Impl>::OzoneTC::setFloatRegBits(int reg_idx, FloatRegBits val) +{ + panic("Unimplemented!"); +} + +template <class Impl> +void +OzoneCPU<Impl>::OzoneTC::setPC(Addr val) +{ + thread->PC = val; + cpu->frontEnd->setPC(val); + + if (!thread->inSyscall) { + cpu->squashFromTC(); + } +} + +template <class Impl> +void +OzoneCPU<Impl>::OzoneTC::setNextPC(Addr val) +{ + thread->nextPC = val; + cpu->frontEnd->setNextPC(val); + + if (!thread->inSyscall) { + cpu->squashFromTC(); + } +} + +template <class Impl> +TheISA::MiscReg +OzoneCPU<Impl>::OzoneTC::readMiscReg(int misc_reg) +{ + return thread->regs.miscRegs.readReg(misc_reg); +} + +template <class Impl> +TheISA::MiscReg +OzoneCPU<Impl>::OzoneTC::readMiscRegWithEffect(int misc_reg, Fault &fault) +{ + return thread->regs.miscRegs.readRegWithEffect(misc_reg, + fault, this); +} + +template <class Impl> +Fault +OzoneCPU<Impl>::OzoneTC::setMiscReg(int misc_reg, const MiscReg &val) +{ + // Needs to setup a squash event unless we're in syscall mode + Fault ret_fault = thread->regs.miscRegs.setReg(misc_reg, val); + + if (!thread->inSyscall) { + cpu->squashFromTC(); + } + + return ret_fault; +} + +template <class Impl> +Fault +OzoneCPU<Impl>::OzoneTC::setMiscRegWithEffect(int misc_reg, const MiscReg &val) +{ + // Needs to setup a squash event unless we're in syscall mode + Fault ret_fault = thread->regs.miscRegs.setRegWithEffect(misc_reg, val, + this); + + if (!thread->inSyscall) { + cpu->squashFromTC(); + } + + return ret_fault; +} diff --git a/src/cpu/ozone/dyn_inst.cc b/src/cpu/ozone/dyn_inst.cc new file mode 100644 index 000000000..732fb96b8 --- /dev/null +++ b/src/cpu/ozone/dyn_inst.cc @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2005-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#include "cpu/ozone/dyn_inst_impl.hh" +#include "cpu/ozone/ozone_impl.hh" +//#include "cpu/ozone/simple_impl.hh" + +template class OzoneDynInst<OzoneImpl>; +//template class OzoneDynInst<SimpleImpl>; + diff --git a/src/cpu/ozone/dyn_inst.hh b/src/cpu/ozone/dyn_inst.hh new file mode 100644 index 000000000..0bb50bd69 --- /dev/null +++ b/src/cpu/ozone/dyn_inst.hh @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2005-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_OZONE_DYN_INST_HH__ +#define __CPU_OZONE_DYN_INST_HH__ + +#include "arch/isa_traits.hh" +#include "config/full_system.hh" +#include "cpu/base_dyn_inst.hh" +#include "cpu/ozone/cpu.hh" // MUST include this +#include "cpu/inst_seq.hh" +//#include "cpu/ozone/simple_impl.hh" // Would be nice to not have to include this +#include "cpu/ozone/ozone_impl.hh" + +#include <list> +#include <vector> + +template <class Impl> +class OzoneDynInst : public BaseDynInst<Impl> +{ + public: + // Typedefs + typedef typename Impl::FullCPU FullCPU; + + typedef typename FullCPU::ImplState ImplState; + + // Typedef for DynInstPtr. This is really just a RefCountingPtr<OoODynInst>. + typedef typename Impl::DynInstPtr DynInstPtr; + + typedef TheISA::ExtMachInst ExtMachInst; + typedef TheISA::MachInst MachInst; + typedef TheISA::MiscReg MiscReg; + typedef typename std::list<DynInstPtr>::iterator ListIt; + + // Note that this is duplicated from the BaseDynInst class; I'm + // simply not sure the enum would carry through so I could use it + // in array declarations in this class. + enum { + MaxInstSrcRegs = TheISA::MaxInstSrcRegs, + MaxInstDestRegs = TheISA::MaxInstDestRegs + }; + + OzoneDynInst(FullCPU *cpu); + + OzoneDynInst(ExtMachInst inst, Addr PC, Addr Pred_PC, + InstSeqNum seq_num, FullCPU *cpu); + + OzoneDynInst(StaticInstPtr inst); + + ~OzoneDynInst(); + + void setSrcInst(DynInstPtr &newSrcInst, int regIdx) + { srcInsts[regIdx] = newSrcInst; } + + bool srcInstReady(int regIdx); + + void setPrevDestInst(DynInstPtr &oldDestInst, int regIdx) + { prevDestInst[regIdx] = oldDestInst; } + + DynInstPtr &getPrevDestInst(int regIdx) + { return prevDestInst[regIdx]; } + + void addDependent(DynInstPtr &dependent_inst); + + std::vector<DynInstPtr> &getDependents() { return dependents; } + std::vector<DynInstPtr> &getMemDeps() { return memDependents; } + std::list<DynInstPtr> &getMemSrcs() { return srcMemInsts; } + + void wakeDependents(); + + void wakeMemDependents(); + + void addMemDependent(DynInstPtr &inst) { memDependents.push_back(inst); } + + void addSrcMemInst(DynInstPtr &inst) { srcMemInsts.push_back(inst); } + + void markMemInstReady(OzoneDynInst<Impl> *inst); + + // For now I will remove instructions from the list when they wake + // up. In the future, you only really need a counter. + bool memDepReady() { return srcMemInsts.empty(); } + + private: + void initInstPtrs(); + + std::vector<DynInstPtr> dependents; + + std::vector<DynInstPtr> memDependents; + + std::list<DynInstPtr> srcMemInsts; + + /** The instruction that produces the value of the source + * registers. These may be NULL if the value has already been + * read from the source instruction. + */ + DynInstPtr srcInsts[MaxInstSrcRegs]; + + /** + * Previous rename instruction for this destination. + */ + DynInstPtr prevDestInst[MaxInstSrcRegs]; + + public: + + Fault initiateAcc(); + + Fault completeAcc(); + + // 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 readIntReg(const StaticInst *si, int idx) + { + return srcInsts[idx]->readIntResult(); + } + + float readFloatRegSingle(const StaticInst *si, int idx) + { + return srcInsts[idx]->readFloatResult(); + } + + double readFloatRegDouble(const StaticInst *si, int idx) + { + return srcInsts[idx]->readDoubleResult(); + } + + uint64_t readFloatRegInt(const StaticInst *si, int idx) + { + return srcInsts[idx]->readIntResult(); + } + + /** @todo: Make results into arrays so they can handle multiple dest + * registers. + */ + void setIntReg(const StaticInst *si, int idx, uint64_t val) + { + BaseDynInst<Impl>::setIntReg(si, idx, val); + } + + void setFloatRegSingle(const StaticInst *si, int idx, float val) + { + BaseDynInst<Impl>::setFloatRegSingle(si, idx, val); + } + + void setFloatRegDouble(const StaticInst *si, int idx, double val) + { + BaseDynInst<Impl>::setFloatRegDouble(si, idx, val); + } + + void setFloatRegInt(const StaticInst *si, int idx, uint64_t val) + { + BaseDynInst<Impl>::setFloatRegInt(si, idx, val); + } + + void setIntResult(uint64_t result) { this->instResult.integer = result; } + void setDoubleResult(double result) { this->instResult.dbl = result; } + + bool srcsReady(); + bool eaSrcsReady(); + + Fault execute(); + + Fault executeEAComp() + { return NoFault; } + + Fault executeMemAcc() + { return this->staticInst->memAccInst()->execute(this, this->traceData); } + + void clearDependents(); + + void clearMemDependents(); + + public: + // ISA stuff + MiscReg readMiscReg(int misc_reg); + + MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault); + + Fault setMiscReg(int misc_reg, const MiscReg &val); + + Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val); + +#if FULL_SYSTEM + Fault hwrei(); + int readIntrFlag(); + void setIntrFlag(int val); + bool inPalMode(); + void trap(Fault fault); + bool simPalCheck(int palFunc); +#else + void syscall(); +#endif + + ListIt iqIt; + bool iqItValid; +}; + +#endif // __CPU_OZONE_DYN_INST_HH__ diff --git a/src/cpu/ozone/dyn_inst_impl.hh b/src/cpu/ozone/dyn_inst_impl.hh new file mode 100644 index 000000000..4149bf144 --- /dev/null +++ b/src/cpu/ozone/dyn_inst_impl.hh @@ -0,0 +1,317 @@ +/* + * Copyright (c) 2005-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 "arch/faults.hh" +#include "arch/isa_traits.hh" +#include "config/full_system.hh" +#include "cpu/ozone/dyn_inst.hh" +#include "kern/kernel_stats.hh" + +using namespace TheISA; + +template <class Impl> +OzoneDynInst<Impl>::OzoneDynInst(FullCPU *cpu) + : BaseDynInst<Impl>(0, 0, 0, 0, cpu) +{ + this->setResultReady(); + + initInstPtrs(); +} + +template <class Impl> +OzoneDynInst<Impl>::OzoneDynInst(ExtMachInst inst, Addr PC, Addr Pred_PC, + InstSeqNum seq_num, FullCPU *cpu) + : BaseDynInst<Impl>(inst, PC, Pred_PC, seq_num, cpu) +{ + initInstPtrs(); +} + +template <class Impl> +OzoneDynInst<Impl>::OzoneDynInst(StaticInstPtr _staticInst) + : BaseDynInst<Impl>(_staticInst) +{ + initInstPtrs(); +} + +template <class Impl> +OzoneDynInst<Impl>::~OzoneDynInst() +{ + DPRINTF(BE, "[sn:%lli] destructor called\n", this->seqNum); + for (int i = 0; i < this->numSrcRegs(); ++i) { + srcInsts[i] = NULL; + } + + for (int i = 0; i < this->numDestRegs(); ++i) { + prevDestInst[i] = NULL; + } + + dependents.clear(); +} + +template <class Impl> +Fault +OzoneDynInst<Impl>::execute() +{ + // @todo: Pretty convoluted way to avoid squashing from happening when using + // the XC during an instruction's execution (specifically for instructions + // that have sideeffects that use the XC). Fix this. + bool in_syscall = this->thread->inSyscall; + this->thread->inSyscall = true; + + this->fault = this->staticInst->execute(this, this->traceData); + + this->thread->inSyscall = in_syscall; + + return this->fault; +} + +template <class Impl> +Fault +OzoneDynInst<Impl>::initiateAcc() +{ + // @todo: Pretty convoluted way to avoid squashing from happening when using + // the XC during an instruction's execution (specifically for instructions + // that have sideeffects that use the XC). Fix this. + bool in_syscall = this->thread->inSyscall; + this->thread->inSyscall = true; + + this->fault = this->staticInst->initiateAcc(this, this->traceData); + + this->thread->inSyscall = in_syscall; + + return this->fault; +} + +template <class Impl> +Fault +OzoneDynInst<Impl>::completeAcc() +{ + if (this->isLoad()) { + this->fault = this->staticInst->completeAcc(this->req->data, + this, + this->traceData); + } else if (this->isStore()) { + this->fault = this->staticInst->completeAcc((uint8_t*)&this->req->result, + this, + this->traceData); + } else { + panic("Unknown type!"); + } + + return this->fault; +} + +template <class Impl> +bool +OzoneDynInst<Impl>::srcInstReady(int regIdx) +{ + return srcInsts[regIdx]->isResultReady(); +} + +template <class Impl> +void +OzoneDynInst<Impl>::addDependent(DynInstPtr &dependent_inst) +{ + dependents.push_back(dependent_inst); +} + +template <class Impl> +void +OzoneDynInst<Impl>::wakeDependents() +{ + for (int i = 0; i < dependents.size(); ++i) { + dependents[i]->markSrcRegReady(); + } +} + +template <class Impl> +void +OzoneDynInst<Impl>::wakeMemDependents() +{ + for (int i = 0; i < memDependents.size(); ++i) { + memDependents[i]->markMemInstReady(this); + } +} + +template <class Impl> +void +OzoneDynInst<Impl>::markMemInstReady(OzoneDynInst<Impl> *inst) +{ + ListIt mem_it = srcMemInsts.begin(); + while ((*mem_it) != inst && mem_it != srcMemInsts.end()) { + mem_it++; + } + assert(mem_it != srcMemInsts.end()); + + srcMemInsts.erase(mem_it); +} + +template <class Impl> +void +OzoneDynInst<Impl>::initInstPtrs() +{ + for (int i = 0; i < MaxInstSrcRegs; ++i) { + srcInsts[i] = NULL; + } + iqItValid = false; +} + +template <class Impl> +bool +OzoneDynInst<Impl>::srcsReady() +{ + for (int i = 0; i < this->numSrcRegs(); ++i) { + if (!srcInsts[i]->isResultReady()) + return false; + } + + return true; +} + +template <class Impl> +bool +OzoneDynInst<Impl>::eaSrcsReady() +{ + for (int i = 1; i < this->numSrcRegs(); ++i) { + if (!srcInsts[i]->isResultReady()) + return false; + } + + return true; +} + +template <class Impl> +void +OzoneDynInst<Impl>::clearDependents() +{ + dependents.clear(); + for (int i = 0; i < this->numSrcRegs(); ++i) { + srcInsts[i] = NULL; + } + for (int i = 0; i < this->numDestRegs(); ++i) { + prevDestInst[i] = NULL; + } +} + +template <class Impl> +void +OzoneDynInst<Impl>::clearMemDependents() +{ + memDependents.clear(); +} + +template <class Impl> +MiscReg +OzoneDynInst<Impl>::readMiscReg(int misc_reg) +{ + return this->thread->readMiscReg(misc_reg); +} + +template <class Impl> +MiscReg +OzoneDynInst<Impl>::readMiscRegWithEffect(int misc_reg, Fault &fault) +{ + return this->thread->readMiscRegWithEffect(misc_reg, fault); +} + +template <class Impl> +Fault +OzoneDynInst<Impl>::setMiscReg(int misc_reg, const MiscReg &val) +{ + this->setIntResult(val); + return this->thread->setMiscReg(misc_reg, val); +} + +template <class Impl> +Fault +OzoneDynInst<Impl>::setMiscRegWithEffect(int misc_reg, const MiscReg &val) +{ + return this->thread->setMiscRegWithEffect(misc_reg, val); +} + +#if FULL_SYSTEM + +template <class Impl> +Fault +OzoneDynInst<Impl>::hwrei() +{ + if (!this->cpu->inPalMode(this->readPC())) + return new AlphaISA::UnimplementedOpcodeFault; + + this->setNextPC(this->thread->readMiscReg(AlphaISA::IPR_EXC_ADDR)); + + this->cpu->hwrei(); + + // FIXME: XXX check for interrupts? XXX + return NoFault; +} + +template <class Impl> +int +OzoneDynInst<Impl>::readIntrFlag() +{ +return this->cpu->readIntrFlag(); +} + +template <class Impl> +void +OzoneDynInst<Impl>::setIntrFlag(int val) +{ + this->cpu->setIntrFlag(val); +} + +template <class Impl> +bool +OzoneDynInst<Impl>::inPalMode() +{ + return this->cpu->inPalMode(); +} + +template <class Impl> +void +OzoneDynInst<Impl>::trap(Fault fault) +{ + fault->invoke(this->thread->getXCProxy()); +} + +template <class Impl> +bool +OzoneDynInst<Impl>::simPalCheck(int palFunc) +{ + return this->cpu->simPalCheck(palFunc); +} +#else +template <class Impl> +void +OzoneDynInst<Impl>::syscall() +{ + this->cpu->syscall(); +} +#endif diff --git a/src/cpu/ozone/ea_list.cc b/src/cpu/ozone/ea_list.cc new file mode 100644 index 000000000..5ef240700 --- /dev/null +++ b/src/cpu/ozone/ea_list.cc @@ -0,0 +1,80 @@ +/* + * Copyright (c) 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 + * Nathan Binkert + */ + +#include "arch/isa_traits.hh" +#include "cpu/inst_seq.hh" +#include "cpu/ooo_cpu/ea_list.hh" + +void +EAList::addAddr(const InstSeqNum &new_sn, const Addr &new_ea) +{ + instEA newEA(new_sn, new_ea); + + eaList.push_back(newEA); +} + +void +EAList::clearAddr(const InstSeqNum &sn_to_clear, const Addr &ea_to_clear) +{ + eaListIt list_it = eaList.begin(); + + while (list_it != eaList.end() && (*list_it).first != sn_to_clear) { + assert((*list_it).second == ea_to_clear); + } +} + +bool +EAList::checkConflict(const InstSeqNum &check_sn, const Addr &check_ea) const +{ + const constEAListIt list_it = eaList.begin(); + + while (list_it != eaList.end() && (*list_it).first < check_sn) { + if ((*list_it).second == check_ea) { + return true; + } + } + + return false; +} + +void +EAList::clear() +{ + eaList.clear(); +} + +void +EAList::commit(const InstSeqNum &commit_sn) +{ + while (!eaList.empty() && eaList.front().first <= commit_sn) { + eaList.pop_front(); + } +} diff --git a/src/cpu/ozone/ea_list.hh b/src/cpu/ozone/ea_list.hh new file mode 100644 index 000000000..64882632c --- /dev/null +++ b/src/cpu/ozone/ea_list.hh @@ -0,0 +1,75 @@ +/* + * Copyright (c) 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 + * Nathan Binkert + */ + +#ifndef __CPU_EA_LIST_HH__ +#define __CPU_EA_LIST_HH__ + +#include <list> +#include <utility> + +#include "arch/isa_traits.hh" +#include "cpu/inst_seq.hh" + +/** + * Simple class to hold onto a list of pairs, each pair having a memory + * instruction's sequence number and effective addr. This list can be used + * for memory disambiguation. However, if I ever want to forward results, I + * may have to use a list that holds DynInstPtrs. Hence this may change in + * the future. + */ +class EAList { + private: + typedef std::pair<InstSeqNum, Addr> instEA; + typedef std::list<instEA>::iterator eaListIt; + typedef std::list<instEA>::const_iterator constEAListIt; + + std::list<instEA> eaList; + + public: + EAList() { } + ~EAList() { } + + void addAddr(const InstSeqNum &new_sn, const Addr &new_ea); + + void clearAddr(const InstSeqNum &sn_to_clear, const Addr &ea_to_clear); + + /** Checks if any instructions older than check_sn have a conflicting + * address with check_ea. Note that this function does not handle the + * sequence number rolling over. + */ + bool checkConflict(const InstSeqNum &check_sn, const Addr &check_ea) const; + + void clear(); + + void commit(const InstSeqNum &commit_sn); +}; + +#endif // __CPU_EA_LIST_HH__ diff --git a/src/cpu/ozone/front_end.cc b/src/cpu/ozone/front_end.cc new file mode 100644 index 000000000..f0ea8eae1 --- /dev/null +++ b/src/cpu/ozone/front_end.cc @@ -0,0 +1,36 @@ +/* + * 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 "cpu/ozone/front_end_impl.hh" +#include "cpu/ozone/ozone_impl.hh" +#include "cpu/ozone/simple_impl.hh" + +template class FrontEnd<OzoneImpl>; +template class FrontEnd<SimpleImpl>; diff --git a/src/cpu/ozone/front_end.hh b/src/cpu/ozone/front_end.hh new file mode 100644 index 000000000..af190008c --- /dev/null +++ b/src/cpu/ozone/front_end.hh @@ -0,0 +1,299 @@ +/* + * 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_OZONE_FRONT_END_HH__ +#define __CPU_OZONE_FRONT_END_HH__ + +#include <deque> + +#include "cpu/inst_seq.hh" +#include "cpu/o3/bpred_unit.hh" +#include "cpu/ozone/rename_table.hh" +#include "mem/request.hh" +#include "sim/eventq.hh" +#include "sim/stats.hh" + +class ThreadContext; +class MemInterface; +template <class> +class OzoneThreadState; +class PageTable; +template <class> +class TimeBuffer; + +template <class Impl> +class FrontEnd +{ + public: + typedef typename Impl::Params Params; + typedef typename Impl::DynInst DynInst; + typedef typename Impl::DynInstPtr DynInstPtr; + typedef typename Impl::FullCPU FullCPU; + typedef typename Impl::BackEnd BackEnd; + + typedef typename Impl::FullCPU::OzoneTC OzoneTC; + typedef typename Impl::FullCPU::CommStruct CommStruct; + + FrontEnd(Params *params); + + std::string name() const; + + void setCPU(FullCPU *cpu_ptr) + { cpu = cpu_ptr; } + + void setBackEnd(BackEnd *back_end_ptr) + { backEnd = back_end_ptr; } + + void setCommBuffer(TimeBuffer<CommStruct> *_comm); + + void setTC(ThreadContext *tc_ptr); + + void setThreadState(OzoneThreadState<Impl> *thread_ptr) + { thread = thread_ptr; } + + void regStats(); + + void tick(); + Fault fetchCacheLine(); + void processInst(DynInstPtr &inst); + void squash(const InstSeqNum &squash_num, const Addr &next_PC, + const bool is_branch = false, const bool branch_taken = false); + DynInstPtr getInst(); + + void processCacheCompletion(Packet *pkt); + + void addFreeRegs(int num_freed); + + bool isEmpty() { return instBuffer.empty(); } + + void switchOut(); + + void doSwitchOut(); + + void takeOverFrom(ThreadContext *old_tc = NULL); + + bool isSwitchedOut() { return switchedOut; } + + bool switchedOut; + + private: + bool updateStatus(); + + void checkBE(); + DynInstPtr getInstFromCacheline(); + void renameInst(DynInstPtr &inst); + // Returns true if we need to stop the front end this cycle + bool processBarriers(DynInstPtr &inst); + + void handleFault(Fault &fault); + public: + Fault getFault() { return fetchFault; } + private: + Fault fetchFault; + + // Align an address (typically a PC) to the start of an I-cache block. + // We fold in the PISA 64- to 32-bit conversion here as well. + Addr icacheBlockAlignPC(Addr addr) + { + addr = TheISA::realPCToFetchPC(addr); + return (addr & ~(cacheBlkMask)); + } + + InstSeqNum getAndIncrementInstSeq() + { return cpu->globalSeqNum++; } + + public: + FullCPU *cpu; + + BackEnd *backEnd; + + ThreadContext *tc; + + OzoneThreadState<Impl> *thread; + + enum Status { + Running, + Idle, + IcacheMissStall, + IcacheMissComplete, + SerializeBlocked, + SerializeComplete, + RenameBlocked, + QuiescePending, + TrapPending, + BEBlocked + }; + + Status status; + + private: + TimeBuffer<CommStruct> *comm; + typename TimeBuffer<CommStruct>::wire fromCommit; + + typedef typename Impl::BranchPred BranchPred; + + BranchPred branchPred; + + class IcachePort : public Port + { + protected: + FrontEnd *fe; + + public: + IcachePort(const std::string &_name, FrontEnd *_fe) + : Port(_name), fe(_fe) + { } + + protected: + virtual Tick recvAtomic(PacketPtr pkt); + + virtual void recvFunctional(PacketPtr pkt); + + virtual void recvStatusChange(Status status); + + virtual void getDeviceAddressRanges(AddrRangeList &resp, + AddrRangeList &snoop) + { resp.clear(); snoop.clear(); } + + virtual bool recvTiming(PacketPtr pkt); + + virtual void recvRetry(); + }; + + IcachePort icachePort; + +#if !FULL_SYSTEM + PageTable *pTable; +#endif + + RequestPtr memReq; + + /** Mask to get a cache block's address. */ + Addr cacheBlkMask; + + unsigned cacheBlkSize; + + Addr cacheBlkPC; + + /** The cache line being fetched. */ + uint8_t *cacheData; + + bool fetchCacheLineNextCycle; + + bool cacheBlkValid; + + public: + RenameTable<Impl> renameTable; + + private: + Addr PC; + Addr nextPC; + + public: + void setPC(Addr val) { PC = val; } + void setNextPC(Addr val) { nextPC = val; } + + void wakeFromQuiesce(); + + void dumpInsts(); + + private: + typedef typename std::deque<DynInstPtr> InstBuff; + typedef typename InstBuff::iterator InstBuffIt; + + InstBuff instBuffer; + + int instBufferSize; + + int maxInstBufferSize; + + int width; + + int freeRegs; + + int numPhysRegs; + + bool serializeNext; + + DynInstPtr barrierInst; + + public: + bool interruptPending; + private: + // number of idle cycles +/* + Stats::Average<> notIdleFraction; + Stats::Formula idleFraction; +*/ + // @todo: Consider making these vectors and tracking on a per thread basis. + /** Stat for total number of cycles stalled due to an icache miss. */ + Stats::Scalar<> icacheStallCycles; + /** Stat for total number of fetched instructions. */ + Stats::Scalar<> fetchedInsts; + Stats::Scalar<> fetchedBranches; + /** Stat for total number of predicted branches. */ + Stats::Scalar<> predictedBranches; + /** Stat for total number of cycles spent fetching. */ + Stats::Scalar<> fetchCycles; + + Stats::Scalar<> fetchIdleCycles; + /** Stat for total number of cycles spent squashing. */ + Stats::Scalar<> fetchSquashCycles; + /** Stat for total number of cycles spent blocked due to other stages in + * the pipeline. + */ + Stats::Scalar<> fetchBlockedCycles; + /** Stat for total number of fetched cache lines. */ + Stats::Scalar<> fetchedCacheLines; + + Stats::Scalar<> fetchIcacheSquashes; + /** Distribution of number of instructions fetched each cycle. */ + Stats::Distribution<> fetchNisnDist; +// Stats::Vector<> qfull_iq_occupancy; +// Stats::VectorDistribution<> qfull_iq_occ_dist_; + Stats::Formula idleRate; + Stats::Formula branchRate; + Stats::Formula fetchRate; + Stats::Scalar<> IFQCount; // cumulative IFQ occupancy + Stats::Formula IFQOccupancy; + Stats::Formula IFQLatency; + Stats::Scalar<> IFQFcount; // cumulative IFQ full count + Stats::Formula IFQFullRate; + + Stats::Scalar<> dispatchCountStat; + Stats::Scalar<> dispatchedSerializing; + Stats::Scalar<> dispatchedTempSerializing; + Stats::Scalar<> dispatchSerializeStallCycles; + Stats::Formula dispatchRate; + Stats::Formula regIntFull; + Stats::Formula regFpFull; +}; + +#endif // __CPU_OZONE_FRONT_END_HH__ diff --git a/src/cpu/ozone/front_end_impl.hh b/src/cpu/ozone/front_end_impl.hh new file mode 100644 index 000000000..467567c10 --- /dev/null +++ b/src/cpu/ozone/front_end_impl.hh @@ -0,0 +1,922 @@ +/* + * 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 "arch/faults.hh" +#include "arch/isa_traits.hh" +#include "base/statistics.hh" +#include "cpu/thread_context.hh" +#include "cpu/exetrace.hh" +#include "cpu/ozone/front_end.hh" +#include "mem/mem_interface.hh" +#include "sim/byte_swap.hh" + +using namespace TheISA; + +template <class Impl> +FrontEnd<Impl>::FrontEnd(Params *params) + : branchPred(params), + icacheInterface(params->icacheInterface), + instBufferSize(0), + maxInstBufferSize(params->maxInstBufferSize), + width(params->frontEndWidth), + freeRegs(params->numPhysicalRegs), + numPhysRegs(params->numPhysicalRegs), + serializeNext(false), + interruptPending(false) +{ + switchedOut = false; + + status = Idle; + + memReq = NULL; + // Size of cache block. + cacheBlkSize = icacheInterface ? icacheInterface->getBlockSize() : 64; + + assert(isPowerOf2(cacheBlkSize)); + + // Create mask to get rid of offset bits. + cacheBlkMask = (cacheBlkSize - 1); + + // Create space to store a cache line. + cacheData = new uint8_t[cacheBlkSize]; + + fetchCacheLineNextCycle = true; + + cacheBlkValid = false; + +#if !FULL_SYSTEM +// pTable = params->pTable; +#endif + fetchFault = NoFault; +} + +template <class Impl> +std::string +FrontEnd<Impl>::name() const +{ + return cpu->name() + ".frontend"; +} + +template <class Impl> +void +FrontEnd<Impl>::setCommBuffer(TimeBuffer<CommStruct> *_comm) +{ + comm = _comm; + // @todo: Hardcoded for now. Allow this to be set by a latency. + fromCommit = comm->getWire(-1); +} + +template <class Impl> +void +FrontEnd<Impl>::setTC(ThreadContext *tc_ptr) +{ + tc = tc_ptr; +} + +template <class Impl> +void +FrontEnd<Impl>::regStats() +{ + icacheStallCycles + .name(name() + ".icacheStallCycles") + .desc("Number of cycles fetch is stalled on an Icache miss") + .prereq(icacheStallCycles); + + fetchedInsts + .name(name() + ".fetchedInsts") + .desc("Number of instructions fetch has processed") + .prereq(fetchedInsts); + + fetchedBranches + .name(name() + ".fetchedBranches") + .desc("Number of fetched branches") + .prereq(fetchedBranches); + + predictedBranches + .name(name() + ".predictedBranches") + .desc("Number of branches that fetch has predicted taken") + .prereq(predictedBranches); + + fetchCycles + .name(name() + ".fetchCycles") + .desc("Number of cycles fetch has run and was not squashing or" + " blocked") + .prereq(fetchCycles); + + fetchIdleCycles + .name(name() + ".fetchIdleCycles") + .desc("Number of cycles fetch was idle") + .prereq(fetchIdleCycles); + + fetchSquashCycles + .name(name() + ".fetchSquashCycles") + .desc("Number of cycles fetch has spent squashing") + .prereq(fetchSquashCycles); + + fetchBlockedCycles + .name(name() + ".fetchBlockedCycles") + .desc("Number of cycles fetch has spent blocked") + .prereq(fetchBlockedCycles); + + fetchedCacheLines + .name(name() + ".fetchedCacheLines") + .desc("Number of cache lines fetched") + .prereq(fetchedCacheLines); + + fetchIcacheSquashes + .name(name() + ".fetchIcacheSquashes") + .desc("Number of outstanding Icache misses that were squashed") + .prereq(fetchIcacheSquashes); + + fetchNisnDist + .init(/* base value */ 0, + /* last value */ width, + /* bucket size */ 1) + .name(name() + ".rateDist") + .desc("Number of instructions fetched each cycle (Total)") + .flags(Stats::pdf); + + idleRate + .name(name() + ".idleRate") + .desc("Percent of cycles fetch was idle") + .prereq(idleRate); + idleRate = fetchIdleCycles * 100 / cpu->numCycles; + + branchRate + .name(name() + ".branchRate") + .desc("Number of branch fetches per cycle") + .flags(Stats::total); + branchRate = fetchedBranches / cpu->numCycles; + + fetchRate + .name(name() + ".rate") + .desc("Number of inst fetches per cycle") + .flags(Stats::total); + fetchRate = fetchedInsts / cpu->numCycles; + + IFQCount + .name(name() + ".IFQ:count") + .desc("cumulative IFQ occupancy") + ; + + IFQFcount + .name(name() + ".IFQ:fullCount") + .desc("cumulative IFQ full count") + .flags(Stats::total) + ; + + IFQOccupancy + .name(name() + ".IFQ:occupancy") + .desc("avg IFQ occupancy (inst's)") + ; + IFQOccupancy = IFQCount / cpu->numCycles; + + IFQLatency + .name(name() + ".IFQ:latency") + .desc("avg IFQ occupant latency (cycle's)") + .flags(Stats::total) + ; + + IFQFullRate + .name(name() + ".IFQ:fullRate") + .desc("fraction of time (cycles) IFQ was full") + .flags(Stats::total); + ; + IFQFullRate = IFQFcount * Stats::constant(100) / cpu->numCycles; + + dispatchCountStat + .name(name() + ".DIS:count") + .desc("cumulative count of dispatched insts") + .flags(Stats::total) + ; + + dispatchedSerializing + .name(name() + ".DIS:serializingInsts") + .desc("count of serializing insts dispatched") + .flags(Stats::total) + ; + + dispatchedTempSerializing + .name(name() + ".DIS:tempSerializingInsts") + .desc("count of temporary serializing insts dispatched") + .flags(Stats::total) + ; + + dispatchSerializeStallCycles + .name(name() + ".DIS:serializeStallCycles") + .desc("count of cycles dispatch stalled for serializing inst") + .flags(Stats::total) + ; + + dispatchRate + .name(name() + ".DIS:rate") + .desc("dispatched insts per cycle") + .flags(Stats::total) + ; + dispatchRate = dispatchCountStat / cpu->numCycles; + + regIntFull + .name(name() + ".REG:int:full") + .desc("number of cycles where there were no INT registers") + ; + + regFpFull + .name(name() + ".REG:fp:full") + .desc("number of cycles where there were no FP registers") + ; + IFQLatency = IFQOccupancy / dispatchRate; + + branchPred.regStats(); +} + +template <class Impl> +void +FrontEnd<Impl>::tick() +{ + if (switchedOut) + return; + + // @todo: Maybe I want to just have direct communication... + if (fromCommit->doneSeqNum) { + branchPred.update(fromCommit->doneSeqNum, 0); + } + + IFQCount += instBufferSize; + IFQFcount += instBufferSize == maxInstBufferSize; + + // Fetch cache line + if (status == IcacheMissComplete) { + cacheBlkValid = true; + + status = Running; + if (barrierInst) + status = SerializeBlocked; + if (freeRegs <= 0) + status = RenameBlocked; + checkBE(); + } else if (status == IcacheMissStall) { + DPRINTF(FE, "Still in Icache miss stall.\n"); + icacheStallCycles++; + return; + } + + if (status == RenameBlocked || status == SerializeBlocked || + status == TrapPending || status == BEBlocked) { + // Will cause a one cycle bubble between changing state and + // restarting. + DPRINTF(FE, "In blocked status.\n"); + + fetchBlockedCycles++; + + if (status == SerializeBlocked) { + dispatchSerializeStallCycles++; + } + updateStatus(); + return; + } else if (status == QuiescePending) { + DPRINTF(FE, "Waiting for quiesce to execute or get squashed.\n"); + return; + } else if (status != IcacheMissComplete) { + if (fetchCacheLineNextCycle) { + Fault fault = fetchCacheLine(); + if (fault != NoFault) { + handleFault(fault); + fetchFault = fault; + return; + } + fetchCacheLineNextCycle = false; + } + // If miss, stall until it returns. + if (status == IcacheMissStall) { + // Tell CPU to not tick me for now. + return; + } + } + + fetchCycles++; + + int num_inst = 0; + + // Otherwise loop and process instructions. + // One way to hack infinite width is to set width and maxInstBufferSize + // both really high. Inelegant, but probably will work. + while (num_inst < width && + instBufferSize < maxInstBufferSize) { + // Get instruction from cache line. + DynInstPtr inst = getInstFromCacheline(); + + if (!inst) { + // PC is no longer in the cache line, end fetch. + // Might want to check this at the end of the cycle so that + // there's no cycle lost to checking for a new cache line. + DPRINTF(FE, "Need to get new cache line\n"); + fetchCacheLineNextCycle = true; + break; + } + + processInst(inst); + + if (status == SerializeBlocked) { + break; + } + + // Possibly push into a time buffer that estimates the front end + // latency + instBuffer.push_back(inst); + ++instBufferSize; + ++num_inst; + +#if FULL_SYSTEM + if (inst->isQuiesce()) { + warn("%lli: Quiesce instruction encountered, halting fetch!", curTick); + status = QuiescePending; + break; + } +#endif + + if (inst->predTaken()) { + // Start over with tick? + break; + } else if (freeRegs <= 0) { + DPRINTF(FE, "Ran out of free registers to rename to!\n"); + status = RenameBlocked; + break; + } else if (serializeNext) { + break; + } + } + + fetchNisnDist.sample(num_inst); + checkBE(); + + DPRINTF(FE, "Num insts processed: %i, Inst Buffer size: %i, Free " + "Regs %i\n", num_inst, instBufferSize, freeRegs); +} + +template <class Impl> +Fault +FrontEnd<Impl>::fetchCacheLine() +{ + // Read a cache line, based on the current PC. +#if FULL_SYSTEM + // Flag to say whether or not address is physical addr. + unsigned flags = cpu->inPalMode(PC) ? PHYSICAL : 0; +#else + unsigned flags = 0; +#endif // FULL_SYSTEM + Fault fault = NoFault; + + if (interruptPending && flags == 0) { + return fault; + } + + // Align the fetch PC so it's at the start of a cache block. + Addr fetch_PC = icacheBlockAlignPC(PC); + + DPRINTF(FE, "Fetching cache line starting at %#x.\n", fetch_PC); + + // Setup the memReq to do a read of the first isntruction's address. + // Set the appropriate read size and flags as well. + memReq = new MemReq(); + + memReq->asid = 0; + memReq->thread_num = 0; + memReq->data = new uint8_t[64]; + memReq->tc = tc; + memReq->cmd = Read; + memReq->reset(fetch_PC, cacheBlkSize, flags); + + // Translate the instruction request. + fault = cpu->translateInstReq(memReq); + + // Now do the timing access to see whether or not the instruction + // exists within the cache. + if (icacheInterface && fault == NoFault) { +#if FULL_SYSTEM + if (cpu->system->memctrl->badaddr(memReq->paddr) || + memReq->flags & UNCACHEABLE) { + DPRINTF(FE, "Fetch: Bad address %#x (hopefully on a " + "misspeculating path!", + memReq->paddr); + return TheISA::genMachineCheckFault(); + } +#endif + + memReq->completionEvent = NULL; + + memReq->time = curTick; + fault = cpu->mem->read(memReq, cacheData); + + MemAccessResult res = icacheInterface->access(memReq); + + // If the cache missed then schedule an event to wake + // up this stage once the cache miss completes. + if (icacheInterface->doEvents() && res != MA_HIT) { + memReq->completionEvent = new ICacheCompletionEvent(memReq, this); + + status = IcacheMissStall; + + cacheBlkValid = false; + + DPRINTF(FE, "Cache miss.\n"); + } else { + DPRINTF(FE, "Cache hit.\n"); + + cacheBlkValid = true; + +// memcpy(cacheData, memReq->data, memReq->size); + } + } + + // Note that this will set the cache block PC a bit earlier than it should + // be set. + cacheBlkPC = fetch_PC; + + ++fetchedCacheLines; + + DPRINTF(FE, "Done fetching cache line.\n"); + + return fault; +} + +template <class Impl> +void +FrontEnd<Impl>::processInst(DynInstPtr &inst) +{ + if (processBarriers(inst)) { + return; + } + + Addr inst_PC = inst->readPC(); + + if (!inst->isControl()) { + inst->setPredTarg(inst->readNextPC()); + } else { + fetchedBranches++; + if (branchPred.predict(inst, inst_PC, inst->threadNumber)) { + predictedBranches++; + } + } + + Addr next_PC = inst->readPredTarg(); + + DPRINTF(FE, "[sn:%lli] Predicted and processed inst PC %#x, next PC " + "%#x\n", inst->seqNum, inst_PC, next_PC); + +// inst->setNextPC(next_PC); + + // Not sure where I should set this + PC = next_PC; + + renameInst(inst); +} + +template <class Impl> +bool +FrontEnd<Impl>::processBarriers(DynInstPtr &inst) +{ + if (serializeNext) { + inst->setSerializeBefore(); + serializeNext = false; + } else if (!inst->isSerializing() && + !inst->isIprAccess() && + !inst->isStoreConditional()) { + return false; + } + + if ((inst->isIprAccess() || inst->isSerializeBefore()) && + !inst->isSerializeHandled()) { + DPRINTF(FE, "Serialize before instruction encountered.\n"); + + if (!inst->isTempSerializeBefore()) { + dispatchedSerializing++; + inst->setSerializeHandled(); + } else { + dispatchedTempSerializing++; + } + + // Change status over to SerializeBlocked so that other stages know + // what this is blocked on. + status = SerializeBlocked; + + barrierInst = inst; + return true; + } else if ((inst->isStoreConditional() || inst->isSerializeAfter()) + && !inst->isSerializeHandled()) { + DPRINTF(FE, "Serialize after instruction encountered.\n"); + + inst->setSerializeHandled(); + + dispatchedSerializing++; + + serializeNext = true; + return false; + } + return false; +} + +template <class Impl> +void +FrontEnd<Impl>::handleFault(Fault &fault) +{ + DPRINTF(FE, "Fault at fetch, telling commit\n"); + + // We're blocked on the back end until it handles this fault. + status = TrapPending; + + // Get a sequence number. + InstSeqNum inst_seq = getAndIncrementInstSeq(); + // We will use a nop in order to carry the fault. + ExtMachInst ext_inst = TheISA::NoopMachInst; + + // Create a new DynInst from the dummy nop. + DynInstPtr instruction = new DynInst(ext_inst, PC, + PC+sizeof(MachInst), + inst_seq, cpu); + instruction->setPredTarg(instruction->readNextPC()); +// instruction->setThread(tid); + +// instruction->setASID(tid); + + instruction->setState(thread); + + instruction->traceData = NULL; + + instruction->fault = fault; + instruction->setCanIssue(); + instBuffer.push_back(instruction); + ++instBufferSize; +} + +template <class Impl> +void +FrontEnd<Impl>::squash(const InstSeqNum &squash_num, const Addr &next_PC, + const bool is_branch, const bool branch_taken) +{ + DPRINTF(FE, "Squashing from [sn:%lli], setting PC to %#x\n", + squash_num, next_PC); + + if (fetchFault != NoFault) + fetchFault = NoFault; + + while (!instBuffer.empty() && + instBuffer.back()->seqNum > squash_num) { + DynInstPtr inst = instBuffer.back(); + + DPRINTF(FE, "Squashing instruction [sn:%lli] PC %#x\n", + inst->seqNum, inst->readPC()); + + inst->clearDependents(); + + instBuffer.pop_back(); + --instBufferSize; + + freeRegs+= inst->numDestRegs(); + } + + // Copy over rename table from the back end. + renameTable.copyFrom(backEnd->renameTable); + + PC = next_PC; + + // Update BP with proper information. + if (is_branch) { + branchPred.squash(squash_num, next_PC, branch_taken, 0); + } else { + branchPred.squash(squash_num, 0); + } + + // Clear the icache miss if it's outstanding. + if (status == IcacheMissStall && icacheInterface) { + DPRINTF(FE, "Squashing outstanding Icache miss.\n"); + memReq = NULL; + } + + if (status == SerializeBlocked) { + assert(barrierInst->seqNum > squash_num); + barrierInst = NULL; + } + + // Unless this squash originated from the front end, we're probably + // in running mode now. + // Actually might want to make this latency dependent. + status = Running; + fetchCacheLineNextCycle = true; +} + +template <class Impl> +typename Impl::DynInstPtr +FrontEnd<Impl>::getInst() +{ + if (instBufferSize == 0) { + return NULL; + } + + DynInstPtr inst = instBuffer.front(); + + instBuffer.pop_front(); + + --instBufferSize; + + dispatchCountStat++; + + return inst; +} + +template <class Impl> +void +FrontEnd<Impl>::processCacheCompletion(MemReqPtr &req) +{ + DPRINTF(FE, "Processing cache completion\n"); + + // Do something here. + if (status != IcacheMissStall || + req != memReq || + switchedOut) { + DPRINTF(FE, "Previous fetch was squashed.\n"); + fetchIcacheSquashes++; + return; + } + + status = IcacheMissComplete; + +/* if (checkStall(tid)) { + fetchStatus[tid] = Blocked; + } else { + fetchStatus[tid] = IcacheMissComplete; + } +*/ +// memcpy(cacheData, memReq->data, memReq->size); + + // Reset the completion event to NULL. +// memReq->completionEvent = NULL; + memReq = NULL; +} + +template <class Impl> +void +FrontEnd<Impl>::addFreeRegs(int num_freed) +{ + if (status == RenameBlocked && freeRegs + num_freed > 0) { + status = Running; + } + + DPRINTF(FE, "Adding %i freed registers\n", num_freed); + + freeRegs+= num_freed; + +// assert(freeRegs <= numPhysRegs); + if (freeRegs > numPhysRegs) + freeRegs = numPhysRegs; +} + +template <class Impl> +bool +FrontEnd<Impl>::updateStatus() +{ + bool serialize_block = !backEnd->robEmpty() || instBufferSize; + bool be_block = cpu->decoupledFrontEnd ? false : backEnd->isBlocked(); + bool ret_val = false; + + if (status == SerializeBlocked && !serialize_block) { + status = SerializeComplete; + ret_val = true; + } + + if (status == BEBlocked && !be_block) { + if (barrierInst) { + status = SerializeBlocked; + } else { + status = Running; + } + ret_val = true; + } + return ret_val; +} + +template <class Impl> +void +FrontEnd<Impl>::checkBE() +{ + bool be_block = cpu->decoupledFrontEnd ? false : backEnd->isBlocked(); + if (be_block) { + if (status == Running || status == Idle) { + status = BEBlocked; + } + } +} + +template <class Impl> +typename Impl::DynInstPtr +FrontEnd<Impl>::getInstFromCacheline() +{ + if (status == SerializeComplete) { + DynInstPtr inst = barrierInst; + status = Running; + barrierInst = NULL; + inst->clearSerializeBefore(); + return inst; + } + + InstSeqNum inst_seq; + MachInst inst; + // @todo: Fix this magic number used here to handle word offset (and + // getting rid of PAL bit) + unsigned offset = (PC & cacheBlkMask) & ~3; + + // PC of inst is not in this cache block + if (PC >= (cacheBlkPC + cacheBlkSize) || PC < cacheBlkPC || !cacheBlkValid) { + return NULL; + } + + ////////////////////////// + // Fetch one instruction + ////////////////////////// + + // Get a sequence number. + inst_seq = getAndIncrementInstSeq(); + + // Make sure this is a valid index. + assert(offset <= cacheBlkSize - sizeof(MachInst)); + + // Get the instruction from the array of the cache line. + inst = htog(*reinterpret_cast<MachInst *>(&cacheData[offset])); + + ExtMachInst decode_inst = TheISA::makeExtMI(inst, PC); + + // Create a new DynInst from the instruction fetched. + DynInstPtr instruction = new DynInst(decode_inst, PC, PC+sizeof(MachInst), + inst_seq, cpu); + + instruction->setState(thread); + + DPRINTF(FE, "Instruction [sn:%lli] created, with PC %#x\n%s\n", + inst_seq, instruction->readPC(), + instruction->staticInst->disassemble(PC)); + + instruction->traceData = + Trace::getInstRecord(curTick, tc, cpu, + instruction->staticInst, + instruction->readPC(), 0); + + // Increment stat of fetched instructions. + ++fetchedInsts; + + return instruction; +} + +template <class Impl> +void +FrontEnd<Impl>::renameInst(DynInstPtr &inst) +{ + DynInstPtr src_inst = NULL; + int num_src_regs = inst->numSrcRegs(); + if (num_src_regs == 0) { + inst->setCanIssue(); + } else { + for (int i = 0; i < num_src_regs; ++i) { + src_inst = renameTable[inst->srcRegIdx(i)]; + + inst->setSrcInst(src_inst, i); + + DPRINTF(FE, "[sn:%lli]: Src reg %i is inst [sn:%lli]\n", + inst->seqNum, (int)inst->srcRegIdx(i), src_inst->seqNum); + + if (src_inst->isResultReady()) { + DPRINTF(FE, "Reg ready.\n"); + inst->markSrcRegReady(i); + } else { + DPRINTF(FE, "Adding to dependent list.\n"); + src_inst->addDependent(inst); + } + } + } + + for (int i = 0; i < inst->numDestRegs(); ++i) { + RegIndex idx = inst->destRegIdx(i); + + DPRINTF(FE, "Dest reg %i is now inst [sn:%lli], was previously " + "[sn:%lli]\n", + (int)inst->destRegIdx(i), inst->seqNum, + renameTable[idx]->seqNum); + + inst->setPrevDestInst(renameTable[idx], i); + + renameTable[idx] = inst; + --freeRegs; + } +} + +template <class Impl> +void +FrontEnd<Impl>::wakeFromQuiesce() +{ + DPRINTF(FE, "Waking up from quiesce\n"); + // Hopefully this is safe + status = Running; +} + +template <class Impl> +void +FrontEnd<Impl>::switchOut() +{ + switchedOut = true; + cpu->signalSwitched(); +} + +template <class Impl> +void +FrontEnd<Impl>::doSwitchOut() +{ + memReq = NULL; + squash(0, 0); + instBuffer.clear(); + instBufferSize = 0; + status = Idle; +} + +template <class Impl> +void +FrontEnd<Impl>::takeOverFrom(ThreadContext *old_tc) +{ + assert(freeRegs == numPhysRegs); + fetchCacheLineNextCycle = true; + + cacheBlkValid = false; + +#if !FULL_SYSTEM +// pTable = params->pTable; +#endif + fetchFault = NoFault; + serializeNext = false; + barrierInst = NULL; + status = Running; + switchedOut = false; + interruptPending = false; +} + +template <class Impl> +void +FrontEnd<Impl>::dumpInsts() +{ + cprintf("instBuffer size: %i\n", instBuffer.size()); + + InstBuffIt buff_it = instBuffer.begin(); + + for (int num = 0; buff_it != instBuffer.end(); num++) { + cprintf("Instruction:%i\nPC:%#x\n[tid:%i]\n[sn:%lli]\nIssued:%i\n" + "Squashed:%i\n\n", + num, (*buff_it)->readPC(), (*buff_it)->threadNumber, + (*buff_it)->seqNum, (*buff_it)->isIssued(), + (*buff_it)->isSquashed()); + buff_it++; + } +} + +template <class Impl> +FrontEnd<Impl>::ICacheCompletionEvent::ICacheCompletionEvent(MemReqPtr &_req, FrontEnd *fe) + : Event(&mainEventQueue, Delayed_Writeback_Pri), req(_req), frontEnd(fe) +{ + this->setFlags(Event::AutoDelete); +} + +template <class Impl> +void +FrontEnd<Impl>::ICacheCompletionEvent::process() +{ + frontEnd->processCacheCompletion(req); +} + +template <class Impl> +const char * +FrontEnd<Impl>::ICacheCompletionEvent::description() +{ + return "ICache completion event"; +} diff --git a/src/cpu/ozone/inorder_back_end.cc b/src/cpu/ozone/inorder_back_end.cc new file mode 100644 index 000000000..bc6618e4a --- /dev/null +++ b/src/cpu/ozone/inorder_back_end.cc @@ -0,0 +1,34 @@ +/* + * 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 "cpu/ozone/inorder_back_end_impl.hh" +#include "cpu/ozone/simple_impl.hh" + +template class InorderBackEnd<SimpleImpl>; diff --git a/src/cpu/ozone/inorder_back_end.hh b/src/cpu/ozone/inorder_back_end.hh new file mode 100644 index 000000000..ffdba2f6c --- /dev/null +++ b/src/cpu/ozone/inorder_back_end.hh @@ -0,0 +1,478 @@ +/* + * 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_OZONE_INORDER_BACK_END_HH__ +#define __CPU_OZONE_INORDER_BACK_END_HH__ + +#include <list> + +#include "arch/faults.hh" +#include "base/timebuf.hh" +#include "cpu/thread_context.hh" +#include "cpu/inst_seq.hh" +#include "cpu/ozone/rename_table.hh" +#include "cpu/ozone/thread_state.hh" +#include "mem/request.hh" +#include "sim/eventq.hh" + +template <class Impl> +class InorderBackEnd +{ + public: + typedef typename Impl::Params Params; + typedef typename Impl::DynInstPtr DynInstPtr; + typedef typename Impl::FullCPU FullCPU; + typedef typename Impl::FrontEnd FrontEnd; + + typedef typename FullCPU::OzoneTC OzoneTC; + typedef typename Impl::FullCPU::CommStruct CommStruct; + + InorderBackEnd(Params *params); + + std::string name() const; + + void setCPU(FullCPU *cpu_ptr) + { cpu = cpu_ptr; } + + void setFrontEnd(FrontEnd *front_end_ptr) + { frontEnd = front_end_ptr; } + + void setCommBuffer(TimeBuffer<CommStruct> *_comm) + { comm = _comm; } + + void setTC(ThreadContext *tc_ptr); + + void setThreadState(OzoneThreadState<Impl> *thread_ptr); + + void regStats() { } + +#if FULL_SYSTEM + void checkInterrupts(); +#endif + + void tick(); + void executeInsts(); + void squash(const InstSeqNum &squash_num, const Addr &next_PC); + + void squashFromXC(); + void generateXCEvent() { } + + bool robEmpty() { return instList.empty(); } + + bool isFull() { return false; } + bool isBlocked() { return status == DcacheMissStoreStall || + status == DcacheMissLoadStall || + interruptBlocked; } + + void fetchFault(Fault &fault); + + void dumpInsts(); + + private: + void handleFault(); + + void setSquashInfoFromTC(); + + bool squashPending; + InstSeqNum squashSeqNum; + Addr squashNextPC; + + Fault faultFromFetch; + + bool interruptBlocked; + + public: + template <class T> + Fault read(Addr addr, T &data, unsigned flags); + + template <class T> + Fault read(RequestPtr req, T &data, int load_idx); + + template <class T> + Fault write(T data, Addr addr, unsigned flags, uint64_t *res); + + template <class T> + Fault write(RequestPtr req, T &data, int store_idx); + + Addr readCommitPC() { return commitPC; } + + Addr commitPC; + + void switchOut() { panic("Not implemented!"); } + void doSwitchOut() { panic("Not implemented!"); } + void takeOverFrom(ThreadContext *old_tc = NULL) { panic("Not implemented!"); } + + public: + FullCPU *cpu; + + FrontEnd *frontEnd; + + ThreadContext *tc; + + OzoneThreadState<Impl> *thread; + + RenameTable<Impl> renameTable; + + protected: + enum Status { + Running, + Idle, + DcacheMissLoadStall, + DcacheMissStoreStall, + DcacheMissComplete, + Blocked + }; + + Status status; + + class DCacheCompletionEvent : public Event + { + private: + InorderBackEnd *be; + + public: + DCacheCompletionEvent(InorderBackEnd *_be); + + virtual void process(); + virtual const char *description(); + + DynInstPtr inst; + }; + + friend class DCacheCompletionEvent; + + DCacheCompletionEvent cacheCompletionEvent; + +// MemInterface *dcacheInterface; + + RequestPtr memReq; + + private: + typedef typename std::list<DynInstPtr>::iterator InstListIt; + + std::list<DynInstPtr> instList; + + // General back end width. Used if the more specific isn't given. + int width; + + int latency; + + int squashLatency; + + TimeBuffer<int> numInstsToWB; + TimeBuffer<int>::wire instsAdded; + TimeBuffer<int>::wire instsToExecute; + + TimeBuffer<CommStruct> *comm; + // number of cycles stalled for D-cache misses + Stats::Scalar<> dcacheStallCycles; + Counter lastDcacheStall; +}; + +template <class Impl> +template <class T> +Fault +InorderBackEnd<Impl>::read(Addr addr, T &data, unsigned flags) +{ + memReq->reset(addr, sizeof(T), flags); + + // translate to physical address + Fault fault = cpu->translateDataReadReq(memReq); + + // if we have a cache, do cache access too + if (fault == NoFault && dcacheInterface) { + memReq->cmd = Read; + memReq->completionEvent = NULL; + memReq->time = curTick; + memReq->flags &= ~INST_READ; + MemAccessResult result = dcacheInterface->access(memReq); + + // Ugly hack to get an event scheduled *only* if the access is + // a miss. We really should add first-class support for this + // at some point. + if (result != MA_HIT) { + // Fix this hack for keeping funcExeInst correct with loads that + // are executed twice. + memReq->completionEvent = &cacheCompletionEvent; + lastDcacheStall = curTick; +// unscheduleTickEvent(); + status = DcacheMissLoadStall; + DPRINTF(IBE, "Dcache miss stall!\n"); + } else { + // do functional access + DPRINTF(IBE, "Dcache hit!\n"); + } + } +/* + if (!dcacheInterface && (memReq->flags & UNCACHEABLE)) + recordEvent("Uncached Read"); +*/ + return fault; +} +#if 0 +template <class Impl> +template <class T> +Fault +InorderBackEnd<Impl>::read(MemReqPtr &req, T &data) +{ +#if FULL_SYSTEM && defined(TARGET_ALPHA) + if (req->flags & LOCKED) { + req->xc->setMiscReg(TheISA::Lock_Addr_DepTag, req->paddr); + req->xc->setMiscReg(TheISA::Lock_Flag_DepTag, true); + } +#endif + + Fault error; + error = thread->mem->read(req, data); + data = LittleEndianGuest::gtoh(data); + return error; +} +#endif + +template <class Impl> +template <class T> +Fault +InorderBackEnd<Impl>::write(T data, Addr addr, unsigned flags, uint64_t *res) +{ + memReq->reset(addr, sizeof(T), flags); + + // translate to physical address + Fault fault = cpu->translateDataWriteReq(memReq); + + if (fault == NoFault && dcacheInterface) { + memReq->cmd = Write; +// memcpy(memReq->data,(uint8_t *)&data,memReq->size); + memReq->completionEvent = NULL; + memReq->time = curTick; + memReq->flags &= ~INST_READ; + MemAccessResult result = dcacheInterface->access(memReq); + + // Ugly hack to get an event scheduled *only* if the access is + // a miss. We really should add first-class support for this + // at some point. + if (result != MA_HIT) { + memReq->completionEvent = &cacheCompletionEvent; + lastDcacheStall = curTick; +// unscheduleTickEvent(); + status = DcacheMissStoreStall; + DPRINTF(IBE, "Dcache miss stall!\n"); + } else { + DPRINTF(IBE, "Dcache hit!\n"); + } + } + + if (res && (fault == NoFault)) + *res = memReq->result; +/* + if (!dcacheInterface && (memReq->flags & UNCACHEABLE)) + recordEvent("Uncached Write"); +*/ + return fault; +} +#if 0 +template <class Impl> +template <class T> +Fault +InorderBackEnd<Impl>::write(MemReqPtr &req, T &data) +{ +#if FULL_SYSTEM && defined(TARGET_ALPHA) + ExecContext *xc; + + // If this is a store conditional, act appropriately + if (req->flags & LOCKED) { + xc = req->xc; + + if (req->flags & UNCACHEABLE) { + // Don't update result register (see stq_c in isa_desc) + req->result = 2; + xc->setStCondFailures(0);//Needed? [RGD] + } else { + bool lock_flag = xc->readMiscReg(TheISA::Lock_Flag_DepTag); + Addr lock_addr = xc->readMiscReg(TheISA::Lock_Addr_DepTag); + req->result = lock_flag; + if (!lock_flag || + ((lock_addr & ~0xf) != (req->paddr & ~0xf))) { + xc->setMiscReg(TheISA::Lock_Flag_DepTag, false); + xc->setStCondFailures(xc->readStCondFailures() + 1); + if (((xc->readStCondFailures()) % 100000) == 0) { + std::cerr << "Warning: " + << xc->readStCondFailures() + << " consecutive store conditional failures " + << "on cpu " << req->xc->readCpuId() + << std::endl; + } + return NoFault; + } + else xc->setStCondFailures(0); + } + } + + // Need to clear any locked flags on other proccessors for + // this address. Only do this for succsful Store Conditionals + // and all other stores (WH64?). Unsuccessful Store + // Conditionals would have returned above, and wouldn't fall + // through. + for (int i = 0; i < cpu->system->execContexts.size(); i++){ + xc = cpu->system->execContexts[i]; + if ((xc->readMiscReg(TheISA::Lock_Addr_DepTag) & ~0xf) == + (req->paddr & ~0xf)) { + xc->setMiscReg(TheISA::Lock_Flag_DepTag, false); + } + } + +#endif + return thread->mem->write(req, (T)LittleEndianGuest::htog(data)); +} +#endif + +template <class Impl> +template <class T> +Fault +InorderBackEnd<Impl>::read(MemReqPtr &req, T &data, int load_idx) +{ +// panic("Unimplemented!"); +// memReq->reset(addr, sizeof(T), flags); + + // translate to physical address +// Fault fault = cpu->translateDataReadReq(req); + req->cmd = Read; + req->completionEvent = NULL; + req->time = curTick; + assert(!req->data); + req->data = new uint8_t[64]; + req->flags &= ~INST_READ; + Fault fault = cpu->read(req, data); + memcpy(req->data, &data, sizeof(T)); + + // if we have a cache, do cache access too + if (dcacheInterface) { + MemAccessResult result = dcacheInterface->access(req); + + // Ugly hack to get an event scheduled *only* if the access is + // a miss. We really should add first-class support for this + // at some point. + if (result != MA_HIT) { + req->completionEvent = &cacheCompletionEvent; + lastDcacheStall = curTick; +// unscheduleTickEvent(); + status = DcacheMissLoadStall; + DPRINTF(IBE, "Dcache miss load stall!\n"); + } else { + DPRINTF(IBE, "Dcache hit!\n"); + + } + } + +/* + if (!dcacheInterface && (req->flags & UNCACHEABLE)) + recordEvent("Uncached Read"); +*/ + return NoFault; +} + +template <class Impl> +template <class T> +Fault +InorderBackEnd<Impl>::write(MemReqPtr &req, T &data, int store_idx) +{ +// req->reset(addr, sizeof(T), flags); + + // translate to physical address +// Fault fault = cpu->translateDataWriteReq(req); + + req->cmd = Write; + req->completionEvent = NULL; + req->time = curTick; + assert(!req->data); + req->data = new uint8_t[64]; + memcpy(req->data, (uint8_t *)&data, req->size); + + switch(req->size) { + case 1: + cpu->write(req, (uint8_t &)data); + break; + case 2: + cpu->write(req, (uint16_t &)data); + break; + case 4: + cpu->write(req, (uint32_t &)data); + break; + case 8: + cpu->write(req, (uint64_t &)data); + break; + default: + panic("Unexpected store size!\n"); + } + + if (dcacheInterface) { + req->cmd = Write; + req->data = new uint8_t[64]; + memcpy(req->data,(uint8_t *)&data,req->size); + req->completionEvent = NULL; + req->time = curTick; + req->flags &= ~INST_READ; + MemAccessResult result = dcacheInterface->access(req); + + // Ugly hack to get an event scheduled *only* if the access is + // a miss. We really should add first-class support for this + // at some point. + if (result != MA_HIT) { + req->completionEvent = &cacheCompletionEvent; + lastDcacheStall = curTick; +// unscheduleTickEvent(); + status = DcacheMissStoreStall; + DPRINTF(IBE, "Dcache miss store stall!\n"); + } else { + DPRINTF(IBE, "Dcache hit!\n"); + + } + } +/* + if (req->flags & LOCKED) { + if (req->flags & UNCACHEABLE) { + // Don't update result register (see stq_c in isa_desc) + req->result = 2; + } else { + req->result = 1; + } + } +*/ +/* + if (res && (fault == NoFault)) + *res = req->result; + */ +/* + if (!dcacheInterface && (req->flags & UNCACHEABLE)) + recordEvent("Uncached Write"); +*/ + return NoFault; +} + +#endif // __CPU_OZONE_INORDER_BACK_END_HH__ diff --git a/src/cpu/ozone/inorder_back_end_impl.hh b/src/cpu/ozone/inorder_back_end_impl.hh new file mode 100644 index 000000000..cbb73364e --- /dev/null +++ b/src/cpu/ozone/inorder_back_end_impl.hh @@ -0,0 +1,548 @@ +/* + * 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 "arch/faults.hh" +#include "arch/isa_traits.hh" +#include "cpu/ozone/inorder_back_end.hh" +#include "cpu/ozone/thread_state.hh" + +using namespace TheISA; + +template <class Impl> +InorderBackEnd<Impl>::InorderBackEnd(Params *params) + : squashPending(false), + squashSeqNum(0), + squashNextPC(0), + faultFromFetch(NoFault), + interruptBlocked(false), + cacheCompletionEvent(this), + dcacheInterface(params->dcacheInterface), + width(params->backEndWidth), + latency(params->backEndLatency), + squashLatency(params->backEndSquashLatency), + numInstsToWB(0, latency + 1) +{ + instsAdded = numInstsToWB.getWire(latency); + instsToExecute = numInstsToWB.getWire(0); + + memReq = new MemReq; + memReq->data = new uint8_t[64]; + status = Running; +} + +template <class Impl> +std::string +InorderBackEnd<Impl>::name() const +{ + return cpu->name() + ".inorderbackend"; +} + +template <class Impl> +void +InorderBackEnd<Impl>::setXC(ExecContext *xc_ptr) +{ + xc = xc_ptr; + memReq->xc = xc; +} + +template <class Impl> +void +InorderBackEnd<Impl>::setThreadState(OzoneThreadState<Impl> *thread_ptr) +{ + thread = thread_ptr; + thread->setFuncExeInst(0); +} + +#if FULL_SYSTEM +template <class Impl> +void +InorderBackEnd<Impl>::checkInterrupts() +{ + //Check if there are any outstanding interrupts + //Handle the interrupts + int ipl = 0; + int summary = 0; + + cpu->checkInterrupts = false; + + if (thread->readMiscReg(IPR_ASTRR)) + panic("asynchronous traps not implemented\n"); + + if (thread->readMiscReg(IPR_SIRR)) { + for (int i = INTLEVEL_SOFTWARE_MIN; + i < INTLEVEL_SOFTWARE_MAX; i++) { + if (thread->readMiscReg(IPR_SIRR) & (ULL(1) << i)) { + // See table 4-19 of the 21164 hardware reference + ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1; + summary |= (ULL(1) << i); + } + } + } + + uint64_t interrupts = cpu->intr_status(); + + if (interrupts) { + for (int i = INTLEVEL_EXTERNAL_MIN; + i < INTLEVEL_EXTERNAL_MAX; i++) { + if (interrupts & (ULL(1) << i)) { + // See table 4-19 of the 21164 hardware reference + ipl = i; + summary |= (ULL(1) << i); + } + } + } + + if (ipl && ipl > thread->readMiscReg(IPR_IPLR)) { + thread->inSyscall = true; + + thread->setMiscReg(IPR_ISR, summary); + thread->setMiscReg(IPR_INTID, ipl); + Fault(new InterruptFault)->invoke(xc); + DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", + thread->readMiscReg(IPR_IPLR), ipl, summary); + + // May need to go 1 inst prior + squashPending = true; + + thread->inSyscall = false; + + setSquashInfoFromXC(); + } +} +#endif + +template <class Impl> +void +InorderBackEnd<Impl>::tick() +{ + // Squash due to an external source + // Not sure if this or an interrupt has higher priority + if (squashPending) { + squash(squashSeqNum, squashNextPC); + return; + } + + // if (interrupt) then set thread PC, stall front end, record that + // I'm waiting for it to drain. (for now just squash) +#if FULL_SYSTEM + if (interruptBlocked || + (cpu->checkInterrupts && + cpu->check_interrupts() && + !cpu->inPalMode())) { + if (!robEmpty()) { + interruptBlocked = true; + } else if (robEmpty() && cpu->inPalMode()) { + // Will need to let the front end continue a bit until + // we're out of pal mode. Hopefully we never get into an + // infinite loop... + interruptBlocked = false; + } else { + interruptBlocked = false; + checkInterrupts(); + return; + } + } +#endif + + if (status != DcacheMissLoadStall && + status != DcacheMissStoreStall) { + for (int i = 0; i < width && (*instsAdded) < width; ++i) { + DynInstPtr inst = frontEnd->getInst(); + + if (!inst) + break; + + instList.push_back(inst); + + (*instsAdded)++; + } + +#if FULL_SYSTEM + if (faultFromFetch && robEmpty() && frontEnd->isEmpty()) { + handleFault(); + } else { + executeInsts(); + } +#else + executeInsts(); +#endif + } +} + +template <class Impl> +void +InorderBackEnd<Impl>::executeInsts() +{ + bool completed_last_inst = true; + int insts_to_execute = *instsToExecute; + int freed_regs = 0; + + while (insts_to_execute > 0) { + assert(!instList.empty()); + DynInstPtr inst = instList.front(); + + commitPC = inst->readPC(); + + thread->setPC(commitPC); + thread->setNextPC(inst->readNextPC()); + +#if FULL_SYSTEM + int count = 0; + Addr oldpc; + do { + if (count == 0) + assert(!thread->inSyscall && !thread->trapPending); + oldpc = thread->readPC(); + cpu->system->pcEventQueue.service( + thread->getXCProxy()); + count++; + } while (oldpc != thread->readPC()); + if (count > 1) { + DPRINTF(IBE, "PC skip function event, stopping commit\n"); + completed_last_inst = false; + squashPending = true; + break; + } +#endif + + Fault inst_fault = NoFault; + + if (status == DcacheMissComplete) { + DPRINTF(IBE, "Completing inst [sn:%lli]\n", inst->seqNum); + status = Running; + } else if (inst->isMemRef() && status != DcacheMissComplete && + (!inst->isDataPrefetch() && !inst->isInstPrefetch())) { + DPRINTF(IBE, "Initiating mem op inst [sn:%lli] PC: %#x\n", + inst->seqNum, inst->readPC()); + + cacheCompletionEvent.inst = inst; + inst_fault = inst->initiateAcc(); + if (inst_fault == NoFault && + status != DcacheMissLoadStall && + status != DcacheMissStoreStall) { + inst_fault = inst->completeAcc(); + } + ++thread->funcExeInst; + } else { + DPRINTF(IBE, "Executing inst [sn:%lli] PC: %#x\n", + inst->seqNum, inst->readPC()); + inst_fault = inst->execute(); + ++thread->funcExeInst; + } + + // Will need to be able to break this loop in case the load + // misses. Split access/complete ops would be useful here + // with writeback events. + if (status == DcacheMissLoadStall) { + *instsToExecute = insts_to_execute; + + completed_last_inst = false; + break; + } else if (status == DcacheMissStoreStall) { + // Figure out how to fix this hack. Probably have DcacheMissLoad + // vs DcacheMissStore. + *instsToExecute = insts_to_execute; + completed_last_inst = false; +/* + instList.pop_front(); + --insts_to_execute; + if (inst->traceData) { + inst->traceData->finalize(); + } +*/ + + // Don't really need to stop for a store stall as long as + // the memory system is able to handle store forwarding + // and such. Breaking out might help avoid the cache + // interface becoming blocked. + break; + } + + inst->setExecuted(); + inst->setCompleted(); + inst->setCanCommit(); + + instList.pop_front(); + + --insts_to_execute; + --(*instsToExecute); + + if (inst->traceData) { + inst->traceData->finalize(); + inst->traceData = NULL; + } + + if (inst_fault != NoFault) { +#if FULL_SYSTEM + DPRINTF(IBE, "Inst [sn:%lli] PC %#x has a fault\n", + inst->seqNum, inst->readPC()); + + assert(!thread->inSyscall); + + thread->inSyscall = true; + + // Hack for now; DTB will sometimes need the machine instruction + // for when faults happen. So we will set it here, prior to the + // DTB possibly needing it for this translation. + thread->setInst( + static_cast<TheISA::MachInst>(inst->staticInst->machInst)); + + // Consider holding onto the trap and waiting until the trap event + // happens for this to be executed. + inst_fault->invoke(xc); + + // Exit state update mode to avoid accidental updating. + thread->inSyscall = false; + + squashPending = true; + + // Generate trap squash event. +// generateTrapEvent(tid); + completed_last_inst = false; + break; +#else // !FULL_SYSTEM + panic("fault (%d) detected @ PC %08p", inst_fault, + inst->PC); +#endif // FULL_SYSTEM + } + + for (int i = 0; i < inst->numDestRegs(); ++i) { + renameTable[inst->destRegIdx(i)] = inst; + thread->renameTable[inst->destRegIdx(i)] = inst; + ++freed_regs; + } + + inst->clearDependents(); + + comm->access(0)->doneSeqNum = inst->seqNum; + + if (inst->mispredicted()) { + squash(inst->seqNum, inst->readNextPC()); + + thread->setNextPC(inst->readNextPC()); + + break; + } else if (squashPending) { + // Something external happened that caused the CPU to squash. + // Break out of commit and handle the squash next cycle. + break; + } + // If it didn't mispredict, then it executed fine. Send back its + // registers and BP info? What about insts that may still have + // latency, like loads? Probably can send back the information after + // it is completed. + + // keep an instruction count + cpu->numInst++; + thread->numInsts++; + } + + frontEnd->addFreeRegs(freed_regs); + + assert(insts_to_execute >= 0); + + // Should only advance this if I have executed all instructions. + if (insts_to_execute == 0) { + numInstsToWB.advance(); + } + + // Should I set the PC to the next PC here? What do I set next PC to? + if (completed_last_inst) { + thread->setPC(thread->readNextPC()); + thread->setNextPC(thread->readPC() + sizeof(MachInst)); + } + + if (squashPending) { + setSquashInfoFromXC(); + } +} + +template <class Impl> +void +InorderBackEnd<Impl>::handleFault() +{ + DPRINTF(Commit, "Handling fault from fetch\n"); + + assert(!thread->inSyscall); + + thread->inSyscall = true; + + // Consider holding onto the trap and waiting until the trap event + // happens for this to be executed. + faultFromFetch->invoke(xc); + + // Exit state update mode to avoid accidental updating. + thread->inSyscall = false; + + squashPending = true; + + setSquashInfoFromXC(); +} + +template <class Impl> +void +InorderBackEnd<Impl>::squash(const InstSeqNum &squash_num, const Addr &next_PC) +{ + DPRINTF(IBE, "Squashing from [sn:%lli], setting PC to %#x\n", + squash_num, next_PC); + + InstListIt squash_it = --(instList.end()); + + int freed_regs = 0; + + while (!instList.empty() && (*squash_it)->seqNum > squash_num) { + DynInstPtr inst = *squash_it; + + DPRINTF(IBE, "Squashing instruction PC %#x, [sn:%lli].\n", + inst->readPC(), + inst->seqNum); + + // May cause problems with misc regs + freed_regs+= inst->numDestRegs(); + inst->clearDependents(); + squash_it--; + instList.pop_back(); + } + + frontEnd->addFreeRegs(freed_regs); + + for (int i = 0; i < latency+1; ++i) { + numInstsToWB.advance(); + } + + squashPending = false; + + // Probably want to make sure that this squash is the one that set the + // thread into inSyscall mode. + thread->inSyscall = false; + + // Tell front end to squash, reset PC to new one. + frontEnd->squash(squash_num, next_PC); + + faultFromFetch = NULL; +} + +template <class Impl> +void +InorderBackEnd<Impl>::squashFromXC() +{ + // Record that I need to squash + squashPending = true; + + thread->inSyscall = true; +} + +template <class Impl> +void +InorderBackEnd<Impl>::setSquashInfoFromXC() +{ + // Need to handle the case of the instList being empty. In that case + // probably any number works, except maybe with stores in the store buffer. + squashSeqNum = instList.empty() ? 0 : instList.front()->seqNum - 1; + + squashNextPC = thread->PC; +} + +template <class Impl> +void +InorderBackEnd<Impl>::fetchFault(Fault &fault) +{ + faultFromFetch = fault; +} + +template <class Impl> +void +InorderBackEnd<Impl>::dumpInsts() +{ + int num = 0; + int valid_num = 0; + + InstListIt inst_list_it = instList.begin(); + + cprintf("Inst list size: %i\n", instList.size()); + + while (inst_list_it != instList.end()) + { + cprintf("Instruction:%i\n", + num); + if (!(*inst_list_it)->isSquashed()) { + if (!(*inst_list_it)->isIssued()) { + ++valid_num; + cprintf("Count:%i\n", valid_num); + } else if ((*inst_list_it)->isMemRef() && + !(*inst_list_it)->memOpDone) { + // Loads that have not been marked as executed still count + // towards the total instructions. + ++valid_num; + cprintf("Count:%i\n", valid_num); + } + } + + cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" + "Issued:%i\nSquashed:%i\n", + (*inst_list_it)->readPC(), + (*inst_list_it)->seqNum, + (*inst_list_it)->threadNumber, + (*inst_list_it)->isIssued(), + (*inst_list_it)->isSquashed()); + + if ((*inst_list_it)->isMemRef()) { + cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone); + } + + cprintf("\n"); + + inst_list_it++; + ++num; + } +} + +template <class Impl> +InorderBackEnd<Impl>::DCacheCompletionEvent::DCacheCompletionEvent( + InorderBackEnd *_be) + : Event(&mainEventQueue, CPU_Tick_Pri), be(_be) +{ +// this->setFlags(Event::AutoDelete); +} + +template <class Impl> +void +InorderBackEnd<Impl>::DCacheCompletionEvent::process() +{ + inst->completeAcc(); + be->status = DcacheMissComplete; +} + +template <class Impl> +const char * +InorderBackEnd<Impl>::DCacheCompletionEvent::description() +{ + return "DCache completion event"; +} diff --git a/src/cpu/ozone/inst_queue.cc b/src/cpu/ozone/inst_queue.cc new file mode 100644 index 000000000..7ce5d67ad --- /dev/null +++ b/src/cpu/ozone/inst_queue.cc @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#include "cpu/ozone/dyn_inst.hh" +#include "cpu/ozone/ozone_impl.hh" +#include "cpu/ozone/simple_impl.hh" +#include "cpu/ozone/inst_queue_impl.hh" + +// Force instantiation of InstructionQueue. +template class InstQueue<SimpleImpl>; +template class InstQueue<OzoneImpl>; diff --git a/src/cpu/ozone/inst_queue.hh b/src/cpu/ozone/inst_queue.hh new file mode 100644 index 000000000..0158fd2d2 --- /dev/null +++ b/src/cpu/ozone/inst_queue.hh @@ -0,0 +1,508 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#ifndef __CPU_OZONE_INST_QUEUE_HH__ +#define __CPU_OZONE_INST_QUEUE_HH__ + +#include <list> +#include <map> +#include <queue> +#include <vector> + +#include "base/statistics.hh" +#include "base/timebuf.hh" +#include "cpu/inst_seq.hh" +#include "sim/host.hh" + +class FUPool; +class MemInterface; + +/** + * A standard instruction queue class. It holds ready instructions, in + * order, in seperate priority queues to facilitate the scheduling of + * instructions. The IQ uses a separate linked list to track dependencies. + * Similar to the rename map and the free list, it expects that + * floating point registers have their indices start after the integer + * registers (ie with 96 int and 96 fp registers, regs 0-95 are integer + * and 96-191 are fp). This remains true even for both logical and + * physical register indices. The IQ depends on the memory dependence unit to + * track when memory operations are ready in terms of ordering; register + * dependencies are tracked normally. Right now the IQ also handles the + * execution timing; this is mainly to allow back-to-back scheduling without + * requiring IEW to be able to peek into the IQ. At the end of the execution + * latency, the instruction is put into the queue to execute, where it will + * have the execute() function called on it. + * @todo: Make IQ able to handle multiple FU pools. + */ +template <class Impl> +class InstQueue +{ + public: + //Typedefs from the Impl. + typedef typename Impl::FullCPU FullCPU; + typedef typename Impl::DynInstPtr DynInstPtr; + typedef typename Impl::Params Params; + typedef typename Impl::IssueStruct IssueStruct; +/* + typedef typename Impl::CPUPol::IEW IEW; + typedef typename Impl::CPUPol::MemDepUnit MemDepUnit; + typedef typename Impl::CPUPol::IssueStruct IssueStruct; + typedef typename Impl::CPUPol::TimeStruct TimeStruct; +*/ + // Typedef of iterator through the list of instructions. + typedef typename std::list<DynInstPtr>::iterator ListIt; + + friend class Impl::FullCPU; +#if 0 + /** FU completion event class. */ + class FUCompletion : public Event { + private: + /** Executing instruction. */ + DynInstPtr inst; + + /** Index of the FU used for executing. */ + int fuIdx; + + /** Pointer back to the instruction queue. */ + InstQueue<Impl> *iqPtr; + + public: + /** Construct a FU completion event. */ + FUCompletion(DynInstPtr &_inst, int fu_idx, + InstQueue<Impl> *iq_ptr); + + virtual void process(); + virtual const char *description(); + }; +#endif + /** Constructs an IQ. */ + InstQueue(Params *params); + + /** Destructs the IQ. */ + ~InstQueue(); + + /** Returns the name of the IQ. */ + std::string name() const; + + /** Registers statistics. */ + void regStats(); + + /** Sets CPU pointer. */ + void setCPU(FullCPU *_cpu) { cpu = _cpu; } +#if 0 + /** Sets active threads list. */ + void setActiveThreads(list<unsigned> *at_ptr); + + /** Sets the IEW pointer. */ + void setIEW(IEW *iew_ptr) { iewStage = iew_ptr; } +#endif + /** Sets the timer buffer between issue and execute. */ + void setIssueToExecuteQueue(TimeBuffer<IssueStruct> *i2eQueue); +#if 0 + /** Sets the global time buffer. */ + void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr); + + /** Number of entries needed for given amount of threads. */ + int entryAmount(int num_threads); + + /** Resets max entries for all threads. */ + void resetEntries(); +#endif + /** Returns total number of free entries. */ + unsigned numFreeEntries(); + + /** Returns number of free entries for a thread. */ + unsigned numFreeEntries(unsigned tid); + + /** Returns whether or not the IQ is full. */ + bool isFull(); + + /** Returns whether or not the IQ is full for a specific thread. */ + bool isFull(unsigned tid); + + /** Returns if there are any ready instructions in the IQ. */ + bool hasReadyInsts(); + + /** Inserts a new instruction into the IQ. */ + void insert(DynInstPtr &new_inst); + + /** Inserts a new, non-speculative instruction into the IQ. */ + void insertNonSpec(DynInstPtr &new_inst); +#if 0 + /** + * Advances the tail of the IQ, used if an instruction is not added to the + * IQ for scheduling. + * @todo: Rename this function. + */ + void advanceTail(DynInstPtr &inst); + + /** Process FU completion event. */ + void processFUCompletion(DynInstPtr &inst, int fu_idx); +#endif + /** + * Schedules ready instructions, adding the ready ones (oldest first) to + * the queue to execute. + */ + void scheduleReadyInsts(); + + /** Schedules a single specific non-speculative instruction. */ + void scheduleNonSpec(const InstSeqNum &inst); + + /** + * Commits all instructions up to and including the given sequence number, + * for a specific thread. + */ + void commit(const InstSeqNum &inst, unsigned tid = 0); + + /** Wakes all dependents of a completed instruction. */ + void wakeDependents(DynInstPtr &completed_inst); + + /** Adds a ready memory instruction to the ready list. */ + void addReadyMemInst(DynInstPtr &ready_inst); +#if 0 + /** + * Reschedules a memory instruction. It will be ready to issue once + * replayMemInst() is called. + */ + void rescheduleMemInst(DynInstPtr &resched_inst); + + /** Replays a memory instruction. It must be rescheduled first. */ + void replayMemInst(DynInstPtr &replay_inst); +#endif + /** Completes a memory operation. */ + void completeMemInst(DynInstPtr &completed_inst); +#if 0 + /** Indicates an ordering violation between a store and a load. */ + void violation(DynInstPtr &store, DynInstPtr &faulting_load); +#endif + /** + * Squashes instructions for a thread. Squashing information is obtained + * from the time buffer. + */ + void squash(unsigned tid); // Probably want the ISN + + /** Returns the number of used entries for a thread. */ + unsigned getCount(unsigned tid) { return count[tid]; }; + + /** Updates the number of free entries. */ + void updateFreeEntries(int num) { freeEntries += num; } + + /** Debug function to print all instructions. */ + void printInsts(); + + private: + /** Does the actual squashing. */ + void doSquash(unsigned tid); + + ///////////////////////// + // Various pointers + ///////////////////////// + + /** Pointer to the CPU. */ + FullCPU *cpu; + + /** Cache interface. */ + MemInterface *dcacheInterface; +#if 0 + /** Pointer to IEW stage. */ + IEW *iewStage; + + /** The memory dependence unit, which tracks/predicts memory dependences + * between instructions. + */ + MemDepUnit memDepUnit[Impl::MaxThreads]; +#endif + /** The queue to the execute stage. Issued instructions will be written + * into it. + */ + TimeBuffer<IssueStruct> *issueToExecuteQueue; +#if 0 + /** The backwards time buffer. */ + TimeBuffer<TimeStruct> *timeBuffer; + + /** Wire to read information from timebuffer. */ + typename TimeBuffer<TimeStruct>::wire fromCommit; + + /** Function unit pool. */ + FUPool *fuPool; +#endif + ////////////////////////////////////// + // Instruction lists, ready queues, and ordering + ////////////////////////////////////// + + /** List of all the instructions in the IQ (some of which may be issued). */ + std::list<DynInstPtr> instList[Impl::MaxThreads]; + + /** + * Struct for comparing entries to be added to the priority queue. This + * gives reverse ordering to the instructions in terms of sequence + * numbers: the instructions with smaller sequence numbers (and hence + * are older) will be at the top of the priority queue. + */ + struct pqCompare { + bool operator() (const DynInstPtr &lhs, const DynInstPtr &rhs) const + { + return lhs->seqNum > rhs->seqNum; + } + }; + + /** + * Struct for an IQ entry. It includes the instruction and an iterator + * to the instruction's spot in the IQ. + */ + struct IQEntry { + DynInstPtr inst; + ListIt iqIt; + }; + + typedef std::priority_queue<DynInstPtr, std::vector<DynInstPtr>, pqCompare> + ReadyInstQueue; + + typedef std::map<DynInstPtr, pqCompare> ReadyInstMap; + typedef typename std::map<DynInstPtr, pqCompare>::iterator ReadyMapIt; + + /** List of ready instructions. + */ + ReadyInstQueue readyInsts; + + /** List of non-speculative instructions that will be scheduled + * once the IQ gets a signal from commit. While it's redundant to + * have the key be a part of the value (the sequence number is stored + * inside of DynInst), when these instructions are woken up only + * the sequence number will be available. Thus it is most efficient to be + * able to search by the sequence number alone. + */ + std::map<InstSeqNum, DynInstPtr> nonSpecInsts; + + typedef typename std::map<InstSeqNum, DynInstPtr>::iterator NonSpecMapIt; +#if 0 + /** Entry for the list age ordering by op class. */ + struct ListOrderEntry { + OpClass queueType; + InstSeqNum oldestInst; + }; + + /** List that contains the age order of the oldest instruction of each + * ready queue. Used to select the oldest instruction available + * among op classes. + */ + std::list<ListOrderEntry> listOrder; + + typedef typename std::list<ListOrderEntry>::iterator ListOrderIt; + + /** Tracks if each ready queue is on the age order list. */ + bool queueOnList[Num_OpClasses]; + + /** Iterators of each ready queue. Points to their spot in the age order + * list. + */ + ListOrderIt readyIt[Num_OpClasses]; + + /** Add an op class to the age order list. */ + void addToOrderList(OpClass op_class); + + /** + * Called when the oldest instruction has been removed from a ready queue; + * this places that ready queue into the proper spot in the age order list. + */ + void moveToYoungerInst(ListOrderIt age_order_it); +#endif + ////////////////////////////////////// + // Various parameters + ////////////////////////////////////// +#if 0 + /** IQ Resource Sharing Policy */ + enum IQPolicy { + Dynamic, + Partitioned, + Threshold + }; + + /** IQ sharing policy for SMT. */ + IQPolicy iqPolicy; +#endif + /** Number of Total Threads*/ + unsigned numThreads; +#if 0 + /** Pointer to list of active threads. */ + list<unsigned> *activeThreads; +#endif + /** Per Thread IQ count */ + unsigned count[Impl::MaxThreads]; + + /** Max IQ Entries Per Thread */ + unsigned maxEntries[Impl::MaxThreads]; + + /** Number of free IQ entries left. */ + unsigned freeEntries; + + /** The number of entries in the instruction queue. */ + unsigned numEntries; + + /** The total number of instructions that can be issued in one cycle. */ + unsigned totalWidth; +#if 0 + /** The number of physical registers in the CPU. */ + unsigned numPhysRegs; + + /** The number of physical integer registers in the CPU. */ + unsigned numPhysIntRegs; + + /** The number of floating point registers in the CPU. */ + unsigned numPhysFloatRegs; +#endif + /** Delay between commit stage and the IQ. + * @todo: Make there be a distinction between the delays within IEW. + */ + unsigned commitToIEWDelay; + + ////////////////////////////////// + // Variables needed for squashing + ////////////////////////////////// + + /** The sequence number of the squashed instruction. */ + InstSeqNum squashedSeqNum[Impl::MaxThreads]; + + /** Iterator that points to the last instruction that has been squashed. + * This will not be valid unless the IQ is in the process of squashing. + */ + ListIt squashIt[Impl::MaxThreads]; +#if 0 + /////////////////////////////////// + // Dependency graph stuff + /////////////////////////////////// + + class DependencyEntry + { + public: + DependencyEntry() + : inst(NULL), next(NULL) + { } + + DynInstPtr inst; + //Might want to include data about what arch. register the + //dependence is waiting on. + DependencyEntry *next; + + //This function, and perhaps this whole class, stand out a little + //bit as they don't fit a classification well. I want access + //to the underlying structure of the linked list, yet at + //the same time it feels like this should be something abstracted + //away. So for now it will sit here, within the IQ, until + //a better implementation is decided upon. + // This function probably shouldn't be within the entry... + void insert(DynInstPtr &new_inst); + + void remove(DynInstPtr &inst_to_remove); + + // Debug variable, remove when done testing. + static unsigned mem_alloc_counter; + }; + + /** Array of linked lists. Each linked list is a list of all the + * instructions that depend upon a given register. The actual + * register's index is used to index into the graph; ie all + * instructions in flight that are dependent upon r34 will be + * in the linked list of dependGraph[34]. + */ + DependencyEntry *dependGraph; + + /** A cache of the recently woken registers. It is 1 if the register + * has been woken up recently, and 0 if the register has been added + * to the dependency graph and has not yet received its value. It + * is basically a secondary scoreboard, and should pretty much mirror + * the scoreboard that exists in the rename map. + */ + vector<bool> regScoreboard; + + /** Adds an instruction to the dependency graph, as a producer. */ + bool addToDependents(DynInstPtr &new_inst); + + /** Adds an instruction to the dependency graph, as a consumer. */ + void createDependency(DynInstPtr &new_inst); +#endif + /** Moves an instruction to the ready queue if it is ready. */ + void addIfReady(DynInstPtr &inst); + + /** Debugging function to count how many entries are in the IQ. It does + * a linear walk through the instructions, so do not call this function + * during normal execution. + */ + int countInsts(); +#if 0 + /** Debugging function to dump out the dependency graph. + */ + void dumpDependGraph(); +#endif + /** Debugging function to dump all the list sizes, as well as print + * out the list of nonspeculative instructions. Should not be used + * in any other capacity, but it has no harmful sideaffects. + */ + void dumpLists(); + + /** Debugging function to dump out all instructions that are in the + * IQ. + */ + void dumpInsts(); + + /** Stat for number of instructions added. */ + Stats::Scalar<> iqInstsAdded; + /** Stat for number of non-speculative instructions added. */ + Stats::Scalar<> iqNonSpecInstsAdded; +// Stats::Scalar<> iqIntInstsAdded; + /** Stat for number of integer instructions issued. */ + Stats::Scalar<> iqIntInstsIssued; +// Stats::Scalar<> iqFloatInstsAdded; + /** Stat for number of floating point instructions issued. */ + Stats::Scalar<> iqFloatInstsIssued; +// Stats::Scalar<> iqBranchInstsAdded; + /** Stat for number of branch instructions issued. */ + Stats::Scalar<> iqBranchInstsIssued; +// Stats::Scalar<> iqMemInstsAdded; + /** Stat for number of memory instructions issued. */ + Stats::Scalar<> iqMemInstsIssued; +// Stats::Scalar<> iqMiscInstsAdded; + /** Stat for number of miscellaneous instructions issued. */ + Stats::Scalar<> iqMiscInstsIssued; + /** Stat for number of squashed instructions that were ready to issue. */ + Stats::Scalar<> iqSquashedInstsIssued; + /** Stat for number of squashed instructions examined when squashing. */ + Stats::Scalar<> iqSquashedInstsExamined; + /** Stat for number of squashed instruction operands examined when + * squashing. + */ + Stats::Scalar<> iqSquashedOperandsExamined; + /** Stat for number of non-speculative instructions removed due to a squash. + */ + Stats::Scalar<> iqSquashedNonSpecRemoved; + +}; + +#endif //__CPU_OZONE_INST_QUEUE_HH__ diff --git a/src/cpu/ozone/inst_queue_impl.hh b/src/cpu/ozone/inst_queue_impl.hh new file mode 100644 index 000000000..f2d80e621 --- /dev/null +++ b/src/cpu/ozone/inst_queue_impl.hh @@ -0,0 +1,1343 @@ +/* + * 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 + */ + +// Todo: +// Current ordering allows for 0 cycle added-to-scheduled. Could maybe fake +// it; either do in reverse order, or have added instructions put into a +// different ready queue that, in scheduleRreadyInsts(), gets put onto the +// normal ready queue. This would however give only a one cycle delay, +// but probably is more flexible to actually add in a delay parameter than +// just running it backwards. + +#include <vector> + +#include "sim/root.hh" + +#include "cpu/ozone/inst_queue.hh" +#if 0 +template <class Impl> +InstQueue<Impl>::FUCompletion::FUCompletion(DynInstPtr &_inst, + int fu_idx, + InstQueue<Impl> *iq_ptr) + : Event(&mainEventQueue, Stat_Event_Pri), + inst(_inst), fuIdx(fu_idx), iqPtr(iq_ptr) +{ + this->setFlags(Event::AutoDelete); +} + +template <class Impl> +void +InstQueue<Impl>::FUCompletion::process() +{ + iqPtr->processFUCompletion(inst, fuIdx); +} + + +template <class Impl> +const char * +InstQueue<Impl>::FUCompletion::description() +{ + return "Functional unit completion event"; +} +#endif +template <class Impl> +InstQueue<Impl>::InstQueue(Params *params) + : dcacheInterface(params->dcacheInterface), +// fuPool(params->fuPool), + numEntries(params->numIQEntries), + totalWidth(params->issueWidth), +// numPhysIntRegs(params->numPhysIntRegs), +// numPhysFloatRegs(params->numPhysFloatRegs), + commitToIEWDelay(params->commitToIEWDelay) +{ +// assert(fuPool); + +// numThreads = params->numberOfThreads; + numThreads = 1; + + //Initialize thread IQ counts + for (int i = 0; i <numThreads; i++) { + count[i] = 0; + } + + // Initialize the number of free IQ entries. + freeEntries = numEntries; + + // Set the number of physical registers as the number of int + float +// numPhysRegs = numPhysIntRegs + numPhysFloatRegs; + +// DPRINTF(IQ, "There are %i physical registers.\n", numPhysRegs); + + //Create an entry for each physical register within the + //dependency graph. +// dependGraph = new DependencyEntry[numPhysRegs]; + + // Resize the register scoreboard. +// regScoreboard.resize(numPhysRegs); +/* + //Initialize Mem Dependence Units + for (int i = 0; i < numThreads; i++) { + memDepUnit[i].init(params,i); + memDepUnit[i].setIQ(this); + } + + // Initialize all the head pointers to point to NULL, and all the + // entries as unready. + // Note that in actuality, the registers corresponding to the logical + // registers start off as ready. However this doesn't matter for the + // IQ as the instruction should have been correctly told if those + // registers are ready in rename. Thus it can all be initialized as + // unready. + for (int i = 0; i < numPhysRegs; ++i) { + dependGraph[i].next = NULL; + dependGraph[i].inst = NULL; + regScoreboard[i] = false; + } +*/ + for (int i = 0; i < numThreads; ++i) { + squashedSeqNum[i] = 0; + } +/* + for (int i = 0; i < Num_OpClasses; ++i) { + queueOnList[i] = false; + readyIt[i] = listOrder.end(); + } + + string policy = params->smtIQPolicy; + + //Convert string to lowercase + std::transform(policy.begin(), policy.end(), policy.begin(), + (int(*)(int)) tolower); + + //Figure out resource sharing policy + if (policy == "dynamic") { + iqPolicy = Dynamic; + + //Set Max Entries to Total ROB Capacity + for (int i = 0; i < numThreads; i++) { + maxEntries[i] = numEntries; + } + + } else if (policy == "partitioned") { + iqPolicy = Partitioned; + + //@todo:make work if part_amt doesnt divide evenly. + int part_amt = numEntries / numThreads; + + //Divide ROB up evenly + for (int i = 0; i < numThreads; i++) { + maxEntries[i] = part_amt; + } + + DPRINTF(Fetch, "IQ sharing policy set to Partitioned:" + "%i entries per thread.\n",part_amt); + + } else if (policy == "threshold") { + iqPolicy = Threshold; + + double threshold = (double)params->smtIQThreshold / 100; + + int thresholdIQ = (int)((double)threshold * numEntries); + + //Divide up by threshold amount + for (int i = 0; i < numThreads; i++) { + maxEntries[i] = thresholdIQ; + } + + DPRINTF(Fetch, "IQ sharing policy set to Threshold:" + "%i entries per thread.\n",thresholdIQ); + } else { + assert(0 && "Invalid IQ Sharing Policy.Options Are:{Dynamic," + "Partitioned, Threshold}"); + } +*/ +} + +template <class Impl> +InstQueue<Impl>::~InstQueue() +{ + // Clear the dependency graph +/* + DependencyEntry *curr; + DependencyEntry *prev; + + for (int i = 0; i < numPhysRegs; ++i) { + curr = dependGraph[i].next; + + while (curr) { + DependencyEntry::mem_alloc_counter--; + + prev = curr; + curr = prev->next; + prev->inst = NULL; + + delete prev; + } + + if (dependGraph[i].inst) { + dependGraph[i].inst = NULL; + } + + dependGraph[i].next = NULL; + } + + assert(DependencyEntry::mem_alloc_counter == 0); + + delete [] dependGraph; +*/ +} + +template <class Impl> +std::string +InstQueue<Impl>::name() const +{ + return cpu->name() + ".iq"; +} + +template <class Impl> +void +InstQueue<Impl>::regStats() +{ + iqInstsAdded + .name(name() + ".iqInstsAdded") + .desc("Number of instructions added to the IQ (excludes non-spec)") + .prereq(iqInstsAdded); + + iqNonSpecInstsAdded + .name(name() + ".iqNonSpecInstsAdded") + .desc("Number of non-speculative instructions added to the IQ") + .prereq(iqNonSpecInstsAdded); + +// iqIntInstsAdded; + + iqIntInstsIssued + .name(name() + ".iqIntInstsIssued") + .desc("Number of integer instructions issued") + .prereq(iqIntInstsIssued); + +// iqFloatInstsAdded; + + iqFloatInstsIssued + .name(name() + ".iqFloatInstsIssued") + .desc("Number of float instructions issued") + .prereq(iqFloatInstsIssued); + +// iqBranchInstsAdded; + + iqBranchInstsIssued + .name(name() + ".iqBranchInstsIssued") + .desc("Number of branch instructions issued") + .prereq(iqBranchInstsIssued); + +// iqMemInstsAdded; + + iqMemInstsIssued + .name(name() + ".iqMemInstsIssued") + .desc("Number of memory instructions issued") + .prereq(iqMemInstsIssued); + +// iqMiscInstsAdded; + + iqMiscInstsIssued + .name(name() + ".iqMiscInstsIssued") + .desc("Number of miscellaneous instructions issued") + .prereq(iqMiscInstsIssued); + + iqSquashedInstsIssued + .name(name() + ".iqSquashedInstsIssued") + .desc("Number of squashed instructions issued") + .prereq(iqSquashedInstsIssued); + + iqSquashedInstsExamined + .name(name() + ".iqSquashedInstsExamined") + .desc("Number of squashed instructions iterated over during squash;" + " mainly for profiling") + .prereq(iqSquashedInstsExamined); + + iqSquashedOperandsExamined + .name(name() + ".iqSquashedOperandsExamined") + .desc("Number of squashed operands that are examined and possibly " + "removed from graph") + .prereq(iqSquashedOperandsExamined); + + iqSquashedNonSpecRemoved + .name(name() + ".iqSquashedNonSpecRemoved") + .desc("Number of squashed non-spec instructions that were removed") + .prereq(iqSquashedNonSpecRemoved); +/* + for ( int i=0; i < numThreads; i++) { + // Tell mem dependence unit to reg stats as well. + memDepUnit[i].regStats(); + } +*/ +} +/* +template <class Impl> +void +InstQueue<Impl>::setActiveThreads(list<unsigned> *at_ptr) +{ + DPRINTF(IQ, "Setting active threads list pointer.\n"); + activeThreads = at_ptr; +} +*/ +template <class Impl> +void +InstQueue<Impl>::setIssueToExecuteQueue(TimeBuffer<IssueStruct> *i2e_ptr) +{ + DPRINTF(IQ, "Set the issue to execute queue.\n"); + issueToExecuteQueue = i2e_ptr; +} +/* +template <class Impl> +void +InstQueue<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) +{ + DPRINTF(IQ, "Set the time buffer.\n"); + timeBuffer = tb_ptr; + + fromCommit = timeBuffer->getWire(-commitToIEWDelay); +} + +template <class Impl> +int +InstQueue<Impl>::entryAmount(int num_threads) +{ + if (iqPolicy == Partitioned) { + return numEntries / num_threads; + } else { + return 0; + } +} + + +template <class Impl> +void +InstQueue<Impl>::resetEntries() +{ + if (iqPolicy != Dynamic || numThreads > 1) { + int active_threads = (*activeThreads).size(); + + list<unsigned>::iterator threads = (*activeThreads).begin(); + list<unsigned>::iterator list_end = (*activeThreads).end(); + + while (threads != list_end) { + if (iqPolicy == Partitioned) { + maxEntries[*threads++] = numEntries / active_threads; + } else if(iqPolicy == Threshold && active_threads == 1) { + maxEntries[*threads++] = numEntries; + } + } + } +} +*/ +template <class Impl> +unsigned +InstQueue<Impl>::numFreeEntries() +{ + return freeEntries; +} + +template <class Impl> +unsigned +InstQueue<Impl>::numFreeEntries(unsigned tid) +{ + return maxEntries[tid] - count[tid]; +} + +// Might want to do something more complex if it knows how many instructions +// will be issued this cycle. +template <class Impl> +bool +InstQueue<Impl>::isFull() +{ + if (freeEntries == 0) { + return(true); + } else { + return(false); + } +} + +template <class Impl> +bool +InstQueue<Impl>::isFull(unsigned tid) +{ + if (numFreeEntries(tid) == 0) { + return(true); + } else { + return(false); + } +} + +template <class Impl> +bool +InstQueue<Impl>::hasReadyInsts() +{ +/* + if (!listOrder.empty()) { + return true; + } + + for (int i = 0; i < Num_OpClasses; ++i) { + if (!readyInsts[i].empty()) { + return true; + } + } + + return false; +*/ + return readyInsts.empty(); +} + +template <class Impl> +void +InstQueue<Impl>::insert(DynInstPtr &new_inst) +{ + // Make sure the instruction is valid + assert(new_inst); + + DPRINTF(IQ, "Adding instruction PC %#x to the IQ.\n", + new_inst->readPC()); + + // Check if there are any free entries. Panic if there are none. + // Might want to have this return a fault in the future instead of + // panicing. + assert(freeEntries != 0); + + instList[new_inst->threadNumber].push_back(new_inst); + + // Decrease the number of free entries. + --freeEntries; + + //Mark Instruction as in IQ +// new_inst->setInIQ(); +/* + // Look through its source registers (physical regs), and mark any + // dependencies. + addToDependents(new_inst); + + // Have this instruction set itself as the producer of its destination + // register(s). + createDependency(new_inst); +*/ + // If it's a memory instruction, add it to the memory dependency + // unit. +// if (new_inst->isMemRef()) { +// memDepUnit[new_inst->threadNumber].insert(new_inst); +// } else { + // If the instruction is ready then add it to the ready list. + addIfReady(new_inst); +// } + + ++iqInstsAdded; + + + //Update Thread IQ Count + count[new_inst->threadNumber]++; + + assert(freeEntries == (numEntries - countInsts())); +} + +template <class Impl> +void +InstQueue<Impl>::insertNonSpec(DynInstPtr &new_inst) +{ + nonSpecInsts[new_inst->seqNum] = new_inst; + + // @todo: Clean up this code; can do it by setting inst as unable + // to issue, then calling normal insert on the inst. + + // Make sure the instruction is valid + assert(new_inst); + + DPRINTF(IQ, "Adding instruction PC %#x to the IQ.\n", + new_inst->readPC()); + + // Check if there are any free entries. Panic if there are none. + // Might want to have this return a fault in the future instead of + // panicing. + assert(freeEntries != 0); + + instList[new_inst->threadNumber].push_back(new_inst); + + // Decrease the number of free entries. + --freeEntries; + + //Mark Instruction as in IQ +// new_inst->setInIQ(); +/* + // Have this instruction set itself as the producer of its destination + // register(s). + createDependency(new_inst); + + // If it's a memory instruction, add it to the memory dependency + // unit. + if (new_inst->isMemRef()) { + memDepUnit[new_inst->threadNumber].insertNonSpec(new_inst); + } +*/ + ++iqNonSpecInstsAdded; + + //Update Thread IQ Count + count[new_inst->threadNumber]++; + + assert(freeEntries == (numEntries - countInsts())); +} +/* +template <class Impl> +void +InstQueue<Impl>::advanceTail(DynInstPtr &inst) +{ + // Have this instruction set itself as the producer of its destination + // register(s). + createDependency(inst); +} + +template <class Impl> +void +InstQueue<Impl>::addToOrderList(OpClass op_class) +{ + assert(!readyInsts[op_class].empty()); + + ListOrderEntry queue_entry; + + queue_entry.queueType = op_class; + + queue_entry.oldestInst = readyInsts[op_class].top()->seqNum; + + ListOrderIt list_it = listOrder.begin(); + ListOrderIt list_end_it = listOrder.end(); + + while (list_it != list_end_it) { + if ((*list_it).oldestInst > queue_entry.oldestInst) { + break; + } + + list_it++; + } + + readyIt[op_class] = listOrder.insert(list_it, queue_entry); + queueOnList[op_class] = true; +} + +template <class Impl> +void +InstQueue<Impl>::moveToYoungerInst(ListOrderIt list_order_it) +{ + // Get iterator of next item on the list + // Delete the original iterator + // Determine if the next item is either the end of the list or younger + // than the new instruction. If so, then add in a new iterator right here. + // If not, then move along. + ListOrderEntry queue_entry; + OpClass op_class = (*list_order_it).queueType; + ListOrderIt next_it = list_order_it; + + ++next_it; + + queue_entry.queueType = op_class; + queue_entry.oldestInst = readyInsts[op_class].top()->seqNum; + + while (next_it != listOrder.end() && + (*next_it).oldestInst < queue_entry.oldestInst) { + ++next_it; + } + + readyIt[op_class] = listOrder.insert(next_it, queue_entry); +} + +template <class Impl> +void +InstQueue<Impl>::processFUCompletion(DynInstPtr &inst, int fu_idx) +{ + // The CPU could have been sleeping until this op completed (*extremely* + // long latency op). Wake it if it was. This may be overkill. + iewStage->wakeCPU(); + + fuPool->freeUnit(fu_idx); + + int &size = issueToExecuteQueue->access(0)->size; + + issueToExecuteQueue->access(0)->insts[size++] = inst; +} +*/ +// @todo: Figure out a better way to remove the squashed items from the +// lists. Checking the top item of each list to see if it's squashed +// wastes time and forces jumps. +template <class Impl> +void +InstQueue<Impl>::scheduleReadyInsts() +{ + DPRINTF(IQ, "Attempting to schedule ready instructions from " + "the IQ.\n"); + +// IssueStruct *i2e_info = issueToExecuteQueue->access(0); +/* + // Will need to reorder the list if either a queue is not on the list, + // or it has an older instruction than last time. + for (int i = 0; i < Num_OpClasses; ++i) { + if (!readyInsts[i].empty()) { + if (!queueOnList[i]) { + addToOrderList(OpClass(i)); + } else if (readyInsts[i].top()->seqNum < + (*readyIt[i]).oldestInst) { + listOrder.erase(readyIt[i]); + addToOrderList(OpClass(i)); + } + } + } + + // Have iterator to head of the list + // While I haven't exceeded bandwidth or reached the end of the list, + // Try to get a FU that can do what this op needs. + // If successful, change the oldestInst to the new top of the list, put + // the queue in the proper place in the list. + // Increment the iterator. + // This will avoid trying to schedule a certain op class if there are no + // FUs that handle it. + ListOrderIt order_it = listOrder.begin(); + ListOrderIt order_end_it = listOrder.end(); + int total_issued = 0; + int exec_queue_slot = i2e_info->size; + + while (exec_queue_slot < totalWidth && order_it != order_end_it) { + OpClass op_class = (*order_it).queueType; + + assert(!readyInsts[op_class].empty()); + + DynInstPtr issuing_inst = readyInsts[op_class].top(); + + assert(issuing_inst->seqNum == (*order_it).oldestInst); + + if (issuing_inst->isSquashed()) { + readyInsts[op_class].pop(); + + if (!readyInsts[op_class].empty()) { + moveToYoungerInst(order_it); + } else { + readyIt[op_class] = listOrder.end(); + queueOnList[op_class] = false; + } + + listOrder.erase(order_it++); + + ++iqSquashedInstsIssued; + + continue; + } + + int idx = fuPool->getUnit(op_class); + + if (idx != -1) { + int op_latency = fuPool->getOpLatency(op_class); + + if (op_latency == 1) { + i2e_info->insts[exec_queue_slot++] = issuing_inst; + i2e_info->size++; + + // Add the FU onto the list of FU's to be freed next cycle. + fuPool->freeUnit(idx); + } else { + int issue_latency = fuPool->getIssueLatency(op_class); + + if (issue_latency > 1) { + // Generate completion event for the FU + FUCompletion *execution = new FUCompletion(issuing_inst, + idx, this); + + execution->schedule(curTick + issue_latency - 1); + } else { + i2e_info->insts[exec_queue_slot++] = issuing_inst; + i2e_info->size++; + + // Add the FU onto the list of FU's to be freed next cycle. + fuPool->freeUnit(idx); + } + } + + DPRINTF(IQ, "Thread %i: Issuing instruction PC %#x " + "[sn:%lli]\n", + issuing_inst->threadNumber, issuing_inst->readPC(), + issuing_inst->seqNum); + + readyInsts[op_class].pop(); + + if (!readyInsts[op_class].empty()) { + moveToYoungerInst(order_it); + } else { + readyIt[op_class] = listOrder.end(); + queueOnList[op_class] = false; + } + + issuing_inst->setIssued(); + ++total_issued; + + if (!issuing_inst->isMemRef()) { + // Memory instructions can not be freed from the IQ until they + // complete. + ++freeEntries; + count[issuing_inst->threadNumber]--; + issuing_inst->removeInIQ(); + } else { + memDepUnit[issuing_inst->threadNumber].issue(issuing_inst); + } + + listOrder.erase(order_it++); + } else { + ++order_it; + } + } + + if (total_issued) { + cpu->activityThisCycle(); + } else { + DPRINTF(IQ, "Not able to schedule any instructions.\n"); + } +*/ +} + +template <class Impl> +void +InstQueue<Impl>::scheduleNonSpec(const InstSeqNum &inst) +{ + DPRINTF(IQ, "Marking nonspeculative instruction with sequence " + "number %i as ready to execute.\n", inst); + + NonSpecMapIt inst_it = nonSpecInsts.find(inst); + + assert(inst_it != nonSpecInsts.end()); + +// unsigned tid = (*inst_it).second->threadNumber; + + // Mark this instruction as ready to issue. + (*inst_it).second->setCanIssue(); + + // Now schedule the instruction. +// if (!(*inst_it).second->isMemRef()) { + addIfReady((*inst_it).second); +// } else { +// memDepUnit[tid].nonSpecInstReady((*inst_it).second); +// } + + nonSpecInsts.erase(inst_it); +} + +template <class Impl> +void +InstQueue<Impl>::commit(const InstSeqNum &inst, unsigned tid) +{ + /*Need to go through each thread??*/ + DPRINTF(IQ, "[tid:%i]: Committing instructions older than [sn:%i]\n", + tid,inst); + + ListIt iq_it = instList[tid].begin(); + + while (iq_it != instList[tid].end() && + (*iq_it)->seqNum <= inst) { + ++iq_it; + instList[tid].pop_front(); + } + + assert(freeEntries == (numEntries - countInsts())); +} + +template <class Impl> +void +InstQueue<Impl>::wakeDependents(DynInstPtr &completed_inst) +{ + DPRINTF(IQ, "Waking dependents of completed instruction.\n"); + // Look at the physical destination register of the DynInst + // and look it up on the dependency graph. Then mark as ready + // any instructions within the instruction queue. +/* + DependencyEntry *curr; + DependencyEntry *prev; +*/ + // Tell the memory dependence unit to wake any dependents on this + // instruction if it is a memory instruction. Also complete the memory + // instruction at this point since we know it executed fine. + // @todo: Might want to rename "completeMemInst" to + // something that indicates that it won't need to be replayed, and call + // this earlier. Might not be a big deal. + if (completed_inst->isMemRef()) { +// memDepUnit[completed_inst->threadNumber].wakeDependents(completed_inst); + completeMemInst(completed_inst); + } + completed_inst->wakeDependents(); +/* + for (int dest_reg_idx = 0; + dest_reg_idx < completed_inst->numDestRegs(); + dest_reg_idx++) + { + PhysRegIndex dest_reg = + completed_inst->renamedDestRegIdx(dest_reg_idx); + + // Special case of uniq or control registers. They are not + // handled by the IQ and thus have no dependency graph entry. + // @todo Figure out a cleaner way to handle this. + if (dest_reg >= numPhysRegs) { + continue; + } + + DPRINTF(IQ, "Waking any dependents on register %i.\n", + (int) dest_reg); + + //Maybe abstract this part into a function. + //Go through the dependency chain, marking the registers as ready + //within the waiting instructions. + + curr = dependGraph[dest_reg].next; + + while (curr) { + DPRINTF(IQ, "Waking up a dependent instruction, PC%#x.\n", + curr->inst->readPC()); + + // Might want to give more information to the instruction + // so that it knows which of its source registers is ready. + // However that would mean that the dependency graph entries + // would need to hold the src_reg_idx. + curr->inst->markSrcRegReady(); + + addIfReady(curr->inst); + + DependencyEntry::mem_alloc_counter--; + + prev = curr; + curr = prev->next; + prev->inst = NULL; + + delete prev; + } + + // Reset the head node now that all of its dependents have been woken + // up. + dependGraph[dest_reg].next = NULL; + dependGraph[dest_reg].inst = NULL; + + // Mark the scoreboard as having that register ready. + regScoreboard[dest_reg] = true; + } +*/ +} + +template <class Impl> +void +InstQueue<Impl>::addReadyMemInst(DynInstPtr &ready_inst) +{ + OpClass op_class = ready_inst->opClass(); + + readyInsts.push(ready_inst); + + DPRINTF(IQ, "Instruction is ready to issue, putting it onto " + "the ready list, PC %#x opclass:%i [sn:%lli].\n", + ready_inst->readPC(), op_class, ready_inst->seqNum); +} +/* +template <class Impl> +void +InstQueue<Impl>::rescheduleMemInst(DynInstPtr &resched_inst) +{ + memDepUnit[resched_inst->threadNumber].reschedule(resched_inst); +} + +template <class Impl> +void +InstQueue<Impl>::replayMemInst(DynInstPtr &replay_inst) +{ + memDepUnit[replay_inst->threadNumber].replay(replay_inst); +} +*/ +template <class Impl> +void +InstQueue<Impl>::completeMemInst(DynInstPtr &completed_inst) +{ + int tid = completed_inst->threadNumber; + + DPRINTF(IQ, "Completing mem instruction PC:%#x [sn:%lli]\n", + completed_inst->readPC(), completed_inst->seqNum); + + ++freeEntries; + +// completed_inst->memOpDone = true; + +// memDepUnit[tid].completed(completed_inst); + + count[tid]--; +} +/* +template <class Impl> +void +InstQueue<Impl>::violation(DynInstPtr &store, + DynInstPtr &faulting_load) +{ + memDepUnit[store->threadNumber].violation(store, faulting_load); +} +*/ +template <class Impl> +void +InstQueue<Impl>::squash(unsigned tid) +{ + DPRINTF(IQ, "[tid:%i]: Starting to squash instructions in " + "the IQ.\n", tid); + + // Read instruction sequence number of last instruction out of the + // time buffer. +// squashedSeqNum[tid] = fromCommit->commitInfo[tid].doneSeqNum; + + // Setup the squash iterator to point to the tail. + squashIt[tid] = instList[tid].end(); + --squashIt[tid]; + + // Call doSquash if there are insts in the IQ + if (count[tid] > 0) { + doSquash(tid); + } + + // Also tell the memory dependence unit to squash. +// memDepUnit[tid].squash(squashedSeqNum[tid], tid); +} + +template <class Impl> +void +InstQueue<Impl>::doSquash(unsigned tid) +{ + // Make sure the squashed sequence number is valid. + assert(squashedSeqNum[tid] != 0); + + DPRINTF(IQ, "[tid:%i]: Squashing until sequence number %i!\n", + tid, squashedSeqNum[tid]); + + // Squash any instructions younger than the squashed sequence number + // given. + while (squashIt[tid] != instList[tid].end() && + (*squashIt[tid])->seqNum > squashedSeqNum[tid]) { + + DynInstPtr squashed_inst = (*squashIt[tid]); + + // Only handle the instruction if it actually is in the IQ and + // hasn't already been squashed in the IQ. + if (squashed_inst->threadNumber != tid || + squashed_inst->isSquashedInIQ()) { + --squashIt[tid]; + continue; + } + + if (!squashed_inst->isIssued() || + (squashed_inst->isMemRef()/* && + !squashed_inst->memOpDone*/)) { + + // Remove the instruction from the dependency list. + if (!squashed_inst->isNonSpeculative()) { +/* + for (int src_reg_idx = 0; + src_reg_idx < squashed_inst->numSrcRegs(); + src_reg_idx++) + { + PhysRegIndex src_reg = + squashed_inst->renamedSrcRegIdx(src_reg_idx); + + // Only remove it from the dependency graph if it was + // placed there in the first place. + // HACK: This assumes that instructions woken up from the + // dependency chain aren't informed that a specific src + // register has become ready. This may not always be true + // in the future. + // Instead of doing a linked list traversal, we can just + // remove these squashed instructions either at issue time, + // or when the register is overwritten. The only downside + // to this is it leaves more room for error. + + if (!squashed_inst->isReadySrcRegIdx(src_reg_idx) && + src_reg < numPhysRegs) { + dependGraph[src_reg].remove(squashed_inst); + } + + + ++iqSquashedOperandsExamined; + } +*/ + // Might want to remove producers as well. + } else { + nonSpecInsts[squashed_inst->seqNum] = NULL; + + nonSpecInsts.erase(squashed_inst->seqNum); + + ++iqSquashedNonSpecRemoved; + } + + // Might want to also clear out the head of the dependency graph. + + // Mark it as squashed within the IQ. + squashed_inst->setSquashedInIQ(); + + // @todo: Remove this hack where several statuses are set so the + // inst will flow through the rest of the pipeline. + squashed_inst->setIssued(); + squashed_inst->setCanCommit(); +// squashed_inst->removeInIQ(); + + //Update Thread IQ Count + count[squashed_inst->threadNumber]--; + + ++freeEntries; + + if (numThreads > 1) { + DPRINTF(IQ, "[tid:%i]: Instruction PC %#x squashed.\n", + tid, squashed_inst->readPC()); + } else { + DPRINTF(IQ, "Instruction PC %#x squashed.\n", + squashed_inst->readPC()); + } + } + + --squashIt[tid]; + ++iqSquashedInstsExamined; + } +} +/* +template <class Impl> +void +InstQueue<Impl>::DependencyEntry::insert(DynInstPtr &new_inst) +{ + //Add this new, dependent instruction at the head of the dependency + //chain. + + // First create the entry that will be added to the head of the + // dependency chain. + DependencyEntry *new_entry = new DependencyEntry; + new_entry->next = this->next; + new_entry->inst = new_inst; + + // Then actually add it to the chain. + this->next = new_entry; + + ++mem_alloc_counter; +} + +template <class Impl> +void +InstQueue<Impl>::DependencyEntry::remove(DynInstPtr &inst_to_remove) +{ + DependencyEntry *prev = this; + DependencyEntry *curr = this->next; + + // Make sure curr isn't NULL. Because this instruction is being + // removed from a dependency list, it must have been placed there at + // an earlier time. The dependency chain should not be empty, + // unless the instruction dependent upon it is already ready. + if (curr == NULL) { + return; + } + + // Find the instruction to remove within the dependency linked list. + while (curr->inst != inst_to_remove) { + prev = curr; + curr = curr->next; + + assert(curr != NULL); + } + + // Now remove this instruction from the list. + prev->next = curr->next; + + --mem_alloc_counter; + + // Could push this off to the destructor of DependencyEntry + curr->inst = NULL; + + delete curr; +} + +template <class Impl> +bool +InstQueue<Impl>::addToDependents(DynInstPtr &new_inst) +{ + // Loop through the instruction's source registers, adding + // them to the dependency list if they are not ready. + int8_t total_src_regs = new_inst->numSrcRegs(); + bool return_val = false; + + for (int src_reg_idx = 0; + src_reg_idx < total_src_regs; + src_reg_idx++) + { + // Only add it to the dependency graph if it's not ready. + if (!new_inst->isReadySrcRegIdx(src_reg_idx)) { + PhysRegIndex src_reg = new_inst->renamedSrcRegIdx(src_reg_idx); + + // Check the IQ's scoreboard to make sure the register + // hasn't become ready while the instruction was in flight + // between stages. Only if it really isn't ready should + // it be added to the dependency graph. + if (src_reg >= numPhysRegs) { + continue; + } else if (regScoreboard[src_reg] == false) { + DPRINTF(IQ, "Instruction PC %#x has src reg %i that " + "is being added to the dependency chain.\n", + new_inst->readPC(), src_reg); + + dependGraph[src_reg].insert(new_inst); + + // Change the return value to indicate that something + // was added to the dependency graph. + return_val = true; + } else { + DPRINTF(IQ, "Instruction PC %#x has src reg %i that " + "became ready before it reached the IQ.\n", + new_inst->readPC(), src_reg); + // Mark a register ready within the instruction. + new_inst->markSrcRegReady(); + } + } + } + + return return_val; +} + +template <class Impl> +void +InstQueue<Impl>::createDependency(DynInstPtr &new_inst) +{ + //Actually nothing really needs to be marked when an + //instruction becomes the producer of a register's value, + //but for convenience a ptr to the producing instruction will + //be placed in the head node of the dependency links. + int8_t total_dest_regs = new_inst->numDestRegs(); + + for (int dest_reg_idx = 0; + dest_reg_idx < total_dest_regs; + dest_reg_idx++) + { + PhysRegIndex dest_reg = new_inst->renamedDestRegIdx(dest_reg_idx); + + // Instructions that use the misc regs will have a reg number + // higher than the normal physical registers. In this case these + // registers are not renamed, and there is no need to track + // dependencies as these instructions must be executed at commit. + if (dest_reg >= numPhysRegs) { + continue; + } + + if (dependGraph[dest_reg].next) { + dumpDependGraph(); + panic("Dependency graph %i not empty!", dest_reg); + } + + dependGraph[dest_reg].inst = new_inst; + + // Mark the scoreboard to say it's not yet ready. + regScoreboard[dest_reg] = false; + } +} +*/ +template <class Impl> +void +InstQueue<Impl>::addIfReady(DynInstPtr &inst) +{ + //If the instruction now has all of its source registers + // available, then add it to the list of ready instructions. + if (inst->readyToIssue()) { + + //Add the instruction to the proper ready list. + if (inst->isMemRef()) { + + DPRINTF(IQ, "Checking if memory instruction can issue.\n"); + + // Message to the mem dependence unit that this instruction has + // its registers ready. + +// memDepUnit[inst->threadNumber].regsReady(inst); + + return; + } + + OpClass op_class = inst->opClass(); + + DPRINTF(IQ, "Instruction is ready to issue, putting it onto " + "the ready list, PC %#x opclass:%i [sn:%lli].\n", + inst->readPC(), op_class, inst->seqNum); + + readyInsts.push(inst); + } +} + +template <class Impl> +int +InstQueue<Impl>::countInsts() +{ + //ksewell:This works but definitely could use a cleaner write + //with a more intuitive way of counting. Right now it's + //just brute force .... + +#if 0 + int total_insts = 0; + + for (int i = 0; i < numThreads; ++i) { + ListIt count_it = instList[i].begin(); + + while (count_it != instList[i].end()) { + if (!(*count_it)->isSquashed() && !(*count_it)->isSquashedInIQ()) { + if (!(*count_it)->isIssued()) { + ++total_insts; + } else if ((*count_it)->isMemRef() && + !(*count_it)->memOpDone) { + // Loads that have not been marked as executed still count + // towards the total instructions. + ++total_insts; + } + } + + ++count_it; + } + } + + return total_insts; +#else + return numEntries - freeEntries; +#endif +} +/* +template <class Impl> +void +InstQueue<Impl>::dumpDependGraph() +{ + DependencyEntry *curr; + + for (int i = 0; i < numPhysRegs; ++i) + { + curr = &dependGraph[i]; + + if (curr->inst) { + cprintf("dependGraph[%i]: producer: %#x [sn:%lli] consumer: ", + i, curr->inst->readPC(), curr->inst->seqNum); + } else { + cprintf("dependGraph[%i]: No producer. consumer: ", i); + } + + while (curr->next != NULL) { + curr = curr->next; + + cprintf("%#x [sn:%lli] ", + curr->inst->readPC(), curr->inst->seqNum); + } + + cprintf("\n"); + } +} +*/ +template <class Impl> +void +InstQueue<Impl>::dumpLists() +{ + for (int i = 0; i < Num_OpClasses; ++i) { + cprintf("Ready list %i size: %i\n", i, readyInsts.size()); + + cprintf("\n"); + } + + cprintf("Non speculative list size: %i\n", nonSpecInsts.size()); + + NonSpecMapIt non_spec_it = nonSpecInsts.begin(); + NonSpecMapIt non_spec_end_it = nonSpecInsts.end(); + + cprintf("Non speculative list: "); + + while (non_spec_it != non_spec_end_it) { + cprintf("%#x [sn:%lli]", (*non_spec_it).second->readPC(), + (*non_spec_it).second->seqNum); + ++non_spec_it; + } + + cprintf("\n"); +/* + ListOrderIt list_order_it = listOrder.begin(); + ListOrderIt list_order_end_it = listOrder.end(); + int i = 1; + + cprintf("List order: "); + + while (list_order_it != list_order_end_it) { + cprintf("%i OpClass:%i [sn:%lli] ", i, (*list_order_it).queueType, + (*list_order_it).oldestInst); + + ++list_order_it; + ++i; + } +*/ + cprintf("\n"); +} + + +template <class Impl> +void +InstQueue<Impl>::dumpInsts() +{ + for (int i = 0; i < numThreads; ++i) { +// int num = 0; +// int valid_num = 0; +/* + ListIt inst_list_it = instList[i].begin(); + + while (inst_list_it != instList[i].end()) + { + cprintf("Instruction:%i\n", + num); + if (!(*inst_list_it)->isSquashed()) { + if (!(*inst_list_it)->isIssued()) { + ++valid_num; + cprintf("Count:%i\n", valid_num); + } else if ((*inst_list_it)->isMemRef() && + !(*inst_list_it)->memOpDone) { + // Loads that have not been marked as executed still count + // towards the total instructions. + ++valid_num; + cprintf("Count:%i\n", valid_num); + } + } + + cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" + "Issued:%i\nSquashed:%i\n", + (*inst_list_it)->readPC(), + (*inst_list_it)->seqNum, + (*inst_list_it)->threadNumber, + (*inst_list_it)->isIssued(), + (*inst_list_it)->isSquashed()); + + if ((*inst_list_it)->isMemRef()) { + cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone); + } + + cprintf("\n"); + + inst_list_it++; + ++num; + } +*/ + } +} diff --git a/src/cpu/ozone/lsq_unit.cc b/src/cpu/ozone/lsq_unit.cc new file mode 100644 index 000000000..e37971dba --- /dev/null +++ b/src/cpu/ozone/lsq_unit.cc @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#include "cpu/ozone/ozone_impl.hh" +#include "cpu/ozone/lsq_unit_impl.hh" + +// Force the instantiation of LDSTQ for all the implementations we care about. +template class OzoneLSQ<OzoneImpl>; + diff --git a/src/cpu/ozone/lsq_unit.hh b/src/cpu/ozone/lsq_unit.hh new file mode 100644 index 000000000..1b5340e55 --- /dev/null +++ b/src/cpu/ozone/lsq_unit.hh @@ -0,0 +1,636 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#ifndef __CPU_OZONE_LSQ_UNIT_HH__ +#define __CPU_OZONE_LSQ_UNIT_HH__ + +#include <map> +#include <queue> +#include <algorithm> + +#include "arch/faults.hh" +#include "arch/isa_traits.hh" +#include "config/full_system.hh" +#include "base/hashmap.hh" +#include "cpu/inst_seq.hh" +#include "mem/mem_interface.hh" +//#include "mem/page_table.hh" +#include "sim/sim_object.hh" + +class PageTable; + +/** + * Class that implements the actual LQ and SQ for each specific thread. + * Both are circular queues; load entries are freed upon committing, while + * store entries are freed once they writeback. The LSQUnit tracks if there + * are memory ordering violations, and also detects partial load to store + * forwarding cases (a store only has part of a load's data) that requires + * the load to wait until the store writes back. In the former case it + * holds onto the instruction until the dependence unit looks at it, and + * in the latter it stalls the LSQ until the store writes back. At that + * point the load is replayed. + */ +template <class Impl> +class OzoneLSQ { + public: + typedef typename Impl::Params Params; + typedef typename Impl::FullCPU FullCPU; + typedef typename Impl::BackEnd BackEnd; + typedef typename Impl::DynInstPtr DynInstPtr; + typedef typename Impl::IssueStruct IssueStruct; + + typedef TheISA::IntReg IntReg; + + typedef typename std::map<InstSeqNum, DynInstPtr>::iterator LdMapIt; + + private: + class StoreCompletionEvent : public Event { + public: + /** Constructs a store completion event. */ + StoreCompletionEvent(int store_idx, Event *wb_event, OzoneLSQ *lsq_ptr); + + /** Processes the store completion event. */ + void process(); + + /** Returns the description of this event. */ + const char *description(); + + private: + /** The store index of the store being written back. */ + int storeIdx; + /** The writeback event for the store. Needed for store + * conditionals. + */ + Event *wbEvent; + /** The pointer to the LSQ unit that issued the store. */ + OzoneLSQ<Impl> *lsqPtr; + }; + + friend class StoreCompletionEvent; + + public: + /** Constructs an LSQ unit. init() must be called prior to use. */ + OzoneLSQ(); + + /** Initializes the LSQ unit with the specified number of entries. */ + void init(Params *params, unsigned maxLQEntries, + unsigned maxSQEntries, unsigned id); + + /** Returns the name of the LSQ unit. */ + std::string name() const; + + /** Sets the CPU pointer. */ + void setCPU(FullCPU *cpu_ptr) + { cpu = cpu_ptr; } + + /** Sets the back-end stage pointer. */ + void setBE(BackEnd *be_ptr) + { be = be_ptr; } + + /** Ticks the LSQ unit, which in this case only resets the number of + * used cache ports. + * @todo: Move the number of used ports up to the LSQ level so it can + * be shared by all LSQ units. + */ + void tick() { usedPorts = 0; } + + /** Inserts an instruction. */ + void insert(DynInstPtr &inst); + /** Inserts a load instruction. */ + void insertLoad(DynInstPtr &load_inst); + /** Inserts a store instruction. */ + void insertStore(DynInstPtr &store_inst); + + /** Executes a load instruction. */ + Fault executeLoad(DynInstPtr &inst); + + Fault executeLoad(int lq_idx); + /** Executes a store instruction. */ + Fault executeStore(DynInstPtr &inst); + + /** Commits the head load. */ + void commitLoad(); + /** Commits a specific load, given by the sequence number. */ + void commitLoad(InstSeqNum &inst); + /** Commits loads older than a specific sequence number. */ + void commitLoads(InstSeqNum &youngest_inst); + + /** Commits stores older than a specific sequence number. */ + void commitStores(InstSeqNum &youngest_inst); + + /** Writes back stores. */ + void writebackStores(); + + // @todo: Include stats in the LSQ unit. + //void regStats(); + + /** Clears all the entries in the LQ. */ + void clearLQ(); + + /** Clears all the entries in the SQ. */ + void clearSQ(); + + /** Resizes the LQ to a given size. */ + void resizeLQ(unsigned size); + + /** Resizes the SQ to a given size. */ + void resizeSQ(unsigned size); + + /** Squashes all instructions younger than a specific sequence number. */ + void squash(const InstSeqNum &squashed_num); + + /** Returns if there is a memory ordering violation. Value is reset upon + * call to getMemDepViolator(). + */ + bool violation() { return memDepViolator; } + + /** Returns the memory ordering violator. */ + DynInstPtr getMemDepViolator(); + + /** Returns if a load became blocked due to the memory system. It clears + * the bool's value upon this being called. + */ + inline bool loadBlocked(); + + /** Returns the number of free entries (min of free LQ and SQ entries). */ + unsigned numFreeEntries(); + + /** Returns the number of loads ready to execute. */ + int numLoadsReady(); + + /** Returns the number of loads in the LQ. */ + int numLoads() { return loads; } + + /** Returns the number of stores in the SQ. */ + int numStores() { return stores; } + + /** Returns if either the LQ or SQ is full. */ + bool isFull() { return lqFull() || sqFull(); } + + /** Returns if the LQ is full. */ + bool lqFull() { return loads >= (LQEntries - 1); } + + /** Returns if the SQ is full. */ + bool sqFull() { return stores >= (SQEntries - 1); } + + /** Debugging function to dump instructions in the LSQ. */ + void dumpInsts(); + + /** Returns the number of instructions in the LSQ. */ + unsigned getCount() { return loads + stores; } + + /** Returns if there are any stores to writeback. */ + bool hasStoresToWB() { return storesToWB; } + + /** Returns the number of stores to writeback. */ + int numStoresToWB() { return storesToWB; } + + /** Returns if the LSQ unit will writeback on this cycle. */ + bool willWB() { return storeQueue[storeWBIdx].canWB && + !storeQueue[storeWBIdx].completed && + !dcacheInterface->isBlocked(); } + + private: + /** Completes the store at the specified index. */ + void completeStore(int store_idx); + + /** Increments the given store index (circular queue). */ + inline void incrStIdx(int &store_idx); + /** Decrements the given store index (circular queue). */ + inline void decrStIdx(int &store_idx); + /** Increments the given load index (circular queue). */ + inline void incrLdIdx(int &load_idx); + /** Decrements the given load index (circular queue). */ + inline void decrLdIdx(int &load_idx); + + private: + /** Pointer to the CPU. */ + FullCPU *cpu; + + /** Pointer to the back-end stage. */ + BackEnd *be; + + /** Pointer to the D-cache. */ + MemInterface *dcacheInterface; + + /** Pointer to the page table. */ + PageTable *pTable; + + public: + struct SQEntry { + /** Constructs an empty store queue entry. */ + SQEntry() + : inst(NULL), req(NULL), size(0), data(0), + canWB(0), committed(0), completed(0) + { } + + /** Constructs a store queue entry for a given instruction. */ + SQEntry(DynInstPtr &_inst) + : inst(_inst), req(NULL), size(0), data(0), + canWB(0), committed(0), completed(0) + { } + + /** The store instruction. */ + DynInstPtr inst; + /** The memory request for the store. */ + MemReqPtr req; + /** The size of the store. */ + int size; + /** The store data. */ + IntReg data; + /** Whether or not the store can writeback. */ + bool canWB; + /** Whether or not the store is committed. */ + bool committed; + /** Whether or not the store is completed. */ + bool completed; + }; + + enum Status { + Running, + Idle, + DcacheMissStall, + DcacheMissSwitch + }; + + private: + /** The OzoneLSQ thread id. */ + unsigned lsqID; + + /** The status of the LSQ unit. */ + Status _status; + + /** The store queue. */ + std::vector<SQEntry> storeQueue; + + /** The load queue. */ + std::vector<DynInstPtr> loadQueue; + + // Consider making these 16 bits + /** The number of LQ entries. */ + unsigned LQEntries; + /** The number of SQ entries. */ + unsigned SQEntries; + + /** The number of load instructions in the LQ. */ + int loads; + /** The number of store instructions in the SQ (excludes those waiting to + * writeback). + */ + int stores; + /** The number of store instructions in the SQ waiting to writeback. */ + int storesToWB; + + /** The index of the head instruction in the LQ. */ + int loadHead; + /** The index of the tail instruction in the LQ. */ + int loadTail; + + /** The index of the head instruction in the SQ. */ + int storeHead; + /** The index of the first instruction that is ready to be written back, + * and has not yet been written back. + */ + int storeWBIdx; + /** The index of the tail instruction in the SQ. */ + int storeTail; + + /// @todo Consider moving to a more advanced model with write vs read ports + /** The number of cache ports available each cycle. */ + int cachePorts; + + /** The number of used cache ports in this cycle. */ + int usedPorts; + + //list<InstSeqNum> mshrSeqNums; + + //Stats::Scalar<> dcacheStallCycles; + Counter lastDcacheStall; + + /** Wire to read information from the issue stage time queue. */ + typename TimeBuffer<IssueStruct>::wire fromIssue; + + // Make these per thread? + /** Whether or not the LSQ is stalled. */ + bool stalled; + /** The store that causes the stall due to partial store to load + * forwarding. + */ + InstSeqNum stallingStoreIsn; + /** The index of the above store. */ + int stallingLoadIdx; + + /** Whether or not a load is blocked due to the memory system. It is + * cleared when this value is checked via loadBlocked(). + */ + bool isLoadBlocked; + + /** The oldest faulting load instruction. */ + DynInstPtr loadFaultInst; + /** The oldest faulting store instruction. */ + DynInstPtr storeFaultInst; + + /** The oldest load that caused a memory ordering violation. */ + DynInstPtr memDepViolator; + + // Will also need how many read/write ports the Dcache has. Or keep track + // of that in stage that is one level up, and only call executeLoad/Store + // the appropriate number of times. + + public: + /** Executes the load at the given index. */ + template <class T> + Fault read(MemReqPtr &req, T &data, int load_idx); + + /** Executes the store at the given index. */ + template <class T> + Fault write(MemReqPtr &req, T &data, int store_idx); + + /** Returns the index of the head load instruction. */ + int getLoadHead() { return loadHead; } + /** Returns the sequence number of the head load instruction. */ + InstSeqNum getLoadHeadSeqNum() + { + if (loadQueue[loadHead]) { + return loadQueue[loadHead]->seqNum; + } else { + return 0; + } + + } + + /** Returns the index of the head store instruction. */ + int getStoreHead() { return storeHead; } + /** Returns the sequence number of the head store instruction. */ + InstSeqNum getStoreHeadSeqNum() + { + if (storeQueue[storeHead].inst) { + return storeQueue[storeHead].inst->seqNum; + } else { + return 0; + } + + } + + /** Returns whether or not the LSQ unit is stalled. */ + bool isStalled() { return stalled; } +}; + +template <class Impl> +template <class T> +Fault +OzoneLSQ<Impl>::read(MemReqPtr &req, T &data, int load_idx) +{ + //Depending on issue2execute delay a squashed load could + //execute if it is found to be squashed in the same + //cycle it is scheduled to execute + assert(loadQueue[load_idx]); + + if (loadQueue[load_idx]->isExecuted()) { + panic("Should not reach this point with split ops!"); + + memcpy(&data,req->data,req->size); + + return NoFault; + } + + // Make sure this isn't an uncacheable access + // A bit of a hackish way to get uncached accesses to work only if they're + // at the head of the LSQ and are ready to commit (at the head of the ROB + // too). + // @todo: Fix uncached accesses. + if (req->flags & UNCACHEABLE && + (load_idx != loadHead || !loadQueue[load_idx]->readyToCommit())) { + + return TheISA::genMachineCheckFault(); + } + + // Check the SQ for any previous stores that might lead to forwarding + int store_idx = loadQueue[load_idx]->sqIdx; + + int store_size = 0; + + DPRINTF(OzoneLSQ, "Read called, load idx: %i, store idx: %i, " + "storeHead: %i addr: %#x\n", + load_idx, store_idx, storeHead, req->paddr); + + while (store_idx != -1) { + // End once we've reached the top of the LSQ + if (store_idx == storeWBIdx) { + break; + } + + // Move the index to one younger + if (--store_idx < 0) + store_idx += SQEntries; + + assert(storeQueue[store_idx].inst); + + store_size = storeQueue[store_idx].size; + + if (store_size == 0) + continue; + + // Check if the store data is within the lower and upper bounds of + // addresses that the request needs. + bool store_has_lower_limit = + req->vaddr >= storeQueue[store_idx].inst->effAddr; + bool store_has_upper_limit = + (req->vaddr + req->size) <= (storeQueue[store_idx].inst->effAddr + + store_size); + bool lower_load_has_store_part = + req->vaddr < (storeQueue[store_idx].inst->effAddr + + store_size); + bool upper_load_has_store_part = + (req->vaddr + req->size) > storeQueue[store_idx].inst->effAddr; + + // If the store's data has all of the data needed, we can forward. + if (store_has_lower_limit && store_has_upper_limit) { + + int shift_amt = req->vaddr & (store_size - 1); + // Assumes byte addressing + shift_amt = shift_amt << 3; + + // Cast this to type T? + data = storeQueue[store_idx].data >> shift_amt; + + req->cmd = Read; + assert(!req->completionEvent); + req->completionEvent = NULL; + req->time = curTick; + assert(!req->data); + req->data = new uint8_t[64]; + + memcpy(req->data, &data, req->size); + + DPRINTF(OzoneLSQ, "Forwarding from store idx %i to load to " + "addr %#x, data %#x\n", + store_idx, req->vaddr, *(req->data)); + + typename BackEnd::LdWritebackEvent *wb = + new typename BackEnd::LdWritebackEvent(loadQueue[load_idx], + be); + + // We'll say this has a 1 cycle load-store forwarding latency + // for now. + // FIXME - Need to make this a parameter. + wb->schedule(curTick); + + // Should keep track of stat for forwarded data + return NoFault; + } else if ((store_has_lower_limit && lower_load_has_store_part) || + (store_has_upper_limit && upper_load_has_store_part) || + (lower_load_has_store_part && upper_load_has_store_part)) { + // This is the partial store-load forwarding case where a store + // has only part of the load's data. + + // If it's already been written back, then don't worry about + // stalling on it. + if (storeQueue[store_idx].completed) { + continue; + } + + // Must stall load and force it to retry, so long as it's the oldest + // load that needs to do so. + if (!stalled || + (stalled && + loadQueue[load_idx]->seqNum < + loadQueue[stallingLoadIdx]->seqNum)) { + stalled = true; + stallingStoreIsn = storeQueue[store_idx].inst->seqNum; + stallingLoadIdx = load_idx; + } + + // Tell IQ/mem dep unit that this instruction will need to be + // rescheduled eventually + be->rescheduleMemInst(loadQueue[load_idx]); + + DPRINTF(OzoneLSQ, "Load-store forwarding mis-match. " + "Store idx %i to load addr %#x\n", + store_idx, req->vaddr); + + return NoFault; + } + } + + + // If there's no forwarding case, then go access memory + DynInstPtr inst = loadQueue[load_idx]; + + ++usedPorts; + + // if we have a cache, do cache access too + if (dcacheInterface) { + if (dcacheInterface->isBlocked()) { + isLoadBlocked = true; + // No fault occurred, even though the interface is blocked. + return NoFault; + } + + DPRINTF(OzoneLSQ, "D-cache: PC:%#x reading from paddr:%#x " + "vaddr:%#x flags:%i\n", + inst->readPC(), req->paddr, req->vaddr, req->flags); + + // Setup MemReq pointer + req->cmd = Read; + req->completionEvent = NULL; + req->time = curTick; + assert(!req->data); + req->data = new uint8_t[64]; + + assert(!req->completionEvent); + typedef typename BackEnd::LdWritebackEvent LdWritebackEvent; + + LdWritebackEvent *wb = new LdWritebackEvent(loadQueue[load_idx], be); + + req->completionEvent = wb; + + // Do Cache Access + MemAccessResult result = dcacheInterface->access(req); + + // Ugly hack to get an event scheduled *only* if the access is + // a miss. We really should add first-class support for this + // at some point. + // @todo: Probably should support having no events + if (result != MA_HIT) { + DPRINTF(OzoneLSQ, "D-cache miss!\n"); + DPRINTF(Activity, "Activity: ld accessing mem miss [sn:%lli]\n", + inst->seqNum); + + lastDcacheStall = curTick; + + _status = DcacheMissStall; + + wb->setDcacheMiss(); + + } else { +// DPRINTF(Activity, "Activity: ld accessing mem hit [sn:%lli]\n", +// inst->seqNum); + + DPRINTF(OzoneLSQ, "D-cache hit!\n"); + } + } else { + fatal("Must use D-cache with new memory system"); + } + + return NoFault; +} + +template <class Impl> +template <class T> +Fault +OzoneLSQ<Impl>::write(MemReqPtr &req, T &data, int store_idx) +{ + assert(storeQueue[store_idx].inst); + + DPRINTF(OzoneLSQ, "Doing write to store idx %i, addr %#x data %#x" + " | storeHead:%i [sn:%i]\n", + store_idx, req->paddr, data, storeHead, + storeQueue[store_idx].inst->seqNum); + + storeQueue[store_idx].req = req; + storeQueue[store_idx].size = sizeof(T); + storeQueue[store_idx].data = data; + + // This function only writes the data to the store queue, so no fault + // can happen here. + return NoFault; +} + +template <class Impl> +inline bool +OzoneLSQ<Impl>::loadBlocked() +{ + bool ret_val = isLoadBlocked; + isLoadBlocked = false; + return ret_val; +} + +#endif // __CPU_OZONE_LSQ_UNIT_HH__ diff --git a/src/cpu/ozone/lsq_unit_impl.hh b/src/cpu/ozone/lsq_unit_impl.hh new file mode 100644 index 000000000..f8cb18634 --- /dev/null +++ b/src/cpu/ozone/lsq_unit_impl.hh @@ -0,0 +1,840 @@ +/* + * 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 "arch/isa_traits.hh" +#include "base/str.hh" +#include "cpu/ozone/lsq_unit.hh" + +template <class Impl> +OzoneLSQ<Impl>::StoreCompletionEvent::StoreCompletionEvent(int store_idx, + Event *wb_event, + OzoneLSQ<Impl> *lsq_ptr) + : Event(&mainEventQueue), + storeIdx(store_idx), + wbEvent(wb_event), + lsqPtr(lsq_ptr) +{ + this->setFlags(Event::AutoDelete); +} + +template <class Impl> +void +OzoneLSQ<Impl>::StoreCompletionEvent::process() +{ + DPRINTF(OzoneLSQ, "Cache miss complete for store idx:%i\n", storeIdx); + + //lsqPtr->removeMSHR(lsqPtr->storeQueue[storeIdx].inst->seqNum); + +// lsqPtr->cpu->wakeCPU(); + if (wbEvent) + wbEvent->process(); + lsqPtr->completeStore(storeIdx); +} + +template <class Impl> +const char * +OzoneLSQ<Impl>::StoreCompletionEvent::description() +{ + return "LSQ store completion event"; +} + +template <class Impl> +OzoneLSQ<Impl>::OzoneLSQ() + : loads(0), stores(0), storesToWB(0), stalled(false), isLoadBlocked(false) +{ +} + +template<class Impl> +void +OzoneLSQ<Impl>::init(Params *params, unsigned maxLQEntries, + unsigned maxSQEntries, unsigned id) + +{ + DPRINTF(OzoneLSQ, "Creating OzoneLSQ%i object.\n",id); + + lsqID = id; + + LQEntries = maxLQEntries; + SQEntries = maxSQEntries; + + loadQueue.resize(LQEntries); + storeQueue.resize(SQEntries); + + + // May want to initialize these entries to NULL + + loadHead = loadTail = 0; + + storeHead = storeWBIdx = storeTail = 0; + + usedPorts = 0; + cachePorts = params->cachePorts; + + dcacheInterface = params->dcacheInterface; + + loadFaultInst = storeFaultInst = memDepViolator = NULL; +} + +template<class Impl> +std::string +OzoneLSQ<Impl>::name() const +{ + return "lsqunit"; +} + +template<class Impl> +void +OzoneLSQ<Impl>::clearLQ() +{ + loadQueue.clear(); +} + +template<class Impl> +void +OzoneLSQ<Impl>::clearSQ() +{ + storeQueue.clear(); +} + +template<class Impl> +void +OzoneLSQ<Impl>::resizeLQ(unsigned size) +{ + assert( size >= LQEntries); + + if (size > LQEntries) { + while (size > loadQueue.size()) { + DynInstPtr dummy; + loadQueue.push_back(dummy); + LQEntries++; + } + } else { + LQEntries = size; + } + +} + +template<class Impl> +void +OzoneLSQ<Impl>::resizeSQ(unsigned size) +{ + if (size > SQEntries) { + while (size > storeQueue.size()) { + SQEntry dummy; + storeQueue.push_back(dummy); + SQEntries++; + } + } else { + SQEntries = size; + } +} + +template <class Impl> +void +OzoneLSQ<Impl>::insert(DynInstPtr &inst) +{ + // Make sure we really have a memory reference. + assert(inst->isMemRef()); + + // Make sure it's one of the two classes of memory references. + assert(inst->isLoad() || inst->isStore()); + + if (inst->isLoad()) { + insertLoad(inst); + } else { + insertStore(inst); + } + +// inst->setInLSQ(); +} + +template <class Impl> +void +OzoneLSQ<Impl>::insertLoad(DynInstPtr &load_inst) +{ + assert((loadTail + 1) % LQEntries != loadHead && loads < LQEntries); + + DPRINTF(OzoneLSQ, "Inserting load PC %#x, idx:%i [sn:%lli]\n", + load_inst->readPC(), loadTail, load_inst->seqNum); + + load_inst->lqIdx = loadTail; + + if (stores == 0) { + load_inst->sqIdx = -1; + } else { + load_inst->sqIdx = storeTail; + } + + loadQueue[loadTail] = load_inst; + + incrLdIdx(loadTail); + + ++loads; +} + +template <class Impl> +void +OzoneLSQ<Impl>::insertStore(DynInstPtr &store_inst) +{ + // Make sure it is not full before inserting an instruction. + assert((storeTail + 1) % SQEntries != storeHead); + assert(stores < SQEntries); + + DPRINTF(OzoneLSQ, "Inserting store PC %#x, idx:%i [sn:%lli]\n", + store_inst->readPC(), storeTail, store_inst->seqNum); + + store_inst->sqIdx = storeTail; + store_inst->lqIdx = loadTail; + + storeQueue[storeTail] = SQEntry(store_inst); + + incrStIdx(storeTail); + + ++stores; + +} + +template <class Impl> +typename Impl::DynInstPtr +OzoneLSQ<Impl>::getMemDepViolator() +{ + DynInstPtr temp = memDepViolator; + + memDepViolator = NULL; + + return temp; +} + +template <class Impl> +unsigned +OzoneLSQ<Impl>::numFreeEntries() +{ + unsigned free_lq_entries = LQEntries - loads; + unsigned free_sq_entries = SQEntries - stores; + + // Both the LQ and SQ entries have an extra dummy entry to differentiate + // empty/full conditions. Subtract 1 from the free entries. + if (free_lq_entries < free_sq_entries) { + return free_lq_entries - 1; + } else { + return free_sq_entries - 1; + } +} + +template <class Impl> +int +OzoneLSQ<Impl>::numLoadsReady() +{ + int load_idx = loadHead; + int retval = 0; + + while (load_idx != loadTail) { + assert(loadQueue[load_idx]); + + if (loadQueue[load_idx]->readyToIssue()) { + ++retval; + } + } + + return retval; +} + +#if 0 +template <class Impl> +Fault +OzoneLSQ<Impl>::executeLoad() +{ + Fault load_fault = NoFault; + DynInstPtr load_inst; + + assert(readyLoads.size() != 0); + + // Execute a ready load. + LdMapIt ready_it = readyLoads.begin(); + + load_inst = (*ready_it).second; + + // Execute the instruction, which is held in the data portion of the + // iterator. + load_fault = load_inst->execute(); + + // If it executed successfully, then switch it over to the executed + // loads list. + if (load_fault == NoFault) { + executedLoads[load_inst->seqNum] = load_inst; + + readyLoads.erase(ready_it); + } else { + loadFaultInst = load_inst; + } + + return load_fault; +} +#endif + +template <class Impl> +Fault +OzoneLSQ<Impl>::executeLoad(DynInstPtr &inst) +{ + // Execute a specific load. + Fault load_fault = NoFault; + + DPRINTF(OzoneLSQ, "Executing load PC %#x, [sn:%lli]\n", + inst->readPC(),inst->seqNum); + + // Make sure it's really in the list. + // Normally it should always be in the list. However, + /* due to a syscall it may not be the list. +#ifdef DEBUG + int i = loadHead; + while (1) { + if (i == loadTail && !find(inst)) { + assert(0 && "Load not in the queue!"); + } else if (loadQueue[i] == inst) { + break; + } + + i = i + 1; + if (i >= LQEntries) { + i = 0; + } + } +#endif // DEBUG*/ + + load_fault = inst->initiateAcc(); + + // Might want to make sure that I'm not overwriting a previously faulting + // instruction that hasn't been checked yet. + // Actually probably want the oldest faulting load + if (load_fault != NoFault) { + // Maybe just set it as can commit here, although that might cause + // some other problems with sending traps to the ROB too quickly. +// iewStage->instToCommit(inst); +// iewStage->activityThisCycle(); + } + + return load_fault; +} + +template <class Impl> +Fault +OzoneLSQ<Impl>::executeLoad(int lq_idx) +{ + // Very hackish. Not sure the best way to check that this + // instruction is at the head of the ROB. I should have some sort + // of extra information here so that I'm not overloading the + // canCommit signal for 15 different things. + loadQueue[lq_idx]->setCanCommit(); + Fault ret_fault = executeLoad(loadQueue[lq_idx]); + loadQueue[lq_idx]->clearCanCommit(); + return ret_fault; +} + +template <class Impl> +Fault +OzoneLSQ<Impl>::executeStore(DynInstPtr &store_inst) +{ + // Make sure that a store exists. + assert(stores != 0); + + int store_idx = store_inst->sqIdx; + + DPRINTF(OzoneLSQ, "Executing store PC %#x [sn:%lli]\n", + store_inst->readPC(), store_inst->seqNum); + + // Check the recently completed loads to see if any match this store's + // address. If so, then we have a memory ordering violation. + int load_idx = store_inst->lqIdx; + + Fault store_fault = store_inst->initiateAcc(); + + // Store size should now be available. Use it to get proper offset for + // addr comparisons. + int size = storeQueue[store_idx].size; + + if (size == 0) { + DPRINTF(OzoneLSQ,"Fault on Store PC %#x, [sn:%lli],Size = 0\n", + store_inst->readPC(),store_inst->seqNum); + + return store_fault; + } + + assert(store_fault == NoFault); + + if (!storeFaultInst) { + if (store_fault != NoFault) { + panic("Fault in a store instruction!"); + storeFaultInst = store_inst; + } else if (store_inst->isNonSpeculative()) { + // Nonspeculative accesses (namely store conditionals) + // need to set themselves as able to writeback if we + // haven't had a fault by here. + storeQueue[store_idx].canWB = true; + + ++storesToWB; + } + } + + if (!memDepViolator) { + while (load_idx != loadTail) { + // Actually should only check loads that have actually executed + // Might be safe because effAddr is set to InvalAddr when the + // dyn inst is created. + + // Must actually check all addrs in the proper size range + // Which is more correct than needs to be. What if for now we just + // assume all loads are quad-word loads, and do the addr based + // on that. + // @todo: Fix this, magic number being used here + if ((loadQueue[load_idx]->effAddr >> 8) == + (store_inst->effAddr >> 8)) { + // A load incorrectly passed this store. Squash and refetch. + // For now return a fault to show that it was unsuccessful. + memDepViolator = loadQueue[load_idx]; + + return TheISA::genMachineCheckFault(); + } + + incrLdIdx(load_idx); + } + + // If we've reached this point, there was no violation. + memDepViolator = NULL; + } + + return store_fault; +} + +template <class Impl> +void +OzoneLSQ<Impl>::commitLoad() +{ + assert(loadQueue[loadHead]); + + DPRINTF(OzoneLSQ, "[sn:%lli] Committing head load instruction, PC %#x\n", + loadQueue[loadHead]->seqNum, loadQueue[loadHead]->readPC()); + + + loadQueue[loadHead] = NULL; + + incrLdIdx(loadHead); + + --loads; +} + +template <class Impl> +void +OzoneLSQ<Impl>::commitLoad(InstSeqNum &inst) +{ + // Hopefully I don't use this function too much + panic("Don't use this function!"); + + int i = loadHead; + while (1) { + if (i == loadTail) { + assert(0 && "Load not in the queue!"); + } else if (loadQueue[i]->seqNum == inst) { + break; + } + + ++i; + if (i >= LQEntries) { + i = 0; + } + } + +// loadQueue[i]->removeInLSQ(); + loadQueue[i] = NULL; + --loads; +} + +template <class Impl> +void +OzoneLSQ<Impl>::commitLoads(InstSeqNum &youngest_inst) +{ + assert(loads == 0 || loadQueue[loadHead]); + + while (loads != 0 && loadQueue[loadHead]->seqNum <= youngest_inst) { + commitLoad(); + } +} + +template <class Impl> +void +OzoneLSQ<Impl>::commitStores(InstSeqNum &youngest_inst) +{ + assert(stores == 0 || storeQueue[storeHead].inst); + + int store_idx = storeHead; + + while (store_idx != storeTail) { + assert(storeQueue[store_idx].inst); + if (!storeQueue[store_idx].canWB) { + if (storeQueue[store_idx].inst->seqNum > youngest_inst) { + break; + } + DPRINTF(OzoneLSQ, "Marking store as able to write back, PC " + "%#x [sn:%lli]\n", + storeQueue[store_idx].inst->readPC(), + storeQueue[store_idx].inst->seqNum); + + storeQueue[store_idx].canWB = true; + +// --stores; + ++storesToWB; + } + + incrStIdx(store_idx); + } +} + +template <class Impl> +void +OzoneLSQ<Impl>::writebackStores() +{ + while (storesToWB > 0 && + storeWBIdx != storeTail && + storeQueue[storeWBIdx].inst && + storeQueue[storeWBIdx].canWB && + usedPorts < cachePorts) { + + if (storeQueue[storeWBIdx].size == 0) { + completeStore(storeWBIdx); + + incrStIdx(storeWBIdx); + + continue; + } + + if (dcacheInterface && dcacheInterface->isBlocked()) { + DPRINTF(OzoneLSQ, "Unable to write back any more stores, cache" + " is blocked!\n"); + break; + } + + ++usedPorts; + + if (storeQueue[storeWBIdx].inst->isDataPrefetch()) { + incrStIdx(storeWBIdx); + + continue; + } + + assert(storeQueue[storeWBIdx].req); + assert(!storeQueue[storeWBIdx].committed); + + MemReqPtr req = storeQueue[storeWBIdx].req; + storeQueue[storeWBIdx].committed = true; + +// Fault fault = cpu->translateDataReadReq(req); + req->cmd = Write; + req->completionEvent = NULL; + req->time = curTick; + assert(!req->data); + req->data = new uint8_t[64]; + memcpy(req->data, (uint8_t *)&storeQueue[storeWBIdx].data, req->size); + + DPRINTF(OzoneLSQ, "D-Cache: Writing back store idx:%i PC:%#x " + "to Addr:%#x, data:%#x [sn:%lli]\n", + storeWBIdx,storeQueue[storeWBIdx].inst->readPC(), + req->paddr, *(req->data), + storeQueue[storeWBIdx].inst->seqNum); + +// if (fault != NoFault) { + //What should we do if there is a fault??? + //for now panic +// panic("Page Table Fault!!!!!\n"); +// } + + if (dcacheInterface) { + MemAccessResult result = dcacheInterface->access(req); + + //@todo temp fix for LL/SC (works fine for 1 CPU) + if (req->flags & LOCKED) { + req->result=1; + panic("LL/SC! oh no no support!!!"); + } + + if (isStalled() && + storeQueue[storeWBIdx].inst->seqNum == stallingStoreIsn) { + DPRINTF(OzoneLSQ, "Unstalling, stalling store [sn:%lli] " + "load idx:%i\n", + stallingStoreIsn, stallingLoadIdx); + stalled = false; + stallingStoreIsn = 0; + be->replayMemInst(loadQueue[stallingLoadIdx]); + } + + if (result != MA_HIT && dcacheInterface->doEvents()) { + Event *wb = NULL; +/* + typename IEW::LdWritebackEvent *wb = NULL; + if (req->flags & LOCKED) { + // Stx_C does not generate a system port transaction. + req->result=0; + wb = new typename IEW::LdWritebackEvent(storeQueue[storeWBIdx].inst, + iewStage); + } +*/ + DPRINTF(OzoneLSQ,"D-Cache Write Miss!\n"); + +// DPRINTF(Activity, "Active st accessing mem miss [sn:%lli]\n", +// storeQueue[storeWBIdx].inst->seqNum); + + // Will stores need their own kind of writeback events? + // Do stores even need writeback events? + assert(!req->completionEvent); + req->completionEvent = new + StoreCompletionEvent(storeWBIdx, wb, this); + + lastDcacheStall = curTick; + + _status = DcacheMissStall; + + //mshrSeqNums.push_back(storeQueue[storeWBIdx].inst->seqNum); + + //DPRINTF(OzoneLSQ, "Added MSHR. count = %i\n",mshrSeqNums.size()); + + // Increment stat here or something + } else { + DPRINTF(OzoneLSQ,"D-Cache: Write Hit on idx:%i !\n", + storeWBIdx); + +// DPRINTF(Activity, "Active st accessing mem hit [sn:%lli]\n", +// storeQueue[storeWBIdx].inst->seqNum); + + if (req->flags & LOCKED) { + // Stx_C does not generate a system port transaction. + req->result=1; + typename BackEnd::LdWritebackEvent *wb = + new typename BackEnd::LdWritebackEvent(storeQueue[storeWBIdx].inst, + be); + wb->schedule(curTick); + } + + completeStore(storeWBIdx); + } + + incrStIdx(storeWBIdx); + } else { + panic("Must HAVE DCACHE!!!!!\n"); + } + } + + // Not sure this should set it to 0. + usedPorts = 0; + + assert(stores >= 0 && storesToWB >= 0); +} + +/*template <class Impl> +void +OzoneLSQ<Impl>::removeMSHR(InstSeqNum seqNum) +{ + list<InstSeqNum>::iterator mshr_it = find(mshrSeqNums.begin(), + mshrSeqNums.end(), + seqNum); + + if (mshr_it != mshrSeqNums.end()) { + mshrSeqNums.erase(mshr_it); + DPRINTF(OzoneLSQ, "Removing MSHR. count = %i\n",mshrSeqNums.size()); + } +}*/ + +template <class Impl> +void +OzoneLSQ<Impl>::squash(const InstSeqNum &squashed_num) +{ + DPRINTF(OzoneLSQ, "Squashing until [sn:%lli]!" + "(Loads:%i Stores:%i)\n",squashed_num,loads,stores); + + int load_idx = loadTail; + decrLdIdx(load_idx); + + while (loads != 0 && loadQueue[load_idx]->seqNum > squashed_num) { + + // Clear the smart pointer to make sure it is decremented. + DPRINTF(OzoneLSQ,"Load Instruction PC %#x squashed, " + "[sn:%lli]\n", + loadQueue[load_idx]->readPC(), + loadQueue[load_idx]->seqNum); + + if (isStalled() && load_idx == stallingLoadIdx) { + stalled = false; + stallingStoreIsn = 0; + stallingLoadIdx = 0; + } + +// loadQueue[load_idx]->squashed = true; + loadQueue[load_idx] = NULL; + --loads; + + // Inefficient! + loadTail = load_idx; + + decrLdIdx(load_idx); + } + + int store_idx = storeTail; + decrStIdx(store_idx); + + while (stores != 0 && storeQueue[store_idx].inst->seqNum > squashed_num) { + + // Clear the smart pointer to make sure it is decremented. + DPRINTF(OzoneLSQ,"Store Instruction PC %#x squashed, " + "idx:%i [sn:%lli]\n", + storeQueue[store_idx].inst->readPC(), + store_idx, storeQueue[store_idx].inst->seqNum); + + // I don't think this can happen. It should have been cleared by the + // stalling load. + if (isStalled() && + storeQueue[store_idx].inst->seqNum == stallingStoreIsn) { + panic("Is stalled should have been cleared by stalling load!\n"); + stalled = false; + stallingStoreIsn = 0; + } + +// storeQueue[store_idx].inst->squashed = true; + storeQueue[store_idx].inst = NULL; + storeQueue[store_idx].canWB = 0; + + if (storeQueue[store_idx].req) { + assert(!storeQueue[store_idx].req->completionEvent); + } + storeQueue[store_idx].req = NULL; + --stores; + + // Inefficient! + storeTail = store_idx; + + decrStIdx(store_idx); + } +} + +template <class Impl> +void +OzoneLSQ<Impl>::dumpInsts() +{ + cprintf("Load store queue: Dumping instructions.\n"); + cprintf("Load queue size: %i\n", loads); + cprintf("Load queue: "); + + int load_idx = loadHead; + + while (load_idx != loadTail && loadQueue[load_idx]) { + cprintf("[sn:%lli] %#x ", loadQueue[load_idx]->seqNum, + loadQueue[load_idx]->readPC()); + + incrLdIdx(load_idx); + } + + cprintf("\nStore queue size: %i\n", stores); + cprintf("Store queue: "); + + int store_idx = storeHead; + + while (store_idx != storeTail && storeQueue[store_idx].inst) { + cprintf("[sn:%lli] %#x ", storeQueue[store_idx].inst->seqNum, + storeQueue[store_idx].inst->readPC()); + + incrStIdx(store_idx); + } + + cprintf("\n"); +} + +template <class Impl> +void +OzoneLSQ<Impl>::completeStore(int store_idx) +{ + assert(storeQueue[store_idx].inst); + storeQueue[store_idx].completed = true; + --storesToWB; + // A bit conservative because a store completion may not free up entries, + // but hopefully avoids two store completions in one cycle from making + // the CPU tick twice. +// cpu->activityThisCycle(); + + if (store_idx == storeHead) { + do { + incrStIdx(storeHead); + + --stores; + } while (storeQueue[storeHead].completed && + storeHead != storeTail); + +// be->updateLSQNextCycle = true; + } + + DPRINTF(OzoneLSQ, "Store head idx:%i\n", storeHead); + + if (isStalled() && + storeQueue[store_idx].inst->seqNum == stallingStoreIsn) { + DPRINTF(OzoneLSQ, "Unstalling, stalling store [sn:%lli] " + "load idx:%i\n", + stallingStoreIsn, stallingLoadIdx); + stalled = false; + stallingStoreIsn = 0; + be->replayMemInst(loadQueue[stallingLoadIdx]); + } +} + +template <class Impl> +inline void +OzoneLSQ<Impl>::incrStIdx(int &store_idx) +{ + if (++store_idx >= SQEntries) + store_idx = 0; +} + +template <class Impl> +inline void +OzoneLSQ<Impl>::decrStIdx(int &store_idx) +{ + if (--store_idx < 0) + store_idx += SQEntries; +} + +template <class Impl> +inline void +OzoneLSQ<Impl>::incrLdIdx(int &load_idx) +{ + if (++load_idx >= LQEntries) + load_idx = 0; +} + +template <class Impl> +inline void +OzoneLSQ<Impl>::decrLdIdx(int &load_idx) +{ + if (--load_idx < 0) + load_idx += LQEntries; +} diff --git a/src/cpu/ozone/lw_back_end.cc b/src/cpu/ozone/lw_back_end.cc new file mode 100644 index 000000000..71e51f038 --- /dev/null +++ b/src/cpu/ozone/lw_back_end.cc @@ -0,0 +1,34 @@ +/* + * 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 "cpu/ozone/lw_back_end_impl.hh" +#include "cpu/ozone/ozone_impl.hh" + +template class LWBackEnd<OzoneImpl>; diff --git a/src/cpu/ozone/lw_back_end.hh b/src/cpu/ozone/lw_back_end.hh new file mode 100644 index 000000000..bb81f60c8 --- /dev/null +++ b/src/cpu/ozone/lw_back_end.hh @@ -0,0 +1,471 @@ +/* + * 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_OZONE_LW_BACK_END_HH__ +#define __CPU_OZONE_LW_BACK_END_HH__ + +#include <list> +#include <queue> +#include <set> +#include <string> + +#include "arch/faults.hh" +#include "base/timebuf.hh" +#include "cpu/inst_seq.hh" +#include "cpu/ozone/rename_table.hh" +#include "cpu/ozone/thread_state.hh" +#include "mem/request.hh" +#include "sim/eventq.hh" + +template <class> +class Checker; +class ThreadContext; + +template <class Impl> +class OzoneThreadState; + +template <class Impl> +class LWBackEnd +{ + public: + typedef OzoneThreadState<Impl> Thread; + + typedef typename Impl::Params Params; + typedef typename Impl::DynInst DynInst; + typedef typename Impl::DynInstPtr DynInstPtr; + typedef typename Impl::FullCPU FullCPU; + typedef typename Impl::FrontEnd FrontEnd; + typedef typename Impl::FullCPU::CommStruct CommStruct; + + struct SizeStruct { + int size; + }; + + typedef SizeStruct DispatchToIssue; + typedef SizeStruct IssueToExec; + typedef SizeStruct ExecToCommit; + typedef SizeStruct Writeback; + + TimeBuffer<DispatchToIssue> d2i; + typename TimeBuffer<DispatchToIssue>::wire instsToDispatch; + TimeBuffer<IssueToExec> i2e; + typename TimeBuffer<IssueToExec>::wire instsToExecute; + TimeBuffer<ExecToCommit> e2c; + TimeBuffer<Writeback> numInstsToWB; + + TimeBuffer<CommStruct> *comm; + typename TimeBuffer<CommStruct>::wire toIEW; + typename TimeBuffer<CommStruct>::wire fromCommit; + + class TrapEvent : public Event { + private: + LWBackEnd<Impl> *be; + + public: + TrapEvent(LWBackEnd<Impl> *_be); + + void process(); + const char *description(); + }; + + /** LdWriteback event for a load completion. */ + class LdWritebackEvent : public Event { + private: + /** Instruction that is writing back data to the register file. */ + DynInstPtr inst; + /** Pointer to IEW stage. */ + LWBackEnd *be; + + bool dcacheMiss; + + public: + /** Constructs a load writeback event. */ + LdWritebackEvent(DynInstPtr &_inst, LWBackEnd *be); + + /** Processes writeback event. */ + virtual void process(); + /** Returns the description of the writeback event. */ + virtual const char *description(); + + void setDcacheMiss() { dcacheMiss = true; be->addDcacheMiss(inst); } + }; + + LWBackEnd(Params *params); + + std::string name() const; + + void regStats(); + + void setCPU(FullCPU *cpu_ptr); + + void setFrontEnd(FrontEnd *front_end_ptr) + { frontEnd = front_end_ptr; } + + void setTC(ThreadContext *tc_ptr) + { tc = tc_ptr; } + + void setThreadState(Thread *thread_ptr) + { thread = thread_ptr; } + + void setCommBuffer(TimeBuffer<CommStruct> *_comm); + + void tick(); + void squash(); + void generateTCEvent() { tcSquash = true; } + void squashFromTC(); + void squashFromTrap(); + void checkInterrupts(); + bool trapSquash; + bool tcSquash; + + template <class T> + Fault read(RequestPtr req, T &data, int load_idx); + + template <class T> + Fault write(RequestPtr req, T &data, int store_idx); + + Addr readCommitPC() { return commitPC; } + + Addr commitPC; + + Tick lastCommitCycle; + + bool robEmpty() { return instList.empty(); } + + bool isFull() { return numInsts >= numROBEntries; } + bool isBlocked() { return status == Blocked || dispatchStatus == Blocked; } + + void fetchFault(Fault &fault); + + int wakeDependents(DynInstPtr &inst, bool memory_deps = false); + + /** Tells memory dependence unit that a memory instruction needs to be + * rescheduled. It will re-execute once replayMemInst() is called. + */ + void rescheduleMemInst(DynInstPtr &inst); + + /** Re-executes all rescheduled memory instructions. */ + void replayMemInst(DynInstPtr &inst); + + /** Completes memory instruction. */ + void completeMemInst(DynInstPtr &inst) { } + + void addDcacheMiss(DynInstPtr &inst) + { + waitingMemOps.insert(inst->seqNum); + numWaitingMemOps++; + DPRINTF(BE, "Adding a Dcache miss mem op [sn:%lli], total %i\n", + inst->seqNum, numWaitingMemOps); + } + + void removeDcacheMiss(DynInstPtr &inst) + { + assert(waitingMemOps.find(inst->seqNum) != waitingMemOps.end()); + waitingMemOps.erase(inst->seqNum); + numWaitingMemOps--; + DPRINTF(BE, "Removing a Dcache miss mem op [sn:%lli], total %i\n", + inst->seqNum, numWaitingMemOps); + } + + void addWaitingMemOp(DynInstPtr &inst) + { + waitingMemOps.insert(inst->seqNum); + numWaitingMemOps++; + DPRINTF(BE, "Adding a waiting mem op [sn:%lli], total %i\n", + inst->seqNum, numWaitingMemOps); + } + + void removeWaitingMemOp(DynInstPtr &inst) + { + assert(waitingMemOps.find(inst->seqNum) != waitingMemOps.end()); + waitingMemOps.erase(inst->seqNum); + numWaitingMemOps--; + DPRINTF(BE, "Removing a waiting mem op [sn:%lli], total %i\n", + inst->seqNum, numWaitingMemOps); + } + + void instToCommit(DynInstPtr &inst); + + void switchOut(); + void doSwitchOut(); + void takeOverFrom(ThreadContext *old_tc = NULL); + + bool isSwitchedOut() { return switchedOut; } + + private: + void generateTrapEvent(Tick latency = 0); + void handleFault(Fault &fault, Tick latency = 0); + void updateStructures(); + void dispatchInsts(); + void dispatchStall(); + void checkDispatchStatus(); + void executeInsts(); + void commitInsts(); + void addToLSQ(DynInstPtr &inst); + void writebackInsts(); + bool commitInst(int inst_num); + void squash(const InstSeqNum &sn); + void squashDueToBranch(DynInstPtr &inst); + void squashDueToMemViolation(DynInstPtr &inst); + void squashDueToMemBlocked(DynInstPtr &inst); + void updateExeInstStats(DynInstPtr &inst); + void updateComInstStats(DynInstPtr &inst); + + public: + FullCPU *cpu; + + FrontEnd *frontEnd; + + ThreadContext *tc; + + Thread *thread; + + enum Status { + Running, + Idle, + DcacheMissStall, + DcacheMissComplete, + Blocked, + TrapPending + }; + + Status status; + + Status dispatchStatus; + + Status commitStatus; + + Counter funcExeInst; + + private: + typedef typename Impl::LdstQueue LdstQueue; + + LdstQueue LSQ; + public: + RenameTable<Impl> commitRenameTable; + + RenameTable<Impl> renameTable; + private: + class DCacheCompletionEvent : public Event + { + private: + LWBackEnd *be; + + public: + DCacheCompletionEvent(LWBackEnd *_be); + + virtual void process(); + virtual const char *description(); + }; + + friend class DCacheCompletionEvent; + + DCacheCompletionEvent cacheCompletionEvent; + + MemInterface *dcacheInterface; + + // General back end width. Used if the more specific isn't given. + int width; + + // Dispatch width. + int dispatchWidth; + int numDispatchEntries; + int dispatchSize; + + int waitingInsts; + + int issueWidth; + + // Writeback width + int wbWidth; + + // Commit width + int commitWidth; + + /** Index into queue of instructions being written back. */ + unsigned wbNumInst; + + /** Cycle number within the queue of instructions being written + * back. Used in case there are too many instructions writing + * back at the current cycle and writesbacks need to be scheduled + * for the future. See comments in instToCommit(). + */ + unsigned wbCycle; + + int numROBEntries; + int numInsts; + + std::set<InstSeqNum> waitingMemOps; + typedef std::set<InstSeqNum>::iterator MemIt; + int numWaitingMemOps; + unsigned maxOutstandingMemOps; + + bool squashPending; + InstSeqNum squashSeqNum; + Addr squashNextPC; + + Fault faultFromFetch; + bool fetchHasFault; + + bool switchedOut; + bool switchPending; + + DynInstPtr memBarrier; + + private: + struct pqCompare { + bool operator() (const DynInstPtr &lhs, const DynInstPtr &rhs) const + { + return lhs->seqNum > rhs->seqNum; + } + }; + + typedef typename std::priority_queue<DynInstPtr, std::vector<DynInstPtr>, pqCompare> ReadyInstQueue; + ReadyInstQueue exeList; + + typedef typename std::list<DynInstPtr>::iterator InstListIt; + + std::list<DynInstPtr> instList; + std::list<DynInstPtr> waitingList; + std::list<DynInstPtr> replayList; + std::list<DynInstPtr> writeback; + + int latency; + + int squashLatency; + + bool exactFullStall; + + // number of cycles stalled for D-cache misses +/* Stats::Scalar<> dcacheStallCycles; + Counter lastDcacheStall; +*/ + Stats::Vector<> rob_cap_events; + Stats::Vector<> rob_cap_inst_count; + Stats::Vector<> iq_cap_events; + Stats::Vector<> iq_cap_inst_count; + // total number of instructions executed + Stats::Vector<> exe_inst; + Stats::Vector<> exe_swp; + Stats::Vector<> exe_nop; + Stats::Vector<> exe_refs; + Stats::Vector<> exe_loads; + Stats::Vector<> exe_branches; + + Stats::Vector<> issued_ops; + + // total number of loads forwaded from LSQ stores + Stats::Vector<> lsq_forw_loads; + + // total number of loads ignored due to invalid addresses + Stats::Vector<> inv_addr_loads; + + // total number of software prefetches ignored due to invalid addresses + Stats::Vector<> inv_addr_swpfs; + // ready loads blocked due to memory disambiguation + Stats::Vector<> lsq_blocked_loads; + + Stats::Scalar<> lsqInversion; + + Stats::Vector<> n_issued_dist; + Stats::VectorDistribution<> issue_delay_dist; + + Stats::VectorDistribution<> queue_res_dist; +/* + Stats::Vector<> stat_fu_busy; + Stats::Vector2d<> stat_fuBusy; + Stats::Vector<> dist_unissued; + Stats::Vector2d<> stat_issued_inst_type; + + Stats::Formula misspec_cnt; + Stats::Formula misspec_ipc; + Stats::Formula issue_rate; + Stats::Formula issue_stores; + Stats::Formula issue_op_rate; + Stats::Formula fu_busy_rate; + Stats::Formula commit_stores; + Stats::Formula commit_ipc; + Stats::Formula commit_ipb; + Stats::Formula lsq_inv_rate; +*/ + Stats::Vector<> writeback_count; + Stats::Vector<> producer_inst; + Stats::Vector<> consumer_inst; + Stats::Vector<> wb_penalized; + + Stats::Formula wb_rate; + Stats::Formula wb_fanout; + Stats::Formula wb_penalized_rate; + + // total number of instructions committed + Stats::Vector<> stat_com_inst; + Stats::Vector<> stat_com_swp; + Stats::Vector<> stat_com_refs; + Stats::Vector<> stat_com_loads; + Stats::Vector<> stat_com_membars; + Stats::Vector<> stat_com_branches; + + Stats::Distribution<> n_committed_dist; + + Stats::Scalar<> commit_eligible_samples; + Stats::Vector<> commit_eligible; + + Stats::Vector<> squashedInsts; + Stats::Vector<> ROBSquashedInsts; + + Stats::Scalar<> ROB_fcount; + Stats::Formula ROB_full_rate; + + Stats::Vector<> ROB_count; // cumulative ROB occupancy + Stats::Formula ROB_occ_rate; + Stats::VectorDistribution<> ROB_occ_dist; + public: + void dumpInsts(); + + Checker<DynInstPtr> *checker; +}; + +template <class Impl> +template <class T> +Fault +LWBackEnd<Impl>::read(RequestPtr req, T &data, int load_idx) +{ + return LSQ.read(req, data, load_idx); +} + +template <class Impl> +template <class T> +Fault +LWBackEnd<Impl>::write(RequestPtr req, T &data, int store_idx) +{ + return LSQ.write(req, data, store_idx); +} + +#endif // __CPU_OZONE_LW_BACK_END_HH__ diff --git a/src/cpu/ozone/lw_back_end_impl.hh b/src/cpu/ozone/lw_back_end_impl.hh new file mode 100644 index 000000000..ed406d5a3 --- /dev/null +++ b/src/cpu/ozone/lw_back_end_impl.hh @@ -0,0 +1,1695 @@ +/* + * 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 "cpu/checker/cpu.hh" +#include "cpu/ozone/lw_back_end.hh" +#include "encumbered/cpu/full/op_class.hh" + +template <class Impl> +void +LWBackEnd<Impl>::generateTrapEvent(Tick latency) +{ + DPRINTF(BE, "Generating trap event\n"); + + TrapEvent *trap = new TrapEvent(this); + + trap->schedule(curTick + cpu->cycles(latency)); + + thread->trapPending = true; +} + +template <class Impl> +int +LWBackEnd<Impl>::wakeDependents(DynInstPtr &inst, bool memory_deps) +{ + assert(!inst->isSquashed()); + std::vector<DynInstPtr> &dependents = memory_deps ? inst->getMemDeps() : + inst->getDependents(); + int num_outputs = dependents.size(); + + DPRINTF(BE, "Waking instruction [sn:%lli] dependents in IQ\n", inst->seqNum); + + for (int i = 0; i < num_outputs; i++) { + DynInstPtr dep_inst = dependents[i]; + if (!memory_deps) { + dep_inst->markSrcRegReady(); + } else { + if (!dep_inst->isSquashed()) + dep_inst->markMemInstReady(inst.get()); + } + + DPRINTF(BE, "Marking source reg ready [sn:%lli] in IQ\n", dep_inst->seqNum); + + if (dep_inst->readyToIssue() && dep_inst->isInROB() && + !dep_inst->isNonSpeculative() && !dep_inst->isStoreConditional() && + dep_inst->memDepReady() && !dep_inst->isMemBarrier() && + !dep_inst->isWriteBarrier()) { + DPRINTF(BE, "Adding instruction to exeList [sn:%lli]\n", + dep_inst->seqNum); + exeList.push(dep_inst); + if (dep_inst->iqItValid) { + DPRINTF(BE, "Removing instruction from waiting list\n"); + waitingList.erase(dep_inst->iqIt); + waitingInsts--; + dep_inst->iqItValid = false; + assert(waitingInsts >= 0); + } + if (dep_inst->isMemRef()) { + removeWaitingMemOp(dep_inst); + DPRINTF(BE, "Issued a waiting mem op [sn:%lli]\n", + dep_inst->seqNum); + } + } + } + return num_outputs; +} + +template <class Impl> +void +LWBackEnd<Impl>::rescheduleMemInst(DynInstPtr &inst) +{ + replayList.push_front(inst); +} + +template <class Impl> +LWBackEnd<Impl>::TrapEvent::TrapEvent(LWBackEnd<Impl> *_be) + : Event(&mainEventQueue, CPU_Tick_Pri), be(_be) +{ + this->setFlags(Event::AutoDelete); +} + +template <class Impl> +void +LWBackEnd<Impl>::TrapEvent::process() +{ + be->trapSquash = true; +} + +template <class Impl> +const char * +LWBackEnd<Impl>::TrapEvent::description() +{ + return "Trap event"; +} + +template <class Impl> +void +LWBackEnd<Impl>::replayMemInst(DynInstPtr &inst) +{ + bool found_inst = false; + while (!replayList.empty()) { + exeList.push(replayList.front()); + if (replayList.front() == inst) { + found_inst = true; + } + replayList.pop_front(); + } + assert(found_inst); +} + +template<class Impl> +LWBackEnd<Impl>::LdWritebackEvent::LdWritebackEvent(DynInstPtr &_inst, + LWBackEnd<Impl> *_be) + : Event(&mainEventQueue), inst(_inst), be(_be), dcacheMiss(false) +{ + this->setFlags(Event::AutoDelete); +} + +template<class Impl> +void +LWBackEnd<Impl>::LdWritebackEvent::process() +{ + DPRINTF(BE, "Load writeback event [sn:%lli]\n", inst->seqNum); +// DPRINTF(Activity, "Activity: Ld Writeback event [sn:%lli]\n", inst->seqNum); + + //iewStage->ldstQueue.removeMSHR(inst->threadNumber,inst->seqNum); + +// iewStage->wakeCPU(); + + if (be->isSwitchedOut()) + return; + + if (dcacheMiss) { + be->removeDcacheMiss(inst); + } + + if (inst->isSquashed()) { + inst = NULL; + return; + } + + if (!inst->isExecuted()) { + inst->setExecuted(); + + // Execute again to copy data to proper place. + inst->completeAcc(); + } + + // Need to insert instruction into queue to commit + be->instToCommit(inst); + + //wroteToTimeBuffer = true; +// iewStage->activityThisCycle(); + + inst = NULL; +} + +template<class Impl> +const char * +LWBackEnd<Impl>::LdWritebackEvent::description() +{ + return "Load writeback event"; +} + + +template <class Impl> +LWBackEnd<Impl>::DCacheCompletionEvent::DCacheCompletionEvent(LWBackEnd *_be) + : Event(&mainEventQueue, CPU_Tick_Pri), be(_be) +{ +} + +template <class Impl> +void +LWBackEnd<Impl>::DCacheCompletionEvent::process() +{ +} + +template <class Impl> +const char * +LWBackEnd<Impl>::DCacheCompletionEvent::description() +{ + return "Cache completion event"; +} + +template <class Impl> +LWBackEnd<Impl>::LWBackEnd(Params *params) + : d2i(5, 5), i2e(5, 5), e2c(5, 5), numInstsToWB(5, 5), + trapSquash(false), tcSquash(false), cacheCompletionEvent(this), + dcacheInterface(params->dcacheInterface), width(params->backEndWidth), + exactFullStall(true) +{ + numROBEntries = params->numROBEntries; + numInsts = 0; + numDispatchEntries = 32; + maxOutstandingMemOps = params->maxOutstandingMemOps; + numWaitingMemOps = 0; + waitingInsts = 0; + switchedOut = false; + switchPending = false; + + LSQ.setBE(this); + + // Setup IQ and LSQ with their parameters here. + instsToDispatch = d2i.getWire(-1); + + instsToExecute = i2e.getWire(-1); + + dispatchWidth = params->dispatchWidth ? params->dispatchWidth : width; + issueWidth = params->issueWidth ? params->issueWidth : width; + wbWidth = params->wbWidth ? params->wbWidth : width; + commitWidth = params->commitWidth ? params->commitWidth : width; + + LSQ.init(params, params->LQEntries, params->SQEntries, 0); + + dispatchStatus = Running; +} + +template <class Impl> +std::string +LWBackEnd<Impl>::name() const +{ + return cpu->name() + ".backend"; +} + +template <class Impl> +void +LWBackEnd<Impl>::regStats() +{ + using namespace Stats; + rob_cap_events + .init(cpu->number_of_threads) + .name(name() + ".ROB:cap_events") + .desc("number of cycles where ROB cap was active") + .flags(total) + ; + + rob_cap_inst_count + .init(cpu->number_of_threads) + .name(name() + ".ROB:cap_inst") + .desc("number of instructions held up by ROB cap") + .flags(total) + ; + + iq_cap_events + .init(cpu->number_of_threads) + .name(name() +".IQ:cap_events" ) + .desc("number of cycles where IQ cap was active") + .flags(total) + ; + + iq_cap_inst_count + .init(cpu->number_of_threads) + .name(name() + ".IQ:cap_inst") + .desc("number of instructions held up by IQ cap") + .flags(total) + ; + + + exe_inst + .init(cpu->number_of_threads) + .name(name() + ".ISSUE:count") + .desc("number of insts issued") + .flags(total) + ; + + exe_swp + .init(cpu->number_of_threads) + .name(name() + ".ISSUE:swp") + .desc("number of swp insts issued") + .flags(total) + ; + + exe_nop + .init(cpu->number_of_threads) + .name(name() + ".ISSUE:nop") + .desc("number of nop insts issued") + .flags(total) + ; + + exe_refs + .init(cpu->number_of_threads) + .name(name() + ".ISSUE:refs") + .desc("number of memory reference insts issued") + .flags(total) + ; + + exe_loads + .init(cpu->number_of_threads) + .name(name() + ".ISSUE:loads") + .desc("number of load insts issued") + .flags(total) + ; + + exe_branches + .init(cpu->number_of_threads) + .name(name() + ".ISSUE:branches") + .desc("Number of branches issued") + .flags(total) + ; + + issued_ops + .init(cpu->number_of_threads) + .name(name() + ".ISSUE:op_count") + .desc("number of insts issued") + .flags(total) + ; + +/* + for (int i=0; i<Num_OpClasses; ++i) { + stringstream subname; + subname << opClassStrings[i] << "_delay"; + issue_delay_dist.subname(i, subname.str()); + } +*/ + // + // Other stats + // + lsq_forw_loads + .init(cpu->number_of_threads) + .name(name() + ".LSQ:forw_loads") + .desc("number of loads forwarded via LSQ") + .flags(total) + ; + + inv_addr_loads + .init(cpu->number_of_threads) + .name(name() + ".ISSUE:addr_loads") + .desc("number of invalid-address loads") + .flags(total) + ; + + inv_addr_swpfs + .init(cpu->number_of_threads) + .name(name() + ".ISSUE:addr_swpfs") + .desc("number of invalid-address SW prefetches") + .flags(total) + ; + + lsq_blocked_loads + .init(cpu->number_of_threads) + .name(name() + ".LSQ:blocked_loads") + .desc("number of ready loads not issued due to memory disambiguation") + .flags(total) + ; + + lsqInversion + .name(name() + ".ISSUE:lsq_invert") + .desc("Number of times LSQ instruction issued early") + ; + + n_issued_dist + .init(issueWidth + 1) + .name(name() + ".ISSUE:issued_per_cycle") + .desc("Number of insts issued each cycle") + .flags(total | pdf | dist) + ; + issue_delay_dist + .init(Num_OpClasses,0,99,2) + .name(name() + ".ISSUE:") + .desc("cycles from operands ready to issue") + .flags(pdf | cdf) + ; + + queue_res_dist + .init(Num_OpClasses, 0, 99, 2) + .name(name() + ".IQ:residence:") + .desc("cycles from dispatch to issue") + .flags(total | pdf | cdf ) + ; + for (int i = 0; i < Num_OpClasses; ++i) { + queue_res_dist.subname(i, opClassStrings[i]); + } + + writeback_count + .init(cpu->number_of_threads) + .name(name() + ".WB:count") + .desc("cumulative count of insts written-back") + .flags(total) + ; + + producer_inst + .init(cpu->number_of_threads) + .name(name() + ".WB:producers") + .desc("num instructions producing a value") + .flags(total) + ; + + consumer_inst + .init(cpu->number_of_threads) + .name(name() + ".WB:consumers") + .desc("num instructions consuming a value") + .flags(total) + ; + + wb_penalized + .init(cpu->number_of_threads) + .name(name() + ".WB:penalized") + .desc("number of instrctions required to write to 'other' IQ") + .flags(total) + ; + + + wb_penalized_rate + .name(name() + ".WB:penalized_rate") + .desc ("fraction of instructions written-back that wrote to 'other' IQ") + .flags(total) + ; + + wb_penalized_rate = wb_penalized / writeback_count; + + wb_fanout + .name(name() + ".WB:fanout") + .desc("average fanout of values written-back") + .flags(total) + ; + + wb_fanout = producer_inst / consumer_inst; + + wb_rate + .name(name() + ".WB:rate") + .desc("insts written-back per cycle") + .flags(total) + ; + wb_rate = writeback_count / cpu->numCycles; + + stat_com_inst + .init(cpu->number_of_threads) + .name(name() + ".COM:count") + .desc("Number of instructions committed") + .flags(total) + ; + + stat_com_swp + .init(cpu->number_of_threads) + .name(name() + ".COM:swp_count") + .desc("Number of s/w prefetches committed") + .flags(total) + ; + + stat_com_refs + .init(cpu->number_of_threads) + .name(name() + ".COM:refs") + .desc("Number of memory references committed") + .flags(total) + ; + + stat_com_loads + .init(cpu->number_of_threads) + .name(name() + ".COM:loads") + .desc("Number of loads committed") + .flags(total) + ; + + stat_com_membars + .init(cpu->number_of_threads) + .name(name() + ".COM:membars") + .desc("Number of memory barriers committed") + .flags(total) + ; + + stat_com_branches + .init(cpu->number_of_threads) + .name(name() + ".COM:branches") + .desc("Number of branches committed") + .flags(total) + ; + n_committed_dist + .init(0,commitWidth,1) + .name(name() + ".COM:committed_per_cycle") + .desc("Number of insts commited each cycle") + .flags(pdf) + ; + + // + // Commit-Eligible instructions... + // + // -> The number of instructions eligible to commit in those + // cycles where we reached our commit BW limit (less the number + // actually committed) + // + // -> The average value is computed over ALL CYCLES... not just + // the BW limited cycles + // + // -> The standard deviation is computed only over cycles where + // we reached the BW limit + // + commit_eligible + .init(cpu->number_of_threads) + .name(name() + ".COM:bw_limited") + .desc("number of insts not committed due to BW limits") + .flags(total) + ; + + commit_eligible_samples + .name(name() + ".COM:bw_lim_events") + .desc("number cycles where commit BW limit reached") + ; + + squashedInsts + .init(cpu->number_of_threads) + .name(name() + ".COM:squashed_insts") + .desc("Number of instructions removed from inst list") + ; + + ROBSquashedInsts + .init(cpu->number_of_threads) + .name(name() + ".COM:rob_squashed_insts") + .desc("Number of instructions removed from inst list when they reached the head of the ROB") + ; + + ROB_fcount + .name(name() + ".ROB:full_count") + .desc("number of cycles where ROB was full") + ; + + ROB_count + .init(cpu->number_of_threads) + .name(name() + ".ROB:occupancy") + .desc(name() + ".ROB occupancy (cumulative)") + .flags(total) + ; + + ROB_full_rate + .name(name() + ".ROB:full_rate") + .desc("ROB full per cycle") + ; + ROB_full_rate = ROB_fcount / cpu->numCycles; + + ROB_occ_rate + .name(name() + ".ROB:occ_rate") + .desc("ROB occupancy rate") + .flags(total) + ; + ROB_occ_rate = ROB_count / cpu->numCycles; + + ROB_occ_dist + .init(cpu->number_of_threads,0,numROBEntries,2) + .name(name() + ".ROB:occ_dist") + .desc("ROB Occupancy per cycle") + .flags(total | cdf) + ; +} + +template <class Impl> +void +LWBackEnd<Impl>::setCPU(FullCPU *cpu_ptr) +{ + cpu = cpu_ptr; + LSQ.setCPU(cpu_ptr); + checker = cpu->checker; +} + +template <class Impl> +void +LWBackEnd<Impl>::setCommBuffer(TimeBuffer<CommStruct> *_comm) +{ + comm = _comm; + toIEW = comm->getWire(0); + fromCommit = comm->getWire(-1); +} + +#if FULL_SYSTEM +template <class Impl> +void +LWBackEnd<Impl>::checkInterrupts() +{ + if (cpu->checkInterrupts && + cpu->check_interrupts() && + !cpu->inPalMode(thread->readPC()) && + !trapSquash && + !tcSquash) { + frontEnd->interruptPending = true; + if (robEmpty() && !LSQ.hasStoresToWB()) { + // Will need to squash all instructions currently in flight and have + // the interrupt handler restart at the last non-committed inst. + // Most of that can be handled through the trap() function. The + // processInterrupts() function really just checks for interrupts + // and then calls trap() if there is an interrupt present. + + // Not sure which thread should be the one to interrupt. For now + // always do thread 0. + assert(!thread->inSyscall); + thread->inSyscall = true; + + // CPU will handle implementation of the interrupt. + cpu->processInterrupts(); + + // Now squash or record that I need to squash this cycle. + commitStatus = TrapPending; + + // Exit state update mode to avoid accidental updating. + thread->inSyscall = false; + + // Generate trap squash event. + generateTrapEvent(); + + DPRINTF(BE, "Interrupt detected.\n"); + } else { + DPRINTF(BE, "Interrupt must wait for ROB to drain.\n"); + } + } +} + +template <class Impl> +void +LWBackEnd<Impl>::handleFault(Fault &fault, Tick latency) +{ + DPRINTF(BE, "Handling fault!\n"); + + assert(!thread->inSyscall); + + thread->inSyscall = true; + + // Consider holding onto the trap and waiting until the trap event + // happens for this to be executed. + fault->invoke(thread->getTCProxy()); + + // Exit state update mode to avoid accidental updating. + thread->inSyscall = false; + + commitStatus = TrapPending; + + // Generate trap squash event. + generateTrapEvent(latency); +} +#endif + +template <class Impl> +void +LWBackEnd<Impl>::tick() +{ + DPRINTF(BE, "Ticking back end\n"); + + if (switchPending && robEmpty() && !LSQ.hasStoresToWB()) { + cpu->signalSwitched(); + return; + } + + ROB_count[0]+= numInsts; + + wbCycle = 0; + + // Read in any done instruction information and update the IQ or LSQ. + updateStructures(); + +#if FULL_SYSTEM + checkInterrupts(); + + if (trapSquash) { + assert(!tcSquash); + squashFromTrap(); + } else if (tcSquash) { + squashFromTC(); + } +#endif + + if (dispatchStatus != Blocked) { + dispatchInsts(); + } else { + checkDispatchStatus(); + } + + if (commitStatus != TrapPending) { + executeInsts(); + + commitInsts(); + } + + LSQ.writebackStores(); + + DPRINTF(BE, "Waiting insts: %i, mem ops: %i, ROB entries in use: %i, " + "LSQ loads: %i, LSQ stores: %i\n", + waitingInsts, numWaitingMemOps, numInsts, + LSQ.numLoads(), LSQ.numStores()); + +#ifdef DEBUG + assert(numInsts == instList.size()); + assert(waitingInsts == waitingList.size()); + assert(numWaitingMemOps == waitingMemOps.size()); + assert(!switchedOut); +#endif +} + +template <class Impl> +void +LWBackEnd<Impl>::updateStructures() +{ + if (fromCommit->doneSeqNum) { + LSQ.commitLoads(fromCommit->doneSeqNum); + LSQ.commitStores(fromCommit->doneSeqNum); + } + + if (fromCommit->nonSpecSeqNum) { + if (fromCommit->uncached) { +// LSQ.executeLoad(fromCommit->lqIdx); + } else { +// IQ.scheduleNonSpec( +// fromCommit->nonSpecSeqNum); + } + } +} + +template <class Impl> +void +LWBackEnd<Impl>::addToLSQ(DynInstPtr &inst) +{ + // Do anything LSQ specific here? + LSQ.insert(inst); +} + +template <class Impl> +void +LWBackEnd<Impl>::dispatchInsts() +{ + DPRINTF(BE, "Trying to dispatch instructions.\n"); + + while (numInsts < numROBEntries && + numWaitingMemOps < maxOutstandingMemOps) { + // Get instruction from front of time buffer + DynInstPtr inst = frontEnd->getInst(); + if (!inst) { + break; + } else if (inst->isSquashed()) { + continue; + } + + ++numInsts; + instList.push_front(inst); + + inst->setInROB(); + + DPRINTF(BE, "Dispatching instruction [sn:%lli] PC:%#x\n", + inst->seqNum, inst->readPC()); + + for (int i = 0; i < inst->numDestRegs(); ++i) + renameTable[inst->destRegIdx(i)] = inst; + + if (inst->isMemBarrier() || inst->isWriteBarrier()) { + if (memBarrier) { + DPRINTF(BE, "Instruction [sn:%lli] is waiting on " + "barrier [sn:%lli].\n", + inst->seqNum, memBarrier->seqNum); + memBarrier->addMemDependent(inst); + inst->addSrcMemInst(memBarrier); + } + memBarrier = inst; + inst->setCanCommit(); + } else if (inst->readyToIssue() && + !inst->isNonSpeculative() && + !inst->isStoreConditional()) { + if (inst->isMemRef()) { + + LSQ.insert(inst); + if (memBarrier) { + DPRINTF(BE, "Instruction [sn:%lli] is waiting on " + "barrier [sn:%lli].\n", + inst->seqNum, memBarrier->seqNum); + memBarrier->addMemDependent(inst); + inst->addSrcMemInst(memBarrier); + addWaitingMemOp(inst); + + waitingList.push_front(inst); + inst->iqIt = waitingList.begin(); + inst->iqItValid = true; + waitingInsts++; + } else { + DPRINTF(BE, "Instruction [sn:%lli] ready, addding to " + "exeList.\n", + inst->seqNum); + exeList.push(inst); + } + } else if (inst->isNop()) { + DPRINTF(BE, "Nop encountered [sn:%lli], skipping exeList.\n", + inst->seqNum); + inst->setIssued(); + inst->setExecuted(); + inst->setCanCommit(); + } else { + DPRINTF(BE, "Instruction [sn:%lli] ready, addding to " + "exeList.\n", + inst->seqNum); + exeList.push(inst); + } + } else { + if (inst->isNonSpeculative() || inst->isStoreConditional()) { + inst->setCanCommit(); + DPRINTF(BE, "Adding non speculative instruction\n"); + } + + if (inst->isMemRef()) { + addWaitingMemOp(inst); + LSQ.insert(inst); + if (memBarrier) { + memBarrier->addMemDependent(inst); + inst->addSrcMemInst(memBarrier); + + DPRINTF(BE, "Instruction [sn:%lli] is waiting on " + "barrier [sn:%lli].\n", + inst->seqNum, memBarrier->seqNum); + } + } + + DPRINTF(BE, "Instruction [sn:%lli] not ready, addding to " + "waitingList.\n", + inst->seqNum); + waitingList.push_front(inst); + inst->iqIt = waitingList.begin(); + inst->iqItValid = true; + waitingInsts++; + } + } + + // Check if IQ or LSQ is full. If so we'll need to break and stop + // removing instructions. Also update the number of insts to remove + // from the queue. Check here if we don't care about exact stall + // conditions. +/* + bool stall = false; + if (IQ.isFull()) { + DPRINTF(BE, "IQ is full!\n"); + stall = true; + } else if (LSQ.isFull()) { + DPRINTF(BE, "LSQ is full!\n"); + stall = true; + } else if (isFull()) { + DPRINTF(BE, "ROB is full!\n"); + stall = true; + ROB_fcount++; + } + if (stall) { + d2i.advance(); + dispatchStall(); + return; + } +*/ +} + +template <class Impl> +void +LWBackEnd<Impl>::dispatchStall() +{ + dispatchStatus = Blocked; + if (!cpu->decoupledFrontEnd) { + // Tell front end to stall here through a timebuffer, or just tell + // it directly. + } +} + +template <class Impl> +void +LWBackEnd<Impl>::checkDispatchStatus() +{ + DPRINTF(BE, "Checking dispatch status\n"); + assert(dispatchStatus == Blocked); + if (!LSQ.isFull() && !isFull()) { + DPRINTF(BE, "Dispatch no longer blocked\n"); + dispatchStatus = Running; + dispatchInsts(); + } +} + +template <class Impl> +void +LWBackEnd<Impl>::executeInsts() +{ + DPRINTF(BE, "Trying to execute instructions\n"); + + int num_executed = 0; + while (!exeList.empty() && num_executed < issueWidth) { + DynInstPtr inst = exeList.top(); + + DPRINTF(BE, "Executing inst [sn:%lli] PC: %#x\n", + inst->seqNum, inst->readPC()); + + // Check if the instruction is squashed; if so then skip it + // and don't count it towards the FU usage. + if (inst->isSquashed()) { + DPRINTF(BE, "Execute: Instruction was squashed.\n"); + + // Not sure how to handle this plus the method of sending # of + // instructions to use. Probably will just have to count it + // towards the bandwidth usage, but not the FU usage. + ++num_executed; + + // Consider this instruction executed so that commit can go + // ahead and retire the instruction. + inst->setExecuted(); + + // Not sure if I should set this here or just let commit try to + // commit any squashed instructions. I like the latter a bit more. + inst->setCanCommit(); + +// ++iewExecSquashedInsts; + exeList.pop(); + + continue; + } + + Fault fault = NoFault; + + // Execute instruction. + // Note that if the instruction faults, it will be handled + // at the commit stage. + if (inst->isMemRef() && + (!inst->isDataPrefetch() && !inst->isInstPrefetch())) { + if (dcacheInterface->isBlocked()) { + // Should I move the instruction aside? + DPRINTF(BE, "Execute: dcache is blocked\n"); + break; + } + DPRINTF(BE, "Execute: Initiating access for memory " + "reference.\n"); + + if (inst->isLoad()) { + LSQ.executeLoad(inst); + } else if (inst->isStore()) { + LSQ.executeStore(inst); + if (inst->req && !(inst->req->flags & LOCKED)) { + inst->setExecuted(); + + instToCommit(inst); + } + } else { + panic("Unknown mem type!"); + } + } else { + inst->execute(); + + inst->setExecuted(); + + instToCommit(inst); + } + + updateExeInstStats(inst); + + ++funcExeInst; + ++num_executed; + + exeList.pop(); + + if (inst->mispredicted()) { + squashDueToBranch(inst); + break; + } else if (LSQ.violation()) { + // Get the DynInst that caused the violation. Note that this + // clears the violation signal. + DynInstPtr violator; + violator = LSQ.getMemDepViolator(); + + DPRINTF(BE, "LDSTQ detected a violation. Violator PC: " + "%#x, inst PC: %#x. Addr is: %#x.\n", + violator->readPC(), inst->readPC(), inst->physEffAddr); + + // Squash. + squashDueToMemViolation(inst); + } + } + + issued_ops[0]+= num_executed; + n_issued_dist[num_executed]++; +} + +template<class Impl> +void +LWBackEnd<Impl>::instToCommit(DynInstPtr &inst) +{ + + DPRINTF(BE, "Sending instructions to commit [sn:%lli] PC %#x.\n", + inst->seqNum, inst->readPC()); + + if (!inst->isSquashed()) { + DPRINTF(BE, "Writing back instruction [sn:%lli] PC %#x.\n", + inst->seqNum, inst->readPC()); + + inst->setCanCommit(); + + if (inst->isExecuted()) { + inst->setResultReady(); + int dependents = wakeDependents(inst); + if (dependents) { + producer_inst[0]++; + consumer_inst[0]+= dependents; + } + } + } + + writeback_count[0]++; +} +#if 0 +template <class Impl> +void +LWBackEnd<Impl>::writebackInsts() +{ + int wb_width = wbWidth; + // Using this method I'm not quite sure how to prevent an + // instruction from waking its own dependents multiple times, + // without the guarantee that commit always has enough bandwidth + // to accept all instructions being written back. This guarantee + // might not be too unrealistic. + InstListIt wb_inst_it = writeback.begin(); + InstListIt wb_end_it = writeback.end(); + int inst_num = 0; + int consumer_insts = 0; + + for (; inst_num < wb_width && + wb_inst_it != wb_end_it; inst_num++) { + DynInstPtr inst = (*wb_inst_it); + + // Some instructions will be sent to commit without having + // executed because they need commit to handle them. + // E.g. Uncached loads have not actually executed when they + // are first sent to commit. Instead commit must tell the LSQ + // when it's ready to execute the uncached load. + if (!inst->isSquashed()) { + DPRINTF(BE, "Writing back instruction [sn:%lli] PC %#x.\n", + inst->seqNum, inst->readPC()); + + inst->setCanCommit(); + inst->setResultReady(); + + if (inst->isExecuted()) { + int dependents = wakeDependents(inst); + if (dependents) { + producer_inst[0]++; + consumer_insts+= dependents; + } + } + } + + writeback.erase(wb_inst_it++); + } + LSQ.writebackStores(); + consumer_inst[0]+= consumer_insts; + writeback_count[0]+= inst_num; +} +#endif +template <class Impl> +bool +LWBackEnd<Impl>::commitInst(int inst_num) +{ + // Read instruction from the head of the ROB + DynInstPtr inst = instList.back(); + + // Make sure instruction is valid + assert(inst); + + if (!inst->readyToCommit()) + return false; + + DPRINTF(BE, "Trying to commit instruction [sn:%lli] PC:%#x\n", + inst->seqNum, inst->readPC()); + + thread->setPC(inst->readPC()); + thread->setNextPC(inst->readNextPC()); + inst->reachedCommit = true; + + // If the instruction is not executed yet, then it is a non-speculative + // or store inst. Signal backwards that it should be executed. + if (!inst->isExecuted()) { + if (inst->isNonSpeculative() || + inst->isStoreConditional() || + inst->isMemBarrier() || + inst->isWriteBarrier()) { +#if !FULL_SYSTEM + // Hack to make sure syscalls aren't executed until all stores + // write back their data. This direct communication shouldn't + // be used for anything other than this. + if (inst_num > 0 || LSQ.hasStoresToWB()) +#else + if ((inst->isMemBarrier() || inst->isWriteBarrier() || + inst->isQuiesce()) && + LSQ.hasStoresToWB()) +#endif + { + DPRINTF(BE, "Waiting for all stores to writeback.\n"); + return false; + } + + DPRINTF(BE, "Encountered a store or non-speculative " + "instruction at the head of the ROB, PC %#x.\n", + inst->readPC()); + + if (inst->isMemBarrier() || inst->isWriteBarrier()) { + DPRINTF(BE, "Waking dependents on barrier [sn:%lli]\n", + inst->seqNum); + assert(memBarrier); + wakeDependents(inst, true); + if (memBarrier == inst) + memBarrier = NULL; + inst->clearMemDependents(); + } + + // Send back the non-speculative instruction's sequence number. + if (inst->iqItValid) { + DPRINTF(BE, "Removing instruction from waiting list\n"); + waitingList.erase(inst->iqIt); + inst->iqItValid = false; + waitingInsts--; + assert(waitingInsts >= 0); + if (inst->isStore()) + removeWaitingMemOp(inst); + } + + exeList.push(inst); + + // Change the instruction so it won't try to commit again until + // it is executed. + inst->clearCanCommit(); + +// ++commitNonSpecStalls; + + return false; + } else if (inst->isLoad()) { + DPRINTF(BE, "[sn:%lli]: Uncached load, PC %#x.\n", + inst->seqNum, inst->readPC()); + + // Send back the non-speculative instruction's sequence + // number. Maybe just tell the lsq to re-execute the load. + + // Send back the non-speculative instruction's sequence number. + if (inst->iqItValid) { + DPRINTF(BE, "Removing instruction from waiting list\n"); + waitingList.erase(inst->iqIt); + inst->iqItValid = false; + waitingInsts--; + assert(waitingInsts >= 0); + removeWaitingMemOp(inst); + } + replayMemInst(inst); + + inst->clearCanCommit(); + + return false; + } else { + panic("Trying to commit un-executed instruction " + "of unknown type!\n"); + } + } + + // Not handled for now. + assert(!inst->isThreadSync()); + assert(inst->memDepReady()); + // Stores will mark themselves as totally completed as they need + // to wait to writeback to memory. @todo: Hack...attempt to fix + // having the checker be forced to wait until a store completes in + // order to check all of the instructions. If the store at the + // head of the check list misses, but a later store hits, then + // loads in the checker may see the younger store values instead + // of the store they should see. Either the checker needs its own + // memory (annoying to update), its own store buffer (how to tell + // which value is correct?), or something else... + if (!inst->isStore()) { + inst->setCompleted(); + } + // Check if the instruction caused a fault. If so, trap. + Fault inst_fault = inst->getFault(); + + // Use checker prior to updating anything due to traps or PC + // based events. + if (checker) { + checker->tick(inst); + } + + if (inst_fault != NoFault) { + DPRINTF(BE, "Inst [sn:%lli] PC %#x has a fault\n", + inst->seqNum, inst->readPC()); + + // Instruction is completed as it has a fault. + inst->setCompleted(); + + if (LSQ.hasStoresToWB()) { + DPRINTF(BE, "Stores still in flight, will wait until drained.\n"); + return false; + } else if (inst_num != 0) { + DPRINTF(BE, "Will wait until instruction is head of commit group.\n"); + return false; + } else if (checker && inst->isStore()) { + checker->tick(inst); + } + + thread->setInst( + static_cast<TheISA::MachInst>(inst->staticInst->machInst)); +#if FULL_SYSTEM + handleFault(inst_fault); + return false; +#else // !FULL_SYSTEM + panic("fault (%d) detected @ PC %08p", inst_fault, + inst->PC); +#endif // FULL_SYSTEM + } + + int freed_regs = 0; + + for (int i = 0; i < inst->numDestRegs(); ++i) { + DPRINTF(BE, "Commit rename map setting reg %i to [sn:%lli]\n", + (int)inst->destRegIdx(i), inst->seqNum); + thread->renameTable[inst->destRegIdx(i)] = inst; + ++freed_regs; + } + + if (inst->traceData) { + inst->traceData->setFetchSeq(inst->seqNum); + inst->traceData->setCPSeq(thread->numInst); + inst->traceData->finalize(); + inst->traceData = NULL; + } + + inst->clearDependents(); + + frontEnd->addFreeRegs(freed_regs); + + instList.pop_back(); + + --numInsts; + ++thread->funcExeInst; + // Maybe move this to where the fault is handled; if the fault is + // handled, don't try to set this myself as the fault will set it. + // If not, then I set thread->PC = thread->nextPC and + // thread->nextPC = thread->nextPC + 4. + thread->setPC(thread->readNextPC()); + thread->setNextPC(thread->readNextPC() + sizeof(TheISA::MachInst)); + updateComInstStats(inst); + + // Write the done sequence number here. + toIEW->doneSeqNum = inst->seqNum; + lastCommitCycle = curTick; + +#if FULL_SYSTEM + int count = 0; + Addr oldpc; + do { + if (count == 0) + assert(!thread->inSyscall && !thread->trapPending); + oldpc = thread->readPC(); + cpu->system->pcEventQueue.service( + thread->getTCProxy()); + count++; + } while (oldpc != thread->readPC()); + if (count > 1) { + DPRINTF(BE, "PC skip function event, stopping commit\n"); + tcSquash = true; + return false; + } +#endif + return true; +} + +template <class Impl> +void +LWBackEnd<Impl>::commitInsts() +{ + // Not sure this should be a loop or not. + int inst_num = 0; + while (!instList.empty() && inst_num < commitWidth) { + if (instList.back()->isSquashed()) { + instList.back()->clearDependents(); + instList.pop_back(); + --numInsts; + ROBSquashedInsts[instList.back()->threadNumber]++; + continue; + } + + if (!commitInst(inst_num++)) { + DPRINTF(BE, "Can't commit, Instruction [sn:%lli] PC " + "%#x is head of ROB and not ready\n", + instList.back()->seqNum, instList.back()->readPC()); + --inst_num; + break; + } + } + n_committed_dist.sample(inst_num); +} + +template <class Impl> +void +LWBackEnd<Impl>::squash(const InstSeqNum &sn) +{ + LSQ.squash(sn); + + int freed_regs = 0; + InstListIt waiting_list_end = waitingList.end(); + InstListIt insts_it = waitingList.begin(); + + while (insts_it != waiting_list_end && (*insts_it)->seqNum > sn) + { + if ((*insts_it)->isSquashed()) { + ++insts_it; + continue; + } + DPRINTF(BE, "Squashing instruction on waitingList PC %#x, [sn:%lli].\n", + (*insts_it)->readPC(), + (*insts_it)->seqNum); + + if ((*insts_it)->isMemRef()) { + DPRINTF(BE, "Squashing a waiting mem op [sn:%lli]\n", + (*insts_it)->seqNum); + removeWaitingMemOp((*insts_it)); + } + + waitingList.erase(insts_it++); + waitingInsts--; + } + assert(waitingInsts >= 0); + + insts_it = instList.begin(); + + while (!instList.empty() && (*insts_it)->seqNum > sn) + { + if ((*insts_it)->isSquashed()) { + ++insts_it; + continue; + } + DPRINTF(BE, "Squashing instruction on inst list PC %#x, [sn:%lli].\n", + (*insts_it)->readPC(), + (*insts_it)->seqNum); + + // Mark the instruction as squashed, and ready to commit so that + // it can drain out of the pipeline. + (*insts_it)->setSquashed(); + + (*insts_it)->setCanCommit(); + + (*insts_it)->removeInROB(); + + for (int i = 0; i < (*insts_it)->numDestRegs(); ++i) { + DynInstPtr prev_dest = (*insts_it)->getPrevDestInst(i); + DPRINTF(BE, "Commit rename map setting reg %i to [sn:%lli]\n", + (int)(*insts_it)->destRegIdx(i), prev_dest->seqNum); + renameTable[(*insts_it)->destRegIdx(i)] = prev_dest; + ++freed_regs; + } + + (*insts_it)->clearDependents(); + + squashedInsts[(*insts_it)->threadNumber]++; + + instList.erase(insts_it++); + --numInsts; + } + + insts_it = waitingList.begin(); + while (!waitingList.empty() && insts_it != waitingList.end()) { + if ((*insts_it)->seqNum < sn) { + ++insts_it; + continue; + } + assert((*insts_it)->isSquashed()); + + waitingList.erase(insts_it++); + waitingInsts--; + } + + while (memBarrier && memBarrier->seqNum > sn) { + DPRINTF(BE, "[sn:%lli] Memory barrier squashed (or previously " + "squashed)\n", memBarrier->seqNum); + memBarrier->clearMemDependents(); + if (memBarrier->memDepReady()) { + DPRINTF(BE, "No previous barrier\n"); + memBarrier = NULL; + } else { + std::list<DynInstPtr> &srcs = memBarrier->getMemSrcs(); + memBarrier = srcs.front(); + srcs.pop_front(); + assert(srcs.empty()); + DPRINTF(BE, "Previous barrier: [sn:%lli]\n", + memBarrier->seqNum); + } + } + + frontEnd->addFreeRegs(freed_regs); +} + +template <class Impl> +void +LWBackEnd<Impl>::squashFromTC() +{ + InstSeqNum squashed_inst = robEmpty() ? 0 : instList.back()->seqNum - 1; + squash(squashed_inst); + frontEnd->squash(squashed_inst, thread->readPC(), + false, false); + frontEnd->interruptPending = false; + + thread->trapPending = false; + thread->inSyscall = false; + tcSquash = false; + commitStatus = Running; +} + +template <class Impl> +void +LWBackEnd<Impl>::squashFromTrap() +{ + InstSeqNum squashed_inst = robEmpty() ? 0 : instList.back()->seqNum - 1; + squash(squashed_inst); + frontEnd->squash(squashed_inst, thread->readPC(), + false, false); + frontEnd->interruptPending = false; + + thread->trapPending = false; + thread->inSyscall = false; + trapSquash = false; + commitStatus = Running; +} + +template <class Impl> +void +LWBackEnd<Impl>::squashDueToBranch(DynInstPtr &inst) +{ + // Update the branch predictor state I guess + DPRINTF(BE, "Squashing due to branch [sn:%lli], will restart at PC %#x\n", + inst->seqNum, inst->readNextPC()); + squash(inst->seqNum); + frontEnd->squash(inst->seqNum, inst->readNextPC(), + true, inst->mispredicted()); +} + +template <class Impl> +void +LWBackEnd<Impl>::squashDueToMemViolation(DynInstPtr &inst) +{ + // Update the branch predictor state I guess + DPRINTF(BE, "Squashing due to violation [sn:%lli], will restart at PC %#x\n", + inst->seqNum, inst->readNextPC()); + squash(inst->seqNum); + frontEnd->squash(inst->seqNum, inst->readNextPC(), + false, inst->mispredicted()); +} + +template <class Impl> +void +LWBackEnd<Impl>::squashDueToMemBlocked(DynInstPtr &inst) +{ + DPRINTF(IEW, "Memory blocked, squashing load and younger insts, " + "PC: %#x [sn:%i].\n", inst->readPC(), inst->seqNum); + + squash(inst->seqNum - 1); + frontEnd->squash(inst->seqNum - 1, inst->readPC()); +} + +template <class Impl> +void +LWBackEnd<Impl>::fetchFault(Fault &fault) +{ + faultFromFetch = fault; + fetchHasFault = true; +} + +template <class Impl> +void +LWBackEnd<Impl>::switchOut() +{ + switchPending = true; +} + +template <class Impl> +void +LWBackEnd<Impl>::doSwitchOut() +{ + switchedOut = true; + switchPending = false; + // Need to get rid of all committed, non-speculative state and write it + // to memory/TC. In this case this is stores that have committed and not + // yet written back. + assert(robEmpty()); + assert(!LSQ.hasStoresToWB()); + + LSQ.switchOut(); + + squash(0); +} + +template <class Impl> +void +LWBackEnd<Impl>::takeOverFrom(ThreadContext *old_xc) +{ + switchedOut = false; + xcSquash = false; + trapSquash = false; + + numInsts = 0; + numWaitingMemOps = 0; + waitingMemOps.clear(); + waitingInsts = 0; + switchedOut = false; + dispatchStatus = Running; + commitStatus = Running; + LSQ.takeOverFrom(old_xc); +} + +template <class Impl> +void +LWBackEnd<Impl>::updateExeInstStats(DynInstPtr &inst) +{ + int thread_number = inst->threadNumber; + + // + // Pick off the software prefetches + // +#ifdef TARGET_ALPHA + if (inst->isDataPrefetch()) + exe_swp[thread_number]++; + else + exe_inst[thread_number]++; +#else + exe_inst[thread_number]++; +#endif + + // + // Control operations + // + if (inst->isControl()) + exe_branches[thread_number]++; + + // + // Memory operations + // + if (inst->isMemRef()) { + exe_refs[thread_number]++; + + if (inst->isLoad()) + exe_loads[thread_number]++; + } +} + +template <class Impl> +void +LWBackEnd<Impl>::updateComInstStats(DynInstPtr &inst) +{ + unsigned tid = inst->threadNumber; + + // keep an instruction count + thread->numInst++; + thread->numInsts++; + + cpu->numInst++; + // + // Pick off the software prefetches + // +#ifdef TARGET_ALPHA + if (inst->isDataPrefetch()) { + stat_com_swp[tid]++; + } else { + stat_com_inst[tid]++; + } +#else + stat_com_inst[tid]++; +#endif + + // + // Control Instructions + // + if (inst->isControl()) + stat_com_branches[tid]++; + + // + // Memory references + // + if (inst->isMemRef()) { + stat_com_refs[tid]++; + + if (inst->isLoad()) { + stat_com_loads[tid]++; + } + } + + if (inst->isMemBarrier()) { + stat_com_membars[tid]++; + } +} + +template <class Impl> +void +LWBackEnd<Impl>::dumpInsts() +{ + int num = 0; + int valid_num = 0; + + InstListIt inst_list_it = --(instList.end()); + + cprintf("ExeList size: %i\n", exeList.size()); + + cprintf("Inst list size: %i\n", instList.size()); + + while (inst_list_it != instList.end()) + { + cprintf("Instruction:%i\n", + num); + if (!(*inst_list_it)->isSquashed()) { + if (!(*inst_list_it)->isIssued()) { + ++valid_num; + cprintf("Count:%i\n", valid_num); + } else if ((*inst_list_it)->isMemRef() && + !(*inst_list_it)->memOpDone) { + // Loads that have not been marked as executed still count + // towards the total instructions. + ++valid_num; + cprintf("Count:%i\n", valid_num); + } + } + + cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" + "Issued:%i\nSquashed:%i\n", + (*inst_list_it)->readPC(), + (*inst_list_it)->seqNum, + (*inst_list_it)->threadNumber, + (*inst_list_it)->isIssued(), + (*inst_list_it)->isSquashed()); + + if ((*inst_list_it)->isMemRef()) { + cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone); + } + + cprintf("\n"); + + inst_list_it--; + ++num; + } + + cprintf("Waiting list size: %i\n", waitingList.size()); + + inst_list_it = --(waitingList.end()); + + while (inst_list_it != waitingList.end()) + { + cprintf("Instruction:%i\n", + num); + if (!(*inst_list_it)->isSquashed()) { + if (!(*inst_list_it)->isIssued()) { + ++valid_num; + cprintf("Count:%i\n", valid_num); + } else if ((*inst_list_it)->isMemRef() && + !(*inst_list_it)->memOpDone) { + // Loads that have not been marked as executed still count + // towards the total instructions. + ++valid_num; + cprintf("Count:%i\n", valid_num); + } + } + + cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n" + "Issued:%i\nSquashed:%i\n", + (*inst_list_it)->readPC(), + (*inst_list_it)->seqNum, + (*inst_list_it)->threadNumber, + (*inst_list_it)->isIssued(), + (*inst_list_it)->isSquashed()); + + if ((*inst_list_it)->isMemRef()) { + cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone); + } + + cprintf("\n"); + + inst_list_it--; + ++num; + } + + cprintf("waitingMemOps list size: %i\n", waitingMemOps.size()); + + MemIt waiting_it = waitingMemOps.begin(); + + while (waiting_it != waitingMemOps.end()) + { + cprintf("[sn:%lli] ", (*waiting_it)); + waiting_it++; + ++num; + } + cprintf("\n"); +} diff --git a/src/cpu/ozone/lw_lsq.cc b/src/cpu/ozone/lw_lsq.cc new file mode 100644 index 000000000..8674e83a0 --- /dev/null +++ b/src/cpu/ozone/lw_lsq.cc @@ -0,0 +1,36 @@ +/* + * 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 "cpu/ozone/ozone_impl.hh" +#include "cpu/ozone/lw_lsq_impl.hh" + +// Force the instantiation of LDSTQ for all the implementations we care about. +template class OzoneLWLSQ<OzoneImpl>; + diff --git a/src/cpu/ozone/lw_lsq.hh b/src/cpu/ozone/lw_lsq.hh new file mode 100644 index 000000000..b2924db54 --- /dev/null +++ b/src/cpu/ozone/lw_lsq.hh @@ -0,0 +1,658 @@ +/* + * 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_OZONE_LW_LSQ_HH__ +#define __CPU_OZONE_LW_LSQ_HH__ + +#include <list> +#include <map> +#include <queue> +#include <algorithm> + +#include "arch/faults.hh" +#include "arch/isa_traits.hh" +#include "config/full_system.hh" +#include "base/hashmap.hh" +#include "cpu/inst_seq.hh" +#include "mem/packet.hh" +#include "mem/port.hh" +//#include "mem/page_table.hh" +#include "sim/debug.hh" +#include "sim/sim_object.hh" + +//class PageTable; + +/** + * Class that implements the actual LQ and SQ for each specific thread. + * Both are circular queues; load entries are freed upon committing, while + * store entries are freed once they writeback. The LSQUnit tracks if there + * are memory ordering violations, and also detects partial load to store + * forwarding cases (a store only has part of a load's data) that requires + * the load to wait until the store writes back. In the former case it + * holds onto the instruction until the dependence unit looks at it, and + * in the latter it stalls the LSQ until the store writes back. At that + * point the load is replayed. + */ +template <class Impl> +class OzoneLWLSQ { + public: + typedef typename Impl::Params Params; + typedef typename Impl::FullCPU FullCPU; + typedef typename Impl::BackEnd BackEnd; + typedef typename Impl::DynInstPtr DynInstPtr; + typedef typename Impl::IssueStruct IssueStruct; + + typedef TheISA::IntReg IntReg; + + typedef typename std::map<InstSeqNum, DynInstPtr>::iterator LdMapIt; + + private: + class StoreCompletionEvent : public Event { + public: + /** Constructs a store completion event. */ + StoreCompletionEvent(DynInstPtr &inst, BackEnd *be, + Event *wb_event, OzoneLWLSQ *lsq_ptr); + + /** Processes the store completion event. */ + void process(); + + /** Returns the description of this event. */ + const char *description(); + + private: + /** The store index of the store being written back. */ + DynInstPtr inst; + + BackEnd *be; + /** The writeback event for the store. Needed for store + * conditionals. + */ + public: + Event *wbEvent; + bool miss; + private: + /** The pointer to the LSQ unit that issued the store. */ + OzoneLWLSQ<Impl> *lsqPtr; + }; + + public: + /** Constructs an LSQ unit. init() must be called prior to use. */ + OzoneLWLSQ(); + + /** Initializes the LSQ unit with the specified number of entries. */ + void init(Params *params, unsigned maxLQEntries, + unsigned maxSQEntries, unsigned id); + + /** Returns the name of the LSQ unit. */ + std::string name() const; + + /** Sets the CPU pointer. */ + void setCPU(FullCPU *cpu_ptr) + { cpu = cpu_ptr; } + + /** Sets the back-end stage pointer. */ + void setBE(BackEnd *be_ptr) + { be = be_ptr; } + + /** Sets the page table pointer. */ +// void setPageTable(PageTable *pt_ptr); + + /** Ticks the LSQ unit, which in this case only resets the number of + * used cache ports. + * @todo: Move the number of used ports up to the LSQ level so it can + * be shared by all LSQ units. + */ + void tick() { usedPorts = 0; } + + /** Inserts an instruction. */ + void insert(DynInstPtr &inst); + /** Inserts a load instruction. */ + void insertLoad(DynInstPtr &load_inst); + /** Inserts a store instruction. */ + void insertStore(DynInstPtr &store_inst); + + /** Executes a load instruction. */ + Fault executeLoad(DynInstPtr &inst); + + /** Executes a store instruction. */ + Fault executeStore(DynInstPtr &inst); + + /** Commits the head load. */ + void commitLoad(); + /** Commits loads older than a specific sequence number. */ + void commitLoads(InstSeqNum &youngest_inst); + + /** Commits stores older than a specific sequence number. */ + void commitStores(InstSeqNum &youngest_inst); + + /** Writes back stores. */ + void writebackStores(); + + // @todo: Include stats in the LSQ unit. + //void regStats(); + + /** Clears all the entries in the LQ. */ + void clearLQ(); + + /** Clears all the entries in the SQ. */ + void clearSQ(); + + /** Resizes the LQ to a given size. */ + void resizeLQ(unsigned size); + + /** Resizes the SQ to a given size. */ + void resizeSQ(unsigned size); + + /** Squashes all instructions younger than a specific sequence number. */ + void squash(const InstSeqNum &squashed_num); + + /** Returns if there is a memory ordering violation. Value is reset upon + * call to getMemDepViolator(). + */ + bool violation() { return memDepViolator; } + + /** Returns the memory ordering violator. */ + DynInstPtr getMemDepViolator(); + + /** Returns if a load became blocked due to the memory system. It clears + * the bool's value upon this being called. + */ + bool loadBlocked() + { return isLoadBlocked; } + + void clearLoadBlocked() + { isLoadBlocked = false; } + + bool isLoadBlockedHandled() + { return loadBlockedHandled; } + + void setLoadBlockedHandled() + { loadBlockedHandled = true; } + + /** Returns the number of free entries (min of free LQ and SQ entries). */ + unsigned numFreeEntries(); + + /** Returns the number of loads ready to execute. */ + int numLoadsReady(); + + /** Returns the number of loads in the LQ. */ + int numLoads() { return loads; } + + /** Returns the number of stores in the SQ. */ + int numStores() { return stores; } + + /** Returns if either the LQ or SQ is full. */ + bool isFull() { return lqFull() || sqFull(); } + + /** Returns if the LQ is full. */ + bool lqFull() { return loads >= (LQEntries - 1); } + + /** Returns if the SQ is full. */ + bool sqFull() { return stores >= (SQEntries - 1); } + + /** Debugging function to dump instructions in the LSQ. */ + void dumpInsts(); + + /** Returns the number of instructions in the LSQ. */ + unsigned getCount() { return loads + stores; } + + /** Returns if there are any stores to writeback. */ + bool hasStoresToWB() { return storesToWB; } + + /** Returns the number of stores to writeback. */ + int numStoresToWB() { return storesToWB; } + + /** Returns if the LSQ unit will writeback on this cycle. */ + bool willWB() { return storeQueue.back().canWB && + !storeQueue.back().completed/* && + !dcacheInterface->isBlocked()*/; } + + void switchOut(); + + void takeOverFrom(ThreadContext *old_tc = NULL); + + bool isSwitchedOut() { return switchedOut; } + + bool switchedOut; + + private: + /** Completes the store at the specified index. */ + void completeStore(int store_idx); + + private: + /** Pointer to the CPU. */ + FullCPU *cpu; + + /** Pointer to the back-end stage. */ + BackEnd *be; + + MemObject *mem; + + class DcachePort : public Port + { + protected: + FullCPU *cpu; + + public: + DcachePort(const std::string &_name, FullCPU *_cpu) + : Port(_name), cpu(_cpu) + { } + + protected: + virtual Tick recvAtomic(PacketPtr pkt); + + virtual void recvFunctional(PacketPtr pkt); + + virtual void recvStatusChange(Status status); + + virtual void getDeviceAddressRanges(AddrRangeList &resp, + AddrRangeList &snoop) + { resp.clear(); snoop.clear(); } + + virtual bool recvTiming(PacketPtr pkt); + + virtual void recvRetry(); + }; + + /** Pointer to the D-cache. */ + DcachePort dcachePort; + + /** Pointer to the page table. */ +// PageTable *pTable; + + public: + struct SQEntry { + /** Constructs an empty store queue entry. */ + SQEntry() + : inst(NULL), req(NULL), size(0), data(0), + canWB(0), committed(0), completed(0), lqIt(NULL) + { } + + /** Constructs a store queue entry for a given instruction. */ + SQEntry(DynInstPtr &_inst) + : inst(_inst), req(NULL), size(0), data(0), + canWB(0), committed(0), completed(0), lqIt(NULL) + { } + + /** The store instruction. */ + DynInstPtr inst; + /** The memory request for the store. */ + RequestPtr req; + /** The size of the store. */ + int size; + /** The store data. */ + IntReg data; + /** Whether or not the store can writeback. */ + bool canWB; + /** Whether or not the store is committed. */ + bool committed; + /** Whether or not the store is completed. */ + bool completed; + + typename std::list<DynInstPtr>::iterator lqIt; + }; + + enum Status { + Running, + Idle, + DcacheMissStall, + DcacheMissSwitch + }; + + private: + /** The OzoneLWLSQ thread id. */ + unsigned lsqID; + + /** The status of the LSQ unit. */ + Status _status; + + /** The store queue. */ + std::list<SQEntry> storeQueue; + /** The load queue. */ + std::list<DynInstPtr> loadQueue; + + typedef typename std::list<SQEntry>::iterator SQIt; + typedef typename std::list<DynInstPtr>::iterator LQIt; + + + struct HashFn { + size_t operator() (const int a) const + { + unsigned hash = (((a >> 14) ^ ((a >> 2) & 0xffff))) & 0x7FFFFFFF; + + return hash; + } + }; + + m5::hash_map<int, SQIt, HashFn> SQItHash; + std::queue<int> SQIndices; + m5::hash_map<int, LQIt, HashFn> LQItHash; + std::queue<int> LQIndices; + + typedef typename m5::hash_map<int, LQIt, HashFn>::iterator LQHashIt; + typedef typename m5::hash_map<int, SQIt, HashFn>::iterator SQHashIt; + // Consider making these 16 bits + /** The number of LQ entries. */ + unsigned LQEntries; + /** The number of SQ entries. */ + unsigned SQEntries; + + /** The number of load instructions in the LQ. */ + int loads; + /** The number of store instructions in the SQ (excludes those waiting to + * writeback). + */ + int stores; + + int storesToWB; + + /// @todo Consider moving to a more advanced model with write vs read ports + /** The number of cache ports available each cycle. */ + int cachePorts; + + /** The number of used cache ports in this cycle. */ + int usedPorts; + + //list<InstSeqNum> mshrSeqNums; + + //Stats::Scalar<> dcacheStallCycles; + Counter lastDcacheStall; + + // Make these per thread? + /** Whether or not the LSQ is stalled. */ + bool stalled; + /** The store that causes the stall due to partial store to load + * forwarding. + */ + InstSeqNum stallingStoreIsn; + /** The index of the above store. */ + LQIt stallingLoad; + + /** Whether or not a load is blocked due to the memory system. It is + * cleared when this value is checked via loadBlocked(). + */ + bool isLoadBlocked; + + bool loadBlockedHandled; + + InstSeqNum blockedLoadSeqNum; + + /** The oldest faulting load instruction. */ + DynInstPtr loadFaultInst; + /** The oldest faulting store instruction. */ + DynInstPtr storeFaultInst; + + /** The oldest load that caused a memory ordering violation. */ + DynInstPtr memDepViolator; + + // Will also need how many read/write ports the Dcache has. Or keep track + // of that in stage that is one level up, and only call executeLoad/Store + // the appropriate number of times. + + public: + /** Executes the load at the given index. */ + template <class T> + Fault read(RequestPtr req, T &data, int load_idx); + + /** Executes the store at the given index. */ + template <class T> + Fault write(RequestPtr req, T &data, int store_idx); + + /** Returns the sequence number of the head load instruction. */ + InstSeqNum getLoadHeadSeqNum() + { + if (!loadQueue.empty()) { + return loadQueue.back()->seqNum; + } else { + return 0; + } + + } + + /** Returns the sequence number of the head store instruction. */ + InstSeqNum getStoreHeadSeqNum() + { + if (!storeQueue.empty()) { + return storeQueue.back().inst->seqNum; + } else { + return 0; + } + + } + + /** Returns whether or not the LSQ unit is stalled. */ + bool isStalled() { return stalled; } +}; + +template <class Impl> +template <class T> +Fault +OzoneLWLSQ<Impl>::read(RequestPtr req, T &data, int load_idx) +{ + //Depending on issue2execute delay a squashed load could + //execute if it is found to be squashed in the same + //cycle it is scheduled to execute + typename m5::hash_map<int, LQIt, HashFn>::iterator + lq_hash_it = LQItHash.find(load_idx); + assert(lq_hash_it != LQItHash.end()); + DynInstPtr inst = (*(*lq_hash_it).second); + + // Make sure this isn't an uncacheable access + // A bit of a hackish way to get uncached accesses to work only if they're + // at the head of the LSQ and are ready to commit (at the head of the ROB + // too). + // @todo: Fix uncached accesses. + if (req->getFlags() & UNCACHEABLE && + (inst != loadQueue.back() || !inst->reachedCommit)) { + DPRINTF(OzoneLSQ, "[sn:%lli] Uncached load and not head of " + "commit/LSQ!\n", + inst->seqNum); + be->rescheduleMemInst(inst); + return TheISA::genMachineCheckFault(); + } + + // Check the SQ for any previous stores that might lead to forwarding + SQIt sq_it = storeQueue.begin(); + int store_size = 0; + + DPRINTF(OzoneLSQ, "Read called, load idx: %i addr: %#x\n", + load_idx, req->getPaddr()); + + while (sq_it != storeQueue.end() && (*sq_it).inst->seqNum > inst->seqNum) + ++sq_it; + + while (1) { + // End once we've reached the top of the LSQ + if (sq_it == storeQueue.end()) { + break; + } + + assert((*sq_it).inst); + + store_size = (*sq_it).size; + + if (store_size == 0) { + sq_it++; + continue; + } + + // Check if the store data is within the lower and upper bounds of + // addresses that the request needs. + bool store_has_lower_limit = + req->getVaddr() >= (*sq_it).inst->effAddr; + bool store_has_upper_limit = + (req->getVaddr() + req->getSize()) <= ((*sq_it).inst->effAddr + + store_size); + bool lower_load_has_store_part = + req->getVaddr() < ((*sq_it).inst->effAddr + + store_size); + bool upper_load_has_store_part = + (req->getVaddr() + req->getSize()) > (*sq_it).inst->effAddr; + + // If the store's data has all of the data needed, we can forward. + if (store_has_lower_limit && store_has_upper_limit) { + int shift_amt = req->getVaddr() & (store_size - 1); + // Assumes byte addressing + shift_amt = shift_amt << 3; + + // Cast this to type T? + data = (*sq_it).data >> shift_amt; + + assert(!inst->memData); + inst->memData = new uint8_t[64]; + + memcpy(inst->memData, &data, req->getSize()); + + DPRINTF(OzoneLSQ, "Forwarding from store [sn:%lli] to load to " + "[sn:%lli] addr %#x, data %#x\n", + (*sq_it).inst->seqNum, inst->seqNum, req->vaddr, *(inst->memData)); +/* + typename BackEnd::LdWritebackEvent *wb = + new typename BackEnd::LdWritebackEvent(inst, + be); + + // We'll say this has a 1 cycle load-store forwarding latency + // for now. + // FIXME - Need to make this a parameter. + wb->schedule(curTick); +*/ + // Should keep track of stat for forwarded data + return NoFault; + } else if ((store_has_lower_limit && lower_load_has_store_part) || + (store_has_upper_limit && upper_load_has_store_part) || + (lower_load_has_store_part && upper_load_has_store_part)) { + // This is the partial store-load forwarding case where a store + // has only part of the load's data. + + // If it's already been written back, then don't worry about + // stalling on it. + if ((*sq_it).completed) { + sq_it++; + break; + } + + // Must stall load and force it to retry, so long as it's the oldest + // load that needs to do so. + if (!stalled || + (stalled && + inst->seqNum < + (*stallingLoad)->seqNum)) { + stalled = true; + stallingStoreIsn = (*sq_it).inst->seqNum; + stallingLoad = (*lq_hash_it).second; + } + + // Tell IQ/mem dep unit that this instruction will need to be + // rescheduled eventually + be->rescheduleMemInst(inst); + + DPRINTF(OzoneLSQ, "Load-store forwarding mis-match. " + "Store [sn:%lli] to load addr %#x\n", + (*sq_it).inst->seqNum, req->vaddr); + + return NoFault; + } + sq_it++; + } + + // If there's no forwarding case, then go access memory + DPRINTF(OzoneLSQ, "Doing functional access for inst PC %#x\n", + inst->readPC()); + + assert(!inst->memData); + inst->memData = new uint8_t[64]; + + ++usedPorts; + + DPRINTF(OzoneLSQ, "Doing timing access for inst PC %#x\n", + inst->readPC()); + + PacketPtr data_pkt = new Packet(req, Packet::ReadReq, Packet::Broadcast); + data_pkt->dataStatic(inst->memData); + + // if we have a cache, do cache access too + if (!dcachePort.sendTiming(data_pkt)) { + // There's an older load that's already going to squash. + if (isLoadBlocked && blockedLoadSeqNum < inst->seqNum) + return NoFault; + + // Record that the load was blocked due to memory. This + // load will squash all instructions after it, be + // refetched, and re-executed. + isLoadBlocked = true; + loadBlockedHandled = false; + blockedLoadSeqNum = inst->seqNum; + // No fault occurred, even though the interface is blocked. + return NoFault; + } + + if (data_pkt->result != Packet::Success) { + DPRINTF(OzoneLSQ, "OzoneLSQ: D-cache miss!\n"); + DPRINTF(Activity, "Activity: ld accessing mem miss [sn:%lli]\n", + inst->seqNum); + } else { + DPRINTF(OzoneLSQ, "OzoneLSQ: D-cache hit!\n"); + DPRINTF(Activity, "Activity: ld accessing mem hit [sn:%lli]\n", + inst->seqNum); + } + + return NoFault; +} + +template <class Impl> +template <class T> +Fault +OzoneLWLSQ<Impl>::write(RequestPtr req, T &data, int store_idx) +{ + SQHashIt sq_hash_it = SQItHash.find(store_idx); + assert(sq_hash_it != SQItHash.end()); + + SQIt sq_it = (*sq_hash_it).second; + assert((*sq_it).inst); + + DPRINTF(OzoneLSQ, "Doing write to store idx %i, addr %#x data %#x" + " | [sn:%lli]\n", + store_idx, req->getPaddr(), data, (*sq_it).inst->seqNum); + + (*sq_it).req = req; + (*sq_it).size = sizeof(T); + (*sq_it).data = data; +/* + assert(!req->data); + req->data = new uint8_t[64]; + memcpy(req->data, (uint8_t *)&(*sq_it).data, req->size); +*/ + + // This function only writes the data to the store queue, so no fault + // can happen here. + return NoFault; +} + +#endif // __CPU_OZONE_LW_LSQ_HH__ diff --git a/src/cpu/ozone/lw_lsq_impl.hh b/src/cpu/ozone/lw_lsq_impl.hh new file mode 100644 index 000000000..05db3028a --- /dev/null +++ b/src/cpu/ozone/lw_lsq_impl.hh @@ -0,0 +1,876 @@ +/* + * 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 "arch/isa_traits.hh" +#include "base/str.hh" +#include "cpu/ozone/lw_lsq.hh" +#include "cpu/checker/cpu.hh" + +template <class Impl> +OzoneLWLSQ<Impl>::StoreCompletionEvent::StoreCompletionEvent(DynInstPtr &_inst, + BackEnd *_be, + Event *wb_event, + OzoneLWLSQ<Impl> *lsq_ptr) + : Event(&mainEventQueue), + inst(_inst), + be(_be), + wbEvent(wb_event), + miss(false), + lsqPtr(lsq_ptr) +{ + this->setFlags(Event::AutoDelete); +} + +template <class Impl> +void +OzoneLWLSQ<Impl>::StoreCompletionEvent::process() +{ + DPRINTF(OzoneLSQ, "Cache miss complete for store [sn:%lli]\n", + inst->seqNum); + + //lsqPtr->removeMSHR(lsqPtr->storeQueue[storeIdx].inst->seqNum); + +// lsqPtr->cpu->wakeCPU(); + if (lsqPtr->isSwitchedOut()) { + if (wbEvent) + delete wbEvent; + + return; + } + + if (wbEvent) { + wbEvent->process(); + delete wbEvent; + } + + lsqPtr->completeStore(inst->sqIdx); + if (miss) + be->removeDcacheMiss(inst); +} + +template <class Impl> +const char * +OzoneLWLSQ<Impl>::StoreCompletionEvent::description() +{ + return "LSQ store completion event"; +} + +template <class Impl> +OzoneLWLSQ<Impl>::OzoneLWLSQ() + : loads(0), stores(0), storesToWB(0), stalled(false), isLoadBlocked(false), + loadBlockedHandled(false) +{ +} + +template<class Impl> +void +OzoneLWLSQ<Impl>::init(Params *params, unsigned maxLQEntries, + unsigned maxSQEntries, unsigned id) +{ + DPRINTF(OzoneLSQ, "Creating OzoneLWLSQ%i object.\n",id); + + lsqID = id; + + LQEntries = maxLQEntries; + SQEntries = maxSQEntries; + + for (int i = 0; i < LQEntries * 2; i++) { + LQIndices.push(i); + SQIndices.push(i); + } + + usedPorts = 0; + cachePorts = params->cachePorts; + + dcacheInterface = params->dcacheInterface; + + loadFaultInst = storeFaultInst = memDepViolator = NULL; + + blockedLoadSeqNum = 0; +} + +template<class Impl> +std::string +OzoneLWLSQ<Impl>::name() const +{ + return "lsqunit"; +} + +template<class Impl> +void +OzoneLWLSQ<Impl>::clearLQ() +{ + loadQueue.clear(); +} + +template<class Impl> +void +OzoneLWLSQ<Impl>::clearSQ() +{ + storeQueue.clear(); +} +/* +template<class Impl> +void +OzoneLWLSQ<Impl>::setPageTable(PageTable *pt_ptr) +{ + DPRINTF(OzoneLSQ, "Setting the page table pointer.\n"); + pTable = pt_ptr; +} +*/ +template<class Impl> +void +OzoneLWLSQ<Impl>::resizeLQ(unsigned size) +{ + assert( size >= LQEntries); + + if (size > LQEntries) { + while (size > loadQueue.size()) { + DynInstPtr dummy; + loadQueue.push_back(dummy); + LQEntries++; + } + } else { + LQEntries = size; + } + +} + +template<class Impl> +void +OzoneLWLSQ<Impl>::resizeSQ(unsigned size) +{ + if (size > SQEntries) { + while (size > storeQueue.size()) { + SQEntry dummy; + storeQueue.push_back(dummy); + SQEntries++; + } + } else { + SQEntries = size; + } +} + +template <class Impl> +void +OzoneLWLSQ<Impl>::insert(DynInstPtr &inst) +{ + // Make sure we really have a memory reference. + assert(inst->isMemRef()); + + // Make sure it's one of the two classes of memory references. + assert(inst->isLoad() || inst->isStore()); + + if (inst->isLoad()) { + insertLoad(inst); + } else { + insertStore(inst); + } +} + +template <class Impl> +void +OzoneLWLSQ<Impl>::insertLoad(DynInstPtr &load_inst) +{ + assert(loads < LQEntries * 2); + assert(!LQIndices.empty()); + int load_index = LQIndices.front(); + LQIndices.pop(); + + DPRINTF(OzoneLSQ, "Inserting load PC %#x, idx:%i [sn:%lli]\n", + load_inst->readPC(), load_index, load_inst->seqNum); + + load_inst->lqIdx = load_index; + + loadQueue.push_front(load_inst); + LQItHash[load_index] = loadQueue.begin(); + + ++loads; +} + +template <class Impl> +void +OzoneLWLSQ<Impl>::insertStore(DynInstPtr &store_inst) +{ + // Make sure it is not full before inserting an instruction. + assert(stores - storesToWB < SQEntries); + + assert(!SQIndices.empty()); + int store_index = SQIndices.front(); + SQIndices.pop(); + + DPRINTF(OzoneLSQ, "Inserting store PC %#x, idx:%i [sn:%lli]\n", + store_inst->readPC(), store_index, store_inst->seqNum); + + store_inst->sqIdx = store_index; + SQEntry entry(store_inst); + if (loadQueue.empty()) { + entry.lqIt = loadQueue.end(); + } else { + entry.lqIt = loadQueue.begin(); + } + storeQueue.push_front(entry); + + SQItHash[store_index] = storeQueue.begin(); + + ++stores; +} + +template <class Impl> +typename Impl::DynInstPtr +OzoneLWLSQ<Impl>::getMemDepViolator() +{ + DynInstPtr temp = memDepViolator; + + memDepViolator = NULL; + + return temp; +} + +template <class Impl> +unsigned +OzoneLWLSQ<Impl>::numFreeEntries() +{ + unsigned free_lq_entries = LQEntries - loads; + unsigned free_sq_entries = SQEntries - stores; + + // Both the LQ and SQ entries have an extra dummy entry to differentiate + // empty/full conditions. Subtract 1 from the free entries. + if (free_lq_entries < free_sq_entries) { + return free_lq_entries - 1; + } else { + return free_sq_entries - 1; + } +} + +template <class Impl> +int +OzoneLWLSQ<Impl>::numLoadsReady() +{ + int retval = 0; + LQIt lq_it = loadQueue.begin(); + LQIt end_it = loadQueue.end(); + + while (lq_it != end_it) { + if ((*lq_it)->readyToIssue()) { + ++retval; + } + } + + return retval; +} + +template <class Impl> +Fault +OzoneLWLSQ<Impl>::executeLoad(DynInstPtr &inst) +{ + // Execute a specific load. + Fault load_fault = NoFault; + + DPRINTF(OzoneLSQ, "Executing load PC %#x, [sn:%lli]\n", + inst->readPC(),inst->seqNum); + + // Make sure it's really in the list. + // Normally it should always be in the list. However, + /* due to a syscall it may not be the list. +#ifdef DEBUG + int i = loadHead; + while (1) { + if (i == loadTail && !find(inst)) { + assert(0 && "Load not in the queue!"); + } else if (loadQueue[i] == inst) { + break; + } + + i = i + 1; + if (i >= LQEntries) { + i = 0; + } + } +#endif // DEBUG*/ + + load_fault = inst->initiateAcc(); + + // Might want to make sure that I'm not overwriting a previously faulting + // instruction that hasn't been checked yet. + // Actually probably want the oldest faulting load + if (load_fault != NoFault) { + DPRINTF(OzoneLSQ, "Load [sn:%lli] has a fault\n", inst->seqNum); + // Maybe just set it as can commit here, although that might cause + // some other problems with sending traps to the ROB too quickly. + be->instToCommit(inst); +// iewStage->activityThisCycle(); + } + + return load_fault; +} + +template <class Impl> +Fault +OzoneLWLSQ<Impl>::executeStore(DynInstPtr &store_inst) +{ + // Make sure that a store exists. + assert(stores != 0); + + int store_idx = store_inst->sqIdx; + SQHashIt sq_hash_it = SQItHash.find(store_idx); + assert(sq_hash_it != SQItHash.end()); + DPRINTF(OzoneLSQ, "Executing store PC %#x [sn:%lli]\n", + store_inst->readPC(), store_inst->seqNum); + + SQIt sq_it = (*sq_hash_it).second; + + Fault store_fault = store_inst->initiateAcc(); + + // Store size should now be available. Use it to get proper offset for + // addr comparisons. + int size = (*sq_it).size; + + if (size == 0) { + DPRINTF(OzoneLSQ,"Fault on Store PC %#x, [sn:%lli],Size = 0\n", + store_inst->readPC(),store_inst->seqNum); + + return store_fault; + } + + assert(store_fault == NoFault); + + if (!storeFaultInst) { + if (store_fault != NoFault) { + panic("Fault in a store instruction!"); + storeFaultInst = store_inst; + } else if (store_inst->isStoreConditional()) { + // Store conditionals need to set themselves as able to + // writeback if we haven't had a fault by here. + (*sq_it).canWB = true; + + ++storesToWB; + DPRINTF(OzoneLSQ, "Nonspeculative store! storesToWB:%i\n", + storesToWB); + } + } + + LQIt lq_it = --(loadQueue.end()); + + if (!memDepViolator) { + while (lq_it != loadQueue.end()) { + if ((*lq_it)->seqNum < store_inst->seqNum) { + lq_it--; + continue; + } + // Actually should only check loads that have actually executed + // Might be safe because effAddr is set to InvalAddr when the + // dyn inst is created. + + // Must actually check all addrs in the proper size range + // Which is more correct than needs to be. What if for now we just + // assume all loads are quad-word loads, and do the addr based + // on that. + // @todo: Fix this, magic number being used here + if (((*lq_it)->effAddr >> 8) == + (store_inst->effAddr >> 8)) { + // A load incorrectly passed this store. Squash and refetch. + // For now return a fault to show that it was unsuccessful. + memDepViolator = (*lq_it); + + return TheISA::genMachineCheckFault(); + } + + lq_it--; + } + + // If we've reached this point, there was no violation. + memDepViolator = NULL; + } + + return store_fault; +} + +template <class Impl> +void +OzoneLWLSQ<Impl>::commitLoad() +{ + assert(!loadQueue.empty()); + + DPRINTF(OzoneLSQ, "[sn:%lli] Committing head load instruction, PC %#x\n", + loadQueue.back()->seqNum, loadQueue.back()->readPC()); + + LQIndices.push(loadQueue.back()->lqIdx); + LQItHash.erase(loadQueue.back()->lqIdx); + + loadQueue.pop_back(); + + --loads; +} + +template <class Impl> +void +OzoneLWLSQ<Impl>::commitLoads(InstSeqNum &youngest_inst) +{ + assert(loads == 0 || !loadQueue.empty()); + + while (loads != 0 && + loadQueue.back()->seqNum <= youngest_inst) { + commitLoad(); + } +} + +template <class Impl> +void +OzoneLWLSQ<Impl>::commitStores(InstSeqNum &youngest_inst) +{ + assert(stores == 0 || !storeQueue.empty()); + + SQIt sq_it = --(storeQueue.end()); + while (!storeQueue.empty() && sq_it != storeQueue.end()) { + assert((*sq_it).inst); + if (!(*sq_it).canWB) { + if ((*sq_it).inst->seqNum > youngest_inst) { + break; + } + ++storesToWB; + + DPRINTF(OzoneLSQ, "Marking store as able to write back, PC " + "%#x [sn:%lli], storesToWB:%i\n", + (*sq_it).inst->readPC(), + (*sq_it).inst->seqNum, + storesToWB); + + (*sq_it).canWB = true; + } + + sq_it--; + } +} + +template <class Impl> +void +OzoneLWLSQ<Impl>::writebackStores() +{ + SQIt sq_it = --(storeQueue.end()); + while (storesToWB > 0 && + sq_it != storeQueue.end() && + (*sq_it).inst && + (*sq_it).canWB && + usedPorts < cachePorts) { + + DynInstPtr inst = (*sq_it).inst; + + if ((*sq_it).size == 0 && !(*sq_it).completed) { + sq_it--; + completeStore(inst->sqIdx); + + continue; + } + + if (inst->isDataPrefetch() || (*sq_it).committed) { + sq_it--; + continue; + } + + if (dcacheInterface && dcacheInterface->isBlocked()) { + DPRINTF(OzoneLSQ, "Unable to write back any more stores, cache" + " is blocked!\n"); + break; + } + + ++usedPorts; + + assert((*sq_it).req); + assert(!(*sq_it).committed); + + (*sq_it).committed = true; + + MemReqPtr req = (*sq_it).req; + + req->cmd = Write; + req->completionEvent = NULL; + req->time = curTick; + + switch((*sq_it).size) { + case 1: + cpu->write(req, (uint8_t &)(*sq_it).data); + break; + case 2: + cpu->write(req, (uint16_t &)(*sq_it).data); + break; + case 4: + cpu->write(req, (uint32_t &)(*sq_it).data); + break; + case 8: + cpu->write(req, (uint64_t &)(*sq_it).data); + break; + default: + panic("Unexpected store size!\n"); + } + if (!(req->flags & LOCKED)) { + (*sq_it).inst->setCompleted(); + if (cpu->checker) { + cpu->checker->tick((*sq_it).inst); + } + } + + DPRINTF(OzoneLSQ, "D-Cache: Writing back store idx:%i PC:%#x " + "to Addr:%#x, data:%#x [sn:%lli]\n", + inst->sqIdx,inst->readPC(), + req->paddr, *(req->data), + inst->seqNum); + + if (dcacheInterface) { + assert(!req->completionEvent); + StoreCompletionEvent *store_event = new + StoreCompletionEvent(inst, be, NULL, this); + req->completionEvent = store_event; + + MemAccessResult result = dcacheInterface->access(req); + + if (isStalled() && + inst->seqNum == stallingStoreIsn) { + DPRINTF(OzoneLSQ, "Unstalling, stalling store [sn:%lli] " + "load [sn:%lli]\n", + stallingStoreIsn, (*stallingLoad)->seqNum); + stalled = false; + stallingStoreIsn = 0; + be->replayMemInst((*stallingLoad)); + } + + if (result != MA_HIT && dcacheInterface->doEvents()) { + store_event->miss = true; + typename BackEnd::LdWritebackEvent *wb = NULL; + if (req->flags & LOCKED) { + wb = new typename BackEnd::LdWritebackEvent(inst, + be); + store_event->wbEvent = wb; + } + + DPRINTF(OzoneLSQ,"D-Cache Write Miss!\n"); + +// DPRINTF(Activity, "Active st accessing mem miss [sn:%lli]\n", +// inst->seqNum); + + be->addDcacheMiss(inst); + + lastDcacheStall = curTick; + + _status = DcacheMissStall; + + // Increment stat here or something + + sq_it--; + } else { + DPRINTF(OzoneLSQ,"D-Cache: Write Hit on idx:%i !\n", + inst->sqIdx); + +// DPRINTF(Activity, "Active st accessing mem hit [sn:%lli]\n", +// inst->seqNum); + + if (req->flags & LOCKED) { + // Stx_C does not generate a system port + // transaction in the 21264, but that might be + // hard to accomplish in this model. + + typename BackEnd::LdWritebackEvent *wb = + new typename BackEnd::LdWritebackEvent(inst, + be); + store_event->wbEvent = wb; + } + sq_it--; + } + } else { + panic("Must HAVE DCACHE!!!!!\n"); + } + } + + // Not sure this should set it to 0. + usedPorts = 0; + + assert(stores >= 0 && storesToWB >= 0); +} + +template <class Impl> +void +OzoneLWLSQ<Impl>::squash(const InstSeqNum &squashed_num) +{ + DPRINTF(OzoneLSQ, "Squashing until [sn:%lli]!" + "(Loads:%i Stores:%i)\n",squashed_num,loads,stores); + + + LQIt lq_it = loadQueue.begin(); + + while (loads != 0 && (*lq_it)->seqNum > squashed_num) { + assert(!loadQueue.empty()); + // Clear the smart pointer to make sure it is decremented. + DPRINTF(OzoneLSQ,"Load Instruction PC %#x squashed, " + "[sn:%lli]\n", + (*lq_it)->readPC(), + (*lq_it)->seqNum); + + if (isStalled() && lq_it == stallingLoad) { + stalled = false; + stallingStoreIsn = 0; + stallingLoad = NULL; + } + + --loads; + + // Inefficient! + LQHashIt lq_hash_it = LQItHash.find((*lq_it)->lqIdx); + assert(lq_hash_it != LQItHash.end()); + LQItHash.erase(lq_hash_it); + LQIndices.push((*lq_it)->lqIdx); + loadQueue.erase(lq_it++); + } + + if (isLoadBlocked) { + if (squashed_num < blockedLoadSeqNum) { + isLoadBlocked = false; + loadBlockedHandled = false; + blockedLoadSeqNum = 0; + } + } + + SQIt sq_it = storeQueue.begin(); + + while (stores != 0 && (*sq_it).inst->seqNum > squashed_num) { + assert(!storeQueue.empty()); + + if ((*sq_it).canWB) { + break; + } + + // Clear the smart pointer to make sure it is decremented. + DPRINTF(OzoneLSQ,"Store Instruction PC %#x idx:%i squashed [sn:%lli]\n", + (*sq_it).inst->readPC(), (*sq_it).inst->sqIdx, + (*sq_it).inst->seqNum); + + // I don't think this can happen. It should have been cleared by the + // stalling load. + if (isStalled() && + (*sq_it).inst->seqNum == stallingStoreIsn) { + panic("Is stalled should have been cleared by stalling load!\n"); + stalled = false; + stallingStoreIsn = 0; + } + + SQHashIt sq_hash_it = SQItHash.find((*sq_it).inst->sqIdx); + assert(sq_hash_it != SQItHash.end()); + SQItHash.erase(sq_hash_it); + SQIndices.push((*sq_it).inst->sqIdx); + (*sq_it).inst = NULL; + (*sq_it).canWB = 0; + + if ((*sq_it).req) { + assert(!(*sq_it).req->completionEvent); + } + (*sq_it).req = NULL; + --stores; + storeQueue.erase(sq_it++); + } +} + +template <class Impl> +void +OzoneLWLSQ<Impl>::dumpInsts() +{ + cprintf("Load store queue: Dumping instructions.\n"); + cprintf("Load queue size: %i\n", loads); + cprintf("Load queue: "); + + LQIt lq_it = --(loadQueue.end()); + + while (lq_it != loadQueue.end() && (*lq_it)) { + cprintf("[sn:%lli] %#x ", (*lq_it)->seqNum, + (*lq_it)->readPC()); + + lq_it--; + } + + cprintf("\nStore queue size: %i\n", stores); + cprintf("Store queue: "); + + SQIt sq_it = --(storeQueue.end()); + + while (sq_it != storeQueue.end() && (*sq_it).inst) { + cprintf("[sn:%lli]\nPC:%#x\nSize:%i\nCommitted:%i\nCompleted:%i\ncanWB:%i\n", + (*sq_it).inst->seqNum, + (*sq_it).inst->readPC(), + (*sq_it).size, + (*sq_it).committed, + (*sq_it).completed, + (*sq_it).canWB); + + sq_it--; + } + + cprintf("\n"); +} + +template <class Impl> +void +OzoneLWLSQ<Impl>::completeStore(int store_idx) +{ + SQHashIt sq_hash_it = SQItHash.find(store_idx); + assert(sq_hash_it != SQItHash.end()); + SQIt sq_it = (*sq_hash_it).second; + + assert((*sq_it).inst); + (*sq_it).completed = true; + DynInstPtr inst = (*sq_it).inst; + + --storesToWB; + + if (isStalled() && + inst->seqNum == stallingStoreIsn) { + DPRINTF(OzoneLSQ, "Unstalling, stalling store [sn:%lli] " + "load [sn:%lli]\n", + stallingStoreIsn, (*stallingLoad)->seqNum); + stalled = false; + stallingStoreIsn = 0; + be->replayMemInst((*stallingLoad)); + } + + DPRINTF(OzoneLSQ, "Completing store idx:%i [sn:%lli], storesToWB:%i\n", + inst->sqIdx, inst->seqNum, storesToWB); + + assert(!storeQueue.empty()); + SQItHash.erase(sq_hash_it); + SQIndices.push(inst->sqIdx); + storeQueue.erase(sq_it); + --stores; + + inst->setCompleted(); + if (cpu->checker) { + cpu->checker->tick(inst); + } +} + +template <class Impl> +void +OzoneLWLSQ<Impl>::switchOut() +{ + assert(storesToWB == 0); + switchedOut = true; + SQIt sq_it = --(storeQueue.end()); + while (storesToWB > 0 && + sq_it != storeQueue.end() && + (*sq_it).inst && + (*sq_it).canWB) { + + DynInstPtr inst = (*sq_it).inst; + + if ((*sq_it).size == 0 && !(*sq_it).completed) { + sq_it--; + continue; + } + + // Store conditionals don't complete until *after* they have written + // back. If it's here and not yet sent to memory, then don't bother + // as it's not part of committed state. + if (inst->isDataPrefetch() || (*sq_it).committed) { + sq_it--; + continue; + } else if ((*sq_it).req->flags & LOCKED) { + sq_it--; + assert(!(*sq_it).canWB || + ((*sq_it).canWB && (*sq_it).req->flags & LOCKED)); + continue; + } + + assert((*sq_it).req); + assert(!(*sq_it).committed); + + MemReqPtr req = (*sq_it).req; + (*sq_it).committed = true; + + req->cmd = Write; + req->completionEvent = NULL; + req->time = curTick; + assert(!req->data); + req->data = new uint8_t[64]; + memcpy(req->data, (uint8_t *)&(*sq_it).data, req->size); + + DPRINTF(OzoneLSQ, "Switching out : Writing back store idx:%i PC:%#x " + "to Addr:%#x, data:%#x directly to memory [sn:%lli]\n", + inst->sqIdx,inst->readPC(), + req->paddr, *(req->data), + inst->seqNum); + + switch((*sq_it).size) { + case 1: + cpu->write(req, (uint8_t &)(*sq_it).data); + break; + case 2: + cpu->write(req, (uint16_t &)(*sq_it).data); + break; + case 4: + cpu->write(req, (uint32_t &)(*sq_it).data); + break; + case 8: + cpu->write(req, (uint64_t &)(*sq_it).data); + break; + default: + panic("Unexpected store size!\n"); + } + } + + // Clear the queue to free up resources + storeQueue.clear(); + loadQueue.clear(); + loads = stores = storesToWB = 0; +} + +template <class Impl> +void +OzoneLWLSQ<Impl>::takeOverFrom(ThreadContext *old_tc) +{ + // Clear out any old state. May be redundant if this is the first time + // the CPU is being used. + stalled = false; + isLoadBlocked = false; + loadBlockedHandled = false; + switchedOut = false; + + // Could do simple checks here to see if indices are on twice + while (!LQIndices.empty()) + LQIndices.pop(); + while (!SQIndices.empty()) + SQIndices.pop(); + + for (int i = 0; i < LQEntries * 2; i++) { + LQIndices.push(i); + SQIndices.push(i); + } + + usedPorts = 0; + + loadFaultInst = storeFaultInst = memDepViolator = NULL; + + blockedLoadSeqNum = 0; +} diff --git a/src/cpu/ozone/null_predictor.hh b/src/cpu/ozone/null_predictor.hh new file mode 100644 index 000000000..a98c89d69 --- /dev/null +++ b/src/cpu/ozone/null_predictor.hh @@ -0,0 +1,105 @@ +/* + * 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_OZONE_NULL_PREDICTOR_HH__ +#define __CPU_OZONE_NULL_PREDICTOR_HH__ + +#include "arch/isa_traits.hh" +#include "cpu/inst_seq.hh" + +template <class Impl> +class NullPredictor +{ + public: + typedef typename Impl::Params Params; + typedef typename Impl::DynInstPtr DynInstPtr; + + NullPredictor(Params *p) { } + + struct BPredInfo { + BPredInfo() + : PC(0), nextPC(0) + { } + + BPredInfo(const Addr &pc, const Addr &next_pc) + : PC(pc), nextPC(next_pc) + { } + + Addr PC; + Addr nextPC; + }; + + BPredInfo lookup(Addr &PC) { return BPredInfo(PC, PC+4); } + + void undo(BPredInfo &bp_info) { return; } + + /** + * Predicts whether or not the instruction is a taken branch, and the + * target of the branch if it is taken. + * @param inst The branch instruction. + * @param PC The predicted PC is passed back through this parameter. + * @param tid The thread id. + * @return Returns if the branch is taken or not. + */ + bool predict(DynInstPtr &inst, Addr &PC, unsigned tid) + { return false; } + + /** + * Tells the branch predictor to commit any updates until the given + * sequence number. + * @param done_sn The sequence number to commit any older updates up until. + * @param tid The thread id. + */ + void update(const InstSeqNum &done_sn, unsigned tid) { } + + /** + * Squashes all outstanding updates until a given sequence number. + * @param squashed_sn The sequence number to squash any younger updates up + * until. + * @param tid The thread id. + */ + void squash(const InstSeqNum &squashed_sn, unsigned tid) { } + + /** + * Squashes all outstanding updates until a given sequence number, and + * corrects that sn's update with the proper address and taken/not taken. + * @param squashed_sn The sequence number to squash any younger updates up + * until. + * @param corr_target The correct branch target. + * @param actually_taken The correct branch direction. + * @param tid The thread id. + */ + void squash(const InstSeqNum &squashed_sn, const Addr &corr_target, + bool actually_taken, unsigned tid) + { } + +}; + +#endif // __CPU_OZONE_NULL_PREDICTOR_HH__ diff --git a/src/cpu/ozone/ozone_impl.hh b/src/cpu/ozone/ozone_impl.hh new file mode 100644 index 000000000..e977d06a9 --- /dev/null +++ b/src/cpu/ozone/ozone_impl.hh @@ -0,0 +1,75 @@ +/* + * 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_OZONE_OZONE_IMPL_HH__ +#define __CPU_OZONE_OZONE_IMPL_HH__ + +#include "arch/alpha/isa_traits.hh" +#include "cpu/o3/bpred_unit.hh" +#include "cpu/ozone/front_end.hh" +#include "cpu/ozone/inst_queue.hh" +#include "cpu/ozone/lw_lsq.hh" +#include "cpu/ozone/lw_back_end.hh" +#include "cpu/ozone/null_predictor.hh" +#include "cpu/ozone/dyn_inst.hh" +#include "cpu/ozone/simple_params.hh" + +template <class Impl> +class OzoneCPU; + +template <class Impl> +class OzoneDynInst; + +struct OzoneImpl { + typedef SimpleParams Params; + typedef OzoneCPU<OzoneImpl> OzoneCPU; + typedef OzoneCPU FullCPU; + + // Would like to put these into their own area. +// typedef NullPredictor BranchPred; + typedef BPredUnit<OzoneImpl> BranchPred; + typedef FrontEnd<OzoneImpl> FrontEnd; + // Will need IQ, LSQ eventually + typedef LWBackEnd<OzoneImpl> BackEnd; + + typedef InstQueue<OzoneImpl> InstQueue; + typedef OzoneLWLSQ<OzoneImpl> LdstQueue; + + typedef OzoneDynInst<OzoneImpl> DynInst; + typedef RefCountingPtr<DynInst> DynInstPtr; + + typedef uint64_t IssueStruct; + + enum { + MaxThreads = 1 + }; +}; + +#endif // __CPU_OZONE_OZONE_IMPL_HH__ diff --git a/src/cpu/ozone/rename_table.cc b/src/cpu/ozone/rename_table.cc new file mode 100644 index 000000000..b0a36afbe --- /dev/null +++ b/src/cpu/ozone/rename_table.cc @@ -0,0 +1,36 @@ +/* + * 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 "cpu/ozone/rename_table_impl.hh" +#include "cpu/ozone/ozone_impl.hh" +#include "cpu/ozone/simple_impl.hh" + +template class RenameTable<OzoneImpl>; +template class RenameTable<SimpleImpl>; diff --git a/src/cpu/ozone/rename_table.hh b/src/cpu/ozone/rename_table.hh new file mode 100644 index 000000000..0b67d9635 --- /dev/null +++ b/src/cpu/ozone/rename_table.hh @@ -0,0 +1,55 @@ +/* + * 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_OZONE_RENAME_TABLE_HH__ +#define __CPU_OZONE_RENAME_TABLE_HH__ + +#include "arch/isa_traits.hh" + +/** Rename table that holds the rename of each architectural register to + * producing DynInst. Needs to support copying from one table to another. + */ + +template <class Impl> +class RenameTable { + public: + typedef typename Impl::DynInstPtr DynInstPtr; + + RenameTable(); + + void copyFrom(const RenameTable<Impl> &table_to_copy); + + DynInstPtr &operator [] (int index) + { return table[index]; } + + DynInstPtr table[TheISA::TotalNumRegs]; +}; + +#endif // __CPU_OZONE_RENAME_TABLE_HH__ diff --git a/src/cpu/ozone/rename_table_impl.hh b/src/cpu/ozone/rename_table_impl.hh new file mode 100644 index 000000000..67bab7337 --- /dev/null +++ b/src/cpu/ozone/rename_table_impl.hh @@ -0,0 +1,52 @@ +/* + * 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 <cstdlib> // Not really sure what to include to get NULL +#include "cpu/ozone/rename_table.hh" + +template <class Impl> +RenameTable<Impl>::RenameTable() +{ + // Actually should set these to dummy dyn insts that have the initial value + // and force their values to be initialized. This keeps everything the + // same. + for (int i = 0; i < TheISA::TotalNumRegs; ++i) { + table[i] = NULL; + } +} + +template <class Impl> +void +RenameTable<Impl>::copyFrom(const RenameTable<Impl> &table_to_copy) +{ + for (int i = 0; i < TheISA::TotalNumRegs; ++i) { + table[i] = table_to_copy.table[i]; + } +} diff --git a/src/cpu/ozone/simple_impl.hh b/src/cpu/ozone/simple_impl.hh new file mode 100644 index 000000000..3199d8d8a --- /dev/null +++ b/src/cpu/ozone/simple_impl.hh @@ -0,0 +1,71 @@ +/* + * 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_OZONE_SIMPLE_IMPL_HH__ +#define __CPU_OZONE_SIMPLE_IMPL_HH__ + +#include "arch/isa_traits.hh" +#include "cpu/o3/bpred_unit.hh" +#include "cpu/ozone/cpu.hh" +#include "cpu/ozone/front_end.hh" +#include "cpu/ozone/inorder_back_end.hh" +#include "cpu/ozone/null_predictor.hh" +#include "cpu/ozone/dyn_inst.hh" +#include "cpu/ozone/simple_params.hh" + +//template <class Impl> +//class OzoneCPU; + +template <class Impl> +class OzoneDynInst; + +struct SimpleImpl { + typedef SimpleParams Params; + typedef OzoneCPU<SimpleImpl> OzoneCPU; + typedef OzoneCPU FullCPU; + + // Would like to put these into their own area. +// typedef NullPredictor BranchPred; + typedef BPredUnit<SimpleImpl> BranchPred; + typedef FrontEnd<SimpleImpl> FrontEnd; + // Will need IQ, LSQ eventually + typedef InorderBackEnd<SimpleImpl> BackEnd; + + typedef OzoneDynInst<SimpleImpl> DynInst; + typedef RefCountingPtr<DynInst> DynInstPtr; + + typedef uint64_t IssueStruct; + + enum { + MaxThreads = 1 + }; +}; + +#endif // __CPU_OZONE_SIMPLE_IMPL_HH__ diff --git a/src/cpu/ozone/simple_params.hh b/src/cpu/ozone/simple_params.hh new file mode 100644 index 000000000..13eb05e77 --- /dev/null +++ b/src/cpu/ozone/simple_params.hh @@ -0,0 +1,193 @@ +/* + * 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_OZONE_SIMPLE_PARAMS_HH__ +#define __CPU_OZONE_SIMPLE_PARAMS_HH__ + +#include "cpu/ozone/cpu.hh" + +//Forward declarations +class AlphaDTB; +class AlphaITB; +class FUPool; +class FunctionalMemory; +class MemInterface; +class PageTable; +class Process; +class System; + +/** + * This file defines the parameters that will be used for the OzoneCPU. + * 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 SimpleParams : public BaseCPU::Params +{ + public: + +#if FULL_SYSTEM + AlphaITB *itb; AlphaDTB *dtb; +#else + std::vector<Process *> workload; +#endif // FULL_SYSTEM + + //Page Table + PageTable *pTable; + + FunctionalMemory *mem; + + // + // Caches + // + MemInterface *icacheInterface; + MemInterface *dcacheInterface; + + unsigned cachePorts; + unsigned width; + unsigned frontEndWidth; + unsigned backEndWidth; + unsigned backEndSquashLatency; + unsigned backEndLatency; + unsigned maxInstBufferSize; + unsigned numPhysicalRegs; + unsigned maxOutstandingMemOps; + // + // Fetch + // + unsigned decodeToFetchDelay; + unsigned renameToFetchDelay; + unsigned iewToFetchDelay; + unsigned commitToFetchDelay; + unsigned fetchWidth; + + // + // Decode + // + unsigned renameToDecodeDelay; + unsigned iewToDecodeDelay; + unsigned commitToDecodeDelay; + unsigned fetchToDecodeDelay; + unsigned decodeWidth; + + // + // Rename + // + unsigned iewToRenameDelay; + unsigned commitToRenameDelay; + unsigned decodeToRenameDelay; + unsigned renameWidth; + + // + // IEW + // + unsigned commitToIEWDelay; + unsigned renameToIEWDelay; + unsigned issueToExecuteDelay; + unsigned issueWidth; + unsigned executeWidth; + unsigned executeIntWidth; + unsigned executeFloatWidth; + unsigned executeBranchWidth; + unsigned executeMemoryWidth; + FUPool *fuPool; + + // + // Commit + // + unsigned iewToCommitDelay; + unsigned renameToROBDelay; + unsigned commitWidth; + unsigned squashWidth; + + // + // 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; + + // + // Load store queue + // + unsigned LQEntries; + unsigned SQEntries; + + // + // Memory dependence + // + unsigned SSITSize; + unsigned LFSTSize; + + // + // Miscellaneous + // + unsigned numPhysIntRegs; + unsigned numPhysFloatRegs; + unsigned numIQEntries; + unsigned numROBEntries; + + bool decoupledFrontEnd; + int dispatchWidth; + int wbWidth; + + //SMT Parameters + unsigned smtNumFetchingThreads; + + std::string smtFetchPolicy; + + std::string smtIQPolicy; + unsigned smtIQThreshold; + + std::string smtLSQPolicy; + unsigned smtLSQThreshold; + + std::string smtCommitPolicy; + + std::string smtROBPolicy; + unsigned smtROBThreshold; + + // Probably can get this from somewhere. + unsigned instShiftAmt; +}; + +#endif // __CPU_OZONE_SIMPLE_PARAMS_HH__ diff --git a/src/cpu/ozone/thread_state.hh b/src/cpu/ozone/thread_state.hh new file mode 100644 index 000000000..299878c29 --- /dev/null +++ b/src/cpu/ozone/thread_state.hh @@ -0,0 +1,169 @@ +/* + * 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_OZONE_THREAD_STATE_HH__ +#define __CPU_OZONE_THREAD_STATE_HH__ + +#include "arch/faults.hh" +#include "arch/isa_traits.hh" +#include "cpu/thread_context.hh" +#include "cpu/thread_state.hh" +#include "sim/process.hh" + +class Event; +//class Process; + +#if FULL_SYSTEM +class EndQuiesceEvent; +class FunctionProfile; +class ProfileNode; +#else +class Process; +class FunctionalMemory; +#endif + +// Maybe this ozone thread state should only really have committed state? +// I need to think about why I'm using this and what it's useful for. Clearly +// has benefits for SMT; basically serves same use as SimpleThread. +// Makes the ExecContext proxy easier. Gives organization/central access point +// to state of a thread that can be accessed normally (i.e. not in-flight +// stuff within a OoO processor). Does this need an TC proxy within it? +template <class Impl> +struct OzoneThreadState : public ThreadState { + typedef typename ThreadContext::Status Status; + typedef typename Impl::FullCPU FullCPU; + typedef TheISA::MiscReg MiscReg; + +#if FULL_SYSTEM + OzoneThreadState(FullCPU *_cpu, int _thread_num) + : ThreadState(-1, _thread_num), + inSyscall(0), trapPending(0) + { + memset(®s, 0, sizeof(TheISA::RegFile)); + } +#else + OzoneThreadState(FullCPU *_cpu, int _thread_num, Process *_process, int _asid) + : ThreadState(-1, _thread_num, NULL, _process, _asid), + cpu(_cpu), inSyscall(0), trapPending(0) + { + memset(®s, 0, sizeof(TheISA::RegFile)); + } + + OzoneThreadState(FullCPU *_cpu, int _thread_num, + int _asid) + : ThreadState(-1, _thread_num, NULL, NULL, _asid), + cpu(_cpu), inSyscall(0), trapPending(0) + { + memset(®s, 0, sizeof(TheISA::RegFile)); + } +#endif + + RenameTable<Impl> renameTable; + + Addr PC; + + Addr nextPC; + + TheISA::RegFile regs; + + typename Impl::FullCPU *cpu; + + bool inSyscall; + + bool trapPending; + + ThreadContext *tc; + + ThreadContext *getTC() { return tc; } + +#if !FULL_SYSTEM + Fault translateInstReq(Request *req) + { + return process->pTable->translate(req); + } + Fault translateDataReadReq(Request *req) + { + return process->pTable->translate(req); + } + Fault translateDataWriteReq(Request *req) + { + return process->pTable->translate(req); + } +#else + Fault translateInstReq(Request *req) + { + return cpu->itb->translate(req); + } + + Fault translateDataReadReq(Request *req) + { + return cpu->dtb->translate(req, false); + } + + Fault translateDataWriteReq(Request *req) + { + return cpu->dtb->translate(req, true); + } +#endif + + MiscReg readMiscReg(int misc_reg) + { + return regs.readMiscReg(misc_reg); + } + + MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) + { + return regs.readMiscRegWithEffect(misc_reg, fault, tc); + } + + Fault setMiscReg(int misc_reg, const MiscReg &val) + { + return regs.setMiscReg(misc_reg, val); + } + + Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) + { + return regs.setMiscRegWithEffect(misc_reg, val, tc); + } + + uint64_t readPC() + { return PC; } + + void setPC(uint64_t val) + { PC = val; } + + uint64_t readNextPC() + { return nextPC; } + + void setNextPC(uint64_t val) + { nextPC = val; } +}; + +#endif // __CPU_OZONE_THREAD_STATE_HH__ diff --git a/src/cpu/pc_event.cc b/src/cpu/pc_event.cc new file mode 100644 index 000000000..fca357fe3 --- /dev/null +++ b/src/cpu/pc_event.cc @@ -0,0 +1,158 @@ +/* + * 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 + * Steve Reinhardt + */ + +#include <algorithm> +#include <map> +#include <string> +#include <utility> + +#include "base/trace.hh" +#include "config/full_system.hh" +#include "cpu/base.hh" +#include "cpu/thread_context.hh" +#include "cpu/pc_event.hh" +#include "sim/debug.hh" +#include "sim/root.hh" +#include "sim/system.hh" + +using namespace std; + +PCEventQueue::PCEventQueue() +{} + +PCEventQueue::~PCEventQueue() +{} + +bool +PCEventQueue::remove(PCEvent *event) +{ + int removed = 0; + range_t range = equal_range(event); + for (iterator i = range.first; i != range.second; ++i) { + if (*i == event) { + DPRINTF(PCEvent, "PC based event removed at %#x: %s\n", + event->pc(), event->descr()); + pc_map.erase(i); + ++removed; + } + } + + return removed > 0; +} + +bool +PCEventQueue::schedule(PCEvent *event) +{ + pc_map.push_back(event); + sort(pc_map.begin(), pc_map.end(), MapCompare()); + + DPRINTF(PCEvent, "PC based event scheduled for %#x: %s\n", + event->pc(), event->descr()); + + return true; +} + +bool +PCEventQueue::doService(ThreadContext *tc) +{ + Addr pc = tc->readPC() & ~0x3; + int serviced = 0; + range_t range = equal_range(pc); + for (iterator i = range.first; i != range.second; ++i) { + // Make sure that the pc wasn't changed as the side effect of + // another event. This for example, prevents two invocations + // of the SkipFuncEvent. Maybe we should have separate PC + // event queues for each processor? + if (pc != (tc->readPC() & ~0x3)) + continue; + + DPRINTF(PCEvent, "PC based event serviced at %#x: %s\n", + (*i)->pc(), (*i)->descr()); + + (*i)->process(tc); + ++serviced; + } + + return serviced > 0; +} + +void +PCEventQueue::dump() const +{ + const_iterator i = pc_map.begin(); + const_iterator e = pc_map.end(); + + for (; i != e; ++i) + cprintf("%d: event at %#x: %s\n", curTick, (*i)->pc(), + (*i)->descr()); +} + +PCEventQueue::range_t +PCEventQueue::equal_range(Addr pc) +{ + return std::equal_range(pc_map.begin(), pc_map.end(), pc, MapCompare()); +} + +BreakPCEvent::BreakPCEvent(PCEventQueue *q, const std::string &desc, Addr addr, + bool del) + : PCEvent(q, desc, addr), remove(del) +{ +} + +void +BreakPCEvent::process(ThreadContext *tc) +{ + StringWrap name(tc->getCpuPtr()->name() + ".break_event"); + DPRINTFN("break event %s triggered\n", descr()); + debug_break(); + if (remove) + delete this; +} + +#if FULL_SYSTEM +extern "C" +void +sched_break_pc_sys(System *sys, Addr addr) +{ + new BreakPCEvent(&sys->pcEventQueue, "debug break", addr, true); +} + +extern "C" +void +sched_break_pc(Addr addr) +{ + for (vector<System *>::iterator sysi = System::systemList.begin(); + sysi != System::systemList.end(); ++sysi) { + sched_break_pc_sys(*sysi, addr); + } + +} +#endif diff --git a/src/cpu/pc_event.hh b/src/cpu/pc_event.hh new file mode 100644 index 000000000..6b048b2c2 --- /dev/null +++ b/src/cpu/pc_event.hh @@ -0,0 +1,143 @@ +/* + * 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 + * Steve Reinhardt + */ + +#ifndef __PC_EVENT_HH__ +#define __PC_EVENT_HH__ + +#include <vector> + +#include "base/misc.hh" + +class ThreadContext; +class PCEventQueue; + +class PCEvent +{ + protected: + std::string description; + PCEventQueue *queue; + Addr evpc; + + public: + PCEvent(PCEventQueue *q, const std::string &desc, Addr pc); + + virtual ~PCEvent() { if (queue) remove(); } + + // for DPRINTF + virtual const std::string name() const { return description; } + + std::string descr() const { return description; } + Addr pc() const { return evpc; } + + bool remove(); + virtual void process(ThreadContext *tc) = 0; +}; + +class PCEventQueue +{ + protected: + typedef PCEvent * record_t; + class MapCompare { + public: + bool operator()(const record_t &l, const record_t &r) const { + return l->pc() < r->pc(); + } + bool operator()(const record_t &l, Addr pc) const { + return l->pc() < pc; + } + bool operator()(Addr pc, const record_t &r) const { + return pc < r->pc(); + } + }; + typedef std::vector<record_t> map_t; + + public: + typedef map_t::iterator iterator; + typedef map_t::const_iterator const_iterator; + + protected: + typedef std::pair<iterator, iterator> range_t; + typedef std::pair<const_iterator, const_iterator> const_range_t; + + protected: + map_t pc_map; + + bool doService(ThreadContext *tc); + + public: + PCEventQueue(); + ~PCEventQueue(); + + bool remove(PCEvent *event); + bool schedule(PCEvent *event); + bool service(ThreadContext *tc) + { + if (pc_map.empty()) + return false; + + return doService(tc); + } + + range_t equal_range(Addr pc); + range_t equal_range(PCEvent *event) { return equal_range(event->pc()); } + + void dump() const; +}; + + +inline +PCEvent::PCEvent(PCEventQueue *q, const std::string &desc, Addr pc) + : description(desc), queue(q), evpc(pc) +{ + queue->schedule(this); +} + +inline bool +PCEvent::remove() +{ + if (!queue) + panic("cannot remove an uninitialized event;"); + + return queue->remove(this); +} + +class BreakPCEvent : public PCEvent +{ + protected: + bool remove; + + public: + BreakPCEvent(PCEventQueue *q, const std::string &desc, Addr addr, + bool del = false); + virtual void process(ThreadContext *tc); +}; + +#endif // __PC_EVENT_HH__ diff --git a/src/cpu/profile.cc b/src/cpu/profile.cc new file mode 100644 index 000000000..4f04615e9 --- /dev/null +++ b/src/cpu/profile.cc @@ -0,0 +1,157 @@ +/* + * Copyright (c) 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 + */ + +#include <string> + +#include "base/bitfield.hh" +#include "base/callback.hh" +#include "base/statistics.hh" +#include "base/trace.hh" +#include "base/loader/symtab.hh" +#include "cpu/base.hh" +#include "cpu/thread_context.hh" +#include "cpu/profile.hh" + +using namespace std; + +ProfileNode::ProfileNode() + : count(0) +{ } + +void +ProfileNode::dump(const string &symbol, uint64_t id, const SymbolTable *symtab, + ostream &os) const +{ + ccprintf(os, "%#x %s %d ", id, symbol, count); + ChildList::const_iterator i, end = children.end(); + for (i = children.begin(); i != end; ++i) { + const ProfileNode *node = i->second; + ccprintf(os, "%#x ", (intptr_t)node); + } + + ccprintf(os, "\n"); + + for (i = children.begin(); i != end; ++i) { + Addr addr = i->first; + string symbol; + if (addr == 1) + symbol = "user"; + else if (addr == 2) + symbol = "console"; + else if (addr == 3) + symbol = "unknown"; + else if (!symtab->findSymbol(addr, symbol)) + panic("could not find symbol for address %#x\n", addr); + + const ProfileNode *node = i->second; + node->dump(symbol, (intptr_t)node, symtab, os); + } +} + +void +ProfileNode::clear() +{ + count = 0; + ChildList::iterator i, end = children.end(); + for (i = children.begin(); i != end; ++i) + i->second->clear(); +} + +FunctionProfile::FunctionProfile(const SymbolTable *_symtab) + : reset(0), symtab(_symtab) +{ + reset = new MakeCallback<FunctionProfile, &FunctionProfile::clear>(this); + Stats::registerResetCallback(reset); +} + +FunctionProfile::~FunctionProfile() +{ + if (reset) + delete reset; +} + +ProfileNode * +FunctionProfile::consume(const vector<Addr> &stack) +{ + ProfileNode *current = ⊤ + for (int i = 0, size = stack.size(); i < size; ++i) { + ProfileNode *&ptr = current->children[stack[size - i - 1]]; + if (ptr == NULL) + ptr = new ProfileNode; + + current = ptr; + } + + return current; +} + +void +FunctionProfile::clear() +{ + top.clear(); + pc_count.clear(); +} + +void +FunctionProfile::dump(ThreadContext *tc, ostream &os) const +{ + ccprintf(os, ">>>PC data\n"); + map<Addr, Counter>::const_iterator i, end = pc_count.end(); + for (i = pc_count.begin(); i != end; ++i) { + Addr pc = i->first; + Counter count = i->second; + + std::string symbol; + if (pc == 1) + ccprintf(os, "user %d\n", count); + else if (symtab->findSymbol(pc, symbol) && !symbol.empty()) + ccprintf(os, "%s %d\n", symbol, count); + else + ccprintf(os, "%#x %d\n", pc, count); + } + + ccprintf(os, ">>>function data\n"); + top.dump("top", 0, symtab, os); +} + +void +FunctionProfile::sample(ProfileNode *node, Addr pc) +{ + node->count++; + + Addr symaddr; + if (symtab->findNearestAddr(pc, symaddr)) { + pc_count[symaddr]++; + } else { + // record PC even if we don't have a symbol to avoid + // silently biasing the histogram + pc_count[pc]++; + } +} diff --git a/src/cpu/profile.hh b/src/cpu/profile.hh new file mode 100644 index 000000000..7f9625241 --- /dev/null +++ b/src/cpu/profile.hh @@ -0,0 +1,91 @@ +/* + * Copyright (c) 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 + */ + +#ifndef __CPU_PROFILE_HH__ +#define __CPU_PROFILE_HH__ + +#include <map> + +#include "cpu/static_inst.hh" +#include "sim/host.hh" +#include "arch/stacktrace.hh" + +class ThreadContext; + +class ProfileNode +{ + private: + friend class FunctionProfile; + + typedef std::map<Addr, ProfileNode *> ChildList; + ChildList children; + + public: + Counter count; + + public: + ProfileNode(); + + void dump(const std::string &symbol, uint64_t id, + const SymbolTable *symtab, std::ostream &os) const; + void clear(); +}; + +class Callback; +class FunctionProfile +{ + private: + Callback *reset; + const SymbolTable *symtab; + ProfileNode top; + std::map<Addr, Counter> pc_count; + StackTrace trace; + + public: + FunctionProfile(const SymbolTable *symtab); + ~FunctionProfile(); + + ProfileNode *consume(ThreadContext *tc, StaticInstPtr inst); + ProfileNode *consume(const std::vector<Addr> &stack); + void clear(); + void dump(ThreadContext *tc, std::ostream &out) const; + void sample(ProfileNode *node, Addr pc); +}; + +inline ProfileNode * +FunctionProfile::consume(ThreadContext *tc, StaticInstPtr inst) +{ + if (!trace.trace(tc, inst)) + return NULL; + trace.dprintf(); + return consume(trace.getstack()); +} + +#endif // __CPU_PROFILE_HH__ diff --git a/src/cpu/quiesce_event.cc b/src/cpu/quiesce_event.cc new file mode 100644 index 000000000..8dd20db02 --- /dev/null +++ b/src/cpu/quiesce_event.cc @@ -0,0 +1,49 @@ +/* + * 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 "cpu/thread_context.hh" +#include "cpu/quiesce_event.hh" + +EndQuiesceEvent::EndQuiesceEvent(ThreadContext *_tc) + : Event(&mainEventQueue), tc(_tc) +{ +} + +void +EndQuiesceEvent::process() +{ + tc->activate(); +} + +const char* +EndQuiesceEvent::description() +{ + return "End Quiesce Event."; +} diff --git a/src/cpu/quiesce_event.hh b/src/cpu/quiesce_event.hh new file mode 100644 index 000000000..3de40f97e --- /dev/null +++ b/src/cpu/quiesce_event.hh @@ -0,0 +1,53 @@ +/* + * 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_QUIESCE_EVENT_HH__ +#define __CPU_QUIESCE_EVENT_HH__ + +#include "sim/eventq.hh" + +class ThreadContext; + +/** Event for timing out quiesce instruction */ +struct EndQuiesceEvent : public Event +{ + /** A pointer to the thread context that is quiesced */ + ThreadContext *tc; + + EndQuiesceEvent(ThreadContext *_tc); + + /** Event process to occur at interrupt*/ + virtual void process(); + + /** Event description */ + virtual const char *description(); +}; + +#endif // __CPU_QUIESCE_EVENT_HH__ diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc new file mode 100644 index 000000000..071193f02 --- /dev/null +++ b/src/cpu/simple/atomic.cc @@ -0,0 +1,530 @@ +/* + * 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: Steve Reinhardt + */ + +#include "arch/utility.hh" +#include "cpu/exetrace.hh" +#include "cpu/simple/atomic.hh" +#include "mem/packet_impl.hh" +#include "sim/builder.hh" + +using namespace std; +using namespace TheISA; + +AtomicSimpleCPU::TickEvent::TickEvent(AtomicSimpleCPU *c) + : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) +{ +} + + +void +AtomicSimpleCPU::TickEvent::process() +{ + cpu->tick(); +} + +const char * +AtomicSimpleCPU::TickEvent::description() +{ + return "AtomicSimpleCPU tick event"; +} + + +void +AtomicSimpleCPU::init() +{ + //Create Memory Ports (conect them up) + Port *mem_dport = mem->getPort(""); + dcachePort.setPeer(mem_dport); + mem_dport->setPeer(&dcachePort); + + Port *mem_iport = mem->getPort(""); + icachePort.setPeer(mem_iport); + mem_iport->setPeer(&icachePort); + + BaseCPU::init(); +#if FULL_SYSTEM + for (int i = 0; i < threadContexts.size(); ++i) { + ThreadContext *tc = threadContexts[i]; + + // initialize CPU, including PC + TheISA::initCPU(tc, tc->readCpuId()); + } +#endif +} + +bool +AtomicSimpleCPU::CpuPort::recvTiming(Packet *pkt) +{ + panic("AtomicSimpleCPU doesn't expect recvAtomic callback!"); + return true; +} + +Tick +AtomicSimpleCPU::CpuPort::recvAtomic(Packet *pkt) +{ + panic("AtomicSimpleCPU doesn't expect recvAtomic callback!"); + return curTick; +} + +void +AtomicSimpleCPU::CpuPort::recvFunctional(Packet *pkt) +{ + panic("AtomicSimpleCPU doesn't expect recvFunctional callback!"); +} + +void +AtomicSimpleCPU::CpuPort::recvStatusChange(Status status) +{ + if (status == RangeChange) + return; + + panic("AtomicSimpleCPU doesn't expect recvStatusChange callback!"); +} + +void +AtomicSimpleCPU::CpuPort::recvRetry() +{ + panic("AtomicSimpleCPU doesn't expect recvRetry callback!"); +} + + +AtomicSimpleCPU::AtomicSimpleCPU(Params *p) + : BaseSimpleCPU(p), tickEvent(this), + width(p->width), simulate_stalls(p->simulate_stalls), + icachePort(name() + "-iport", this), dcachePort(name() + "-iport", this) +{ + _status = Idle; + + // @todo fix me and get the real cpu id & thread number!!! + ifetch_req = new Request(); + ifetch_pkt = new Packet(ifetch_req, Packet::ReadReq, Packet::Broadcast); + ifetch_pkt->dataStatic(&inst); + + data_read_req = new Request(); + data_read_pkt = new Packet(data_read_req, Packet::ReadReq, + Packet::Broadcast); + data_read_pkt->dataStatic(&dataReg); + + data_write_req = new Request(); + data_write_pkt = new Packet(data_write_req, Packet::WriteReq, + Packet::Broadcast); +} + + +AtomicSimpleCPU::~AtomicSimpleCPU() +{ +} + +void +AtomicSimpleCPU::serialize(ostream &os) +{ + BaseSimpleCPU::serialize(os); + SERIALIZE_ENUM(_status); + nameOut(os, csprintf("%s.tickEvent", name())); + tickEvent.serialize(os); +} + +void +AtomicSimpleCPU::unserialize(Checkpoint *cp, const string §ion) +{ + BaseSimpleCPU::unserialize(cp, section); + UNSERIALIZE_ENUM(_status); + tickEvent.unserialize(cp, csprintf("%s.tickEvent", section)); +} + +void +AtomicSimpleCPU::switchOut(Sampler *s) +{ + sampler = s; + if (status() == Running) { + _status = SwitchedOut; + + tickEvent.squash(); + } + sampler->signalSwitched(); +} + + +void +AtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU) +{ + BaseCPU::takeOverFrom(oldCPU); + + assert(!tickEvent.scheduled()); + + // if any of this CPU's ThreadContexts are active, mark the CPU as + // running and schedule its tick event. + for (int i = 0; i < threadContexts.size(); ++i) { + ThreadContext *tc = threadContexts[i]; + if (tc->status() == ThreadContext::Active && _status != Running) { + _status = Running; + tickEvent.schedule(curTick); + break; + } + } +} + + +void +AtomicSimpleCPU::activateContext(int thread_num, int delay) +{ + assert(thread_num == 0); + assert(thread); + + assert(_status == Idle); + assert(!tickEvent.scheduled()); + + notIdleFraction++; + tickEvent.schedule(curTick + cycles(delay)); + _status = Running; +} + + +void +AtomicSimpleCPU::suspendContext(int thread_num) +{ + assert(thread_num == 0); + assert(thread); + + assert(_status == Running); + + // tick event may not be scheduled if this gets called from inside + // an instruction's execution, e.g. "quiesce" + if (tickEvent.scheduled()) + tickEvent.deschedule(); + + notIdleFraction--; + _status = Idle; +} + + +template <class T> +Fault +AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags) +{ + data_read_req->setVirt(0, addr, sizeof(T), flags, thread->readPC()); + + if (traceData) { + traceData->setAddr(addr); + } + + // translate to physical address + Fault fault = thread->translateDataReadReq(data_read_req); + + // Now do the access. + if (fault == NoFault) { + data_read_pkt->reinitFromRequest(); + + dcache_latency = dcachePort.sendAtomic(data_read_pkt); + dcache_access = true; + + assert(data_read_pkt->result == Packet::Success); + data = data_read_pkt->get<T>(); + + } + + // This will need a new way to tell if it has a dcache attached. + if (data_read_req->getFlags() & UNCACHEABLE) + recordEvent("Uncached Read"); + + return fault; +} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +template +Fault +AtomicSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); + +template +Fault +AtomicSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); + +template +Fault +AtomicSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); + +template +Fault +AtomicSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); + +#endif //DOXYGEN_SHOULD_SKIP_THIS + +template<> +Fault +AtomicSimpleCPU::read(Addr addr, double &data, unsigned flags) +{ + return read(addr, *(uint64_t*)&data, flags); +} + +template<> +Fault +AtomicSimpleCPU::read(Addr addr, float &data, unsigned flags) +{ + return read(addr, *(uint32_t*)&data, flags); +} + + +template<> +Fault +AtomicSimpleCPU::read(Addr addr, int32_t &data, unsigned flags) +{ + return read(addr, (uint32_t&)data, flags); +} + + +template <class T> +Fault +AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) +{ + data_write_req->setVirt(0, addr, sizeof(T), flags, thread->readPC()); + + if (traceData) { + traceData->setAddr(addr); + } + + // translate to physical address + Fault fault = thread->translateDataWriteReq(data_write_req); + + // Now do the access. + if (fault == NoFault) { + data = htog(data); + data_write_pkt->reinitFromRequest(); + data_write_pkt->dataStatic(&data); + + dcache_latency = dcachePort.sendAtomic(data_write_pkt); + dcache_access = true; + + assert(data_write_pkt->result == Packet::Success); + + if (res && data_write_req->getFlags() & LOCKED) { + *res = data_write_req->getScResult(); + } + } + + // This will need a new way to tell if it's hooked up to a cache or not. + if (data_write_req->getFlags() & UNCACHEABLE) + recordEvent("Uncached Write"); + + // If the write needs to have a fault on the access, consider calling + // changeStatus() and changing it to "bad addr write" or something. + return fault; +} + + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +template +Fault +AtomicSimpleCPU::write(uint64_t data, Addr addr, + unsigned flags, uint64_t *res); + +template +Fault +AtomicSimpleCPU::write(uint32_t data, Addr addr, + unsigned flags, uint64_t *res); + +template +Fault +AtomicSimpleCPU::write(uint16_t data, Addr addr, + unsigned flags, uint64_t *res); + +template +Fault +AtomicSimpleCPU::write(uint8_t data, Addr addr, + unsigned flags, uint64_t *res); + +#endif //DOXYGEN_SHOULD_SKIP_THIS + +template<> +Fault +AtomicSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) +{ + return write(*(uint64_t*)&data, addr, flags, res); +} + +template<> +Fault +AtomicSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) +{ + return write(*(uint32_t*)&data, addr, flags, res); +} + + +template<> +Fault +AtomicSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) +{ + return write((uint32_t)data, addr, flags, res); +} + + +void +AtomicSimpleCPU::tick() +{ + Tick latency = cycles(1); // instruction takes one cycle by default + + for (int i = 0; i < width; ++i) { + numCycles++; + + checkForInterrupts(); + + Fault fault = setupFetchRequest(ifetch_req); + + if (fault == NoFault) { + ifetch_pkt->reinitFromRequest(); + + Tick icache_latency = icachePort.sendAtomic(ifetch_pkt); + // ifetch_req is initialized to read the instruction directly + // into the CPU object's inst field. + + dcache_access = false; // assume no dcache access + preExecute(); + fault = curStaticInst->execute(this, traceData); + postExecute(); + + if (simulate_stalls) { + // This calculation assumes that the icache and dcache + // access latencies are always a multiple of the CPU's + // cycle time. If not, the next tick event may get + // scheduled at a non-integer multiple of the CPU + // cycle time. + Tick icache_stall = icache_latency - cycles(1); + Tick dcache_stall = + dcache_access ? dcache_latency - cycles(1) : 0; + latency += icache_stall + dcache_stall; + } + + } + + advancePC(fault); + } + + if (_status != Idle) + tickEvent.schedule(curTick + latency); +} + + +//////////////////////////////////////////////////////////////////////// +// +// AtomicSimpleCPU Simulation Object +// +BEGIN_DECLARE_SIM_OBJECT_PARAMS(AtomicSimpleCPU) + + Param<Counter> max_insts_any_thread; + Param<Counter> max_insts_all_threads; + Param<Counter> max_loads_any_thread; + Param<Counter> max_loads_all_threads; + SimObjectParam<MemObject *> mem; + +#if FULL_SYSTEM + SimObjectParam<AlphaITB *> itb; + SimObjectParam<AlphaDTB *> dtb; + SimObjectParam<System *> system; + Param<int> cpu_id; + Param<Tick> profile; +#else + SimObjectParam<Process *> workload; +#endif // FULL_SYSTEM + + Param<int> clock; + + Param<bool> defer_registration; + Param<int> width; + Param<bool> function_trace; + Param<Tick> function_trace_start; + Param<bool> simulate_stalls; + +END_DECLARE_SIM_OBJECT_PARAMS(AtomicSimpleCPU) + +BEGIN_INIT_SIM_OBJECT_PARAMS(AtomicSimpleCPU) + + INIT_PARAM(max_insts_any_thread, + "terminate when any thread reaches this inst count"), + INIT_PARAM(max_insts_all_threads, + "terminate when all threads have reached this inst count"), + INIT_PARAM(max_loads_any_thread, + "terminate when any thread reaches this load count"), + INIT_PARAM(max_loads_all_threads, + "terminate when all threads have reached this load count"), + INIT_PARAM(mem, "memory"), + +#if FULL_SYSTEM + INIT_PARAM(itb, "Instruction TLB"), + INIT_PARAM(dtb, "Data TLB"), + INIT_PARAM(system, "system object"), + INIT_PARAM(cpu_id, "processor ID"), + INIT_PARAM(profile, ""), +#else + INIT_PARAM(workload, "processes to run"), +#endif // FULL_SYSTEM + + INIT_PARAM(clock, "clock speed"), + INIT_PARAM(defer_registration, "defer system registration (for sampling)"), + INIT_PARAM(width, "cpu width"), + INIT_PARAM(function_trace, "Enable function trace"), + INIT_PARAM(function_trace_start, "Cycle to start function trace"), + INIT_PARAM(simulate_stalls, "Simulate cache stall cycles") + +END_INIT_SIM_OBJECT_PARAMS(AtomicSimpleCPU) + + +CREATE_SIM_OBJECT(AtomicSimpleCPU) +{ + AtomicSimpleCPU::Params *params = new AtomicSimpleCPU::Params(); + params->name = getInstanceName(); + params->numberOfThreads = 1; + params->max_insts_any_thread = max_insts_any_thread; + params->max_insts_all_threads = max_insts_all_threads; + params->max_loads_any_thread = max_loads_any_thread; + params->max_loads_all_threads = max_loads_all_threads; + params->deferRegistration = defer_registration; + params->clock = clock; + params->functionTrace = function_trace; + params->functionTraceStart = function_trace_start; + params->width = width; + params->simulate_stalls = simulate_stalls; + params->mem = mem; + +#if FULL_SYSTEM + params->itb = itb; + params->dtb = dtb; + params->system = system; + params->cpu_id = cpu_id; + params->profile = profile; +#else + params->process = workload; +#endif + + AtomicSimpleCPU *cpu = new AtomicSimpleCPU(params); + return cpu; +} + +REGISTER_SIM_OBJECT("AtomicSimpleCPU", AtomicSimpleCPU) + diff --git a/src/cpu/simple/atomic.hh b/src/cpu/simple/atomic.hh new file mode 100644 index 000000000..7f4956da9 --- /dev/null +++ b/src/cpu/simple/atomic.hh @@ -0,0 +1,141 @@ +/* + * 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: Steve Reinhardt + */ + +#ifndef __CPU_SIMPLE_ATOMIC_HH__ +#define __CPU_SIMPLE_ATOMIC_HH__ + +#include "cpu/simple/base.hh" + +class AtomicSimpleCPU : public BaseSimpleCPU +{ + public: + + struct Params : public BaseSimpleCPU::Params { + int width; + bool simulate_stalls; + }; + + AtomicSimpleCPU(Params *params); + virtual ~AtomicSimpleCPU(); + + virtual void init(); + + public: + // + enum Status { + Running, + Idle, + SwitchedOut + }; + + protected: + Status _status; + + Status status() const { return _status; } + + private: + + struct TickEvent : public Event + { + AtomicSimpleCPU *cpu; + + TickEvent(AtomicSimpleCPU *c); + void process(); + const char *description(); + }; + + TickEvent tickEvent; + + const int width; + const bool simulate_stalls; + + // main simulation loop (one cycle) + void tick(); + + class CpuPort : public Port + { + + AtomicSimpleCPU *cpu; + + public: + + CpuPort(const std::string &_name, AtomicSimpleCPU *_cpu) + : Port(_name), cpu(_cpu) + { } + + protected: + + virtual bool recvTiming(Packet *pkt); + + virtual Tick recvAtomic(Packet *pkt); + + virtual void recvFunctional(Packet *pkt); + + virtual void recvStatusChange(Status status); + + virtual void recvRetry(); + + virtual void getDeviceAddressRanges(AddrRangeList &resp, + AddrRangeList &snoop) + { resp.clear(); snoop.clear(); } + }; + + CpuPort icachePort; + CpuPort dcachePort; + + Request *ifetch_req; + Packet *ifetch_pkt; + Request *data_read_req; + Packet *data_read_pkt; + Request *data_write_req; + Packet *data_write_pkt; + + bool dcache_access; + Tick dcache_latency; + + public: + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + + void switchOut(Sampler *s); + void takeOverFrom(BaseCPU *oldCPU); + + virtual void activateContext(int thread_num, int delay); + virtual void suspendContext(int thread_num); + + template <class T> + Fault read(Addr addr, T &data, unsigned flags); + + template <class T> + Fault write(T data, Addr addr, unsigned flags, uint64_t *res); +}; + +#endif // __CPU_SIMPLE_ATOMIC_HH__ diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc new file mode 100644 index 000000000..d94b0e079 --- /dev/null +++ b/src/cpu/simple/base.cc @@ -0,0 +1,469 @@ +/* + * 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: Steve Reinhardt + */ + +#include "arch/utility.hh" +#include "base/cprintf.hh" +#include "base/inifile.hh" +#include "base/loader/symtab.hh" +#include "base/misc.hh" +#include "base/pollevent.hh" +#include "base/range.hh" +#include "base/stats/events.hh" +#include "base/trace.hh" +#include "cpu/base.hh" +#include "cpu/exetrace.hh" +#include "cpu/profile.hh" +#include "cpu/sampler/sampler.hh" +#include "cpu/simple/base.hh" +#include "cpu/simple_thread.hh" +#include "cpu/smt.hh" +#include "cpu/static_inst.hh" +#include "cpu/thread_context.hh" +#include "kern/kernel_stats.hh" +#include "mem/packet_impl.hh" +#include "sim/builder.hh" +#include "sim/byteswap.hh" +#include "sim/debug.hh" +#include "sim/host.hh" +#include "sim/sim_events.hh" +#include "sim/sim_object.hh" +#include "sim/stats.hh" + +#if FULL_SYSTEM +#include "base/remote_gdb.hh" +#include "sim/system.hh" +#include "arch/tlb.hh" +#include "arch/stacktrace.hh" +#include "arch/vtophys.hh" +#else // !FULL_SYSTEM +#include "mem/mem_object.hh" +#endif // FULL_SYSTEM + +using namespace std; +using namespace TheISA; + +BaseSimpleCPU::BaseSimpleCPU(Params *p) + : BaseCPU(p), mem(p->mem), thread(NULL) +{ +#if FULL_SYSTEM + thread = new SimpleThread(this, 0, p->system, p->itb, p->dtb); +#else + thread = new SimpleThread(this, /* thread_num */ 0, p->process, + /* asid */ 0, mem); +#endif // !FULL_SYSTEM + + thread->setStatus(ThreadContext::Suspended); + + tc = thread->getTC(); + + numInst = 0; + startNumInst = 0; + numLoad = 0; + startNumLoad = 0; + lastIcacheStall = 0; + lastDcacheStall = 0; + + threadContexts.push_back(tc); +} + +BaseSimpleCPU::~BaseSimpleCPU() +{ +} + +void +BaseSimpleCPU::deallocateContext(int thread_num) +{ + // for now, these are equivalent + suspendContext(thread_num); +} + + +void +BaseSimpleCPU::haltContext(int thread_num) +{ + // for now, these are equivalent + suspendContext(thread_num); +} + + +void +BaseSimpleCPU::regStats() +{ + using namespace Stats; + + BaseCPU::regStats(); + + numInsts + .name(name() + ".num_insts") + .desc("Number of instructions executed") + ; + + numMemRefs + .name(name() + ".num_refs") + .desc("Number of memory references") + ; + + notIdleFraction + .name(name() + ".not_idle_fraction") + .desc("Percentage of non-idle cycles") + ; + + idleFraction + .name(name() + ".idle_fraction") + .desc("Percentage of idle cycles") + ; + + icacheStallCycles + .name(name() + ".icache_stall_cycles") + .desc("ICache total stall cycles") + .prereq(icacheStallCycles) + ; + + dcacheStallCycles + .name(name() + ".dcache_stall_cycles") + .desc("DCache total stall cycles") + .prereq(dcacheStallCycles) + ; + + icacheRetryCycles + .name(name() + ".icache_retry_cycles") + .desc("ICache total retry cycles") + .prereq(icacheRetryCycles) + ; + + dcacheRetryCycles + .name(name() + ".dcache_retry_cycles") + .desc("DCache total retry cycles") + .prereq(dcacheRetryCycles) + ; + + idleFraction = constant(1.0) - notIdleFraction; +} + +void +BaseSimpleCPU::resetStats() +{ + startNumInst = numInst; + // notIdleFraction = (_status != Idle); +} + +void +BaseSimpleCPU::serialize(ostream &os) +{ + BaseCPU::serialize(os); + SERIALIZE_SCALAR(inst); + nameOut(os, csprintf("%s.xc", name())); + thread->serialize(os); +} + +void +BaseSimpleCPU::unserialize(Checkpoint *cp, const string §ion) +{ + BaseCPU::unserialize(cp, section); + UNSERIALIZE_SCALAR(inst); + thread->unserialize(cp, csprintf("%s.xc", section)); +} + +void +change_thread_state(int thread_number, int activate, int priority) +{ +} + +Fault +BaseSimpleCPU::copySrcTranslate(Addr src) +{ +#if 0 + static bool no_warn = true; + int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; + // Only support block sizes of 64 atm. + assert(blk_size == 64); + int offset = src & (blk_size - 1); + + // Make sure block doesn't span page + if (no_warn && + (src & PageMask) != ((src + blk_size) & PageMask) && + (src >> 40) != 0xfffffc) { + warn("Copied block source spans pages %x.", src); + no_warn = false; + } + + memReq->reset(src & ~(blk_size - 1), blk_size); + + // translate to physical address + Fault fault = thread->translateDataReadReq(req); + + if (fault == NoFault) { + thread->copySrcAddr = src; + thread->copySrcPhysAddr = memReq->paddr + offset; + } else { + assert(!fault->isAlignmentFault()); + + thread->copySrcAddr = 0; + thread->copySrcPhysAddr = 0; + } + return fault; +#else + return NoFault; +#endif +} + +Fault +BaseSimpleCPU::copy(Addr dest) +{ +#if 0 + static bool no_warn = true; + int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64; + // Only support block sizes of 64 atm. + assert(blk_size == 64); + uint8_t data[blk_size]; + //assert(thread->copySrcAddr); + int offset = dest & (blk_size - 1); + + // Make sure block doesn't span page + if (no_warn && + (dest & PageMask) != ((dest + blk_size) & PageMask) && + (dest >> 40) != 0xfffffc) { + no_warn = false; + warn("Copied block destination spans pages %x. ", dest); + } + + memReq->reset(dest & ~(blk_size -1), blk_size); + // translate to physical address + Fault fault = thread->translateDataWriteReq(req); + + if (fault == NoFault) { + Addr dest_addr = memReq->paddr + offset; + // Need to read straight from memory since we have more than 8 bytes. + memReq->paddr = thread->copySrcPhysAddr; + thread->mem->read(memReq, data); + memReq->paddr = dest_addr; + thread->mem->write(memReq, data); + if (dcacheInterface) { + memReq->cmd = Copy; + memReq->completionEvent = NULL; + memReq->paddr = thread->copySrcPhysAddr; + memReq->dest = dest_addr; + memReq->size = 64; + memReq->time = curTick; + memReq->flags &= ~INST_READ; + dcacheInterface->access(memReq); + } + } + else + assert(!fault->isAlignmentFault()); + + return fault; +#else + panic("copy not implemented"); + return NoFault; +#endif +} + +#if FULL_SYSTEM +Addr +BaseSimpleCPU::dbg_vtophys(Addr addr) +{ + return vtophys(tc, addr); +} +#endif // FULL_SYSTEM + +#if FULL_SYSTEM +void +BaseSimpleCPU::post_interrupt(int int_num, int index) +{ + BaseCPU::post_interrupt(int_num, index); + + if (thread->status() == ThreadContext::Suspended) { + DPRINTF(IPI,"Suspended Processor awoke\n"); + thread->activate(); + } +} +#endif // FULL_SYSTEM + +void +BaseSimpleCPU::checkForInterrupts() +{ +#if FULL_SYSTEM + if (checkInterrupts && check_interrupts() && !thread->inPalMode()) { + int ipl = 0; + int summary = 0; + checkInterrupts = false; + + if (thread->readMiscReg(IPR_SIRR)) { + for (int i = INTLEVEL_SOFTWARE_MIN; + i < INTLEVEL_SOFTWARE_MAX; i++) { + if (thread->readMiscReg(IPR_SIRR) & (ULL(1) << i)) { + // See table 4-19 of 21164 hardware reference + ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1; + summary |= (ULL(1) << i); + } + } + } + + uint64_t interrupts = thread->cpu->intr_status(); + for (int i = INTLEVEL_EXTERNAL_MIN; + i < INTLEVEL_EXTERNAL_MAX; i++) { + if (interrupts & (ULL(1) << i)) { + // See table 4-19 of 21164 hardware reference + ipl = i; + summary |= (ULL(1) << i); + } + } + + if (thread->readMiscReg(IPR_ASTRR)) + panic("asynchronous traps not implemented\n"); + + if (ipl && ipl > thread->readMiscReg(IPR_IPLR)) { + thread->setMiscReg(IPR_ISR, summary); + thread->setMiscReg(IPR_INTID, ipl); + + Fault(new InterruptFault)->invoke(tc); + + DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n", + thread->readMiscReg(IPR_IPLR), ipl, summary); + } + } +#endif +} + + +Fault +BaseSimpleCPU::setupFetchRequest(Request *req) +{ + // set up memory request for instruction fetch + DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p NNPC:%08p\n",thread->readPC(), + thread->readNextPC(),thread->readNextNPC()); + + req->setVirt(0, thread->readPC() & ~3, sizeof(MachInst), + (FULL_SYSTEM && (thread->readPC() & 1)) ? PHYSICAL : 0, + thread->readPC()); + + Fault fault = thread->translateInstReq(req); + + return fault; +} + + +void +BaseSimpleCPU::preExecute() +{ + // maintain $r0 semantics + thread->setIntReg(ZeroReg, 0); +#if THE_ISA == ALPHA_ISA + thread->setFloatReg(ZeroReg, 0.0); +#endif // ALPHA_ISA + + // keep an instruction count + numInst++; + numInsts++; + + thread->funcExeInst++; + + // check for instruction-count-based events + comInstEventQueue[0]->serviceEvents(numInst); + + // decode the instruction + inst = gtoh(inst); + curStaticInst = StaticInst::decode(makeExtMI(inst, thread->readPC())); + + traceData = Trace::getInstRecord(curTick, tc, this, curStaticInst, + thread->readPC()); + + DPRINTF(Decode,"Decode: Decoded %s instruction (opcode: 0x%x): 0x%x\n", + curStaticInst->getName(), curStaticInst->getOpcode(), + curStaticInst->machInst); + +#if FULL_SYSTEM + thread->setInst(inst); +#endif // FULL_SYSTEM +} + +void +BaseSimpleCPU::postExecute() +{ +#if FULL_SYSTEM + if (thread->profile) { + bool usermode = + (thread->readMiscReg(AlphaISA::IPR_DTB_CM) & 0x18) != 0; + thread->profilePC = usermode ? 1 : thread->readPC(); + ProfileNode *node = thread->profile->consume(tc, inst); + if (node) + thread->profileNode = node; + } +#endif + + if (curStaticInst->isMemRef()) { + numMemRefs++; + } + + if (curStaticInst->isLoad()) { + ++numLoad; + comLoadEventQueue[0]->serviceEvents(numLoad); + } + + traceFunctions(thread->readPC()); + + if (traceData) { + traceData->finalize(); + } +} + + +void +BaseSimpleCPU::advancePC(Fault fault) +{ + if (fault != NoFault) { +#if FULL_SYSTEM + fault->invoke(tc); +#else // !FULL_SYSTEM + fatal("fault (%s) detected @ PC %08p", fault->name(), thread->readPC()); +#endif // FULL_SYSTEM + } + else { + // go to the next instruction + thread->setPC(thread->readNextPC()); +#if THE_ISA == ALPHA_ISA + thread->setNextPC(thread->readNextPC() + sizeof(MachInst)); +#else + thread->setNextPC(thread->readNextNPC()); + thread->setNextNPC(thread->readNextNPC() + sizeof(MachInst)); +#endif + + } + +#if FULL_SYSTEM + Addr oldpc; + do { + oldpc = thread->readPC(); + system->pcEventQueue.service(tc); + } while (oldpc != thread->readPC()); +#endif +} + diff --git a/src/cpu/simple/base.hh b/src/cpu/simple/base.hh new file mode 100644 index 000000000..39bc86050 --- /dev/null +++ b/src/cpu/simple/base.hh @@ -0,0 +1,323 @@ +/* + * 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: Steve Reinhardt + * Dave Greene + * Nathan Binkert + */ + +#ifndef __CPU_SIMPLE_BASE_HH__ +#define __CPU_SIMPLE_BASE_HH__ + +#include "base/statistics.hh" +#include "config/full_system.hh" +#include "cpu/base.hh" +#include "cpu/simple_thread.hh" +#include "cpu/pc_event.hh" +#include "cpu/sampler/sampler.hh" +#include "cpu/static_inst.hh" +#include "mem/packet.hh" +#include "mem/port.hh" +#include "mem/request.hh" +#include "sim/eventq.hh" + +// forward declarations +#if FULL_SYSTEM +class Processor; +class AlphaITB; +class AlphaDTB; +class MemObject; + +class RemoteGDB; +class GDBListener; + +#else + +class Process; + +#endif // FULL_SYSTEM + +class ThreadContext; +class Checkpoint; + +namespace Trace { + class InstRecord; +} + + +class BaseSimpleCPU : public BaseCPU +{ + protected: + typedef TheISA::MachInst MachInst; + typedef TheISA::MiscReg MiscReg; + typedef TheISA::FloatReg FloatReg; + typedef TheISA::FloatRegBits FloatRegBits; + + MemObject *mem; + + protected: + Trace::InstRecord *traceData; + + public: + void post_interrupt(int int_num, int index); + + void zero_fill_64(Addr addr) { + static int warned = 0; + if (!warned) { + warn ("WH64 is not implemented"); + warned = 1; + } + }; + + public: + struct Params : public BaseCPU::Params + { + MemObject *mem; +#if FULL_SYSTEM + AlphaITB *itb; + AlphaDTB *dtb; +#else + Process *process; +#endif + }; + BaseSimpleCPU(Params *params); + virtual ~BaseSimpleCPU(); + + public: + /** SimpleThread object, provides all the architectural state. */ + SimpleThread *thread; + + /** ThreadContext object, provides an interface for external + * objects to modify this thread's state. + */ + ThreadContext *tc; + +#if FULL_SYSTEM + Addr dbg_vtophys(Addr addr); + + bool interval_stats; +#endif + + // current instruction + MachInst inst; + + // Static data storage + TheISA::IntReg dataReg; + + // Pointer to the sampler that is telling us to switchover. + // Used to signal the completion of the pipe drain and schedule + // the next switchover + Sampler *sampler; + + StaticInstPtr curStaticInst; + + void checkForInterrupts(); + Fault setupFetchRequest(Request *req); + void preExecute(); + void postExecute(); + void advancePC(Fault fault); + + virtual void deallocateContext(int thread_num); + virtual void haltContext(int thread_num); + + // statistics + virtual void regStats(); + virtual void resetStats(); + + // number of simulated instructions + Counter numInst; + Counter startNumInst; + Stats::Scalar<> numInsts; + + virtual Counter totalInstructions() const + { + return numInst - startNumInst; + } + + // number of simulated memory references + Stats::Scalar<> numMemRefs; + + // number of simulated loads + Counter numLoad; + Counter startNumLoad; + + // number of idle cycles + Stats::Average<> notIdleFraction; + Stats::Formula idleFraction; + + // number of cycles stalled for I-cache responses + Stats::Scalar<> icacheStallCycles; + Counter lastIcacheStall; + + // number of cycles stalled for I-cache retries + Stats::Scalar<> icacheRetryCycles; + Counter lastIcacheRetry; + + // number of cycles stalled for D-cache responses + Stats::Scalar<> dcacheStallCycles; + Counter lastDcacheStall; + + // number of cycles stalled for D-cache retries + Stats::Scalar<> dcacheRetryCycles; + Counter lastDcacheRetry; + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + + // These functions are only used in CPU models that split + // effective address computation from the actual memory access. + void setEA(Addr EA) { panic("BaseSimpleCPU::setEA() not implemented\n"); } + Addr getEA() { panic("BaseSimpleCPU::getEA() not implemented\n"); } + + void prefetch(Addr addr, unsigned flags) + { + // need to do this... + } + + void writeHint(Addr addr, int size, unsigned flags) + { + // need to do this... + } + + Fault copySrcTranslate(Addr src); + + Fault copy(Addr dest); + + // 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 readIntReg(const StaticInst *si, int idx) + { + return thread->readIntReg(si->srcRegIdx(idx)); + } + + FloatReg readFloatReg(const StaticInst *si, int idx, int width) + { + int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag; + return thread->readFloatReg(reg_idx, width); + } + + FloatReg readFloatReg(const StaticInst *si, int idx) + { + int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag; + return thread->readFloatReg(reg_idx); + } + + FloatRegBits readFloatRegBits(const StaticInst *si, int idx, int width) + { + int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag; + return thread->readFloatRegBits(reg_idx, width); + } + + FloatRegBits readFloatRegBits(const StaticInst *si, int idx) + { + int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag; + return thread->readFloatRegBits(reg_idx); + } + + void setIntReg(const StaticInst *si, int idx, uint64_t val) + { + thread->setIntReg(si->destRegIdx(idx), val); + } + + void setFloatReg(const StaticInst *si, int idx, FloatReg val, int width) + { + int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag; + thread->setFloatReg(reg_idx, val, width); + } + + void setFloatReg(const StaticInst *si, int idx, FloatReg val) + { + int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag; + thread->setFloatReg(reg_idx, val); + } + + void setFloatRegBits(const StaticInst *si, int idx, + FloatRegBits val, int width) + { + int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag; + thread->setFloatRegBits(reg_idx, val, width); + } + + void setFloatRegBits(const StaticInst *si, int idx, FloatRegBits val) + { + int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag; + thread->setFloatRegBits(reg_idx, val); + } + + uint64_t readPC() { return thread->readPC(); } + uint64_t readNextPC() { return thread->readNextPC(); } + uint64_t readNextNPC() { return thread->readNextNPC(); } + + void setPC(uint64_t val) { thread->setPC(val); } + void setNextPC(uint64_t val) { thread->setNextPC(val); } + void setNextNPC(uint64_t val) { thread->setNextNPC(val); } + + MiscReg readMiscReg(int misc_reg) + { + return thread->readMiscReg(misc_reg); + } + + MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) + { + return thread->readMiscRegWithEffect(misc_reg, fault); + } + + Fault setMiscReg(int misc_reg, const MiscReg &val) + { + return thread->setMiscReg(misc_reg, val); + } + + Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) + { + return thread->setMiscRegWithEffect(misc_reg, val); + } + +#if FULL_SYSTEM + Fault hwrei() { return thread->hwrei(); } + int readIntrFlag() { return thread->readIntrFlag(); } + void setIntrFlag(int val) { thread->setIntrFlag(val); } + bool inPalMode() { return thread->inPalMode(); } + void ev5_trap(Fault fault) { fault->invoke(tc); } + bool simPalCheck(int palFunc) { return thread->simPalCheck(palFunc); } +#else + void syscall(int64_t callnum) { thread->syscall(callnum); } +#endif + + bool misspeculating() { return thread->misspeculating(); } + ThreadContext *tcBase() { return tc; } +}; + +#endif // __CPU_SIMPLE_BASE_HH__ diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc new file mode 100644 index 000000000..c99db8fbf --- /dev/null +++ b/src/cpu/simple/timing.cc @@ -0,0 +1,570 @@ +/* + * 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: Steve Reinhardt + */ + +#include "arch/utility.hh" +#include "cpu/exetrace.hh" +#include "cpu/simple/timing.hh" +#include "mem/packet_impl.hh" +#include "sim/builder.hh" + +using namespace std; +using namespace TheISA; + + +void +TimingSimpleCPU::init() +{ + //Create Memory Ports (conect them up) + Port *mem_dport = mem->getPort(""); + dcachePort.setPeer(mem_dport); + mem_dport->setPeer(&dcachePort); + + Port *mem_iport = mem->getPort(""); + icachePort.setPeer(mem_iport); + mem_iport->setPeer(&icachePort); + + BaseCPU::init(); +#if FULL_SYSTEM + for (int i = 0; i < threadContexts.size(); ++i) { + ThreadContext *tc = threadContexts[i]; + + // initialize CPU, including PC + TheISA::initCPU(tc, tc->readCpuId()); + } +#endif +} + +Tick +TimingSimpleCPU::CpuPort::recvAtomic(Packet *pkt) +{ + panic("TimingSimpleCPU doesn't expect recvAtomic callback!"); + return curTick; +} + +void +TimingSimpleCPU::CpuPort::recvFunctional(Packet *pkt) +{ + panic("TimingSimpleCPU doesn't expect recvFunctional callback!"); +} + +void +TimingSimpleCPU::CpuPort::recvStatusChange(Status status) +{ + if (status == RangeChange) + return; + + panic("TimingSimpleCPU doesn't expect recvStatusChange callback!"); +} + +TimingSimpleCPU::TimingSimpleCPU(Params *p) + : BaseSimpleCPU(p), icachePort(this), dcachePort(this) +{ + _status = Idle; + ifetch_pkt = dcache_pkt = NULL; +} + + +TimingSimpleCPU::~TimingSimpleCPU() +{ +} + +void +TimingSimpleCPU::serialize(ostream &os) +{ + BaseSimpleCPU::serialize(os); + SERIALIZE_ENUM(_status); +} + +void +TimingSimpleCPU::unserialize(Checkpoint *cp, const string §ion) +{ + BaseSimpleCPU::unserialize(cp, section); + UNSERIALIZE_ENUM(_status); +} + +void +TimingSimpleCPU::switchOut(Sampler *s) +{ + sampler = s; + if (status() == Running) { + _status = SwitchedOut; + } + sampler->signalSwitched(); +} + + +void +TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU) +{ + BaseCPU::takeOverFrom(oldCPU); + + // if any of this CPU's ThreadContexts are active, mark the CPU as + // running and schedule its tick event. + for (int i = 0; i < threadContexts.size(); ++i) { + ThreadContext *tc = threadContexts[i]; + if (tc->status() == ThreadContext::Active && _status != Running) { + _status = Running; + break; + } + } +} + + +void +TimingSimpleCPU::activateContext(int thread_num, int delay) +{ + assert(thread_num == 0); + assert(thread); + + assert(_status == Idle); + + notIdleFraction++; + _status = Running; + // kick things off by initiating the fetch of the next instruction + Event *e = + new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, true); + e->schedule(curTick + cycles(delay)); +} + + +void +TimingSimpleCPU::suspendContext(int thread_num) +{ + assert(thread_num == 0); + assert(thread); + + assert(_status == Running); + + // just change status to Idle... if status != Running, + // completeInst() will not initiate fetch of next instruction. + + notIdleFraction--; + _status = Idle; +} + + +template <class T> +Fault +TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) +{ + // need to fill in CPU & thread IDs here + Request *data_read_req = new Request(); + + data_read_req->setVirt(0, addr, sizeof(T), flags, thread->readPC()); + + if (traceData) { + traceData->setAddr(data_read_req->getVaddr()); + } + + // translate to physical address + Fault fault = thread->translateDataReadReq(data_read_req); + + // Now do the access. + if (fault == NoFault) { + Packet *data_read_pkt = + new Packet(data_read_req, Packet::ReadReq, Packet::Broadcast); + data_read_pkt->dataDynamic<T>(new T); + + if (!dcachePort.sendTiming(data_read_pkt)) { + _status = DcacheRetry; + dcache_pkt = data_read_pkt; + } else { + _status = DcacheWaitResponse; + dcache_pkt = NULL; + } + } + + // This will need a new way to tell if it has a dcache attached. + if (data_read_req->getFlags() & UNCACHEABLE) + recordEvent("Uncached Read"); + + return fault; +} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +template +Fault +TimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags); + +template +Fault +TimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags); + +template +Fault +TimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags); + +template +Fault +TimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags); + +#endif //DOXYGEN_SHOULD_SKIP_THIS + +template<> +Fault +TimingSimpleCPU::read(Addr addr, double &data, unsigned flags) +{ + return read(addr, *(uint64_t*)&data, flags); +} + +template<> +Fault +TimingSimpleCPU::read(Addr addr, float &data, unsigned flags) +{ + return read(addr, *(uint32_t*)&data, flags); +} + + +template<> +Fault +TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags) +{ + return read(addr, (uint32_t&)data, flags); +} + + +template <class T> +Fault +TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) +{ + // need to fill in CPU & thread IDs here + Request *data_write_req = new Request(); + data_write_req->setVirt(0, addr, sizeof(T), flags, thread->readPC()); + + // translate to physical address + Fault fault = thread->translateDataWriteReq(data_write_req); + // Now do the access. + if (fault == NoFault) { + Packet *data_write_pkt = + new Packet(data_write_req, Packet::WriteReq, Packet::Broadcast); + data_write_pkt->allocate(); + data_write_pkt->set(data); + + if (!dcachePort.sendTiming(data_write_pkt)) { + _status = DcacheRetry; + dcache_pkt = data_write_pkt; + } else { + _status = DcacheWaitResponse; + dcache_pkt = NULL; + } + } + + // This will need a new way to tell if it's hooked up to a cache or not. + if (data_write_req->getFlags() & UNCACHEABLE) + recordEvent("Uncached Write"); + + // If the write needs to have a fault on the access, consider calling + // changeStatus() and changing it to "bad addr write" or something. + return fault; +} + + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +template +Fault +TimingSimpleCPU::write(uint64_t data, Addr addr, + unsigned flags, uint64_t *res); + +template +Fault +TimingSimpleCPU::write(uint32_t data, Addr addr, + unsigned flags, uint64_t *res); + +template +Fault +TimingSimpleCPU::write(uint16_t data, Addr addr, + unsigned flags, uint64_t *res); + +template +Fault +TimingSimpleCPU::write(uint8_t data, Addr addr, + unsigned flags, uint64_t *res); + +#endif //DOXYGEN_SHOULD_SKIP_THIS + +template<> +Fault +TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) +{ + return write(*(uint64_t*)&data, addr, flags, res); +} + +template<> +Fault +TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) +{ + return write(*(uint32_t*)&data, addr, flags, res); +} + + +template<> +Fault +TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) +{ + return write((uint32_t)data, addr, flags, res); +} + + +void +TimingSimpleCPU::fetch() +{ + checkForInterrupts(); + + // need to fill in CPU & thread IDs here + Request *ifetch_req = new Request(); + Fault fault = setupFetchRequest(ifetch_req); + + ifetch_pkt = new Packet(ifetch_req, Packet::ReadReq, Packet::Broadcast); + ifetch_pkt->dataStatic(&inst); + + if (fault == NoFault) { + if (!icachePort.sendTiming(ifetch_pkt)) { + // Need to wait for retry + _status = IcacheRetry; + } else { + // Need to wait for cache to respond + _status = IcacheWaitResponse; + // ownership of packet transferred to memory system + ifetch_pkt = NULL; + } + } else { + // fetch fault: advance directly to next instruction (fault handler) + advanceInst(fault); + } +} + + +void +TimingSimpleCPU::advanceInst(Fault fault) +{ + advancePC(fault); + + if (_status == Running) { + // kick off fetch of next instruction... callback from icache + // response will cause that instruction to be executed, + // keeping the CPU running. + fetch(); + } +} + + +void +TimingSimpleCPU::completeIfetch(Packet *pkt) +{ + // received a response from the icache: execute the received + // instruction + assert(pkt->result == Packet::Success); + assert(_status == IcacheWaitResponse); + _status = Running; + + delete pkt->req; + delete pkt; + + preExecute(); + if (curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) { + // load or store: just send to dcache + Fault fault = curStaticInst->initiateAcc(this, traceData); + if (fault == NoFault) { + // successfully initiated access: instruction will + // complete in dcache response callback + assert(_status == DcacheWaitResponse); + } else { + // fault: complete now to invoke fault handler + postExecute(); + advanceInst(fault); + } + } else { + // non-memory instruction: execute completely now + Fault fault = curStaticInst->execute(this, traceData); + postExecute(); + advanceInst(fault); + } +} + + +bool +TimingSimpleCPU::IcachePort::recvTiming(Packet *pkt) +{ + cpu->completeIfetch(pkt); + return true; +} + +void +TimingSimpleCPU::IcachePort::recvRetry() +{ + // we shouldn't get a retry unless we have a packet that we're + // waiting to transmit + assert(cpu->ifetch_pkt != NULL); + assert(cpu->_status == IcacheRetry); + Packet *tmp = cpu->ifetch_pkt; + if (sendTiming(tmp)) { + cpu->_status = IcacheWaitResponse; + cpu->ifetch_pkt = NULL; + } +} + +void +TimingSimpleCPU::completeDataAccess(Packet *pkt) +{ + // received a response from the dcache: complete the load or store + // instruction + assert(pkt->result == Packet::Success); + assert(_status == DcacheWaitResponse); + _status = Running; + + Fault fault = curStaticInst->completeAcc(pkt, this, traceData); + + delete pkt->req; + delete pkt; + + postExecute(); + advanceInst(fault); +} + + + +bool +TimingSimpleCPU::DcachePort::recvTiming(Packet *pkt) +{ + cpu->completeDataAccess(pkt); + return true; +} + +void +TimingSimpleCPU::DcachePort::recvRetry() +{ + // we shouldn't get a retry unless we have a packet that we're + // waiting to transmit + assert(cpu->dcache_pkt != NULL); + assert(cpu->_status == DcacheRetry); + Packet *tmp = cpu->dcache_pkt; + if (sendTiming(tmp)) { + cpu->_status = DcacheWaitResponse; + cpu->dcache_pkt = NULL; + } +} + + +//////////////////////////////////////////////////////////////////////// +// +// TimingSimpleCPU Simulation Object +// +BEGIN_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU) + + Param<Counter> max_insts_any_thread; + Param<Counter> max_insts_all_threads; + Param<Counter> max_loads_any_thread; + Param<Counter> max_loads_all_threads; + SimObjectParam<MemObject *> mem; + +#if FULL_SYSTEM + SimObjectParam<AlphaITB *> itb; + SimObjectParam<AlphaDTB *> dtb; + SimObjectParam<System *> system; + Param<int> cpu_id; + Param<Tick> profile; +#else + SimObjectParam<Process *> workload; +#endif // FULL_SYSTEM + + Param<int> clock; + + Param<bool> defer_registration; + Param<int> width; + Param<bool> function_trace; + Param<Tick> function_trace_start; + Param<bool> simulate_stalls; + +END_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU) + +BEGIN_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU) + + INIT_PARAM(max_insts_any_thread, + "terminate when any thread reaches this inst count"), + INIT_PARAM(max_insts_all_threads, + "terminate when all threads have reached this inst count"), + INIT_PARAM(max_loads_any_thread, + "terminate when any thread reaches this load count"), + INIT_PARAM(max_loads_all_threads, + "terminate when all threads have reached this load count"), + INIT_PARAM(mem, "memory"), + +#if FULL_SYSTEM + INIT_PARAM(itb, "Instruction TLB"), + INIT_PARAM(dtb, "Data TLB"), + INIT_PARAM(system, "system object"), + INIT_PARAM(cpu_id, "processor ID"), + INIT_PARAM(profile, ""), +#else + INIT_PARAM(workload, "processes to run"), +#endif // FULL_SYSTEM + + INIT_PARAM(clock, "clock speed"), + INIT_PARAM(defer_registration, "defer system registration (for sampling)"), + INIT_PARAM(width, "cpu width"), + INIT_PARAM(function_trace, "Enable function trace"), + INIT_PARAM(function_trace_start, "Cycle to start function trace"), + INIT_PARAM(simulate_stalls, "Simulate cache stall cycles") + +END_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU) + + +CREATE_SIM_OBJECT(TimingSimpleCPU) +{ + TimingSimpleCPU::Params *params = new TimingSimpleCPU::Params(); + params->name = getInstanceName(); + params->numberOfThreads = 1; + params->max_insts_any_thread = max_insts_any_thread; + params->max_insts_all_threads = max_insts_all_threads; + params->max_loads_any_thread = max_loads_any_thread; + params->max_loads_all_threads = max_loads_all_threads; + params->deferRegistration = defer_registration; + params->clock = clock; + params->functionTrace = function_trace; + params->functionTraceStart = function_trace_start; + params->mem = mem; + +#if FULL_SYSTEM + params->itb = itb; + params->dtb = dtb; + params->system = system; + params->cpu_id = cpu_id; + params->profile = profile; +#else + params->process = workload; +#endif + + TimingSimpleCPU *cpu = new TimingSimpleCPU(params); + return cpu; +} + +REGISTER_SIM_OBJECT("TimingSimpleCPU", TimingSimpleCPU) + diff --git a/src/cpu/simple/timing.hh b/src/cpu/simple/timing.hh new file mode 100644 index 000000000..ab0b2d2ca --- /dev/null +++ b/src/cpu/simple/timing.hh @@ -0,0 +1,152 @@ +/* + * 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: Steve Reinhardt + */ + +#ifndef __CPU_SIMPLE_TIMING_HH__ +#define __CPU_SIMPLE_TIMING_HH__ + +#include "cpu/simple/base.hh" + +class TimingSimpleCPU : public BaseSimpleCPU +{ + public: + + struct Params : public BaseSimpleCPU::Params { + }; + + TimingSimpleCPU(Params *params); + virtual ~TimingSimpleCPU(); + + virtual void init(); + + public: + // + enum Status { + Idle, + Running, + IcacheRetry, + IcacheWaitResponse, + IcacheWaitSwitch, + DcacheRetry, + DcacheWaitResponse, + DcacheWaitSwitch, + SwitchedOut + }; + + protected: + Status _status; + + Status status() const { return _status; } + + private: + + class CpuPort : public Port + { + protected: + TimingSimpleCPU *cpu; + + public: + + CpuPort(const std::string &_name, TimingSimpleCPU *_cpu) + : Port(_name), cpu(_cpu) + { } + + protected: + + virtual Tick recvAtomic(Packet *pkt); + + virtual void recvFunctional(Packet *pkt); + + virtual void recvStatusChange(Status status); + + virtual void getDeviceAddressRanges(AddrRangeList &resp, + AddrRangeList &snoop) + { resp.clear(); snoop.clear(); } + }; + + class IcachePort : public CpuPort + { + public: + + IcachePort(TimingSimpleCPU *_cpu) + : CpuPort(_cpu->name() + "-iport", _cpu) + { } + + protected: + + virtual bool recvTiming(Packet *pkt); + + virtual void recvRetry(); + }; + + class DcachePort : public CpuPort + { + public: + + DcachePort(TimingSimpleCPU *_cpu) + : CpuPort(_cpu->name() + "-dport", _cpu) + { } + + protected: + + virtual bool recvTiming(Packet *pkt); + + virtual void recvRetry(); + }; + + IcachePort icachePort; + DcachePort dcachePort; + + Packet *ifetch_pkt; + Packet *dcache_pkt; + + public: + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + + void switchOut(Sampler *s); + void takeOverFrom(BaseCPU *oldCPU); + + virtual void activateContext(int thread_num, int delay); + virtual void suspendContext(int thread_num); + + template <class T> + Fault read(Addr addr, T &data, unsigned flags); + + template <class T> + Fault write(T data, Addr addr, unsigned flags, uint64_t *res); + + void fetch(); + void completeIfetch(Packet *); + void completeDataAccess(Packet *); + void advanceInst(Fault fault); +}; + +#endif // __CPU_SIMPLE_TIMING_HH__ diff --git a/src/cpu/simple_thread.cc b/src/cpu/simple_thread.cc new file mode 100644 index 000000000..48383ca93 --- /dev/null +++ b/src/cpu/simple_thread.cc @@ -0,0 +1,325 @@ +/* + * Copyright (c) 2001-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 + * Nathan Binkert + * Lisa Hsu + * Kevin Lim + */ + +#include <string> + +#include "arch/isa_traits.hh" +#include "cpu/base.hh" +#include "cpu/simple_thread.hh" +#include "cpu/thread_context.hh" + +#if FULL_SYSTEM +#include "base/callback.hh" +#include "base/cprintf.hh" +#include "base/output.hh" +#include "base/trace.hh" +#include "cpu/profile.hh" +#include "cpu/quiesce_event.hh" +#include "kern/kernel_stats.hh" +#include "sim/serialize.hh" +#include "sim/sim_exit.hh" +#include "arch/stacktrace.hh" +#else +#include "sim/process.hh" +#include "sim/system.hh" +#include "mem/translating_port.hh" +#endif + +using namespace std; + +// constructor +#if FULL_SYSTEM +SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, System *_sys, + AlphaITB *_itb, AlphaDTB *_dtb, + bool use_kernel_stats) + : ThreadState(-1, _thread_num), cpu(_cpu), system(_sys), itb(_itb), + dtb(_dtb) + +{ + tc = new ProxyThreadContext<SimpleThread>(this); + + quiesceEvent = new EndQuiesceEvent(tc); + + regs.clear(); + + if (cpu->params->profile) { + profile = new FunctionProfile(system->kernelSymtab); + Callback *cb = + new MakeCallback<SimpleThread, + &SimpleThread::dumpFuncProfile>(this); + registerExitCallback(cb); + } + + // let's fill with a dummy node for now so we don't get a segfault + // on the first cycle when there's no node available. + static ProfileNode dummyNode; + profileNode = &dummyNode; + profilePC = 3; + + if (use_kernel_stats) { + kernelStats = new Kernel::Statistics(system); + } else { + kernelStats = NULL; + } + Port *mem_port; + physPort = new FunctionalPort(csprintf("%s-%d-funcport", + cpu->name(), tid)); + mem_port = system->physmem->getPort("functional"); + mem_port->setPeer(physPort); + physPort->setPeer(mem_port); + + virtPort = new VirtualPort(csprintf("%s-%d-vport", + cpu->name(), tid)); + mem_port = system->physmem->getPort("functional"); + mem_port->setPeer(virtPort); + virtPort->setPeer(mem_port); +} +#else +SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, + Process *_process, int _asid, MemObject* memobj) + : ThreadState(-1, _thread_num, memobj, _process, _asid), + cpu(_cpu) +{ + /* Use this port to for syscall emulation writes to memory. */ + Port *mem_port; + port = new TranslatingPort(csprintf("%s-%d-funcport", + cpu->name(), tid), + process->pTable, false); + mem_port = memobj->getPort("functional"); + mem_port->setPeer(port); + port->setPeer(mem_port); + + regs.clear(); + tc = new ProxyThreadContext<SimpleThread>(this); +} + +SimpleThread::SimpleThread(RegFile *regFile) + : ThreadState(-1, -1, NULL, NULL, -1), cpu(NULL) +{ + regs = *regFile; + tc = new ProxyThreadContext<SimpleThread>(this); +} + +#endif + +SimpleThread::~SimpleThread() +{ + delete tc; +} + +void +SimpleThread::takeOverFrom(ThreadContext *oldContext) +{ + // some things should already be set up +#if FULL_SYSTEM + assert(system == oldContext->getSystemPtr()); +#else + assert(process == oldContext->getProcessPtr()); +#endif + + // copy over functional state + _status = oldContext->status(); + copyArchRegs(oldContext); + cpuId = oldContext->readCpuId(); +#if !FULL_SYSTEM + funcExeInst = oldContext->readFuncExeInst(); +#else + EndQuiesceEvent *quiesce = oldContext->getQuiesceEvent(); + if (quiesce) { + // Point the quiesce event's TC at this TC so that it wakes up + // the proper CPU. + quiesce->tc = tc; + } + if (quiesceEvent) { + quiesceEvent->tc = tc; + } +#endif + + storeCondFailures = 0; + + oldContext->setStatus(ThreadContext::Unallocated); +} + +void +SimpleThread::serialize(ostream &os) +{ + SERIALIZE_ENUM(_status); + regs.serialize(os); + // thread_num and cpu_id are deterministic from the config + SERIALIZE_SCALAR(funcExeInst); + SERIALIZE_SCALAR(inst); + +#if FULL_SYSTEM + Tick quiesceEndTick = 0; + if (quiesceEvent->scheduled()) + quiesceEndTick = quiesceEvent->when(); + SERIALIZE_SCALAR(quiesceEndTick); + if (kernelStats) + kernelStats->serialize(os); +#endif +} + + +void +SimpleThread::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_ENUM(_status); + regs.unserialize(cp, section); + // thread_num and cpu_id are deterministic from the config + UNSERIALIZE_SCALAR(funcExeInst); + UNSERIALIZE_SCALAR(inst); + +#if FULL_SYSTEM + Tick quiesceEndTick; + UNSERIALIZE_SCALAR(quiesceEndTick); + if (quiesceEndTick) + quiesceEvent->schedule(quiesceEndTick); + if (kernelStats) + kernelStats->unserialize(cp, section); +#endif +} + +#if FULL_SYSTEM +void +SimpleThread::dumpFuncProfile() +{ + std::ostream *os = simout.create(csprintf("profile.%s.dat", cpu->name())); + profile->dump(tc, *os); +} +#endif + +void +SimpleThread::activate(int delay) +{ + if (status() == ThreadContext::Active) + return; + + lastActivate = curTick; + + if (status() == ThreadContext::Unallocated) { + cpu->activateWhenReady(tid); + return; + } + + _status = ThreadContext::Active; + + // status() == Suspended + cpu->activateContext(tid, delay); +} + +void +SimpleThread::suspend() +{ + if (status() == ThreadContext::Suspended) + return; + + lastActivate = curTick; + lastSuspend = curTick; +/* +#if FULL_SYSTEM + // Don't change the status from active if there are pending interrupts + if (cpu->check_interrupts()) { + assert(status() == ThreadContext::Active); + return; + } +#endif +*/ + _status = ThreadContext::Suspended; + cpu->suspendContext(tid); +} + +void +SimpleThread::deallocate() +{ + if (status() == ThreadContext::Unallocated) + return; + + _status = ThreadContext::Unallocated; + cpu->deallocateContext(tid); +} + +void +SimpleThread::halt() +{ + if (status() == ThreadContext::Halted) + return; + + _status = ThreadContext::Halted; + cpu->haltContext(tid); +} + + +void +SimpleThread::regStats(const string &name) +{ +#if FULL_SYSTEM + if (kernelStats) + kernelStats->regStats(name + ".kern"); +#endif +} + +void +SimpleThread::copyArchRegs(ThreadContext *src_tc) +{ + TheISA::copyRegs(src_tc, tc); +} + +#if FULL_SYSTEM +VirtualPort* +SimpleThread::getVirtPort(ThreadContext *src_tc) +{ + if (!src_tc) + return virtPort; + + VirtualPort *vp; + Port *mem_port; + + vp = new VirtualPort("tc-vport", src_tc); + mem_port = system->physmem->getPort("functional"); + mem_port->setPeer(vp); + vp->setPeer(mem_port); + return vp; +} + +void +SimpleThread::delVirtPort(VirtualPort *vp) +{ + if (vp != virtPort) { + delete vp->getPeer(); + delete vp; + } +} + + +#endif + diff --git a/src/cpu/simple_thread.hh b/src/cpu/simple_thread.hh new file mode 100644 index 000000000..de65e9891 --- /dev/null +++ b/src/cpu/simple_thread.hh @@ -0,0 +1,463 @@ +/* + * Copyright (c) 2001-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 + * Nathan Binkert + */ + +#ifndef __CPU_SIMPLE_THREAD_HH__ +#define __CPU_SIMPLE_THREAD_HH__ + +#include "arch/isa_traits.hh" +#include "config/full_system.hh" +#include "cpu/thread_context.hh" +#include "cpu/thread_state.hh" +#include "mem/physical.hh" +#include "mem/request.hh" +#include "sim/byteswap.hh" +#include "sim/eventq.hh" +#include "sim/host.hh" +#include "sim/serialize.hh" + +class BaseCPU; + +#if FULL_SYSTEM + +#include "sim/system.hh" +#include "arch/tlb.hh" + +class FunctionProfile; +class ProfileNode; +class FunctionalPort; +class PhysicalPort; + +namespace Kernel { + class Statistics; +}; + +#else // !FULL_SYSTEM + +#include "sim/process.hh" +#include "mem/page_table.hh" +class TranslatingPort; + +#endif // FULL_SYSTEM + +/** + * The SimpleThread object provides a combination of the ThreadState + * object and the ThreadContext interface. It implements the + * ThreadContext interface so that a ProxyThreadContext class can be + * made using SimpleThread as the template parameter (see + * thread_context.hh). It adds to the ThreadState object by adding all + * the objects needed for simple functional execution, including a + * simple architectural register file, and pointers to the ITB and DTB + * in full system mode. For CPU models that do not need more advanced + * ways to hold state (i.e. a separate physical register file, or + * separate fetch and commit PC's), this SimpleThread class provides + * all the necessary state for full architecture-level functional + * simulation. See the AtomicSimpleCPU or TimingSimpleCPU for + * examples. + */ + +class SimpleThread : public ThreadState +{ + protected: + typedef TheISA::RegFile RegFile; + typedef TheISA::MachInst MachInst; + typedef TheISA::MiscRegFile MiscRegFile; + typedef TheISA::MiscReg MiscReg; + typedef TheISA::FloatReg FloatReg; + typedef TheISA::FloatRegBits FloatRegBits; + public: + typedef ThreadContext::Status Status; + + protected: + RegFile regs; // correct-path register context + + public: + // pointer to CPU associated with this SimpleThread + BaseCPU *cpu; + + ProxyThreadContext<SimpleThread> *tc; + + System *system; + +#if FULL_SYSTEM + AlphaITB *itb; + AlphaDTB *dtb; +#endif + + // constructor: initialize SimpleThread from given process structure +#if FULL_SYSTEM + SimpleThread(BaseCPU *_cpu, int _thread_num, System *_system, + AlphaITB *_itb, AlphaDTB *_dtb, + bool use_kernel_stats = true); +#else + SimpleThread(BaseCPU *_cpu, int _thread_num, Process *_process, int _asid, + MemObject *memobj); + // Constructor to use SimpleThread to pass reg file around. Not + // used for anything else. + SimpleThread(RegFile *regFile); +#endif + virtual ~SimpleThread(); + + virtual void takeOverFrom(ThreadContext *oldContext); + + void regStats(const std::string &name); + + void serialize(std::ostream &os); + void unserialize(Checkpoint *cp, const std::string §ion); + + /*************************************************************** + * SimpleThread functions to provide CPU with access to various + * state, and to provide address translation methods. + **************************************************************/ + + /** Returns the pointer to this SimpleThread's ThreadContext. Used + * when a ThreadContext must be passed to objects outside of the + * CPU. + */ + ThreadContext *getTC() { return tc; } + +#if FULL_SYSTEM + int getInstAsid() { return regs.instAsid(); } + int getDataAsid() { return regs.dataAsid(); } + + Fault translateInstReq(RequestPtr &req) + { + return itb->translate(req, tc); + } + + Fault translateDataReadReq(RequestPtr &req) + { + return dtb->translate(req, tc, false); + } + + Fault translateDataWriteReq(RequestPtr &req) + { + return dtb->translate(req, tc, true); + } + + void dumpFuncProfile(); + + int readIntrFlag() { return regs.intrflag; } + void setIntrFlag(int val) { regs.intrflag = val; } + Fault hwrei(); + + bool simPalCheck(int palFunc); +#else + Fault translateInstReq(RequestPtr &req) + { + return process->pTable->translate(req); + } + + Fault translateDataReadReq(RequestPtr &req) + { + return process->pTable->translate(req); + } + + Fault translateDataWriteReq(RequestPtr &req) + { + return process->pTable->translate(req); + } +#endif + + /******************************************* + * ThreadContext interface functions. + ******************************************/ + + BaseCPU *getCpuPtr() { return cpu; } + + int getThreadNum() { return tid; } + +#if FULL_SYSTEM + System *getSystemPtr() { return system; } + + AlphaITB *getITBPtr() { return itb; } + + AlphaDTB *getDTBPtr() { return dtb; } + + FunctionalPort *getPhysPort() { return physPort; } + + /** Return a virtual port. If no thread context is specified then a static + * port is returned. Otherwise a port is created and returned. It must be + * deleted by deleteVirtPort(). */ + VirtualPort *getVirtPort(ThreadContext *tc); + + void delVirtPort(VirtualPort *vp); +#endif + + Status status() const { return _status; } + + void setStatus(Status newStatus) { _status = newStatus; } + + /// 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(); + + /// Set the status to Unallocated. + void deallocate(); + + /// Set the status to Halted. + void halt(); + +/* + template <class T> + Fault read(RequestPtr &req, T &data) + { +#if FULL_SYSTEM && THE_ISA == ALPHA_ISA + if (req->flags & LOCKED) { + req->xc->setMiscReg(TheISA::Lock_Addr_DepTag, req->paddr); + req->xc->setMiscReg(TheISA::Lock_Flag_DepTag, true); + } +#endif + + Fault error; + error = mem->prot_read(req->paddr, data, req->size); + data = LittleEndianGuest::gtoh(data); + return error; + } + + template <class T> + Fault write(RequestPtr &req, T &data) + { +#if FULL_SYSTEM && THE_ISA == ALPHA_ISA + ExecContext *xc; + + // If this is a store conditional, act appropriately + if (req->flags & LOCKED) { + xc = req->xc; + + if (req->flags & UNCACHEABLE) { + // Don't update result register (see stq_c in isa_desc) + req->result = 2; + xc->setStCondFailures(0);//Needed? [RGD] + } else { + bool lock_flag = xc->readMiscReg(TheISA::Lock_Flag_DepTag); + Addr lock_addr = xc->readMiscReg(TheISA::Lock_Addr_DepTag); + req->result = lock_flag; + if (!lock_flag || + ((lock_addr & ~0xf) != (req->paddr & ~0xf))) { + xc->setMiscReg(TheISA::Lock_Flag_DepTag, false); + xc->setStCondFailures(xc->readStCondFailures() + 1); + if (((xc->readStCondFailures()) % 100000) == 0) { + std::cerr << "Warning: " + << xc->readStCondFailures() + << " consecutive store conditional failures " + << "on cpu " << req->xc->readCpuId() + << std::endl; + } + return NoFault; + } + else xc->setStCondFailures(0); + } + } + + // Need to clear any locked flags on other proccessors for + // this address. Only do this for succsful Store Conditionals + // and all other stores (WH64?). Unsuccessful Store + // Conditionals would have returned above, and wouldn't fall + // through. + for (int i = 0; i < system->execContexts.size(); i++){ + xc = system->execContexts[i]; + if ((xc->readMiscReg(TheISA::Lock_Addr_DepTag) & ~0xf) == + (req->paddr & ~0xf)) { + xc->setMiscReg(TheISA::Lock_Flag_DepTag, false); + } + } + +#endif + return mem->prot_write(req->paddr, (T)htog(data), req->size); + } +*/ + virtual bool misspeculating(); + + Fault instRead(RequestPtr &req) + { + panic("instRead not implemented"); + // return funcPhysMem->read(req, inst); + return NoFault; + } + + void copyArchRegs(ThreadContext *tc); + + void clearArchRegs() { regs.clear(); } + + // + // New accessors for new decoder. + // + uint64_t readIntReg(int reg_idx) + { + return regs.readIntReg(reg_idx); + } + + FloatReg readFloatReg(int reg_idx, int width) + { + return regs.readFloatReg(reg_idx, width); + } + + FloatReg readFloatReg(int reg_idx) + { + return regs.readFloatReg(reg_idx); + } + + FloatRegBits readFloatRegBits(int reg_idx, int width) + { + return regs.readFloatRegBits(reg_idx, width); + } + + FloatRegBits readFloatRegBits(int reg_idx) + { + return regs.readFloatRegBits(reg_idx); + } + + void setIntReg(int reg_idx, uint64_t val) + { + regs.setIntReg(reg_idx, val); + } + + void setFloatReg(int reg_idx, FloatReg val, int width) + { + regs.setFloatReg(reg_idx, val, width); + } + + void setFloatReg(int reg_idx, FloatReg val) + { + regs.setFloatReg(reg_idx, val); + } + + void setFloatRegBits(int reg_idx, FloatRegBits val, int width) + { + regs.setFloatRegBits(reg_idx, val, width); + } + + void setFloatRegBits(int reg_idx, FloatRegBits val) + { + regs.setFloatRegBits(reg_idx, val); + } + + uint64_t readPC() + { + return regs.readPC(); + } + + void setPC(uint64_t val) + { + regs.setPC(val); + } + + uint64_t readNextPC() + { + return regs.readNextPC(); + } + + void setNextPC(uint64_t val) + { + regs.setNextPC(val); + } + + uint64_t readNextNPC() + { + return regs.readNextNPC(); + } + + void setNextNPC(uint64_t val) + { + regs.setNextNPC(val); + } + + MiscReg readMiscReg(int misc_reg) + { + return regs.readMiscReg(misc_reg); + } + + MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) + { + return regs.readMiscRegWithEffect(misc_reg, fault, tc); + } + + Fault setMiscReg(int misc_reg, const MiscReg &val) + { + return regs.setMiscReg(misc_reg, val); + } + + Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) + { + return regs.setMiscRegWithEffect(misc_reg, val, tc); + } + + unsigned readStCondFailures() { return storeCondFailures; } + + void setStCondFailures(unsigned sc_failures) + { storeCondFailures = sc_failures; } + +#if FULL_SYSTEM + bool inPalMode() { return AlphaISA::PcPAL(regs.readPC()); } +#endif + +#if !FULL_SYSTEM + TheISA::IntReg getSyscallArg(int i) + { + return regs.readIntReg(TheISA::ArgumentReg0 + i); + } + + // used to shift args for indirect syscall + void setSyscallArg(int i, TheISA::IntReg val) + { + regs.setIntReg(TheISA::ArgumentReg0 + i, val); + } + + void setSyscallReturn(SyscallReturn return_value) + { + TheISA::setSyscallReturn(return_value, ®s); + } + + void syscall(int64_t callnum) + { + process->syscall(callnum, tc); + } +#endif + + void changeRegFileContext(RegFile::ContextParam param, + RegFile::ContextVal val) + { + regs.changeContext(param, val); + } +}; + + +// for non-speculative execution context, spec_mode is always false +inline bool +SimpleThread::misspeculating() +{ + return false; +} + +#endif // __CPU_CPU_EXEC_CONTEXT_HH__ diff --git a/src/cpu/smt.hh b/src/cpu/smt.hh new file mode 100644 index 000000000..cac1a8fd5 --- /dev/null +++ b/src/cpu/smt.hh @@ -0,0 +1,61 @@ +/* + * Copyright (c) 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: Nathan Binkert + */ + +/** + * @file + * Defines SMT_MAX_THREADS. + */ + +#ifndef __SMT_HH__ +#define __SMT_HH__ + +#ifndef SMT_MAX_THREADS +/** The number of TPUs in any processor. */ +#define SMT_MAX_THREADS 4 +#endif + +/** + * The maximum number of active threads across all cpus. Used to + * initialize per-thread statistics in the cache. + * + * NB: Be careful to only use it once all the CPUs that you care about + * have been initialized + */ +extern int maxThreadsPerCPU; + +/** + * Changes the status and priority of the thread with the given number. + * @param thread_number The thread to change. + * @param activate The new active status. + * @param priority The new priority. + */ +void change_thread_state(int thread_number, int activate, int priority); + +#endif // __SMT_HH__ diff --git a/src/cpu/static_inst.cc b/src/cpu/static_inst.cc new file mode 100644 index 000000000..c311d2282 --- /dev/null +++ b/src/cpu/static_inst.cc @@ -0,0 +1,77 @@ +/* + * Copyright (c) 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 Reinhardt + * Nathan Binkert + */ + +#include <iostream> +#include "cpu/static_inst.hh" +#include "sim/root.hh" + +StaticInstPtr StaticInst::nullStaticInstPtr; + +// Define the decode cache hash map. +StaticInst::DecodeCache StaticInst::decodeCache; + +void +StaticInst::dumpDecodeCacheStats() +{ + using namespace std; + + cerr << "Decode hash table stats @ " << curTick << ":" << endl; + cerr << "\tnum entries = " << decodeCache.size() << endl; + cerr << "\tnum buckets = " << decodeCache.bucket_count() << endl; + vector<int> hist(100, 0); + int max_hist = 0; + for (int i = 0; i < decodeCache.bucket_count(); ++i) { + int count = decodeCache.elems_in_bucket(i); + if (count > max_hist) + max_hist = count; + hist[count]++; + } + for (int i = 0; i <= max_hist; ++i) { + cerr << "\tbuckets of size " << i << " = " << hist[i] << endl; + } +} + +bool +StaticInst::hasBranchTarget(Addr pc, ThreadContext *tc, Addr &tgt) const +{ + if (isDirectCtrl()) { + tgt = branchTarget(pc); + return true; + } + + if (isIndirectCtrl()) { + tgt = branchTarget(tc); + return true; + } + + return false; +} + diff --git a/src/cpu/static_inst.hh b/src/cpu/static_inst.hh new file mode 100644 index 000000000..bea52f510 --- /dev/null +++ b/src/cpu/static_inst.hh @@ -0,0 +1,492 @@ +/* + * Copyright (c) 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 Reinhardt + */ + +#ifndef __CPU_STATIC_INST_HH__ +#define __CPU_STATIC_INST_HH__ + +#include <bitset> +#include <string> + +#include "base/hashmap.hh" +#include "base/misc.hh" +#include "base/refcnt.hh" +#include "cpu/op_class.hh" +#include "sim/host.hh" +#include "arch/isa_traits.hh" + +// forward declarations +struct AlphaSimpleImpl; +struct OzoneImpl; +struct SimpleImpl; +class ThreadContext; +class DynInst; +class Packet; + +template <class Impl> +class AlphaDynInst; + +template <class Impl> +class OzoneDynInst; + +class CheckerCPU; +class FastCPU; +class AtomicSimpleCPU; +class TimingSimpleCPU; +class InorderCPU; +class SymbolTable; + +namespace Trace { + class InstRecord; +} + +/** + * Base, ISA-independent static instruction class. + * + * The main component of this class is the vector of flags and the + * associated methods for reading them. Any object that can rely + * solely on these flags can process instructions without being + * recompiled for multiple ISAs. + */ +class StaticInstBase : public RefCounted +{ + protected: + + /// Set of boolean static instruction properties. + /// + /// Notes: + /// - The IsInteger and IsFloating flags are based on the class of + /// registers accessed by the instruction. Although most + /// instructions will have exactly one of these two flags set, it + /// is possible for an instruction to have neither (e.g., direct + /// unconditional branches, memory barriers) or both (e.g., an + /// FP/int conversion). + /// - If IsMemRef is set, then exactly one of IsLoad or IsStore + /// will be set. + /// - If IsControl is set, then exactly one of IsDirectControl or + /// IsIndirect Control will be set, and exactly one of + /// IsCondControl or IsUncondControl will be set. + /// - IsSerializing, IsMemBarrier, and IsWriteBarrier are + /// implemented as flags since in the current model there's no + /// other way for instructions to inject behavior into the + /// pipeline outside of fetch. Once we go to an exec-in-exec CPU + /// model we should be able to get rid of these flags and + /// implement this behavior via the execute() methods. + /// + enum Flags { + IsNop, ///< Is a no-op (no effect at all). + + IsInteger, ///< References integer regs. + IsFloating, ///< References FP regs. + + IsMemRef, ///< References memory (load, store, or prefetch). + IsLoad, ///< Reads from memory (load or prefetch). + IsStore, ///< Writes to memory. + IsStoreConditional, ///< Store conditional instruction. + IsInstPrefetch, ///< Instruction-cache prefetch. + IsDataPrefetch, ///< Data-cache prefetch. + IsCopy, ///< Fast Cache block copy + + IsControl, ///< Control transfer instruction. + IsDirectControl, ///< PC relative control transfer. + IsIndirectControl, ///< Register indirect control transfer. + IsCondControl, ///< Conditional control transfer. + IsUncondControl, ///< Unconditional control transfer. + IsCall, ///< Subroutine call. + IsReturn, ///< Subroutine return. + + IsCondDelaySlot,///< Conditional Delay-Slot Instruction + + IsThreadSync, ///< Thread synchronization operation. + + IsSerializing, ///< Serializes pipeline: won't execute until all + /// older instructions have committed. + IsSerializeBefore, + IsSerializeAfter, + IsMemBarrier, ///< Is a memory barrier + IsWriteBarrier, ///< Is a write barrier + + IsNonSpeculative, ///< Should not be executed speculatively + IsQuiesce, ///< Is a quiesce instruction + + IsIprAccess, ///< Accesses IPRs + IsUnverifiable, ///< Can't be verified by a checker + + NumFlags + }; + + /// Flag values for this instruction. + std::bitset<NumFlags> flags; + + /// See opClass(). + OpClass _opClass; + + /// See numSrcRegs(). + int8_t _numSrcRegs; + + /// See numDestRegs(). + int8_t _numDestRegs; + + /// The following are used to track physical register usage + /// for machines with separate int & FP reg files. + //@{ + int8_t _numFPDestRegs; + int8_t _numIntDestRegs; + //@} + + /// Constructor. + /// It's important to initialize everything here to a sane + /// default, since the decoder generally only overrides + /// the fields that are meaningful for the particular + /// instruction. + StaticInstBase(OpClass __opClass) + : _opClass(__opClass), _numSrcRegs(0), _numDestRegs(0), + _numFPDestRegs(0), _numIntDestRegs(0) + { + } + + public: + + /// @name Register information. + /// The sum of numFPDestRegs() and numIntDestRegs() equals + /// numDestRegs(). The former two functions are used to track + /// physical register usage for machines with separate int & FP + /// reg files. + //@{ + /// Number of source registers. + int8_t numSrcRegs() const { return _numSrcRegs; } + /// Number of destination registers. + int8_t numDestRegs() const { return _numDestRegs; } + /// Number of floating-point destination regs. + int8_t numFPDestRegs() const { return _numFPDestRegs; } + /// Number of integer destination regs. + int8_t numIntDestRegs() const { return _numIntDestRegs; } + //@} + + /// @name Flag accessors. + /// These functions are used to access the values of the various + /// instruction property flags. See StaticInstBase::Flags for descriptions + /// of the individual flags. + //@{ + + bool isNop() const { return flags[IsNop]; } + + bool isMemRef() const { return flags[IsMemRef]; } + bool isLoad() const { return flags[IsLoad]; } + bool isStore() const { return flags[IsStore]; } + bool isStoreConditional() const { return flags[IsStoreConditional]; } + bool isInstPrefetch() const { return flags[IsInstPrefetch]; } + bool isDataPrefetch() const { return flags[IsDataPrefetch]; } + bool isCopy() const { return flags[IsCopy];} + + bool isInteger() const { return flags[IsInteger]; } + bool isFloating() const { return flags[IsFloating]; } + + bool isControl() const { return flags[IsControl]; } + bool isCall() const { return flags[IsCall]; } + bool isReturn() const { return flags[IsReturn]; } + bool isDirectCtrl() const { return flags[IsDirectControl]; } + bool isIndirectCtrl() const { return flags[IsIndirectControl]; } + bool isCondCtrl() const { return flags[IsCondControl]; } + bool isUncondCtrl() const { return flags[IsUncondControl]; } + + bool isThreadSync() const { return flags[IsThreadSync]; } + bool isSerializing() const { return flags[IsSerializing] || + flags[IsSerializeBefore] || + flags[IsSerializeAfter]; } + bool isSerializeBefore() const { return flags[IsSerializeBefore]; } + bool isSerializeAfter() const { return flags[IsSerializeAfter]; } + bool isMemBarrier() const { return flags[IsMemBarrier]; } + bool isWriteBarrier() const { return flags[IsWriteBarrier]; } + bool isNonSpeculative() const { return flags[IsNonSpeculative]; } + bool isQuiesce() const { return flags[IsQuiesce]; } + bool isIprAccess() const { return flags[IsIprAccess]; } + bool isUnverifiable() const { return flags[IsUnverifiable]; } + //@} + + /// Operation class. Used to select appropriate function unit in issue. + OpClass opClass() const { return _opClass; } +}; + + +// forward declaration +class StaticInstPtr; + +/** + * Generic yet ISA-dependent static instruction class. + * + * This class builds on StaticInstBase, defining fields and interfaces + * that are generic across all ISAs but that differ in details + * according to the specific ISA being used. + */ +class StaticInst : public StaticInstBase +{ + public: + + /// Binary machine instruction type. + typedef TheISA::MachInst MachInst; + /// Binary extended machine instruction type. + typedef TheISA::ExtMachInst ExtMachInst; + /// Logical register index type. + typedef TheISA::RegIndex RegIndex; + + enum { + MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs + MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs + }; + + + /// Return logical index (architectural reg num) of i'th destination reg. + /// Only the entries from 0 through numDestRegs()-1 are valid. + RegIndex destRegIdx(int i) const { return _destRegIdx[i]; } + + /// Return logical index (architectural reg num) of i'th source reg. + /// Only the entries from 0 through numSrcRegs()-1 are valid. + RegIndex srcRegIdx(int i) const { return _srcRegIdx[i]; } + + /// Pointer to a statically allocated "null" instruction object. + /// Used to give eaCompInst() and memAccInst() something to return + /// when called on non-memory instructions. + static StaticInstPtr nullStaticInstPtr; + + /** + * Memory references only: returns "fake" instruction representing + * the effective address part of the memory operation. Used to + * obtain the dependence info (numSrcRegs and srcRegIdx[]) for + * just the EA computation. + */ + virtual const + StaticInstPtr &eaCompInst() const { return nullStaticInstPtr; } + + /** + * Memory references only: returns "fake" instruction representing + * the memory access part of the memory operation. Used to + * obtain the dependence info (numSrcRegs and srcRegIdx[]) for + * just the memory access (not the EA computation). + */ + virtual const + StaticInstPtr &memAccInst() const { return nullStaticInstPtr; } + + /// The binary machine instruction. + const ExtMachInst machInst; + + protected: + + /// See destRegIdx(). + RegIndex _destRegIdx[MaxInstDestRegs]; + /// See srcRegIdx(). + RegIndex _srcRegIdx[MaxInstSrcRegs]; + + /** + * Base mnemonic (e.g., "add"). Used by generateDisassembly() + * methods. Also useful to readily identify instructions from + * within the debugger when #cachedDisassembly has not been + * initialized. + */ + const char *mnemonic; + + /** + * String representation of disassembly (lazily evaluated via + * disassemble()). + */ + mutable std::string *cachedDisassembly; + + /** + * Internal function to generate disassembly string. + */ + virtual std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const = 0; + + /// Constructor. + StaticInst(const char *_mnemonic, ExtMachInst _machInst, OpClass __opClass) + : StaticInstBase(__opClass), + machInst(_machInst), mnemonic(_mnemonic), cachedDisassembly(0) + { + } + + public: + + virtual ~StaticInst() + { + if (cachedDisassembly) + delete cachedDisassembly; + } + +/** + * The execute() signatures are auto-generated by scons based on the + * set of CPU models we are compiling in today. + */ +#include "cpu/static_inst_exec_sigs.hh" + + /** + * Return the target address for a PC-relative branch. + * Invalid if not a PC-relative branch (i.e. isDirectCtrl() + * should be true). + */ + virtual Addr branchTarget(Addr branchPC) const + { + panic("StaticInst::branchTarget() called on instruction " + "that is not a PC-relative branch."); + } + + /** + * Return the target address for an indirect branch (jump). The + * register value is read from the supplied thread context, so + * the result is valid only if the thread context is about to + * execute the branch in question. Invalid if not an indirect + * branch (i.e. isIndirectCtrl() should be true). + */ + virtual Addr branchTarget(ThreadContext *tc) const + { + panic("StaticInst::branchTarget() called on instruction " + "that is not an indirect branch."); + } + + /** + * Return true if the instruction is a control transfer, and if so, + * return the target address as well. + */ + bool hasBranchTarget(Addr pc, ThreadContext *tc, Addr &tgt) const; + + /** + * Return string representation of disassembled instruction. + * The default version of this function will call the internal + * virtual generateDisassembly() function to get the string, + * then cache it in #cachedDisassembly. If the disassembly + * should not be cached, this function should be overridden directly. + */ + virtual const std::string &disassemble(Addr pc, + const SymbolTable *symtab = 0) const + { + if (!cachedDisassembly) + cachedDisassembly = + new std::string(generateDisassembly(pc, symtab)); + + return *cachedDisassembly; + } + + /// Decoded instruction cache type. + /// For now we're using a generic hash_map; this seems to work + /// pretty well. + typedef m5::hash_map<ExtMachInst, StaticInstPtr> DecodeCache; + + /// A cache of decoded instruction objects. + static DecodeCache decodeCache; + + /** + * Dump some basic stats on the decode cache hash map. + * Only gets called if DECODE_CACHE_HASH_STATS is defined. + */ + static void dumpDecodeCacheStats(); + + /// Decode a machine instruction. + /// @param mach_inst The binary instruction to decode. + /// @retval A pointer to the corresponding StaticInst object. + //This is defined as inline below. + static StaticInstPtr decode(ExtMachInst mach_inst); + + //MIPS Decoder Debug Functions + int getOpcode() { return (machInst & 0xFC000000) >> 26 ; }//31..26 + int getRs() { return (machInst & 0x03E00000) >> 21; } //25...21 + int getRt() { return (machInst & 0x001F0000) >> 16; } //20...16 + int getRd() { return (machInst & 0x0000F800) >> 11; } //15...11 + int getImm() { return (machInst & 0x0000FFFF); } //15...0 + int getFunction(){ return (machInst & 0x0000003F); }//5...0 + int getBranch(){ return (machInst & 0x0000FFFF); }//15...0 + int getJump(){ return (machInst & 0x03FFFFFF); }//5...0 + int getHint(){ return (machInst & 0x000007C0) >> 6; } //10...6 + std::string getName() { return mnemonic; } +}; + +typedef RefCountingPtr<StaticInstBase> StaticInstBasePtr; + +/// Reference-counted pointer to a StaticInst object. +/// This type should be used instead of "StaticInst *" so that +/// StaticInst objects can be properly reference-counted. +class StaticInstPtr : public RefCountingPtr<StaticInst> +{ + public: + /// Constructor. + StaticInstPtr() + : RefCountingPtr<StaticInst>() + { + } + + /// Conversion from "StaticInst *". + StaticInstPtr(StaticInst *p) + : RefCountingPtr<StaticInst>(p) + { + } + + /// Copy constructor. + StaticInstPtr(const StaticInstPtr &r) + : RefCountingPtr<StaticInst>(r) + { + } + + /// Construct directly from machine instruction. + /// Calls StaticInst::decode(). + StaticInstPtr(TheISA::ExtMachInst mach_inst) + : RefCountingPtr<StaticInst>(StaticInst::decode(mach_inst)) + { + } + + /// Convert to pointer to StaticInstBase class. + operator const StaticInstBasePtr() + { + return this->get(); + } +}; + +inline StaticInstPtr +StaticInst::decode(StaticInst::ExtMachInst mach_inst) +{ +#ifdef DECODE_CACHE_HASH_STATS + // Simple stats on decode hash_map. Turns out the default + // hash function is as good as anything I could come up with. + const int dump_every_n = 10000000; + static int decodes_til_dump = dump_every_n; + + if (--decodes_til_dump == 0) { + dumpDecodeCacheStats(); + decodes_til_dump = dump_every_n; + } +#endif + + DecodeCache::iterator iter = decodeCache.find(mach_inst); + if (iter != decodeCache.end()) { + return iter->second; + } + + StaticInstPtr si = TheISA::decodeInst(mach_inst); + decodeCache[mach_inst] = si; + return si; +} + +#endif // __CPU_STATIC_INST_HH__ diff --git a/src/cpu/thread_context.hh b/src/cpu/thread_context.hh new file mode 100644 index 000000000..48c8fa28d --- /dev/null +++ b/src/cpu/thread_context.hh @@ -0,0 +1,447 @@ +/* + * 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_THREAD_CONTEXT_HH__ +#define __CPU_THREAD_CONTEXT_HH__ + +#include "config/full_system.hh" +#include "mem/request.hh" +#include "sim/faults.hh" +#include "sim/host.hh" +#include "sim/serialize.hh" +#include "sim/byteswap.hh" + +// @todo: Figure out a more architecture independent way to obtain the ITB and +// DTB pointers. +class AlphaDTB; +class AlphaITB; +class BaseCPU; +class EndQuiesceEvent; +class Event; +class TranslatingPort; +class FunctionalPort; +class VirtualPort; +class Process; +class System; +namespace Kernel { + class Statistics; +}; + +/** + * ThreadContext is the external interface to all thread state for + * anything outside of the CPU. It provides all accessor methods to + * state that might be needed by external objects, ranging from + * register values to things such as kernel stats. It is an abstract + * base class; the CPU can create its own ThreadContext by either + * deriving from it, or using the templated ProxyThreadContext. + * + * The ThreadContext is slightly different than the ExecContext. The + * ThreadContext provides access to an individual thread's state; an + * ExecContext provides ISA access to the CPU (meaning it is + * implicitly multithreaded on SMT systems). Additionally the + * ThreadState is an abstract class that exactly defines the + * interface; the ExecContext is a more implicit interface that must + * be implemented so that the ISA can access whatever state it needs. + */ +class ThreadContext +{ + protected: + typedef TheISA::RegFile RegFile; + typedef TheISA::MachInst MachInst; + typedef TheISA::IntReg IntReg; + typedef TheISA::FloatReg FloatReg; + typedef TheISA::FloatRegBits FloatRegBits; + typedef TheISA::MiscRegFile MiscRegFile; + typedef TheISA::MiscReg MiscReg; + public: + enum Status + { + /// Initialized but not running yet. All CPUs start in + /// this state, but most transition to Active on cycle 1. + /// In MP or SMT systems, non-primary contexts will stay + /// in this state until a thread is assigned to them. + Unallocated, + + /// Running. Instructions should be executed only when + /// the context is in this state. + Active, + + /// Temporarily inactive. Entered while waiting for + /// synchronization, etc. + Suspended, + + /// Permanently shut down. Entered when target executes + /// m5exit pseudo-instruction. When all contexts enter + /// this state, the simulation will terminate. + Halted + }; + + virtual ~ThreadContext() { }; + + virtual BaseCPU *getCpuPtr() = 0; + + virtual void setCpuId(int id) = 0; + + virtual int readCpuId() = 0; + +#if FULL_SYSTEM + virtual System *getSystemPtr() = 0; + + virtual AlphaITB *getITBPtr() = 0; + + virtual AlphaDTB * getDTBPtr() = 0; + + virtual Kernel::Statistics *getKernelStats() = 0; + + virtual FunctionalPort *getPhysPort() = 0; + + virtual VirtualPort *getVirtPort(ThreadContext *tc = NULL) = 0; + + virtual void delVirtPort(VirtualPort *vp) = 0; +#else + virtual TranslatingPort *getMemPort() = 0; + + virtual Process *getProcessPtr() = 0; +#endif + + virtual Status status() const = 0; + + virtual void setStatus(Status new_status) = 0; + + /// Set the status to Active. Optional delay indicates number of + /// cycles to wait before beginning execution. + virtual void activate(int delay = 1) = 0; + + /// Set the status to Suspended. + virtual void suspend() = 0; + + /// Set the status to Unallocated. + virtual void deallocate() = 0; + + /// Set the status to Halted. + virtual void halt() = 0; + +#if FULL_SYSTEM + virtual void dumpFuncProfile() = 0; +#endif + + virtual void takeOverFrom(ThreadContext *old_context) = 0; + + virtual void regStats(const std::string &name) = 0; + + virtual void serialize(std::ostream &os) = 0; + virtual void unserialize(Checkpoint *cp, const std::string §ion) = 0; + +#if FULL_SYSTEM + virtual EndQuiesceEvent *getQuiesceEvent() = 0; + + // Not necessarily the best location for these... + // Having an extra function just to read these is obnoxious + virtual Tick readLastActivate() = 0; + virtual Tick readLastSuspend() = 0; + + virtual void profileClear() = 0; + virtual void profileSample() = 0; +#endif + + virtual int getThreadNum() = 0; + + // Also somewhat obnoxious. Really only used for the TLB fault. + // However, may be quite useful in SPARC. + virtual TheISA::MachInst getInst() = 0; + + virtual void copyArchRegs(ThreadContext *tc) = 0; + + virtual void clearArchRegs() = 0; + + // + // New accessors for new decoder. + // + virtual uint64_t readIntReg(int reg_idx) = 0; + + virtual FloatReg readFloatReg(int reg_idx, int width) = 0; + + virtual FloatReg readFloatReg(int reg_idx) = 0; + + virtual FloatRegBits readFloatRegBits(int reg_idx, int width) = 0; + + virtual FloatRegBits readFloatRegBits(int reg_idx) = 0; + + virtual void setIntReg(int reg_idx, uint64_t val) = 0; + + virtual void setFloatReg(int reg_idx, FloatReg val, int width) = 0; + + virtual void setFloatReg(int reg_idx, FloatReg val) = 0; + + virtual void setFloatRegBits(int reg_idx, FloatRegBits val) = 0; + + virtual void setFloatRegBits(int reg_idx, FloatRegBits val, int width) = 0; + + virtual uint64_t readPC() = 0; + + virtual void setPC(uint64_t val) = 0; + + virtual uint64_t readNextPC() = 0; + + virtual void setNextPC(uint64_t val) = 0; + + virtual uint64_t readNextNPC() = 0; + + virtual void setNextNPC(uint64_t val) = 0; + + virtual MiscReg readMiscReg(int misc_reg) = 0; + + virtual MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) = 0; + + virtual Fault setMiscReg(int misc_reg, const MiscReg &val) = 0; + + virtual Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) = 0; + + // Also not necessarily the best location for these two. Hopefully will go + // away once we decide upon where st cond failures goes. + virtual unsigned readStCondFailures() = 0; + + virtual void setStCondFailures(unsigned sc_failures) = 0; + +#if FULL_SYSTEM + virtual bool inPalMode() = 0; +#endif + + // Only really makes sense for old CPU model. Still could be useful though. + virtual bool misspeculating() = 0; + +#if !FULL_SYSTEM + virtual IntReg getSyscallArg(int i) = 0; + + // used to shift args for indirect syscall + virtual void setSyscallArg(int i, IntReg val) = 0; + + virtual void setSyscallReturn(SyscallReturn return_value) = 0; + + virtual void syscall(int64_t callnum) = 0; + + // Same with st cond failures. + virtual Counter readFuncExeInst() = 0; +#endif + + virtual void changeRegFileContext(RegFile::ContextParam param, + RegFile::ContextVal val) = 0; +}; + +/** + * ProxyThreadContext class that provides a way to implement a + * ThreadContext without having to derive from it. ThreadContext is an + * abstract class, so anything that derives from it and uses its + * interface will pay the overhead of virtual function calls. This + * class is created to enable a user-defined Thread object to be used + * wherever ThreadContexts are used, without paying the overhead of + * virtual function calls when it is used by itself. See + * simple_thread.hh for an example of this. + */ +template <class TC> +class ProxyThreadContext : public ThreadContext +{ + public: + ProxyThreadContext(TC *actual_tc) + { actualTC = actual_tc; } + + private: + TC *actualTC; + + public: + + BaseCPU *getCpuPtr() { return actualTC->getCpuPtr(); } + + void setCpuId(int id) { actualTC->setCpuId(id); } + + int readCpuId() { return actualTC->readCpuId(); } + +#if FULL_SYSTEM + System *getSystemPtr() { return actualTC->getSystemPtr(); } + + AlphaITB *getITBPtr() { return actualTC->getITBPtr(); } + + AlphaDTB *getDTBPtr() { return actualTC->getDTBPtr(); } + + Kernel::Statistics *getKernelStats() { return actualTC->getKernelStats(); } + + FunctionalPort *getPhysPort() { return actualTC->getPhysPort(); } + + VirtualPort *getVirtPort(ThreadContext *tc = NULL) { return actualTC->getVirtPort(tc); } + + void delVirtPort(VirtualPort *vp) { return actualTC->delVirtPort(vp); } +#else + TranslatingPort *getMemPort() { return actualTC->getMemPort(); } + + Process *getProcessPtr() { return actualTC->getProcessPtr(); } +#endif + + Status status() const { return actualTC->status(); } + + void setStatus(Status new_status) { actualTC->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() { actualTC->suspend(); } + + /// Set the status to Unallocated. + void deallocate() { actualTC->deallocate(); } + + /// Set the status to Halted. + void halt() { actualTC->halt(); } + +#if FULL_SYSTEM + void dumpFuncProfile() { actualTC->dumpFuncProfile(); } +#endif + + void takeOverFrom(ThreadContext *oldContext) + { actualTC->takeOverFrom(oldContext); } + + void regStats(const std::string &name) { actualTC->regStats(name); } + + void serialize(std::ostream &os) { actualTC->serialize(os); } + void unserialize(Checkpoint *cp, const std::string §ion) + { actualTC->unserialize(cp, section); } + +#if FULL_SYSTEM + 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(); } +#endif + + int getThreadNum() { return actualTC->getThreadNum(); } + + // @todo: Do I need this? + MachInst getInst() { return actualTC->getInst(); } + + // @todo: Do I need this? + void copyArchRegs(ThreadContext *tc) { actualTC->copyArchRegs(tc); } + + void clearArchRegs() { actualTC->clearArchRegs(); } + + // + // New accessors for new decoder. + // + uint64_t readIntReg(int reg_idx) + { return actualTC->readIntReg(reg_idx); } + + FloatReg readFloatReg(int reg_idx, int width) + { return actualTC->readFloatReg(reg_idx, width); } + + FloatReg readFloatReg(int reg_idx) + { return actualTC->readFloatReg(reg_idx); } + + FloatRegBits readFloatRegBits(int reg_idx, int width) + { return actualTC->readFloatRegBits(reg_idx, width); } + + FloatRegBits readFloatRegBits(int reg_idx) + { return actualTC->readFloatRegBits(reg_idx); } + + void setIntReg(int reg_idx, uint64_t val) + { actualTC->setIntReg(reg_idx, val); } + + void setFloatReg(int reg_idx, FloatReg val, int width) + { actualTC->setFloatReg(reg_idx, val, width); } + + void setFloatReg(int reg_idx, FloatReg val) + { actualTC->setFloatReg(reg_idx, val); } + + void setFloatRegBits(int reg_idx, FloatRegBits val, int width) + { actualTC->setFloatRegBits(reg_idx, val, width); } + + void setFloatRegBits(int reg_idx, FloatRegBits val) + { actualTC->setFloatRegBits(reg_idx, val); } + + uint64_t readPC() { return actualTC->readPC(); } + + void setPC(uint64_t val) { actualTC->setPC(val); } + + uint64_t readNextPC() { return actualTC->readNextPC(); } + + void setNextPC(uint64_t val) { actualTC->setNextPC(val); } + + uint64_t readNextNPC() { return actualTC->readNextNPC(); } + + void setNextNPC(uint64_t val) { actualTC->setNextNPC(val); } + + MiscReg readMiscReg(int misc_reg) + { return actualTC->readMiscReg(misc_reg); } + + MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) + { return actualTC->readMiscRegWithEffect(misc_reg, fault); } + + Fault setMiscReg(int misc_reg, const MiscReg &val) + { return actualTC->setMiscReg(misc_reg, val); } + + Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) + { return actualTC->setMiscRegWithEffect(misc_reg, val); } + + unsigned readStCondFailures() + { return actualTC->readStCondFailures(); } + + void setStCondFailures(unsigned sc_failures) + { actualTC->setStCondFailures(sc_failures); } +#if FULL_SYSTEM + bool inPalMode() { return actualTC->inPalMode(); } +#endif + + // @todo: Fix this! + bool misspeculating() { return actualTC->misspeculating(); } + +#if !FULL_SYSTEM + IntReg getSyscallArg(int i) { return actualTC->getSyscallArg(i); } + + // used to shift args for indirect syscall + void setSyscallArg(int i, IntReg val) + { actualTC->setSyscallArg(i, val); } + + void setSyscallReturn(SyscallReturn return_value) + { actualTC->setSyscallReturn(return_value); } + + void syscall(int64_t callnum) { actualTC->syscall(callnum); } + + Counter readFuncExeInst() { return actualTC->readFuncExeInst(); } +#endif + + void changeRegFileContext(RegFile::ContextParam param, + RegFile::ContextVal val) + { + actualTC->changeRegFileContext(param, val); + } +}; + +#endif diff --git a/src/cpu/thread_state.cc b/src/cpu/thread_state.cc new file mode 100644 index 000000000..dcfa93c3e --- /dev/null +++ b/src/cpu/thread_state.cc @@ -0,0 +1,68 @@ +/* + * 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 "base/output.hh" +#include "cpu/profile.hh" +#include "cpu/thread_state.hh" + +#if FULL_SYSTEM +ThreadState::ThreadState(int _cpuId, int _tid) + : cpuId(_cpuId), tid(_tid), lastActivate(0), lastSuspend(0), + profile(NULL), profileNode(NULL), profilePC(0), quiesceEvent(NULL), + funcExeInst(0), storeCondFailures(0) +#else +ThreadState::ThreadState(int _cpuId, int _tid, MemObject *mem, + Process *_process, short _asid) + : cpuId(_cpuId), tid(_tid), lastActivate(0), lastSuspend(0), + process(_process), asid(_asid), + funcExeInst(0), storeCondFailures(0) +#endif +{ + numInst = 0; + numLoad = 0; +} + +#if FULL_SYSTEM + +void +ThreadState::profileClear() +{ + if (profile) + profile->clear(); +} + +void +ThreadState::profileSample() +{ + if (profile) + profile->sample(profileNode, profilePC); +} + +#endif diff --git a/src/cpu/thread_state.hh b/src/cpu/thread_state.hh new file mode 100644 index 000000000..de9b2f14e --- /dev/null +++ b/src/cpu/thread_state.hh @@ -0,0 +1,220 @@ +/* + * 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_THREAD_STATE_HH__ +#define __CPU_THREAD_STATE_HH__ + +#include "arch/isa_traits.hh" +#include "cpu/thread_context.hh" + +#if !FULL_SYSTEM +#include "mem/mem_object.hh" +#include "mem/translating_port.hh" +#include "sim/process.hh" +#endif + +#if FULL_SYSTEM +class EndQuiesceEvent; +class FunctionProfile; +class ProfileNode; +namespace Kernel { + class Statistics; +}; +#endif + +/** + * Struct for holding general thread state that is needed across CPU + * models. This includes things such as pointers to the process, + * memory, quiesce events, and certain stats. This can be expanded + * to hold more thread-specific stats within it. + */ +struct ThreadState { + typedef ThreadContext::Status Status; + +#if FULL_SYSTEM + ThreadState(int _cpuId, int _tid); +#else + ThreadState(int _cpuId, int _tid, MemObject *mem, + Process *_process, short _asid); +#endif + + void setCpuId(int id) { cpuId = id; } + + int readCpuId() { return cpuId; } + + void setTid(int id) { tid = id; } + + int readTid() { return tid; } + + Tick readLastActivate() { return lastActivate; } + + Tick readLastSuspend() { return lastSuspend; } + +#if FULL_SYSTEM + void dumpFuncProfile(); + + EndQuiesceEvent *getQuiesceEvent() { return quiesceEvent; } + + void profileClear(); + + void profileSample(); + + Kernel::Statistics *getKernelStats() { return kernelStats; } + + FunctionalPort *getPhysPort() { return physPort; } + + void setPhysPort(FunctionalPort *port) { physPort = port; } + + VirtualPort *getVirtPort(ThreadContext *tc = NULL) { return virtPort; } + + void setVirtPort(VirtualPort *port) { virtPort = port; } +#else + Process *getProcessPtr() { return process; } + + TranslatingPort *getMemPort() { return port; } + + void setMemPort(TranslatingPort *_port) { port = _port; } + + int getInstAsid() { return asid; } + int getDataAsid() { return asid; } +#endif + + /** Sets the current instruction being committed. */ + void setInst(TheISA::MachInst _inst) { inst = _inst; } + + /** Returns the current instruction being committed. */ + TheISA::MachInst getInst() { return inst; } + + /** Reads the number of instructions functionally executed and + * committed. + */ + Counter readFuncExeInst() { return funcExeInst; } + + /** Sets the total number of instructions functionally executed + * and committed. + */ + void setFuncExeInst(Counter new_val) { funcExeInst = new_val; } + + /** Returns the status of this thread. */ + Status status() const { return _status; } + + /** Sets the status of this thread. */ + void setStatus(Status new_status) { _status = new_status; } + + /** Number of instructions committed. */ + Counter numInst; + /** Stat for number instructions committed. */ + Stats::Scalar<> numInsts; + /** Stat for number of memory references. */ + Stats::Scalar<> numMemRefs; + + /** Number of simulated loads, used for tracking events based on + * the number of loads committed. + */ + Counter numLoad; + + /** The number of simulated loads committed prior to this run. */ + Counter startNumLoad; + + protected: + ThreadContext::Status _status; + + // ID of this context w.r.t. the System or Process object to which + // it belongs. For full-system mode, this is the system CPU ID. + int cpuId; + + // Index of hardware thread context on the CPU that this represents. + int tid; + + public: + /** Last time activate was called on this thread. */ + Tick lastActivate; + + /** Last time suspend was called on this thread. */ + Tick lastSuspend; + +#if FULL_SYSTEM + public: + FunctionProfile *profile; + ProfileNode *profileNode; + Addr profilePC; + EndQuiesceEvent *quiesceEvent; + + Kernel::Statistics *kernelStats; + protected: + /** A functional port outgoing only for functional accesses to physical + * addresses.*/ + FunctionalPort *physPort; + + /** A functional port, outgoing only, for functional accesse to virtual + * addresses. That doen't require execution context information */ + VirtualPort *virtPort; +#else + TranslatingPort *port; + + Process *process; + + // Address space ID. Note that this is used for TIMING cache + // simulation only; all functional memory accesses should use + // one of the FunctionalMemory pointers above. + short asid; +#endif + + /** Current instruction the thread is committing. Only set and + * used for DTB faults currently. + */ + TheISA::MachInst inst; + + public: + /** + * Temporary storage to pass the source address from copy_load to + * copy_store. + * @todo Remove this temporary when we have a better way to do it. + */ + Addr copySrcAddr; + /** + * Temp storage for the physical source address of a copy. + * @todo Remove this temporary when we have a better way to do it. + */ + Addr copySrcPhysAddr; + + /* + * number of executed instructions, for matching with syscall trace + * points in EIO files. + */ + Counter funcExeInst; + + // + // Count failed store conditionals so we can warn of apparent + // application deadlock situations. + unsigned storeCondFailures; +}; + +#endif // __CPU_THREAD_STATE_HH__ diff --git a/src/cpu/trace/opt_cpu.cc b/src/cpu/trace/opt_cpu.cc new file mode 100644 index 000000000..996e89f01 --- /dev/null +++ b/src/cpu/trace/opt_cpu.cc @@ -0,0 +1,241 @@ +/* + * 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: Erik Hallnor + */ + +/** + * @file + * Definition of a memory trace CPU object for optimal caches. Uses a memory + * trace to access a fully associative cache with optimal replacement. + */ + +#include <algorithm> // For heap functions. + +#include "cpu/trace/opt_cpu.hh" +#include "cpu/trace/reader/mem_trace_reader.hh" + +#include "sim/builder.hh" +#include "sim/sim_events.hh" + +using namespace std; + +OptCPU::OptCPU(const string &name, + MemTraceReader *_trace, + int block_size, + int cache_size, + int _assoc) + : SimObject(name), tickEvent(this), trace(_trace), + numBlks(cache_size/block_size), assoc(_assoc), numSets(numBlks/assoc), + setMask(numSets - 1) +{ + int log_block_size = 0; + int tmp_block_size = block_size; + while (tmp_block_size > 1) { + ++log_block_size; + tmp_block_size = tmp_block_size >> 1; + } + assert(1<<log_block_size == block_size); + MemReqPtr req; + trace->getNextReq(req); + refInfo.resize(numSets); + while (req) { + RefInfo temp; + temp.addr = req->paddr >> log_block_size; + int set = temp.addr & setMask; + refInfo[set].push_back(temp); + trace->getNextReq(req); + } + + // Initialize top level of lookup table. + lookupTable.resize(16); + + // Annotate references with next ref time. + for (int k = 0; k < numSets; ++k) { + for (RefIndex i = refInfo[k].size() - 1; i >= 0; --i) { + Addr addr = refInfo[k][i].addr; + initTable(addr, InfiniteRef); + refInfo[k][i].nextRefTime = lookupValue(addr); + setValue(addr, i); + } + } + + // Reset the lookup table + for (int j = 0; j < 16; ++j) { + if (lookupTable[j].size() == (1<<16)) { + for (int k = 0; k < (1<<16); ++k) { + if (lookupTable[j][k].size() == (1<<16)) { + for (int l = 0; l < (1<<16); ++l) { + lookupTable[j][k][l] = -1; + } + } + } + } + } + + tickEvent.schedule(0); + + hits = 0; + misses = 0; +} + +void +OptCPU::processSet(int set) +{ + // Initialize cache + int blks_in_cache = 0; + RefIndex i = 0; + cacheHeap.clear(); + cacheHeap.resize(assoc); + + while (blks_in_cache < assoc) { + RefIndex cache_index = lookupValue(refInfo[set][i].addr); + if (cache_index == -1) { + // First reference to this block + misses++; + cache_index = blks_in_cache++; + setValue(refInfo[set][i].addr, cache_index); + } else { + hits++; + } + // update cache heap to most recent reference + cacheHeap[cache_index] = i; + if (++i >= refInfo[set].size()) { + return; + } + } + for (int start = assoc/2; start >= 0; --start) { + heapify(set,start); + } + //verifyHeap(set,0); + + for (; i < refInfo[set].size(); ++i) { + RefIndex cache_index = lookupValue(refInfo[set][i].addr); + if (cache_index == -1) { + // miss + misses++; + // replace from cacheHeap[0] + // mark replaced block as absent + setValue(refInfo[set][cacheHeap[0]].addr, -1); + setValue(refInfo[set][i].addr, 0); + cacheHeap[0] = i; + heapify(set, 0); + // Make sure its in the cache + assert(lookupValue(refInfo[set][i].addr) != -1); + } else { + // hit + hits++; + assert(refInfo[set][cacheHeap[cache_index]].addr == + refInfo[set][i].addr); + assert(refInfo[set][cacheHeap[cache_index]].nextRefTime == i); + assert(heapLeft(cache_index) >= assoc); + + cacheHeap[cache_index] = i; + processRankIncrease(set, cache_index); + assert(lookupValue(refInfo[set][i].addr) != -1); + } + } +} +void +OptCPU::tick() +{ + // Do opt simulation + + int references = 0; + for (int set = 0; set < numSets; ++set) { + if (!refInfo[set].empty()) { + processSet(set); + } + references += refInfo[set].size(); + } + // exit; + fprintf(stderr,"sys.cpu.misses %d #opt cache misses\n",misses); + fprintf(stderr,"sys.cpu.hits %d #opt cache hits\n", hits); + fprintf(stderr,"sys.cpu.accesses %d #opt cache acceses\n", references); + exitSimLoop("end of memory trace reached"); +} + +void +OptCPU::initTable(Addr addr, RefIndex index) +{ + int l1_index = (addr >> 32) & 0x0f; + int l2_index = (addr >> 16) & 0xffff; + assert(l1_index == addr >> 32); + if (lookupTable[l1_index].size() != (1<<16)) { + lookupTable[l1_index].resize(1<<16); + } + if (lookupTable[l1_index][l2_index].size() != (1<<16)) { + lookupTable[l1_index][l2_index].resize(1<<16, index); + } +} + +OptCPU::TickEvent::TickEvent(OptCPU *c) + : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) +{ +} + +void +OptCPU::TickEvent::process() +{ + cpu->tick(); +} + +const char * +OptCPU::TickEvent::description() +{ + return "OptCPU tick event"; +} + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(OptCPU) + + SimObjectParam<MemTraceReader *> data_trace; + Param<int> size; + Param<int> block_size; +Param<int> assoc; + +END_DECLARE_SIM_OBJECT_PARAMS(OptCPU) + +BEGIN_INIT_SIM_OBJECT_PARAMS(OptCPU) + + INIT_PARAM_DFLT(data_trace, "memory trace", NULL), + INIT_PARAM(size, "cache size"), + INIT_PARAM(block_size, "block size"), + INIT_PARAM(assoc,"associativity") + +END_INIT_SIM_OBJECT_PARAMS(OptCPU) + +CREATE_SIM_OBJECT(OptCPU) +{ + return new OptCPU(getInstanceName(), + data_trace, + block_size, + size, + assoc); +} + +REGISTER_SIM_OBJECT("OptCPU", OptCPU) diff --git a/src/cpu/trace/opt_cpu.hh b/src/cpu/trace/opt_cpu.hh new file mode 100644 index 000000000..dfb122319 --- /dev/null +++ b/src/cpu/trace/opt_cpu.hh @@ -0,0 +1,225 @@ +/* + * 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: Erik Hallnor + */ + +/** + * @file + * Declaration of a memory trace CPU object for optimal caches. Uses a memory + * trace to access a fully associative cache with optimal replacement. + */ + +#ifndef __CPU_TRACE_OPT_CPU_HH__ +#define __CPU_TRACE_OPT_CPU_HH__ + +#include <vector> + +#include "mem/mem_req.hh" // for MemReqPtr +#include "sim/eventq.hh" // for Event +#include "sim/sim_object.hh" + +// Forward Declaration +class MemTraceReader; + +/** + * A CPU object to simulate a fully-associative cache with optimal replacement. + */ +class OptCPU : public SimObject +{ + private: + typedef int RefIndex; + + typedef std::vector<RefIndex> L3Table; + typedef std::vector<L3Table> L2Table; + typedef std::vector<L2Table> L1Table; + + /** + * Event to call OptCPU::tick + */ + class TickEvent : public Event + { + private: + /** The associated CPU */ + OptCPU *cpu; + + public: + /** + * Construct this event; + */ + TickEvent(OptCPU *c); + + /** + * Call the tick function. + */ + void process(); + + /** + * Return a string description of this event. + */ + const char *description(); + }; + + TickEvent tickEvent; + + class RefInfo + { + public: + RefIndex nextRefTime; + Addr addr; + }; + + /** Reference Information, per set. */ + std::vector<std::vector<RefInfo> > refInfo; + + /** Lookup table to track blocks in the cache heap */ + L1Table lookupTable; + + /** + * Return the correct value in the lookup table. + */ + RefIndex lookupValue(Addr addr) + { + int l1_index = (addr >> 32) & 0x0f; + int l2_index = (addr >> 16) & 0xffff; + int l3_index = addr & 0xffff; + assert(l1_index == addr >> 32); + return lookupTable[l1_index][l2_index][l3_index]; + } + + /** + * Set the value in the lookup table. + */ + void setValue(Addr addr, RefIndex index) + { + int l1_index = (addr >> 32) & 0x0f; + int l2_index = (addr >> 16) & 0xffff; + int l3_index = addr & 0xffff; + assert(l1_index == addr >> 32); + lookupTable[l1_index][l2_index][l3_index]=index; + } + + /** + * Initialize the lookup table to the given value. + */ + void initTable(Addr addr, RefIndex index); + + void heapSwap(int set, int a, int b) { + RefIndex tmp = cacheHeap[a]; + cacheHeap[a] = cacheHeap[b]; + cacheHeap[b] = tmp; + + setValue(refInfo[set][cacheHeap[a]].addr, a); + setValue(refInfo[set][cacheHeap[b]].addr, b); + } + + int heapLeft(int index) { return index + index + 1; } + int heapRight(int index) { return index + index + 2; } + int heapParent(int index) { return (index - 1) >> 1; } + + RefIndex heapRank(int set, int index) { + return refInfo[set][cacheHeap[index]].nextRefTime; + } + + void heapify(int set, int start){ + int left = heapLeft(start); + int right = heapRight(start); + int max = start; + if (left < assoc && heapRank(set, left) > heapRank(set, start)) { + max = left; + } + if (right < assoc && heapRank(set, right) > heapRank(set, max)) { + max = right; + } + + if (max != start) { + heapSwap(set, start, max); + heapify(set, max); + } + } + + void verifyHeap(int set, int start) { + int left = heapLeft(start); + int right = heapRight(start); + + if (left < assoc) { + assert(heapRank(set, start) >= heapRank(set, left)); + verifyHeap(set, left); + } + if (right < assoc) { + assert(heapRank(set, start) >= heapRank(set, right)); + verifyHeap(set, right); + } + } + + void processRankIncrease(int set, int start) { + int parent = heapParent(start); + while (start > 0 && heapRank(set,parent) < heapRank(set,start)) { + heapSwap(set, parent, start); + start = parent; + parent = heapParent(start); + } + } + + void processSet(int set); + + static const RefIndex InfiniteRef = 0x7fffffff; + + /** Memory reference trace. */ + MemTraceReader *trace; + + /** Cache heap for replacement. */ + std::vector<RefIndex> cacheHeap; + + /** The number of blocks in the cache. */ + const int numBlks; + + const int assoc; + const int numSets; + const int setMask; + + + int misses; + int hits; + + public: + /** + * Construct a OptCPU object. + */ + OptCPU(const std::string &name, + MemTraceReader *_trace, + int block_size, + int cache_size, + int assoc); + + /** + * Perform the optimal replacement simulation. + */ + void tick(); +}; + +#endif // __CPU_TRACE_OPT_CPU_HH__ diff --git a/src/cpu/trace/reader/ibm_reader.cc b/src/cpu/trace/reader/ibm_reader.cc new file mode 100644 index 000000000..87e13f307 --- /dev/null +++ b/src/cpu/trace/reader/ibm_reader.cc @@ -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: Erik Hallnor + */ + +/** + * @file + * Declaration of a IBM memory trace format reader. + */ +#include <sstream> + +#include "cpu/trace/reader/ibm_reader.hh" +#include "sim/builder.hh" +#include "base/misc.hh" // for fatal + +using namespace std; + +IBMReader::IBMReader(const string &name, const string &filename) + : MemTraceReader(name) +{ + if (strcmp((filename.c_str() + filename.length() -3), ".gz") == 0) { + // Compressed file, need to use a pipe to gzip. + stringstream buf; + buf << "gzip -d -c " << filename << endl; + trace = popen(buf.str().c_str(), "r"); + } else { + trace = fopen(filename.c_str(), "rb"); + } + if (!trace) { + fatal("Can't open file %s", filename); + } +} + +Tick +IBMReader::getNextReq(MemReqPtr &req) +{ + MemReqPtr tmp_req; + + int c = getc(trace); + if (c != EOF) { + tmp_req = new MemReq(); + //int cpu_id = (c & 0xf0) >> 4; + int type = c & 0x0f; + // We have L1 miss traces, so all accesses are 128 bytes + tmp_req->size = 128; + + tmp_req->paddr = 0; + for (int i = 2; i >= 0; --i) { + c = getc(trace); + if (c == EOF) { + fatal("Unexpected end of file"); + } + tmp_req->paddr |= ((c & 0xff) << (8 * i)); + } + tmp_req->paddr = tmp_req->paddr << 7; + + switch(type) { + case IBM_COND_EXCLUSIVE_FETCH: + case IBM_READ_ONLY_FETCH: + tmp_req->cmd = Read; + break; + case IBM_EXCLUSIVE_FETCH: + case IBM_FETCH_NO_DATA: + tmp_req->cmd = Write; + break; + case IBM_INST_FETCH: + tmp_req->cmd = Read; + break; + default: + fatal("Unknown trace entry type."); + } + + } + req = tmp_req; + return 0; +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(IBMReader) + + Param<string> filename; + +END_DECLARE_SIM_OBJECT_PARAMS(IBMReader) + + +BEGIN_INIT_SIM_OBJECT_PARAMS(IBMReader) + + INIT_PARAM(filename, "trace file") + +END_INIT_SIM_OBJECT_PARAMS(IBMReader) + + +CREATE_SIM_OBJECT(IBMReader) +{ + return new IBMReader(getInstanceName(), filename); +} + +REGISTER_SIM_OBJECT("IBMReader", IBMReader) diff --git a/src/cpu/trace/reader/ibm_reader.hh b/src/cpu/trace/reader/ibm_reader.hh new file mode 100644 index 000000000..a72f62e03 --- /dev/null +++ b/src/cpu/trace/reader/ibm_reader.hh @@ -0,0 +1,75 @@ +/* + * 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: Erik Hallnor + */ + +/** + * @file + * Definition of a IBM memory trace format reader. + */ + +#ifndef __IBM_READER_HH__ +#define __IBM_READER_HH__ + +#include <stdio.h> +#include "cpu/trace/reader/mem_trace_reader.hh" +#include "mem/mem_req.hh" + +/** + * A memory trace reader for the IBM memory trace format. + */ +class IBMReader : public MemTraceReader +{ + /** IBM trace file. */ + FILE* trace; + + enum IBMType { + IBM_INST_FETCH, + IBM_READ_ONLY_FETCH, + IBM_COND_EXCLUSIVE_FETCH, + IBM_EXCLUSIVE_FETCH, + IBM_FETCH_NO_DATA + }; + + public: + /** + * Construct an IBMReader. + */ + IBMReader(const std::string &name, const std::string &filename); + + /** + * Read the next request from the trace. Returns the request in the + * provided MemReqPtr and the cycle of the request in the return value. + * @param req Return the next request from the trace. + * @return IBM traces don't store timing information, return 0 + */ + virtual Tick getNextReq(MemReqPtr &req); +}; + +#endif //__IBM_READER_HH__ + diff --git a/src/cpu/trace/reader/itx_reader.cc b/src/cpu/trace/reader/itx_reader.cc new file mode 100644 index 000000000..e4738eed8 --- /dev/null +++ b/src/cpu/trace/reader/itx_reader.cc @@ -0,0 +1,208 @@ +/* + * 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: Erik Hallnor + */ + +/** + * @file + * Declaration of a Intel ITX memory trace format reader. + */ +#include <sstream> + +#include "cpu/trace/reader/itx_reader.hh" +#include "sim/builder.hh" +#include "base/misc.hh" // for fatal + +using namespace std; + +ITXReader::ITXReader(const string &name, const string &filename) + : MemTraceReader(name) +{ + if (strcmp((filename.c_str() + filename.length() -3), ".gz") == 0) { + // Compressed file, need to use a pipe to gzip. + stringstream buf; + buf << "gzip -d -c " << filename << endl; + trace = popen(buf.str().c_str(), "r"); + } else { + trace = fopen(filename.c_str(), "rb"); + } + if (!trace) { + fatal("Can't open file %s", filename); + } + traceFormat = 0; + int c; + for (int i = 0; i < 4; ++i) { + c = getc(trace); + if (c == EOF) { + fatal("Unexpected end of trace file."); + } + traceFormat |= (c & 0xff) << (8 * i); + } + if (traceFormat > 2) + fatal("Invalid trace format."); +} + +Tick +ITXReader::getNextReq(MemReqPtr &req) +{ + MemReqPtr tmp_req = new MemReq(); + bool phys_val; + do { + int c = getc(trace); + if (c != EOF) { + // Decode first byte + // phys_val<1> | type <2:0> | size <3:0> + phys_val = c & 0x80; + tmp_req->size = (c & 0x0f) + 1; + int type = (c & 0x70) >> 4; + + // Could be a compressed instruction entry, expand if necessary + if (type == ITXCodeComp) { + if (traceFormat != 2) { + fatal("Compressed code entry in non CompCode trace."); + } + if (!codeVirtValid) { + fatal("Corrupt CodeComp entry."); + } + + tmp_req->vaddr = codeVirtAddr; + codeVirtAddr += tmp_req->size; + if (phys_val) { + if (!codePhysValid) { + fatal("Corrupt CodeComp entry."); + } + tmp_req->paddr = codePhysAddr; + if (((tmp_req->paddr & 0xfff) + tmp_req->size) & ~0xfff) { + // Crossed page boundary, next physical address is + // invalid + codePhysValid = false; + } else { + codePhysAddr += tmp_req->size; + } + assert(tmp_req->paddr >> 36 == 0); + } else { + codePhysValid = false; + } + type = ITXCode; + tmp_req->cmd = Read; + } else { + // Normal entry + tmp_req->vaddr = 0; + for (int i = 0; i < 4; ++i) { + c = getc(trace); + if (c == EOF) { + fatal("Unexpected end of trace file."); + } + tmp_req->vaddr |= (c & 0xff) << (8 * i); + } + if (type == ITXCode) { + codeVirtAddr = tmp_req->vaddr + tmp_req->size; + codeVirtValid = true; + } + tmp_req->paddr = 0; + if (phys_val) { + c = getc(trace); + if (c == EOF) { + fatal("Unexpected end of trace file."); + } + // Get the page offset from the virtual address. + tmp_req->paddr = tmp_req->vaddr & 0xfff; + tmp_req->paddr |= (c & 0xf0) << 8; + tmp_req->paddr |= (Addr)(c & 0x0f) << 32; + for (int i = 2; i < 4; ++i) { + c = getc(trace); + if (c == EOF) { + fatal("Unexpected end of trace file."); + } + tmp_req->paddr |= (Addr)(c & 0xff) << (8 * i); + } + if (type == ITXCode) { + if (((tmp_req->paddr & 0xfff) + tmp_req->size) + & ~0xfff) { + // Crossing the page boundary, next physical + // address isn't valid + codePhysValid = false; + } else { + codePhysAddr = tmp_req->paddr + tmp_req->size; + codePhysValid = true; + } + } + assert(tmp_req->paddr >> 36 == 0); + } else if (type == ITXCode) { + codePhysValid = false; + } + switch(type) { + case ITXRead: + tmp_req->cmd = Read; + break; + case ITXWrite: + tmp_req->cmd = Write; + break; + case ITXWriteback: + tmp_req->cmd = Writeback; + break; + case ITXCode: + tmp_req->cmd = Read; + tmp_req->flags |= INST_READ; + break; + default: + fatal("Unknown ITX type"); + } + } + } else { + // EOF need to return a null request + MemReqPtr null_req; + req = null_req; + return 0; + } + } while (!phys_val); + req = tmp_req; + assert(!req || (req->paddr >> 36) == 0); + return 0; +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(ITXReader) + + Param<string> filename; + +END_DECLARE_SIM_OBJECT_PARAMS(ITXReader) + + +BEGIN_INIT_SIM_OBJECT_PARAMS(ITXReader) + + INIT_PARAM(filename, "trace file") + +END_INIT_SIM_OBJECT_PARAMS(ITXReader) + + +CREATE_SIM_OBJECT(ITXReader) +{ + return new ITXReader(getInstanceName(), filename); +} + +REGISTER_SIM_OBJECT("ITXReader", ITXReader) diff --git a/src/cpu/trace/reader/itx_reader.hh b/src/cpu/trace/reader/itx_reader.hh new file mode 100644 index 000000000..63a4c9ac9 --- /dev/null +++ b/src/cpu/trace/reader/itx_reader.hh @@ -0,0 +1,86 @@ +/* + * 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: Erik Hallnor + */ + +/** + * @file + * Definition of a Intel ITX memory trace format reader. + */ + +#ifndef __ITX_READER_HH__ +#define __ITX_READER_HH__ + +#include <stdio.h> +#include <string> + +#include "cpu/trace/reader/mem_trace_reader.hh" +#include "mem/mem_req.hh" + + +/** + * A memory trace reader for the Intel ITX memory trace format. + */ +class ITXReader : public MemTraceReader +{ + private: + /** Trace file. */ + FILE *trace; + + bool codeVirtValid; + Addr codeVirtAddr; + bool codePhysValid; + Addr codePhysAddr; + + int traceFormat; + + enum ITXType { + ITXRead, + ITXWrite, + ITXWriteback, + ITXCode, + ITXCodeComp + }; + + public: + /** + * Construct an ITXReader. + */ + ITXReader(const std::string &name, const std::string &filename); + + /** + * Read the next request from the trace. Returns the request in the + * provided MemReqPtr and the cycle of the request in the return value. + * @param req Return the next request from the trace. + * @return ITX traces don't store timing information, return 0 + */ + virtual Tick getNextReq(MemReqPtr &req); +}; + +#endif //__ITX_READER_HH__ + diff --git a/src/cpu/trace/reader/m5_reader.cc b/src/cpu/trace/reader/m5_reader.cc new file mode 100644 index 000000000..8efcb022b --- /dev/null +++ b/src/cpu/trace/reader/m5_reader.cc @@ -0,0 +1,99 @@ +/* + * 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: Erik Hallnor + */ + +/** + * @file + * Declaration of a memory trace reader for a M5 memory trace. + */ + +#include "cpu/trace/reader/m5_reader.hh" +#include "mem/trace/m5_format.hh" +#include "mem/mem_cmd.hh" +#include "sim/builder.hh" + +using namespace std; + +M5Reader::M5Reader(const string &name, const string &filename) + : MemTraceReader(name) +{ + traceFile.open(filename.c_str(), ios::binary); +} + +Tick +M5Reader::getNextReq(MemReqPtr &req) +{ + M5Format ref; + + MemReqPtr tmp_req; + // Need to read EOF char before eof() will return true. + traceFile.read((char*) &ref, sizeof(ref)); + if (!traceFile.eof()) { + //traceFile.read((char*) &ref, sizeof(ref)); +#ifndef NDEBUG + int gcount = traceFile.gcount(); + assert(gcount != 0 || traceFile.eof()); + assert(gcount == sizeof(ref)); + assert(ref.cmd < 12); +#endif + tmp_req = new MemReq(); + tmp_req->paddr = ref.paddr; + tmp_req->asid = ref.asid; + // Assume asid == thread_num + tmp_req->thread_num = ref.asid; + tmp_req->cmd = (MemCmdEnum)ref.cmd; + tmp_req->size = ref.size; + tmp_req->dest = ref.dest; + } else { + ref.cycle = 0; + } + req = tmp_req; + return ref.cycle; +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(M5Reader) + + Param<string> filename; + +END_DECLARE_SIM_OBJECT_PARAMS(M5Reader) + + +BEGIN_INIT_SIM_OBJECT_PARAMS(M5Reader) + + INIT_PARAM(filename, "trace file") + +END_INIT_SIM_OBJECT_PARAMS(M5Reader) + + +CREATE_SIM_OBJECT(M5Reader) +{ + return new M5Reader(getInstanceName(), filename); +} + +REGISTER_SIM_OBJECT("M5Reader", M5Reader) diff --git a/src/cpu/trace/reader/m5_reader.hh b/src/cpu/trace/reader/m5_reader.hh new file mode 100644 index 000000000..5007bfd5b --- /dev/null +++ b/src/cpu/trace/reader/m5_reader.hh @@ -0,0 +1,69 @@ +/* + * 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: Erik Hallnor + */ + +/** + * @file + * Definition of a memory trace reader for a M5 memory trace. + */ + +#ifndef __M5_READER_HH__ +#define __M5_READER_HH__ + +#include <fstream> + +#include "cpu/trace/reader/mem_trace_reader.hh" + +/** + * A memory trace reader for an M5 memory trace. @sa M5Writer. + */ +class M5Reader : public MemTraceReader +{ + /** The traceFile. */ + std::ifstream traceFile; + + std::string fn; + + public: + /** + * Construct an M5 memory trace reader. + */ + M5Reader(const std::string &name, const std::string &filename); + + + /** + * Read the next request from the trace. Returns the request in the + * provided MemReqPtr and the cycle of the request in the return value. + * @param req Return the next request from the trace. + * @return The cycle the reference was started. + */ + virtual Tick getNextReq(MemReqPtr &req); +}; + +#endif // __M5_READER_HH__ diff --git a/src/cpu/trace/reader/mem_trace_reader.cc b/src/cpu/trace/reader/mem_trace_reader.cc new file mode 100644 index 000000000..5623f168a --- /dev/null +++ b/src/cpu/trace/reader/mem_trace_reader.cc @@ -0,0 +1,39 @@ +/* + * 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: Erik Hallnor + */ + +/** + * @file + * SimObject Declaration of pure virtual MemTraceReader class. + */ + +#include "cpu/trace/reader/mem_trace_reader.hh" +#include "sim/param.hh" + +DEFINE_SIM_OBJECT_CLASS_NAME("MemTraceReader", MemTraceReader); diff --git a/src/cpu/trace/reader/mem_trace_reader.hh b/src/cpu/trace/reader/mem_trace_reader.hh new file mode 100644 index 000000000..628a3ecdc --- /dev/null +++ b/src/cpu/trace/reader/mem_trace_reader.hh @@ -0,0 +1,59 @@ +/* + * 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: Erik Hallnor + */ + +/** + * Definitions for a pure virtual interface to a memory trace reader. + */ + +#ifndef __MEM_TRACE_READER_HH__ +#define __MEM_TRACE_READER_HH__ + +#include "sim/sim_object.hh" +#include "mem/mem_req.hh" // For MemReqPtr + +/** + * Pure virtual base class for memory trace readers. + */ +class MemTraceReader : public SimObject +{ + public: + /** Construct this MemoryTrace reader. */ + MemTraceReader(const std::string &name) : SimObject(name) {} + + /** + * Read the next request from the trace. Returns the request in the + * provided MemReqPtr and the cycle of the request in the return value. + * @param req Return the next request from the trace. + * @return The cycle of the request, 0 if none in trace. + */ + virtual Tick getNextReq(MemReqPtr &req) = 0; +}; + +#endif //__MEM_TRACE_READER_HH__ diff --git a/src/cpu/trace/trace_cpu.cc b/src/cpu/trace/trace_cpu.cc new file mode 100644 index 000000000..3c9da4849 --- /dev/null +++ b/src/cpu/trace/trace_cpu.cc @@ -0,0 +1,181 @@ +/* + * 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: Erik Hallnor + */ + +/** + * @file + * Declaration of a memory trace CPU object. Uses a memory trace to drive the + * provided memory hierarchy. + */ + +#include <algorithm> // For min + +#include "cpu/trace/trace_cpu.hh" +#include "cpu/trace/reader/mem_trace_reader.hh" +#include "mem/base_mem.hh" // For PARAM constructor +#include "mem/mem_interface.hh" +#include "sim/builder.hh" +#include "sim/sim_events.hh" + +using namespace std; + +TraceCPU::TraceCPU(const string &name, + MemInterface *icache_interface, + MemInterface *dcache_interface, + MemTraceReader *data_trace) + : SimObject(name), icacheInterface(icache_interface), + dcacheInterface(dcache_interface), + dataTrace(data_trace), outstandingRequests(0), tickEvent(this) +{ + assert(dcacheInterface); + nextCycle = dataTrace->getNextReq(nextReq); + tickEvent.schedule(0); +} + +void +TraceCPU::tick() +{ + assert(outstandingRequests >= 0); + assert(outstandingRequests < 1000); + int instReqs = 0; + int dataReqs = 0; + + while (nextReq && curTick >= nextCycle) { + assert(nextReq->thread_num < 4 && "Not enough threads"); + if (nextReq->isInstRead() && icacheInterface) { + if (icacheInterface->isBlocked()) + break; + + nextReq->time = curTick; + if (nextReq->cmd == Squash) { + icacheInterface->squash(nextReq->asid); + } else { + ++instReqs; + if (icacheInterface->doEvents()) { + nextReq->completionEvent = + new TraceCompleteEvent(nextReq, this); + icacheInterface->access(nextReq); + } else { + icacheInterface->access(nextReq); + completeRequest(nextReq); + } + } + } else { + if (dcacheInterface->isBlocked()) + break; + + ++dataReqs; + nextReq->time = curTick; + if (dcacheInterface->doEvents()) { + nextReq->completionEvent = + new TraceCompleteEvent(nextReq, this); + dcacheInterface->access(nextReq); + } else { + dcacheInterface->access(nextReq); + completeRequest(nextReq); + } + + } + nextCycle = dataTrace->getNextReq(nextReq); + } + + if (!nextReq) { + // No more requests to send. Finish trailing events and exit. + if (mainEventQueue.empty()) { + exitSimLoop("end of memory trace reached"); + } else { + tickEvent.schedule(mainEventQueue.nextEventTime() + cycles(1)); + } + } else { + tickEvent.schedule(max(curTick + cycles(1), nextCycle)); + } +} + +void +TraceCPU::completeRequest(MemReqPtr& req) +{ +} + +void +TraceCompleteEvent::process() +{ + tester->completeRequest(req); +} + +const char * +TraceCompleteEvent::description() +{ + return "trace access complete"; +} + +TraceCPU::TickEvent::TickEvent(TraceCPU *c) + : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) +{ +} + +void +TraceCPU::TickEvent::process() +{ + cpu->tick(); +} + +const char * +TraceCPU::TickEvent::description() +{ + return "TraceCPU tick event"; +} + + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(TraceCPU) + + SimObjectParam<BaseMem *> icache; + SimObjectParam<BaseMem *> dcache; + SimObjectParam<MemTraceReader *> data_trace; + +END_DECLARE_SIM_OBJECT_PARAMS(TraceCPU) + +BEGIN_INIT_SIM_OBJECT_PARAMS(TraceCPU) + + INIT_PARAM_DFLT(icache, "instruction cache", NULL), + INIT_PARAM_DFLT(dcache, "data cache", NULL), + INIT_PARAM_DFLT(data_trace, "data trace", NULL) + +END_INIT_SIM_OBJECT_PARAMS(TraceCPU) + +CREATE_SIM_OBJECT(TraceCPU) +{ + return new TraceCPU(getInstanceName(), + (icache) ? icache->getInterface() : NULL, + (dcache) ? dcache->getInterface() : NULL, + data_trace); +} + +REGISTER_SIM_OBJECT("TraceCPU", TraceCPU) + diff --git a/src/cpu/trace/trace_cpu.hh b/src/cpu/trace/trace_cpu.hh new file mode 100644 index 000000000..9c96d71d5 --- /dev/null +++ b/src/cpu/trace/trace_cpu.hh @@ -0,0 +1,142 @@ +/* + * 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: Erik Hallnor + */ + +/** + * @file + * Declaration of a memory trace CPU object. Uses a memory trace to drive the + * provided memory hierarchy. + */ + +#ifndef __CPU_TRACE_TRACE_CPU_HH__ +#define __CPU_TRACE_TRACE_CPU_HH__ + +#include <string> + +#include "mem/mem_req.hh" // for MemReqPtr +#include "sim/eventq.hh" // for Event +#include "sim/sim_object.hh" + +// Forward declaration. +class MemInterface; +class MemTraceReader; + +/** + * A cpu object for running memory traces through a memory hierarchy. + */ +class TraceCPU : public SimObject +{ + private: + /** Interface for instruction trace requests, if any. */ + MemInterface *icacheInterface; + /** Interface for data trace requests, if any. */ + MemInterface *dcacheInterface; + + /** Data reference trace. */ + MemTraceReader *dataTrace; + + /** Number of outstanding requests. */ + int outstandingRequests; + + /** Cycle of the next request, 0 if not available. */ + Tick nextCycle; + + /** Next request. */ + MemReqPtr nextReq; + + /** + * Event to call the TraceCPU::tick + */ + class TickEvent : public Event + { + private: + /** The associated CPU */ + TraceCPU *cpu; + + public: + /** + * Construct this event; + */ + TickEvent(TraceCPU *c); + + /** + * Call the tick function. + */ + void process(); + + /** + * Return a string description of this event. + */ + const char *description(); + }; + + TickEvent tickEvent; + + public: + /** + * Construct a TraceCPU object. + */ + TraceCPU(const std::string &name, + MemInterface *icache_interface, + MemInterface *dcache_interface, + MemTraceReader *data_trace); + + inline Tick cycles(int numCycles) { return numCycles; } + + /** + * Perform all the accesses for one cycle. + */ + void tick(); + + /** + * Handle a completed memory request. + */ + void completeRequest(MemReqPtr &req); +}; + +class TraceCompleteEvent : public Event +{ + MemReqPtr req; + TraceCPU *tester; + + public: + + TraceCompleteEvent(MemReqPtr &_req, TraceCPU *_tester) + : Event(&mainEventQueue), req(_req), tester(_tester) + { + setFlags(AutoDelete); + } + + void process(); + + virtual const char *description(); +}; + +#endif // __CPU_TRACE_TRACE_CPU_HH__ + diff --git a/src/dev/alpha_access.h b/src/dev/alpha_access.h new file mode 100644 index 000000000..4adeaf84b --- /dev/null +++ b/src/dev/alpha_access.h @@ -0,0 +1,75 @@ +/* + * 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 + */ + +#ifndef __ALPHA_ACCESS_H__ +#define __ALPHA_ACCESS_H__ + +/** @file + * System Console Memory Mapped Register Definition + */ + +#define ALPHA_ACCESS_VERSION (1305) + +#ifdef CONSOLE +typedef unsigned uint32_t; +typedef unsigned long uint64_t; +#endif + +// This structure hacked up from simos +struct AlphaAccess +{ + uint32_t last_offset; // 00: must be first field + uint32_t version; // 04: + uint32_t numCPUs; // 08: + uint32_t intrClockFrequency; // 0C: Hz + uint64_t cpuClock; // 10: MHz + uint64_t mem_size; // 18: + + // Loaded kernel + uint64_t kernStart; // 20: + uint64_t kernEnd; // 28: + uint64_t entryPoint; // 30: + + // console disk stuff + uint64_t diskUnit; // 38: + uint64_t diskCount; // 40: + uint64_t diskPAddr; // 48: + uint64_t diskBlock; // 50: + uint64_t diskOperation; // 58: + + // console simple output stuff + uint64_t outputChar; // 60: Placeholder for output + uint64_t inputChar; // 68: Placeholder for input + + // MP boot + uint64_t cpuStack[64]; // 70: +}; + +#endif // __ALPHA_ACCESS_H__ diff --git a/src/dev/alpha_console.cc b/src/dev/alpha_console.cc new file mode 100644 index 000000000..181bbf934 --- /dev/null +++ b/src/dev/alpha_console.cc @@ -0,0 +1,346 @@ +/* + * 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 + * Ali Saidi + * Steve Reinhardt + * Erik Hallnor + */ + +/** @file + * Alpha Console Definition + */ + +#include <cstddef> +#include <string> + +#include "arch/alpha/system.hh" +#include "base/inifile.hh" +#include "base/str.hh" +#include "base/trace.hh" +#include "cpu/base.hh" +#include "cpu/thread_context.hh" +#include "dev/alpha_console.hh" +#include "dev/platform.hh" +#include "dev/simconsole.hh" +#include "dev/simple_disk.hh" +#include "mem/physical.hh" +#include "sim/builder.hh" +#include "sim/sim_object.hh" + +using namespace std; +using namespace AlphaISA; + +AlphaConsole::AlphaConsole(Params *p) + : BasicPioDevice(p), disk(p->disk), + console(params()->cons), system(params()->alpha_sys), cpu(params()->cpu) +{ + + pioSize = sizeof(struct AlphaAccess); + + alphaAccess = new Access(); + alphaAccess->last_offset = pioSize - 1; + + alphaAccess->version = ALPHA_ACCESS_VERSION; + alphaAccess->diskUnit = 1; + + alphaAccess->diskCount = 0; + alphaAccess->diskPAddr = 0; + alphaAccess->diskBlock = 0; + alphaAccess->diskOperation = 0; + alphaAccess->outputChar = 0; + alphaAccess->inputChar = 0; + bzero(alphaAccess->cpuStack, sizeof(alphaAccess->cpuStack)); + +} + +void +AlphaConsole::startup() +{ + system->setAlphaAccess(pioAddr); + alphaAccess->numCPUs = system->getNumCPUs(); + alphaAccess->kernStart = system->getKernelStart(); + alphaAccess->kernEnd = system->getKernelEnd(); + alphaAccess->entryPoint = system->getKernelEntry(); + alphaAccess->mem_size = system->physmem->size(); + alphaAccess->cpuClock = cpu->frequency() / 1000000; // In MHz + alphaAccess->intrClockFrequency = params()->platform->intrFrequency(); +} + +Tick +AlphaConsole::read(Packet *pkt) +{ + + /** XXX Do we want to push the addr munging to a bus brige or something? So + * the device has it's physical address and then the bridge adds on whatever + * machine dependent address swizzle is required? + */ + + assert(pkt->result == Packet::Unknown); + assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); + + Addr daddr = pkt->getAddr() - pioAddr; + + pkt->allocate(); + + switch (pkt->getSize()) + { + case sizeof(uint32_t): + switch (daddr) + { + case offsetof(AlphaAccess, last_offset): + pkt->set(alphaAccess->last_offset); + break; + case offsetof(AlphaAccess, version): + pkt->set(alphaAccess->version); + break; + case offsetof(AlphaAccess, numCPUs): + pkt->set(alphaAccess->numCPUs); + break; + case offsetof(AlphaAccess, intrClockFrequency): + pkt->set(alphaAccess->intrClockFrequency); + break; + default: + /* Old console code read in everyting as a 32bit int + * we now break that for better error checking. + */ + pkt->result = Packet::BadAddress; + } + DPRINTF(AlphaConsole, "read: offset=%#x val=%#x\n", daddr, + pkt->get<uint32_t>()); + break; + case sizeof(uint64_t): + switch (daddr) + { + case offsetof(AlphaAccess, inputChar): + pkt->set(console->console_in()); + break; + case offsetof(AlphaAccess, cpuClock): + pkt->set(alphaAccess->cpuClock); + break; + case offsetof(AlphaAccess, mem_size): + pkt->set(alphaAccess->mem_size); + break; + case offsetof(AlphaAccess, kernStart): + pkt->set(alphaAccess->kernStart); + break; + case offsetof(AlphaAccess, kernEnd): + pkt->set(alphaAccess->kernEnd); + break; + case offsetof(AlphaAccess, entryPoint): + pkt->set(alphaAccess->entryPoint); + break; + case offsetof(AlphaAccess, diskUnit): + pkt->set(alphaAccess->diskUnit); + break; + case offsetof(AlphaAccess, diskCount): + pkt->set(alphaAccess->diskCount); + break; + case offsetof(AlphaAccess, diskPAddr): + pkt->set(alphaAccess->diskPAddr); + break; + case offsetof(AlphaAccess, diskBlock): + pkt->set(alphaAccess->diskBlock); + break; + case offsetof(AlphaAccess, diskOperation): + pkt->set(alphaAccess->diskOperation); + break; + case offsetof(AlphaAccess, outputChar): + pkt->set(alphaAccess->outputChar); + break; + default: + int cpunum = (daddr - offsetof(AlphaAccess, cpuStack)) / + sizeof(alphaAccess->cpuStack[0]); + + if (cpunum >= 0 && cpunum < 64) + pkt->set(alphaAccess->cpuStack[cpunum]); + else + panic("Unknown 64bit access, %#x\n", daddr); + } + DPRINTF(AlphaConsole, "read: offset=%#x val=%#x\n", daddr, + pkt->get<uint64_t>()); + break; + default: + pkt->result = Packet::BadAddress; + } + if (pkt->result == Packet::Unknown) + pkt->result = Packet::Success; + return pioDelay; +} + +Tick +AlphaConsole::write(Packet *pkt) +{ + assert(pkt->result == Packet::Unknown); + assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); + Addr daddr = pkt->getAddr() - pioAddr; + + uint64_t val = pkt->get<uint64_t>(); + assert(pkt->getSize() == sizeof(uint64_t)); + + switch (daddr) { + case offsetof(AlphaAccess, diskUnit): + alphaAccess->diskUnit = val; + break; + + case offsetof(AlphaAccess, diskCount): + alphaAccess->diskCount = val; + break; + + case offsetof(AlphaAccess, diskPAddr): + alphaAccess->diskPAddr = val; + break; + + case offsetof(AlphaAccess, diskBlock): + alphaAccess->diskBlock = val; + break; + + case offsetof(AlphaAccess, diskOperation): + if (val == 0x13) + disk->read(alphaAccess->diskPAddr, alphaAccess->diskBlock, + alphaAccess->diskCount); + else + panic("Invalid disk operation!"); + + break; + + case offsetof(AlphaAccess, outputChar): + console->out((char)(val & 0xff)); + break; + + default: + int cpunum = (daddr - offsetof(AlphaAccess, cpuStack)) / + sizeof(alphaAccess->cpuStack[0]); + warn("%d: Trying to launch CPU number %d!", curTick, cpunum); + assert(val > 0 && "Must not access primary cpu"); + if (cpunum >= 0 && cpunum < 64) + alphaAccess->cpuStack[cpunum] = val; + else + panic("Unknown 64bit access, %#x\n", daddr); + } + + pkt->result = Packet::Success; + + return pioDelay; +} + +void +AlphaConsole::Access::serialize(ostream &os) +{ + SERIALIZE_SCALAR(last_offset); + SERIALIZE_SCALAR(version); + SERIALIZE_SCALAR(numCPUs); + SERIALIZE_SCALAR(mem_size); + SERIALIZE_SCALAR(cpuClock); + SERIALIZE_SCALAR(intrClockFrequency); + SERIALIZE_SCALAR(kernStart); + SERIALIZE_SCALAR(kernEnd); + SERIALIZE_SCALAR(entryPoint); + SERIALIZE_SCALAR(diskUnit); + SERIALIZE_SCALAR(diskCount); + SERIALIZE_SCALAR(diskPAddr); + SERIALIZE_SCALAR(diskBlock); + SERIALIZE_SCALAR(diskOperation); + SERIALIZE_SCALAR(outputChar); + SERIALIZE_SCALAR(inputChar); + SERIALIZE_ARRAY(cpuStack,64); +} + +void +AlphaConsole::Access::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_SCALAR(last_offset); + UNSERIALIZE_SCALAR(version); + UNSERIALIZE_SCALAR(numCPUs); + UNSERIALIZE_SCALAR(mem_size); + UNSERIALIZE_SCALAR(cpuClock); + UNSERIALIZE_SCALAR(intrClockFrequency); + UNSERIALIZE_SCALAR(kernStart); + UNSERIALIZE_SCALAR(kernEnd); + UNSERIALIZE_SCALAR(entryPoint); + UNSERIALIZE_SCALAR(diskUnit); + UNSERIALIZE_SCALAR(diskCount); + UNSERIALIZE_SCALAR(diskPAddr); + UNSERIALIZE_SCALAR(diskBlock); + UNSERIALIZE_SCALAR(diskOperation); + UNSERIALIZE_SCALAR(outputChar); + UNSERIALIZE_SCALAR(inputChar); + UNSERIALIZE_ARRAY(cpuStack, 64); +} + +void +AlphaConsole::serialize(ostream &os) +{ + alphaAccess->serialize(os); +} + +void +AlphaConsole::unserialize(Checkpoint *cp, const std::string §ion) +{ + alphaAccess->unserialize(cp, section); +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaConsole) + + SimObjectParam<SimConsole *> sim_console; + SimObjectParam<SimpleDisk *> disk; + Param<Addr> pio_addr; + SimObjectParam<AlphaSystem *> system; + SimObjectParam<BaseCPU *> cpu; + SimObjectParam<Platform *> platform; + Param<Tick> pio_latency; + +END_DECLARE_SIM_OBJECT_PARAMS(AlphaConsole) + +BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaConsole) + + INIT_PARAM(sim_console, "The Simulator Console"), + INIT_PARAM(disk, "Simple Disk"), + INIT_PARAM(pio_addr, "Device Address"), + INIT_PARAM(system, "system object"), + INIT_PARAM(cpu, "Processor"), + INIT_PARAM(platform, "platform"), + INIT_PARAM_DFLT(pio_latency, "Programmed IO latency", 1000) + +END_INIT_SIM_OBJECT_PARAMS(AlphaConsole) + +CREATE_SIM_OBJECT(AlphaConsole) +{ + AlphaConsole::Params *p = new AlphaConsole::Params; + p->name = getInstanceName(); + p->platform = platform; + p->pio_addr = pio_addr; + p->pio_delay = pio_latency; + p->cons = sim_console; + p->disk = disk; + p->alpha_sys = system; + p->system = system; + p->cpu = cpu; + return new AlphaConsole(p); +} + +REGISTER_SIM_OBJECT("AlphaConsole", AlphaConsole) diff --git a/src/dev/alpha_console.hh b/src/dev/alpha_console.hh new file mode 100644 index 000000000..b6360d40f --- /dev/null +++ b/src/dev/alpha_console.hh @@ -0,0 +1,131 @@ +/* + * 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 + */ + +/** @file + * System Console Interface + */ + +#ifndef __ALPHA_CONSOLE_HH__ +#define __ALPHA_CONSOLE_HH__ + +#include "base/range.hh" +#include "dev/alpha_access.h" +#include "dev/io_device.hh" +#include "sim/host.hh" +#include "sim/sim_object.hh" + +class BaseCPU; +class SimConsole; +class AlphaSystem; +class SimpleDisk; + +/** + * Memory mapped interface to the system console. This device + * represents a shared data region between the OS Kernel and the + * System Console. + * + * The system console is a small standalone program that is initially + * run when the system boots. It contains the necessary code to + * access the boot disk, to read/write from the console, and to pass + * boot parameters to the kernel. + * + * This version of the system console is very different from the one + * that would be found in a real system. Many of the functions use + * some sort of backdoor to get their job done. For example, reading + * from the boot device on a real system would require a minimal + * device driver to access the disk controller, but since we have a + * simulator here, we are able to bypass the disk controller and + * access the disk image directly. There are also some things like + * reading the kernel off the disk image into memory that are normally + * taken care of by the console that are now taken care of by the + * simulator. + * + * These shortcuts are acceptable since the system console is + * primarily used doing boot before the kernel has loaded its device + * drivers. + */ +class AlphaConsole : public BasicPioDevice +{ + protected: + struct Access : public AlphaAccess + { + void serialize(std::ostream &os); + void unserialize(Checkpoint *cp, const std::string §ion); + }; + + union { + Access *alphaAccess; + uint8_t *consoleData; + }; + + /** the disk must be accessed from the console */ + SimpleDisk *disk; + + /** the system console (the terminal) is accessable from the console */ + SimConsole *console; + + /** a pointer to the system we are running in */ + AlphaSystem *system; + + /** a pointer to the CPU boot cpu */ + BaseCPU *cpu; + + public: + struct Params : public BasicPioDevice::Params + { + SimConsole *cons; + SimpleDisk *disk; + AlphaSystem *alpha_sys; + BaseCPU *cpu; + }; + protected: + const Params *params() const {return (const Params *)_params; } + + public: + + /** Standard Constructor */ + AlphaConsole(Params *p); + + virtual void startup(); + + /** + * memory mapped reads and writes + */ + virtual Tick read(Packet *pkt); + virtual Tick write(Packet *pkt); + + /** + * standard serialization routines for checkpointing + */ + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); +}; + +#endif // __ALPHA_CONSOLE_HH__ diff --git a/src/dev/baddev.cc b/src/dev/baddev.cc new file mode 100644 index 000000000..e4297be19 --- /dev/null +++ b/src/dev/baddev.cc @@ -0,0 +1,99 @@ +/* + * 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: Ali Saidi + */ + +/** @file + * BadDevice implemenation + */ + +#include <deque> +#include <string> +#include <vector> + +#include "base/trace.hh" +#include "dev/baddev.hh" +#include "dev/platform.hh" +#include "mem/port.hh" +#include "sim/builder.hh" +#include "sim/system.hh" + +using namespace std; +using namespace TheISA; + +BadDevice::BadDevice(Params *p) + : BasicPioDevice(p), devname(p->device_name) +{ + pioSize = 0xf; +} + +Tick +BadDevice::read(Packet *pkt) +{ + panic("Device %s not imlpmented\n", devname); +} + +Tick +BadDevice::write(Packet *pkt) +{ + panic("Device %s not imlpmented\n", devname); +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(BadDevice) + + Param<string> devicename; + Param<Addr> pio_addr; + SimObjectParam<System *> system; + SimObjectParam<Platform *> platform; + Param<Tick> pio_latency; + +END_DECLARE_SIM_OBJECT_PARAMS(BadDevice) + +BEGIN_INIT_SIM_OBJECT_PARAMS(BadDevice) + + INIT_PARAM(devicename, "Name of device to error on"), + INIT_PARAM(pio_addr, "Device Address"), + INIT_PARAM(system, "system object"), + INIT_PARAM(platform, "platform"), + INIT_PARAM_DFLT(pio_latency, "Programmed IO latency", 1000) + +END_INIT_SIM_OBJECT_PARAMS(BadDevice) + +CREATE_SIM_OBJECT(BadDevice) +{ + BadDevice::Params *p = new BadDevice::Params; + p->name =getInstanceName(); + p->platform = platform; + p->pio_addr = pio_addr; + p->pio_delay = pio_latency; + p->system = system; + p->device_name = devicename; + return new BadDevice(p); +} + +REGISTER_SIM_OBJECT("BadDevice", BadDevice) diff --git a/src/dev/baddev.hh b/src/dev/baddev.hh new file mode 100644 index 000000000..d7d778af4 --- /dev/null +++ b/src/dev/baddev.hh @@ -0,0 +1,74 @@ +/* + * 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: Ali Saidi + */ + +/** @file + * This devices just panics when touched. For example if you have a + * kernel that touches the frame buffer which isn't allowed. + */ + +#ifndef __DEV_BADDEV_HH__ +#define __DEV_BADDEV_HH__ + +#include "base/range.hh" +#include "dev/io_device.hh" + + +/** + * BadDevice + * This device just panics when accessed. It is supposed to warn + * the user that the kernel they are running has unsupported + * options (i.e. frame buffer) + */ +class BadDevice : public BasicPioDevice +{ + private: + std::string devname; + + public: + struct Params : public BasicPioDevice::Params + { + std::string device_name; + }; + protected: + const Params *params() const { return (const Params *)_params; } + + public: + /** + * Constructor for the Baddev Class. + * @param p object parameters + * @param a base address of the write + */ + BadDevice(Params *p); + + virtual Tick read(Packet *pkt); + virtual Tick write(Packet *pkt); +}; + +#endif // __DEV_BADDEV_HH__ diff --git a/src/dev/disk_image.cc b/src/dev/disk_image.cc new file mode 100644 index 000000000..f70d2ccdb --- /dev/null +++ b/src/dev/disk_image.cc @@ -0,0 +1,472 @@ +/* + * 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 + */ + +/** @file + * Disk Image Definitions + */ + +#include <sys/types.h> +#include <sys/uio.h> +#include <errno.h> +#include <unistd.h> + +#include <cstring> +#include <fstream> +#include <string> + +#include "base/callback.hh" +#include "base/misc.hh" +#include "base/trace.hh" +#include "dev/disk_image.hh" +#include "sim/builder.hh" +#include "sim/sim_exit.hh" +#include "sim/byteswap.hh" + +using namespace std; + +//////////////////////////////////////////////////////////////////////// +// +// Raw Disk image +// +RawDiskImage::RawDiskImage(const string &name, const string &filename, + bool rd_only) + : DiskImage(name), disk_size(0) +{ open(filename, rd_only); } + +RawDiskImage::~RawDiskImage() +{ close(); } + +void +RawDiskImage::open(const string &filename, bool rd_only) +{ + if (!filename.empty()) { + initialized = true; + readonly = rd_only; + file = filename; + + ios::openmode mode = ios::in | ios::binary; + if (!readonly) + mode |= ios::out; + stream.open(file.c_str(), mode); + if (!stream.is_open()) + panic("Error opening %s", filename); + } +} + +void +RawDiskImage::close() +{ + stream.close(); +} + +off_t +RawDiskImage::size() const +{ + if (disk_size == 0) { + if (!stream.is_open()) + panic("file not open!\n"); + stream.seekg(0, ios::end); + disk_size = stream.tellg(); + } + + return disk_size / SectorSize; +} + +off_t +RawDiskImage::read(uint8_t *data, off_t offset) const +{ + if (!initialized) + panic("RawDiskImage not initialized"); + + if (!stream.is_open()) + panic("file not open!\n"); + + if (stream.seekg(offset * SectorSize, ios::beg) < 0) + panic("Could not seek to location in file"); + + streampos pos = stream.tellg(); + stream.read((char *)data, SectorSize); + + DPRINTF(DiskImageRead, "read: offset=%d\n", (uint64_t)offset); + DDUMP(DiskImageRead, data, SectorSize); + + return stream.tellg() - pos; +} + +off_t +RawDiskImage::write(const uint8_t *data, off_t offset) +{ + if (!initialized) + panic("RawDiskImage not initialized"); + + if (readonly) + panic("Cannot write to a read only disk image"); + + if (!stream.is_open()) + panic("file not open!\n"); + + if (stream.seekp(offset * SectorSize, ios::beg) < 0) + panic("Could not seek to location in file"); + + DPRINTF(DiskImageWrite, "write: offset=%d\n", (uint64_t)offset); + DDUMP(DiskImageWrite, data, SectorSize); + + streampos pos = stream.tellp(); + stream.write((const char *)data, SectorSize); + return stream.tellp() - pos; +} + +DEFINE_SIM_OBJECT_CLASS_NAME("DiskImage", DiskImage) + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(RawDiskImage) + + Param<string> image_file; + Param<bool> read_only; + +END_DECLARE_SIM_OBJECT_PARAMS(RawDiskImage) + +BEGIN_INIT_SIM_OBJECT_PARAMS(RawDiskImage) + + INIT_PARAM(image_file, "disk image file"), + INIT_PARAM_DFLT(read_only, "read only image", false) + +END_INIT_SIM_OBJECT_PARAMS(RawDiskImage) + + +CREATE_SIM_OBJECT(RawDiskImage) +{ + return new RawDiskImage(getInstanceName(), image_file, read_only); +} + +REGISTER_SIM_OBJECT("RawDiskImage", RawDiskImage) + +//////////////////////////////////////////////////////////////////////// +// +// Copy on Write Disk image +// +const int CowDiskImage::VersionMajor = 1; +const int CowDiskImage::VersionMinor = 0; + +CowDiskImage::CowDiskImage(const string &name, DiskImage *kid, int hash_size) + : DiskImage(name), child(kid), table(NULL) +{ init(hash_size); } + +class CowDiskCallback : public Callback +{ + private: + CowDiskImage *image; + + public: + CowDiskCallback(CowDiskImage *i) : image(i) {} + void process() { image->save(); delete this; } +}; + +CowDiskImage::CowDiskImage(const string &name, DiskImage *kid, int hash_size, + const string &file, bool read_only) + : DiskImage(name), filename(file), child(kid), table(NULL) +{ + if (!open(filename)) { + assert(!read_only && "why have a non-existent read only file?"); + init(hash_size); + } + + if (!read_only) + registerExitCallback(new CowDiskCallback(this)); +} + +CowDiskImage::~CowDiskImage() +{ + SectorTable::iterator i = table->begin(); + SectorTable::iterator end = table->end(); + + while (i != end) { + delete (*i).second; + ++i; + } +} + +void +SafeRead(ifstream &stream, void *data, int count) +{ + stream.read((char *)data, count); + if (!stream.is_open()) + panic("file not open"); + + if (stream.eof()) + panic("premature end-of-file"); + + if (stream.bad() || stream.fail()) + panic("error reading cowdisk image"); +} + +template<class T> +void +SafeRead(ifstream &stream, T &data) +{ + SafeRead(stream, &data, sizeof(data)); +} + +template<class T> +void +SafeReadSwap(ifstream &stream, T &data) +{ + SafeRead(stream, &data, sizeof(data)); + data = letoh(data); //is this the proper byte order conversion? +} + +bool +CowDiskImage::open(const string &file) +{ + ifstream stream(file.c_str()); + if (!stream.is_open()) + return false; + + if (stream.fail() || stream.bad()) + panic("Error opening %s", file); + + uint64_t magic; + SafeRead(stream, magic); + + if (memcmp(&magic, "COWDISK!", sizeof(magic)) != 0) + panic("Could not open %s: Invalid magic", file); + + uint32_t major, minor; + SafeReadSwap(stream, major); + SafeReadSwap(stream, minor); + + if (major != VersionMajor && minor != VersionMinor) + panic("Could not open %s: invalid version %d.%d != %d.%d", + file, major, minor, VersionMajor, VersionMinor); + + uint64_t sector_count; + SafeReadSwap(stream, sector_count); + table = new SectorTable(sector_count); + + + for (uint64_t i = 0; i < sector_count; i++) { + uint64_t offset; + SafeReadSwap(stream, offset); + + Sector *sector = new Sector; + SafeRead(stream, sector, sizeof(Sector)); + + assert(table->find(offset) == table->end()); + (*table)[offset] = sector; + } + + stream.close(); + + initialized = true; + return true; +} + +void +CowDiskImage::init(int hash_size) +{ + table = new SectorTable(hash_size); + + initialized = true; +} + +void +SafeWrite(ofstream &stream, const void *data, int count) +{ + stream.write((const char *)data, count); + if (!stream.is_open()) + panic("file not open"); + + if (stream.eof()) + panic("premature end-of-file"); + + if (stream.bad() || stream.fail()) + panic("error reading cowdisk image"); +} + +template<class T> +void +SafeWrite(ofstream &stream, const T &data) +{ + SafeWrite(stream, &data, sizeof(data)); +} + +template<class T> +void +SafeWriteSwap(ofstream &stream, const T &data) +{ + T swappeddata = letoh(data); //is this the proper byte order conversion? + SafeWrite(stream, &swappeddata, sizeof(data)); +} +void +CowDiskImage::save() +{ + save(filename); +} + +void +CowDiskImage::save(const string &file) +{ + if (!initialized) + panic("RawDiskImage not initialized"); + + ofstream stream(file.c_str()); + if (!stream.is_open() || stream.fail() || stream.bad()) + panic("Error opening %s", file); + + uint64_t magic; + memcpy(&magic, "COWDISK!", sizeof(magic)); + SafeWrite(stream, magic); + + SafeWriteSwap(stream, (uint32_t)VersionMajor); + SafeWriteSwap(stream, (uint32_t)VersionMinor); + SafeWriteSwap(stream, (uint64_t)table->size()); + + uint64_t size = table->size(); + SectorTable::iterator iter = table->begin(); + SectorTable::iterator end = table->end(); + + for (uint64_t i = 0; i < size; i++) { + if (iter == end) + panic("Incorrect Table Size during save of COW disk image"); + + SafeWriteSwap(stream, (uint64_t)(*iter).first); + SafeWrite(stream, (*iter).second->data, sizeof(Sector)); + ++iter; + } + + stream.close(); +} + +void +CowDiskImage::writeback() +{ + SectorTable::iterator i = table->begin(); + SectorTable::iterator end = table->end(); + + while (i != end) { + child->write((*i).second->data, (*i).first); + ++i; + } +} + +off_t +CowDiskImage::size() const +{ return child->size(); } + +off_t +CowDiskImage::read(uint8_t *data, off_t offset) const +{ + if (!initialized) + panic("CowDiskImage not initialized"); + + if (offset > size()) + panic("access out of bounds"); + + SectorTable::const_iterator i = table->find(offset); + if (i == table->end()) + return child->read(data, offset); + else { + memcpy(data, (*i).second->data, SectorSize); + DPRINTF(DiskImageRead, "read: offset=%d\n", (uint64_t)offset); + DDUMP(DiskImageRead, data, SectorSize); + return SectorSize; + } +} + +off_t +CowDiskImage::write(const uint8_t *data, off_t offset) +{ + if (!initialized) + panic("RawDiskImage not initialized"); + + if (offset > size()) + panic("access out of bounds"); + + SectorTable::iterator i = table->find(offset); + if (i == table->end()) { + Sector *sector = new Sector; + memcpy(sector, data, SectorSize); + table->insert(make_pair(offset, sector)); + } else { + memcpy((*i).second->data, data, SectorSize); + } + + DPRINTF(DiskImageWrite, "write: offset=%d\n", (uint64_t)offset); + DDUMP(DiskImageWrite, data, SectorSize); + + return SectorSize; +} + +void +CowDiskImage::serialize(ostream &os) +{ + string cowFilename = name() + ".cow"; + SERIALIZE_SCALAR(cowFilename); + save(Checkpoint::dir() + "/" + cowFilename); +} + +void +CowDiskImage::unserialize(Checkpoint *cp, const string §ion) +{ + string cowFilename; + UNSERIALIZE_SCALAR(cowFilename); + cowFilename = cp->cptDir + "/" + cowFilename; + open(cowFilename); +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(CowDiskImage) + + SimObjectParam<DiskImage *> child; + Param<string> image_file; + Param<int> table_size; + Param<bool> read_only; + +END_DECLARE_SIM_OBJECT_PARAMS(CowDiskImage) + +BEGIN_INIT_SIM_OBJECT_PARAMS(CowDiskImage) + + INIT_PARAM(child, "child image"), + INIT_PARAM_DFLT(image_file, "disk image file", ""), + INIT_PARAM_DFLT(table_size, "initial table size", 65536), + INIT_PARAM_DFLT(read_only, "don't write back to the copy-on-write file", + true) + +END_INIT_SIM_OBJECT_PARAMS(CowDiskImage) + + +CREATE_SIM_OBJECT(CowDiskImage) +{ + if (((string)image_file).empty()) + return new CowDiskImage(getInstanceName(), child, table_size); + else + return new CowDiskImage(getInstanceName(), child, table_size, + image_file, read_only); +} + +REGISTER_SIM_OBJECT("CowDiskImage", CowDiskImage) diff --git a/src/dev/disk_image.hh b/src/dev/disk_image.hh new file mode 100644 index 000000000..45d5af649 --- /dev/null +++ b/src/dev/disk_image.hh @@ -0,0 +1,135 @@ +/* + * 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 + */ + +/** @file + * Disk Image Interfaces + */ + +#ifndef __DISK_IMAGE_HH__ +#define __DISK_IMAGE_HH__ + +#include <fstream> + +#include "base/hashmap.hh" +#include "sim/sim_object.hh" + +#define SectorSize (512) + +/** + * Basic interface for accessing a disk image. + */ +class DiskImage : public SimObject +{ + protected: + bool initialized; + + public: + DiskImage(const std::string &name) : SimObject(name), initialized(false) {} + virtual ~DiskImage() {} + + virtual off_t size() const = 0; + + virtual off_t read(uint8_t *data, off_t offset) const = 0; + virtual off_t write(const uint8_t *data, off_t offset) = 0; +}; + +/** + * Specialization for accessing a raw disk image + */ +class RawDiskImage : public DiskImage +{ + protected: + mutable std::fstream stream; + std::string file; + bool readonly; + mutable off_t disk_size; + + public: + RawDiskImage(const std::string &name, const std::string &filename, + bool rd_only); + ~RawDiskImage(); + + void close(); + void open(const std::string &filename, bool rd_only = false); + + virtual off_t size() const; + + virtual off_t read(uint8_t *data, off_t offset) const; + virtual off_t write(const uint8_t *data, off_t offset); +}; + +/** + * Specialization for accessing a copy-on-write disk image layer. + * A copy-on-write(COW) layer must be stacked on top of another disk + * image layer this layer can be another CowDiskImage, or a + * RawDiskImage. + * + * This object is designed to provide a mechanism for persistant + * changes to a main disk image, or to provide a place for temporary + * changes to the image to take place that later may be thrown away. + */ +class CowDiskImage : public DiskImage +{ + public: + static const int VersionMajor; + static const int VersionMinor; + + protected: + struct Sector { + uint8_t data[SectorSize]; + }; + typedef m5::hash_map<uint64_t, Sector *> SectorTable; + + protected: + std::string filename; + DiskImage *child; + SectorTable *table; + + public: + CowDiskImage(const std::string &name, DiskImage *kid, int hash_size); + CowDiskImage(const std::string &name, DiskImage *kid, int hash_size, + const std::string &filename, bool read_only); + ~CowDiskImage(); + + void init(int hash_size); + bool open(const std::string &file); + void save(); + void save(const std::string &file); + void writeback(); + void serialize(std::ostream &os); + void unserialize(Checkpoint *cp, const std::string §ion); + + virtual off_t size() const; + + virtual off_t read(uint8_t *data, off_t offset) const; + virtual off_t write(const uint8_t *data, off_t offset); +}; + +#endif // __DISK_IMAGE_HH__ diff --git a/src/dev/etherbus.cc b/src/dev/etherbus.cc new file mode 100644 index 000000000..348bb818a --- /dev/null +++ b/src/dev/etherbus.cc @@ -0,0 +1,127 @@ +/* + * 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 + */ + +/* @file + * Device module for modelling an ethernet hub + */ + +#include <cmath> +#include <deque> +#include <string> +#include <vector> + +#include "base/trace.hh" +#include "dev/etherbus.hh" +#include "dev/etherdump.hh" +#include "dev/etherint.hh" +#include "dev/etherpkt.hh" +#include "sim/builder.hh" +#include "sim/root.hh" + +using namespace std; + +EtherBus::EtherBus(const string &name, double speed, bool loop, + EtherDump *packet_dump) + : SimObject(name), ticksPerByte(speed), loopback(loop), + event(&mainEventQueue, this), sender(0), dump(packet_dump) +{ +} + +void +EtherBus::txDone() +{ + devlist_t::iterator i = devlist.begin(); + devlist_t::iterator end = devlist.end(); + + DPRINTF(Ethernet, "ethernet packet received: length=%d\n", packet->length); + DDUMP(EthernetData, packet->data, packet->length); + + while (i != end) { + if (loopback || *i != sender) + (*i)->sendPacket(packet); + ++i; + } + + sender->sendDone(); + + if (dump) + dump->dump(packet); + + sender = 0; + packet = 0; +} + +void +EtherBus::reg(EtherInt *dev) +{ devlist.push_back(dev); } + +bool +EtherBus::send(EtherInt *sndr, EthPacketPtr &pkt) +{ + if (busy()) { + DPRINTF(Ethernet, "ethernet packet not sent, bus busy\n", curTick); + return false; + } + + DPRINTF(Ethernet, "ethernet packet sent: length=%d\n", pkt->length); + DDUMP(EthernetData, pkt->data, pkt->length); + + packet = pkt; + sender = sndr; + int delay = (int)ceil(((double)pkt->length * ticksPerByte) + 1.0); + DPRINTF(Ethernet, "scheduling packet: delay=%d, (rate=%f)\n", + delay, ticksPerByte); + event.schedule(curTick + delay); + + return true; +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherBus) + + Param<bool> loopback; + Param<double> speed; + SimObjectParam<EtherDump *> packet_dump; + +END_DECLARE_SIM_OBJECT_PARAMS(EtherBus) + +BEGIN_INIT_SIM_OBJECT_PARAMS(EtherBus) + + INIT_PARAM(loopback, "send the packet back to the sending interface"), + INIT_PARAM(speed, "bus speed in ticks per byte"), + INIT_PARAM(packet_dump, "object to dump network packets to") + +END_INIT_SIM_OBJECT_PARAMS(EtherBus) + +CREATE_SIM_OBJECT(EtherBus) +{ + return new EtherBus(getInstanceName(), speed, loopback, packet_dump); +} + +REGISTER_SIM_OBJECT("EtherBus", EtherBus) diff --git a/src/dev/etherbus.hh b/src/dev/etherbus.hh new file mode 100644 index 000000000..2ff1d0a5e --- /dev/null +++ b/src/dev/etherbus.hh @@ -0,0 +1,81 @@ +/* + * 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 + */ + +/* @file + * Device module for modelling an ethernet hub + */ + +#ifndef __ETHERBUS_H__ +#define __ETHERBUS_H__ + +#include "sim/eventq.hh" +#include "dev/etherpkt.hh" +#include "sim/sim_object.hh" + +class EtherDump; +class EtherInt; +class EtherBus : public SimObject +{ + protected: + typedef std::list<EtherInt *> devlist_t; + devlist_t devlist; + double ticksPerByte; + bool loopback; + + protected: + class DoneEvent : public Event + { + protected: + EtherBus *bus; + + public: + DoneEvent(EventQueue *q, EtherBus *b) + : Event(q), bus(b) {} + virtual void process() { bus->txDone(); } + virtual const char *description() { return "ethernet bus completion"; } + }; + + DoneEvent event; + EthPacketPtr packet; + EtherInt *sender; + EtherDump *dump; + + public: + EtherBus(const std::string &name, double speed, bool loopback, + EtherDump *dump); + virtual ~EtherBus() {} + + void txDone(); + void reg(EtherInt *dev); + bool busy() const { return (bool)packet; } + bool send(EtherInt *sender, EthPacketPtr &packet); +}; + +#endif // __ETHERBUS_H__ diff --git a/src/dev/etherdump.cc b/src/dev/etherdump.cc new file mode 100644 index 000000000..0c986cc21 --- /dev/null +++ b/src/dev/etherdump.cc @@ -0,0 +1,138 @@ +/* + * 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 + */ + +/* @file + * Simple object for creating a simple pcap style packet trace + */ + +#include <sys/time.h> + +#include <algorithm> +#include <string> + +#include "base/misc.hh" +#include "base/output.hh" +#include "dev/etherdump.hh" +#include "sim/builder.hh" +#include "sim/root.hh" + +using std::string; + +EtherDump::EtherDump(const string &name, const string &file, int max) + : SimObject(name), stream(file.c_str()), maxlen(max) +{ +} + +#define DLT_EN10MB 1 // Ethernet (10Mb) +#define TCPDUMP_MAGIC 0xa1b2c3d4 +#define PCAP_VERSION_MAJOR 2 +#define PCAP_VERSION_MINOR 4 + +struct pcap_file_header { + uint32_t magic; + uint16_t version_major; + uint16_t version_minor; + int32_t thiszone; // gmt to local correction + uint32_t sigfigs; // accuracy of timestamps + uint32_t snaplen; // max length saved portion of each pkt + uint32_t linktype; // data link type (DLT_*) +}; + +struct pcap_pkthdr { + uint32_t seconds; + uint32_t microseconds; + uint32_t caplen; // length of portion present + uint32_t len; // length this packet (off wire) +}; + +void +EtherDump::init() +{ + curtime = time(NULL); + struct pcap_file_header hdr; + hdr.magic = TCPDUMP_MAGIC; + hdr.version_major = PCAP_VERSION_MAJOR; + hdr.version_minor = PCAP_VERSION_MINOR; + + hdr.thiszone = -5 * 3600; + hdr.snaplen = 1500; + hdr.sigfigs = 0; + hdr.linktype = DLT_EN10MB; + + stream.write(reinterpret_cast<char *>(&hdr), sizeof(hdr)); + + /* + * output an empty packet with the current time so that we know + * when the simulation began. This allows us to correlate packets + * to sim_cycles. + */ + pcap_pkthdr pkthdr; + pkthdr.seconds = curtime; + pkthdr.microseconds = 0; + pkthdr.caplen = 0; + pkthdr.len = 0; + stream.write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr)); + + stream.flush(); +} + +void +EtherDump::dumpPacket(EthPacketPtr &packet) +{ + pcap_pkthdr pkthdr; + pkthdr.seconds = curtime + (curTick / Clock::Int::s); + pkthdr.microseconds = (curTick / Clock::Int::us) % ULL(1000000); + pkthdr.caplen = std::min(packet->length, maxlen); + pkthdr.len = packet->length; + stream.write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr)); + stream.write(reinterpret_cast<char *>(packet->data), pkthdr.caplen); + stream.flush(); +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherDump) + + Param<string> file; + Param<int> maxlen; + +END_DECLARE_SIM_OBJECT_PARAMS(EtherDump) + +BEGIN_INIT_SIM_OBJECT_PARAMS(EtherDump) + + INIT_PARAM(file, "file to dump packets to"), + INIT_PARAM(maxlen, "max portion of packet data to dump") + +END_INIT_SIM_OBJECT_PARAMS(EtherDump) + +CREATE_SIM_OBJECT(EtherDump) +{ + return new EtherDump(getInstanceName(), simout.resolve(file), maxlen); +} + +REGISTER_SIM_OBJECT("EtherDump", EtherDump) diff --git a/src/dev/etherdump.hh b/src/dev/etherdump.hh new file mode 100644 index 000000000..f3080f341 --- /dev/null +++ b/src/dev/etherdump.hh @@ -0,0 +1,61 @@ +/* + * 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 + */ + +/* @file + * Simple object for creating a simple pcap style packet trace + */ + +#ifndef __ETHERDUMP_H__ +#define __ETHERDUMP_H__ + +#include <fstream> +#include "dev/etherpkt.hh" +#include "sim/sim_object.hh" + +/* + * Simple object for creating a simple pcap style packet trace + */ +class EtherDump : public SimObject +{ + private: + std::ofstream stream; + const int maxlen; + void dumpPacket(EthPacketPtr &packet); + void init(); + + Tick curtime; + + public: + EtherDump(const std::string &name, const std::string &file, int max); + + inline void dump(EthPacketPtr &pkt) { dumpPacket(pkt); } +}; + +#endif // __ETHERDUMP_H__ diff --git a/src/dev/etherint.cc b/src/dev/etherint.cc new file mode 100644 index 000000000..3f81591e9 --- /dev/null +++ b/src/dev/etherint.cc @@ -0,0 +1,47 @@ +/* + * 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 + */ + +#include "dev/etherint.hh" +#include "base/misc.hh" +#include "sim/param.hh" +#include "sim/sim_object.hh" + +void +EtherInt::setPeer(EtherInt *p) +{ + if (peer && peer != p) + panic("You cannot change the peer once it is set.\n" + "Current peer=%s Desired peer=%s", peer->name(), p->name()); + + peer = p; +} + +DEFINE_SIM_OBJECT_CLASS_NAME("EtherInt", EtherInt) + diff --git a/src/dev/etherint.hh b/src/dev/etherint.hh new file mode 100644 index 000000000..dfc224ecc --- /dev/null +++ b/src/dev/etherint.hh @@ -0,0 +1,68 @@ +/* + * 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 + */ + +/* @file + * Class representing the actual interface between two ethernet + * components. + */ + +#ifndef __DEV_ETHERINT_HH__ +#define __DEV_ETHERINT_HH__ + +#include <string> + +#include "dev/etherpkt.hh" +#include "sim/sim_object.hh" + +/* + * Class representing the actual interface between two ethernet + * components. These components are intended to attach to another + * ethernet interface on one side and whatever device on the other. + */ +class EtherInt : public SimObject +{ + protected: + EtherInt *peer; + + public: + EtherInt(const std::string &name) : SimObject(name), peer(NULL) {} + virtual ~EtherInt() {} + + void setPeer(EtherInt *p); + + void recvDone() { peer->sendDone(); } + virtual void sendDone() = 0; + + bool sendPacket(EthPacketPtr packet) + { return peer ? peer->recvPacket(packet) : true; } + virtual bool recvPacket(EthPacketPtr packet) = 0; +}; + +#endif // __DEV_ETHERINT_HH__ diff --git a/src/dev/etherlink.cc b/src/dev/etherlink.cc new file mode 100644 index 000000000..cd3812270 --- /dev/null +++ b/src/dev/etherlink.cc @@ -0,0 +1,303 @@ +/* + * 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 + */ + +/* @file + * Device module for modelling a fixed bandwidth full duplex ethernet link + */ + +#include <cmath> +#include <deque> +#include <string> +#include <vector> + +#include "base/random.hh" +#include "base/trace.hh" +#include "dev/etherdump.hh" +#include "dev/etherint.hh" +#include "dev/etherlink.hh" +#include "dev/etherpkt.hh" +#include "sim/builder.hh" +#include "sim/serialize.hh" +#include "sim/system.hh" +#include "sim/root.hh" + +using namespace std; + +EtherLink::EtherLink(const string &name, EtherInt *peer0, EtherInt *peer1, + double rate, Tick delay, Tick delayVar, EtherDump *dump) + : SimObject(name) +{ + link[0] = new Link(name + ".link0", this, 0, rate, delay, delayVar, dump); + link[1] = new Link(name + ".link1", this, 1, rate, delay, delayVar, dump); + + interface[0] = new Interface(name + ".int0", link[0], link[1]); + interface[1] = new Interface(name + ".int1", link[1], link[0]); + + interface[0]->setPeer(peer0); + peer0->setPeer(interface[0]); + interface[1]->setPeer(peer1); + peer1->setPeer(interface[1]); +} + +EtherLink::~EtherLink() +{ + delete link[0]; + delete link[1]; + + delete interface[0]; + delete interface[1]; +} + +EtherLink::Interface::Interface(const string &name, Link *tx, Link *rx) + : EtherInt(name), txlink(tx) +{ + tx->setTxInt(this); + rx->setRxInt(this); +} + +EtherLink::Link::Link(const string &name, EtherLink *p, int num, + double rate, Tick delay, Tick delay_var, EtherDump *d) + : objName(name), parent(p), number(num), txint(NULL), rxint(NULL), + ticksPerByte(rate), linkDelay(delay), delayVar(delay_var), dump(d), + doneEvent(this) +{ } + +void +EtherLink::serialize(ostream &os) +{ + link[0]->serialize("link0", os); + link[1]->serialize("link1", os); +} + +void +EtherLink::unserialize(Checkpoint *cp, const string §ion) +{ + link[0]->unserialize("link0", cp, section); + link[1]->unserialize("link1", cp, section); +} + +void +EtherLink::Link::txComplete(EthPacketPtr packet) +{ + DPRINTF(Ethernet, "packet received: len=%d\n", packet->length); + DDUMP(EthernetData, packet->data, packet->length); + rxint->sendPacket(packet); +} + +class LinkDelayEvent : public Event +{ + protected: + EtherLink::Link *link; + EthPacketPtr packet; + + public: + // non-scheduling version for createForUnserialize() + LinkDelayEvent(); + LinkDelayEvent(EtherLink::Link *link, EthPacketPtr pkt, Tick when); + + void process(); + + virtual void serialize(ostream &os); + virtual void unserialize(Checkpoint *cp, const string §ion); + static Serializable *createForUnserialize(Checkpoint *cp, + const string §ion); +}; + +void +EtherLink::Link::txDone() +{ + if (dump) + dump->dump(packet); + + if (linkDelay > 0) { + DPRINTF(Ethernet, "packet delayed: delay=%d\n", linkDelay); + new LinkDelayEvent(this, packet, curTick + linkDelay); + } else { + txComplete(packet); + } + + packet = 0; + assert(!busy()); + + txint->sendDone(); +} + +bool +EtherLink::Link::transmit(EthPacketPtr pkt) +{ + if (busy()) { + DPRINTF(Ethernet, "packet not sent, link busy\n"); + return false; + } + + DPRINTF(Ethernet, "packet sent: len=%d\n", pkt->length); + DDUMP(EthernetData, pkt->data, pkt->length); + + packet = pkt; + Tick delay = (Tick)ceil(((double)pkt->length * ticksPerByte) + 1.0); + if (delayVar != 0) { + Random<Tick> var; + delay += var.uniform(0, delayVar); + } + DPRINTF(Ethernet, "scheduling packet: delay=%d, (rate=%f)\n", + delay, ticksPerByte); + doneEvent.schedule(curTick + delay); + + return true; +} + +void +EtherLink::Link::serialize(const string &base, ostream &os) +{ + bool packet_exists = packet; + paramOut(os, base + ".packet_exists", packet_exists); + if (packet_exists) + packet->serialize(base + ".packet", os); + + bool event_scheduled = doneEvent.scheduled(); + paramOut(os, base + ".event_scheduled", event_scheduled); + if (event_scheduled) { + Tick event_time = doneEvent.when(); + paramOut(os, base + ".event_time", event_time); + } + +} + +void +EtherLink::Link::unserialize(const string &base, Checkpoint *cp, + const string §ion) +{ + bool packet_exists; + paramIn(cp, section, base + ".packet_exists", packet_exists); + if (packet_exists) { + packet = new EthPacketData(16384); + packet->unserialize(base + ".packet", cp, section); + } + + bool event_scheduled; + paramIn(cp, section, base + ".event_scheduled", event_scheduled); + if (event_scheduled) { + Tick event_time; + paramIn(cp, section, base + ".event_time", event_time); + doneEvent.schedule(event_time); + } +} + +LinkDelayEvent::LinkDelayEvent() + : Event(&mainEventQueue), link(NULL) +{ + setFlags(AutoSerialize); + setFlags(AutoDelete); +} + +LinkDelayEvent::LinkDelayEvent(EtherLink::Link *l, EthPacketPtr p, Tick when) + : Event(&mainEventQueue), link(l), packet(p) +{ + setFlags(AutoSerialize); + setFlags(AutoDelete); + schedule(when); +} + +void +LinkDelayEvent::process() +{ + link->txComplete(packet); +} + +void +LinkDelayEvent::serialize(ostream &os) +{ + paramOut(os, "type", string("LinkDelayEvent")); + Event::serialize(os); + + EtherLink *parent = link->parent; + bool number = link->number; + SERIALIZE_OBJPTR(parent); + SERIALIZE_SCALAR(number); + + packet->serialize("packet", os); +} + + +void +LinkDelayEvent::unserialize(Checkpoint *cp, const string §ion) +{ + Event::unserialize(cp, section); + + EtherLink *parent; + bool number; + UNSERIALIZE_OBJPTR(parent); + UNSERIALIZE_SCALAR(number); + + link = parent->link[number]; + + packet = new EthPacketData(16384); + packet->unserialize("packet", cp, section); +} + + +Serializable * +LinkDelayEvent::createForUnserialize(Checkpoint *cp, const string §ion) +{ + return new LinkDelayEvent(); +} + +REGISTER_SERIALIZEABLE("LinkDelayEvent", LinkDelayEvent) + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherLink) + + SimObjectParam<EtherInt *> int1; + SimObjectParam<EtherInt *> int2; + Param<double> speed; + Param<Tick> delay; + Param<Tick> delay_var; + SimObjectParam<EtherDump *> dump; + +END_DECLARE_SIM_OBJECT_PARAMS(EtherLink) + +BEGIN_INIT_SIM_OBJECT_PARAMS(EtherLink) + + INIT_PARAM(int1, "interface 1"), + INIT_PARAM(int2, "interface 2"), + INIT_PARAM(speed, "link speed in bits per second"), + INIT_PARAM(delay, "transmit delay of packets in us"), + INIT_PARAM(delay_var, "Difference in amount of time to traverse wire"), + INIT_PARAM(dump, "object to dump network packets to") + +END_INIT_SIM_OBJECT_PARAMS(EtherLink) + +CREATE_SIM_OBJECT(EtherLink) +{ + return new EtherLink(getInstanceName(), int1, int2, speed, delay, delay_var, + dump); +} + +REGISTER_SIM_OBJECT("EtherLink", EtherLink) diff --git a/src/dev/etherlink.hh b/src/dev/etherlink.hh new file mode 100644 index 000000000..bb2854810 --- /dev/null +++ b/src/dev/etherlink.hh @@ -0,0 +1,132 @@ +/* + * 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 + */ + +/* @file + * Device module for modelling a fixed bandwidth full duplex ethernet link + */ + +#ifndef __DEV_ETHERLINK_HH__ +#define __DEV_ETHERLINK_HH__ + +#include "dev/etherint.hh" +#include "dev/etherpkt.hh" +#include "sim/eventq.hh" +#include "sim/host.hh" +#include "sim/sim_object.hh" + +class EtherDump; +class Checkpoint; +/* + * Model for a fixed bandwidth full duplex ethernet link + */ +class EtherLink : public SimObject +{ + protected: + class Interface; + + friend class LinkDelayEvent; + /* + * Model for a single uni-directional link + */ + class Link + { + protected: + std::string objName; + + EtherLink *parent; + int number; + + Interface *txint; + Interface *rxint; + + double ticksPerByte; + Tick linkDelay; + Tick delayVar; + EtherDump *dump; + + protected: + /* + * Transfer is complete + */ + EthPacketPtr packet; + void txDone(); + typedef EventWrapper<Link, &Link::txDone> DoneEvent; + friend void DoneEvent::process(); + DoneEvent doneEvent; + + friend class LinkDelayEvent; + void txComplete(EthPacketPtr packet); + + public: + Link(const std::string &name, EtherLink *p, int num, + double rate, Tick delay, Tick delay_var, EtherDump *dump); + ~Link() {} + + const std::string name() const { return objName; } + + bool busy() const { return (bool)packet; } + bool transmit(EthPacketPtr packet); + + void setTxInt(Interface *i) { assert(!txint); txint = i; } + void setRxInt(Interface *i) { assert(!rxint); rxint = i; } + + void serialize(const std::string &base, std::ostream &os); + void unserialize(const std::string &base, Checkpoint *cp, + const std::string §ion); + }; + + /* + * Interface at each end of the link + */ + class Interface : public EtherInt + { + private: + Link *txlink; + + public: + Interface(const std::string &name, Link *txlink, Link *rxlink); + bool recvPacket(EthPacketPtr packet) { return txlink->transmit(packet); } + void sendDone() { peer->sendDone(); } + }; + + Link *link[2]; + EtherInt *interface[2]; + + public: + EtherLink(const std::string &name, EtherInt *peer0, EtherInt *peer1, + double rate, Tick delay, Tick delayVar, EtherDump *dump); + virtual ~EtherLink(); + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + +}; + +#endif // __ETHERLINK_HH__ diff --git a/src/dev/etherpkt.cc b/src/dev/etherpkt.cc new file mode 100644 index 000000000..5c552b4bd --- /dev/null +++ b/src/dev/etherpkt.cc @@ -0,0 +1,55 @@ +/* + * 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: Nathan Binkert + */ + +#include <iostream> + +#include "base/misc.hh" +#include "dev/etherpkt.hh" +#include "sim/serialize.hh" + +using namespace std; + +void +EthPacketData::serialize(const string &base, ostream &os) +{ + paramOut(os, base + ".length", length); + paramOut(os, base + ".slack", slack); + arrayParamOut(os, base + ".data", data, length); +} + +void +EthPacketData::unserialize(const string &base, Checkpoint *cp, + const string §ion) +{ + paramIn(cp, section, base + ".length", length); + paramIn(cp, section, base + ".slack", slack); + if (length) + arrayParamIn(cp, section, base + ".data", data, length); +} diff --git a/src/dev/etherpkt.hh b/src/dev/etherpkt.hh new file mode 100644 index 000000000..80c7baff7 --- /dev/null +++ b/src/dev/etherpkt.hh @@ -0,0 +1,87 @@ +/* + * 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 + * Lisa Hsu + */ + +/* @file + * Reference counted class containing ethernet packet data + */ + +#ifndef __ETHERPKT_HH__ +#define __ETHERPKT_HH__ + +#include <iosfwd> +#include <memory> +#include <assert.h> + +#include "base/refcnt.hh" +#include "sim/host.hh" + +/* + * Reference counted class containing ethernet packet data + */ +class Checkpoint; +class EthPacketData : public RefCounted +{ + public: + /* + * Pointer to packet data will be deleted + */ + uint8_t *data; + + /* + * Length of the current packet + */ + int length; + + /* + * Extra space taken up by the packet in whatever data structure + * it is in. + * + * NOTE: This can only be use by *one* data structure at a time! + */ + int slack; + + public: + EthPacketData() : data(NULL), length(0), slack(0) { } + explicit EthPacketData(size_t size) + : data(new uint8_t[size]), length(0), slack(0) { } + EthPacketData(std::auto_ptr<uint8_t> d, int l, int s = 0) + : data(d.release()), length(l), slack(s) { } + ~EthPacketData() { if (data) delete [] data; } + + public: + void serialize(const std::string &base, std::ostream &os); + void unserialize(const std::string &base, Checkpoint *cp, + const std::string §ion); +}; + +typedef RefCountingPtr<EthPacketData> EthPacketPtr; + +#endif // __ETHERPKT_HH__ diff --git a/src/dev/ethertap.cc b/src/dev/ethertap.cc new file mode 100644 index 000000000..2d72383c5 --- /dev/null +++ b/src/dev/ethertap.cc @@ -0,0 +1,347 @@ +/* + * Copyright (c) 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: Nathan Binkert + */ + +/* @file + * Interface to connect a simulated ethernet device to the real world + */ + +#if defined(__OpenBSD__) || defined(__APPLE__) +#include <sys/param.h> +#endif +#include <netinet/in.h> + +#include <unistd.h> + +#include <deque> +#include <string> + +#include "base/misc.hh" +#include "base/pollevent.hh" +#include "base/socket.hh" +#include "base/trace.hh" +#include "dev/etherdump.hh" +#include "dev/etherint.hh" +#include "dev/etherpkt.hh" +#include "dev/ethertap.hh" +#include "sim/builder.hh" + +using namespace std; + +/** + */ +class TapListener +{ + protected: + /** + */ + class Event : public PollEvent + { + protected: + TapListener *listener; + + public: + Event(TapListener *l, int fd, int e) + : PollEvent(fd, e), listener(l) {} + + virtual void process(int revent) { listener->accept(); } + }; + + friend class Event; + Event *event; + + protected: + ListenSocket listener; + EtherTap *tap; + int port; + + public: + TapListener(EtherTap *t, int p) + : event(NULL), tap(t), port(p) {} + ~TapListener() { if (event) delete event; } + + void accept(); + void listen(); +}; + +void +TapListener::listen() +{ + while (!listener.listen(port, true)) { + DPRINTF(Ethernet, "TapListener(listen): Can't bind port %d\n", port); + port++; + } + + ccprintf(cerr, "Listening for tap connection on port %d\n", port); + event = new Event(this, listener.getfd(), POLLIN|POLLERR); + pollQueue.schedule(event); +} + +void +TapListener::accept() +{ + if (!listener.islistening()) + panic("TapListener(accept): cannot accept if we're not listening!"); + + int sfd = listener.accept(true); + if (sfd != -1) + tap->attach(sfd); +} + +/** + */ +class TapEvent : public PollEvent +{ + protected: + EtherTap *tap; + + public: + TapEvent(EtherTap *_tap, int fd, int e) + : PollEvent(fd, e), tap(_tap) {} + virtual void process(int revent) { tap->process(revent); } +}; + +EtherTap::EtherTap(const string &name, EtherDump *d, int port, int bufsz) + : EtherInt(name), event(NULL), socket(-1), buflen(bufsz), dump(d), + txEvent(this) +{ + buffer = new char[buflen]; + listener = new TapListener(this, port); + listener->listen(); +} + +EtherTap::~EtherTap() +{ + if (event) + delete event; + if (buffer) + delete [] buffer; + + delete listener; +} + +void +EtherTap::attach(int fd) +{ + if (socket != -1) + close(fd); + + buffer_offset = 0; + data_len = 0; + socket = fd; + DPRINTF(Ethernet, "EtherTap attached\n"); + event = new TapEvent(this, socket, POLLIN|POLLERR); + pollQueue.schedule(event); +} + +void +EtherTap::detach() +{ + DPRINTF(Ethernet, "EtherTap detached\n"); + delete event; + event = 0; + close(socket); + socket = -1; +} + +bool +EtherTap::recvPacket(EthPacketPtr packet) +{ + if (dump) + dump->dump(packet); + + DPRINTF(Ethernet, "EtherTap output len=%d\n", packet->length); + DDUMP(EthernetData, packet->data, packet->length); + u_int32_t len = htonl(packet->length); + write(socket, &len, sizeof(len)); + write(socket, packet->data, packet->length); + + recvDone(); + + return true; +} + +void +EtherTap::sendDone() +{} + +void +EtherTap::process(int revent) +{ + if (revent & POLLERR) { + detach(); + return; + } + + char *data = buffer + sizeof(u_int32_t); + if (!(revent & POLLIN)) + return; + + if (buffer_offset < data_len + sizeof(u_int32_t)) { + int len = read(socket, buffer + buffer_offset, buflen - buffer_offset); + if (len == 0) { + detach(); + return; + } + + buffer_offset += len; + + if (data_len == 0) + data_len = ntohl(*(u_int32_t *)buffer); + + DPRINTF(Ethernet, "Received data from peer: len=%d buffer_offset=%d " + "data_len=%d\n", len, buffer_offset, data_len); + } + + while (data_len != 0 && buffer_offset >= data_len + sizeof(u_int32_t)) { + EthPacketPtr packet; + packet = new EthPacketData(data_len); + packet->length = data_len; + memcpy(packet->data, data, data_len); + + buffer_offset -= data_len + sizeof(u_int32_t); + assert(buffer_offset >= 0); + if (buffer_offset > 0) { + memmove(buffer, data + data_len, buffer_offset); + data_len = ntohl(*(u_int32_t *)buffer); + } else + data_len = 0; + + DPRINTF(Ethernet, "EtherTap input len=%d\n", packet->length); + DDUMP(EthernetData, packet->data, packet->length); + if (!sendPacket(packet)) { + DPRINTF(Ethernet, "bus busy...buffer for retransmission\n"); + packetBuffer.push(packet); + if (!txEvent.scheduled()) + txEvent.schedule(curTick + retryTime); + } else if (dump) { + dump->dump(packet); + } + } +} + +void +EtherTap::retransmit() +{ + if (packetBuffer.empty()) + return; + + EthPacketPtr packet = packetBuffer.front(); + if (sendPacket(packet)) { + if (dump) + dump->dump(packet); + DPRINTF(Ethernet, "EtherTap retransmit\n"); + packetBuffer.front() = NULL; + packetBuffer.pop(); + } + + if (!packetBuffer.empty() && !txEvent.scheduled()) + txEvent.schedule(curTick + retryTime); +} + +//===================================================================== + +void +EtherTap::serialize(ostream &os) +{ + SERIALIZE_SCALAR(socket); + SERIALIZE_SCALAR(buflen); + uint8_t *buffer = (uint8_t *)this->buffer; + SERIALIZE_ARRAY(buffer, buflen); + SERIALIZE_SCALAR(buffer_offset); + SERIALIZE_SCALAR(data_len); + + bool tapevent_present = false; + if (event) { + tapevent_present = true; + SERIALIZE_SCALAR(tapevent_present); + event->serialize(os); + } + else { + SERIALIZE_SCALAR(tapevent_present); + } +} + +void +EtherTap::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_SCALAR(socket); + UNSERIALIZE_SCALAR(buflen); + uint8_t *buffer = (uint8_t *)this->buffer; + UNSERIALIZE_ARRAY(buffer, buflen); + UNSERIALIZE_SCALAR(buffer_offset); + UNSERIALIZE_SCALAR(data_len); + + bool tapevent_present; + UNSERIALIZE_SCALAR(tapevent_present); + if (tapevent_present) { + event = new TapEvent(this, socket, POLLIN|POLLERR); + + event->unserialize(cp,section); + + if (event->queued()) { + pollQueue.schedule(event); + } + } +} + +//===================================================================== + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherTap) + + SimObjectParam<EtherInt *> peer; + SimObjectParam<EtherDump *> dump; + Param<unsigned> port; + Param<unsigned> bufsz; + +END_DECLARE_SIM_OBJECT_PARAMS(EtherTap) + +BEGIN_INIT_SIM_OBJECT_PARAMS(EtherTap) + + INIT_PARAM_DFLT(peer, "peer interface", NULL), + INIT_PARAM_DFLT(dump, "object to dump network packets to", NULL), + INIT_PARAM_DFLT(port, "tap port", 3500), + INIT_PARAM_DFLT(bufsz, "tap buffer size", 10000) + +END_INIT_SIM_OBJECT_PARAMS(EtherTap) + + +CREATE_SIM_OBJECT(EtherTap) +{ + EtherTap *tap = new EtherTap(getInstanceName(), dump, port, bufsz); + + if (peer) { + tap->setPeer(peer); + peer->setPeer(tap); + } + + return tap; +} + +REGISTER_SIM_OBJECT("EtherTap", EtherTap) diff --git a/src/dev/ethertap.hh b/src/dev/ethertap.hh new file mode 100644 index 000000000..f64ed7187 --- /dev/null +++ b/src/dev/ethertap.hh @@ -0,0 +1,109 @@ +/* + * Copyright (c) 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: Nathan Binkert + */ + +/* @file + * Interface to connect a simulated ethernet device to the real world + */ + +#ifndef __ETHERTAP_HH__ +#define __ETHERTAP_HH__ + +#include <queue> +#include <string> + +#include "dev/etherint.hh" +#include "dev/etherpkt.hh" +#include "sim/eventq.hh" +#include "base/pollevent.hh" +#include "sim/sim_object.hh" + +class TapEvent; +class TapListener; + +/* + * Interface to connect a simulated ethernet device to the real world + */ +class EtherTap : public EtherInt +{ + protected: + friend class TapEvent; + TapEvent *event; + + protected: + friend class TapListener; + TapListener *listener; + int socket; + char *buffer; + int buflen; + int32_t buffer_offset; + int32_t data_len; + + EtherDump *dump; + + void attach(int fd); + void detach(); + + protected: + std::string device; + std::queue<EthPacketPtr> packetBuffer; + + void process(int revent); + void enqueue(EthPacketData *packet); + void retransmit(); + + /* + */ + class TxEvent : public Event + { + protected: + EtherTap *tap; + + public: + TxEvent(EtherTap *_tap) + : Event(&mainEventQueue), tap(_tap) {} + void process() { tap->retransmit(); } + virtual const char *description() { return "retransmit event"; } + }; + + friend class TxEvent; + TxEvent txEvent; + + public: + EtherTap(const std::string &name, EtherDump *dump, int port, int bufsz); + virtual ~EtherTap(); + + virtual bool recvPacket(EthPacketPtr packet); + virtual void sendDone(); + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); +}; + +#endif // __ETHERTAP_HH__ diff --git a/dev/ide_atareg.h b/src/dev/ide_atareg.h index 5320529c8..5320529c8 100644 --- a/dev/ide_atareg.h +++ b/src/dev/ide_atareg.h diff --git a/src/dev/ide_ctrl.cc b/src/dev/ide_ctrl.cc new file mode 100644 index 000000000..63435e87c --- /dev/null +++ b/src/dev/ide_ctrl.cc @@ -0,0 +1,815 @@ +/* + * 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: Andrew Schultz + * Ali Saidi + * Miguel Serrano + */ + +#include <cstddef> +#include <cstdlib> +#include <string> +#include <vector> + +#include "base/trace.hh" +#include "cpu/intr_control.hh" +#include "dev/ide_ctrl.hh" +#include "dev/ide_disk.hh" +#include "dev/pciconfigall.hh" +#include "dev/pcireg.h" +#include "dev/platform.hh" +#include "mem/packet.hh" +#include "sim/builder.hh" +#include "sim/sim_object.hh" +#include "sim/byteswap.hh" + +using namespace std; + +//// +// Initialization and destruction +//// + +IdeController::IdeController(Params *p) + : PciDev(p) +{ + // initialize the PIO interface addresses + pri_cmd_addr = 0; + pri_cmd_size = BARSize[0]; + + pri_ctrl_addr = 0; + pri_ctrl_size = BARSize[1]; + + sec_cmd_addr = 0; + sec_cmd_size = BARSize[2]; + + sec_ctrl_addr = 0; + sec_ctrl_size = BARSize[3]; + + // initialize the bus master interface (BMI) address to be configured + // via PCI + bmi_addr = 0; + bmi_size = BARSize[4]; + + // zero out all of the registers + memset(bmi_regs.data, 0, sizeof(bmi_regs)); + memset(config_regs.data, 0, sizeof(config_regs.data)); + + // setup initial values + // enable both channels + config_regs.idetim0 = htole((uint16_t)IDETIM_DECODE_EN); + config_regs.idetim1 = htole((uint16_t)IDETIM_DECODE_EN); + bmi_regs.bmis0 = DMA1CAP | DMA0CAP; + bmi_regs.bmis1 = DMA1CAP | DMA0CAP; + + // reset all internal variables + io_enabled = false; + bm_enabled = false; + memset(cmd_in_progress, 0, sizeof(cmd_in_progress)); + + // setup the disks attached to controller + memset(disks, 0, sizeof(disks)); + dev[0] = 0; + dev[1] = 0; + + if (params()->disks.size() > 3) + panic("IDE controllers support a maximum of 4 devices attached!\n"); + + for (int i = 0; i < params()->disks.size(); i++) { + disks[i] = params()->disks[i]; + disks[i]->setController(this); + } +} + +IdeController::~IdeController() +{ + for (int i = 0; i < 4; i++) + if (disks[i]) + delete disks[i]; +} + +//// +// Utility functions +/// + +void +IdeController::parseAddr(const Addr &addr, Addr &offset, IdeChannel &channel, + IdeRegType ®_type) +{ + offset = addr; + + if (addr >= pri_cmd_addr && addr < (pri_cmd_addr + pri_cmd_size)) { + offset -= pri_cmd_addr; + reg_type = COMMAND_BLOCK; + channel = PRIMARY; + } else if (addr >= pri_ctrl_addr && + addr < (pri_ctrl_addr + pri_ctrl_size)) { + offset -= pri_ctrl_addr; + reg_type = CONTROL_BLOCK; + channel = PRIMARY; + } else if (addr >= sec_cmd_addr && + addr < (sec_cmd_addr + sec_cmd_size)) { + offset -= sec_cmd_addr; + reg_type = COMMAND_BLOCK; + channel = SECONDARY; + } else if (addr >= sec_ctrl_addr && + addr < (sec_ctrl_addr + sec_ctrl_size)) { + offset -= sec_ctrl_addr; + reg_type = CONTROL_BLOCK; + channel = SECONDARY; + } else if (addr >= bmi_addr && addr < (bmi_addr + bmi_size)) { + offset -= bmi_addr; + reg_type = BMI_BLOCK; + channel = (offset < BMIC1) ? PRIMARY : SECONDARY; + } else { + panic("IDE controller access to invalid address: %#x\n", addr); + } +} + +int +IdeController::getDisk(IdeChannel channel) +{ + int disk = 0; + uint8_t *devBit = &dev[0]; + + if (channel == SECONDARY) { + disk += 2; + devBit = &dev[1]; + } + + disk += *devBit; + + assert(*devBit == 0 || *devBit == 1); + + return disk; +} + +int +IdeController::getDisk(IdeDisk *diskPtr) +{ + for (int i = 0; i < 4; i++) { + if ((long)diskPtr == (long)disks[i]) + return i; + } + return -1; +} + +bool +IdeController::isDiskSelected(IdeDisk *diskPtr) +{ + for (int i = 0; i < 4; i++) { + if ((long)diskPtr == (long)disks[i]) { + // is disk is on primary or secondary channel + int channel = i/2; + // is disk the master or slave + int devID = i%2; + + return (dev[channel] == devID); + } + } + panic("Unable to find disk by pointer!!\n"); +} + +//// +// Command completion +//// + +void +IdeController::setDmaComplete(IdeDisk *disk) +{ + int diskNum = getDisk(disk); + + if (diskNum < 0) + panic("Unable to find disk based on pointer %#x\n", disk); + + if (diskNum < 2) { + // clear the start/stop bit in the command register + bmi_regs.bmic0 &= ~SSBM; + // clear the bus master active bit in the status register + bmi_regs.bmis0 &= ~BMIDEA; + // set the interrupt bit + bmi_regs.bmis0 |= IDEINTS; + } else { + // clear the start/stop bit in the command register + bmi_regs.bmic1 &= ~SSBM; + // clear the bus master active bit in the status register + bmi_regs.bmis1 &= ~BMIDEA; + // set the interrupt bit + bmi_regs.bmis1 |= IDEINTS; + } +} + + +//// +// Read and write handling +//// + +void +IdeController::readConfig(int offset, uint8_t *data) +{ + if (offset < PCI_DEVICE_SPECIFIC) { + PciDev::readConfig(offset, data); + } else if (offset >= IDE_CTRL_CONF_START && + (offset + 1) <= IDE_CTRL_CONF_END) { + + switch (offset) { + case IDE_CTRL_CONF_DEV_TIMING: + *data = config_regs.sidetim; + break; + case IDE_CTRL_CONF_UDMA_CNTRL: + *data = config_regs.udmactl; + break; + case IDE_CTRL_CONF_PRIM_TIMING+1: + *data = htole(config_regs.idetim0) >> 8; + break; + case IDE_CTRL_CONF_SEC_TIMING+1: + *data = htole(config_regs.idetim1) >> 8; + break; + case IDE_CTRL_CONF_IDE_CONFIG: + *data = htole(config_regs.ideconfig) & 0xFF; + break; + case IDE_CTRL_CONF_IDE_CONFIG+1: + *data = htole(config_regs.ideconfig) >> 8; + break; + default: + panic("Invalid PCI configuration read for size 1 at offset: %#x!\n", + offset); + } + + } else { + panic("Read of unimplemented PCI config. register: %x\n", offset); + } + DPRINTF(IdeCtrl, "PCI read offset: %#x size: 1 data: %#x\n", + offset, (uint32_t)*data); +} + +void +IdeController::readConfig(int offset, uint16_t *data) +{ + if (offset < PCI_DEVICE_SPECIFIC) { + PciDev::readConfig(offset, data); + } else if (offset >= IDE_CTRL_CONF_START && + (offset + 2) <= IDE_CTRL_CONF_END) { + + switch (offset) { + case IDE_CTRL_CONF_PRIM_TIMING: + *data = config_regs.idetim0; + break; + case IDE_CTRL_CONF_SEC_TIMING: + *data = config_regs.idetim1; + break; + case IDE_CTRL_CONF_UDMA_TIMING: + *data = config_regs.udmatim; + break; + case IDE_CTRL_CONF_IDE_CONFIG: + *data = config_regs.ideconfig; + break; + default: + panic("Invalid PCI configuration read for size 2 offset: %#x!\n", + offset); + } + + } else { + panic("Read of unimplemented PCI config. register: %x\n", offset); + } + DPRINTF(IdeCtrl, "PCI read offset: %#x size: 2 data: %#x\n", offset, *data); +} + +void +IdeController::readConfig(int offset, uint32_t *data) +{ + if (offset < PCI_DEVICE_SPECIFIC) { + PciDev::readConfig(offset, data); + } else { + panic("Read of unimplemented PCI config. register: %x\n", offset); + } + DPRINTF(IdeCtrl, "PCI read offset: %#x size: 4 data: %#x\n", offset, *data); +} +void +IdeController::writeConfig(int offset, const uint8_t data) +{ + if (offset < PCI_DEVICE_SPECIFIC) { + PciDev::writeConfig(offset, data); + } else if (offset >= IDE_CTRL_CONF_START && + (offset + 1) <= IDE_CTRL_CONF_END) { + + switch (offset) { + case IDE_CTRL_CONF_DEV_TIMING: + config_regs.sidetim = data; + break; + case IDE_CTRL_CONF_UDMA_CNTRL: + config_regs.udmactl = data; + break; + case IDE_CTRL_CONF_IDE_CONFIG: + config_regs.ideconfig = (config_regs.ideconfig & 0xFF00) | (data); + break; + case IDE_CTRL_CONF_IDE_CONFIG+1: + config_regs.ideconfig = (config_regs.ideconfig & 0x00FF) | data << 8; + break; + default: + panic("Invalid PCI configuration write for size 1 offset: %#x!\n", + offset); + } + + } else { + panic("Read of unimplemented PCI config. register: %x\n", offset); + } + DPRINTF(IdeCtrl, "PCI write offset: %#x size: 1 data: %#x\n", + offset, (uint32_t)data); +} + +void +IdeController::writeConfig(int offset, const uint16_t data) +{ + if (offset < PCI_DEVICE_SPECIFIC) { + PciDev::writeConfig(offset, data); + } else if (offset >= IDE_CTRL_CONF_START && + (offset + 2) <= IDE_CTRL_CONF_END) { + + switch (offset) { + case IDE_CTRL_CONF_PRIM_TIMING: + config_regs.idetim0 = data; + break; + case IDE_CTRL_CONF_SEC_TIMING: + config_regs.idetim1 = data; + break; + case IDE_CTRL_CONF_UDMA_TIMING: + config_regs.udmatim = data; + break; + case IDE_CTRL_CONF_IDE_CONFIG: + config_regs.ideconfig = data; + break; + default: + panic("Invalid PCI configuration write for size 2 offset: %#x!\n", + offset); + } + + } else { + panic("Write of unimplemented PCI config. register: %x\n", offset); + } + DPRINTF(IdeCtrl, "PCI write offset: %#x size: 2 data: %#x\n", offset, data); + + /* Trap command register writes and enable IO/BM as appropriate. */ + if (offset == PCI_COMMAND) { + if (letoh(config.command) & PCI_CMD_IOSE) + io_enabled = true; + else + io_enabled = false; + + if (letoh(config.command) & PCI_CMD_BME) + bm_enabled = true; + else + bm_enabled = false; + } + +} + +void +IdeController::writeConfig(int offset, const uint32_t data) +{ + if (offset < PCI_DEVICE_SPECIFIC) { + PciDev::writeConfig(offset, data); + } else { + panic("Read of unimplemented PCI config. register: %x\n", offset); + } + + DPRINTF(IdeCtrl, "PCI write offset: %#x size: 4 data: %#x\n", offset, data); + + switch(offset) { + case PCI0_BASE_ADDR0: + if (BARAddrs[0] != 0) + pri_cmd_addr = BARAddrs[0]; + break; + + case PCI0_BASE_ADDR1: + if (BARAddrs[1] != 0) + pri_ctrl_addr = BARAddrs[1]; + break; + + case PCI0_BASE_ADDR2: + if (BARAddrs[2] != 0) + sec_cmd_addr = BARAddrs[2]; + break; + + case PCI0_BASE_ADDR3: + if (BARAddrs[3] != 0) + sec_ctrl_addr = BARAddrs[3]; + break; + + case PCI0_BASE_ADDR4: + if (BARAddrs[4] != 0) + bmi_addr = BARAddrs[4]; + break; + } +} + +Tick +IdeController::read(Packet *pkt) +{ + Addr offset; + IdeChannel channel; + IdeRegType reg_type; + int disk; + + pkt->allocate(); + if (pkt->getSize() != 1 && pkt->getSize() != 2 && pkt->getSize() !=4) + panic("Bad IDE read size: %d\n", pkt->getSize()); + + parseAddr(pkt->getAddr(), offset, channel, reg_type); + + if (!io_enabled) { + pkt->result = Packet::Success; + return pioDelay; + } + + switch (reg_type) { + case BMI_BLOCK: + switch (pkt->getSize()) { + case sizeof(uint8_t): + pkt->set(bmi_regs.data[offset]); + break; + case sizeof(uint16_t): + pkt->set(*(uint16_t*)&bmi_regs.data[offset]); + break; + case sizeof(uint32_t): + pkt->set(*(uint32_t*)&bmi_regs.data[offset]); + break; + default: + panic("IDE read of BMI reg invalid size: %#x\n", pkt->getSize()); + } + break; + + case COMMAND_BLOCK: + case CONTROL_BLOCK: + disk = getDisk(channel); + + if (disks[disk] == NULL) { + pkt->set<uint8_t>(0); + break; + } + + switch (offset) { + case DATA_OFFSET: + switch (pkt->getSize()) { + case sizeof(uint16_t): + disks[disk]->read(offset, reg_type, pkt->getPtr<uint8_t>()); + break; + + case sizeof(uint32_t): + disks[disk]->read(offset, reg_type, pkt->getPtr<uint8_t>()); + disks[disk]->read(offset, reg_type, + pkt->getPtr<uint8_t>() + sizeof(uint16_t)); + break; + + default: + panic("IDE read of data reg invalid size: %#x\n", pkt->getSize()); + } + break; + default: + if (pkt->getSize() == sizeof(uint8_t)) { + disks[disk]->read(offset, reg_type, pkt->getPtr<uint8_t>()); + } else + panic("IDE read of command reg of invalid size: %#x\n", pkt->getSize()); + } + break; + default: + panic("IDE controller read of unknown register block type!\n"); + } + if (pkt->getSize() == 1) + DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n", + offset, pkt->getSize(), (uint32_t)pkt->get<uint8_t>()); + else if (pkt->getSize() == 2) + DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n", + offset, pkt->getSize(), pkt->get<uint16_t>()); + else + DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n", + offset, pkt->getSize(), pkt->get<uint32_t>()); + + pkt->result = Packet::Success; + return pioDelay; +} + +Tick +IdeController::write(Packet *pkt) +{ + Addr offset; + IdeChannel channel; + IdeRegType reg_type; + int disk; + uint8_t oldVal, newVal; + + parseAddr(pkt->getAddr(), offset, channel, reg_type); + + if (!io_enabled) { + pkt->result = Packet::Success; + DPRINTF(IdeCtrl, "io not enabled\n"); + return pioDelay; + } + + switch (reg_type) { + case BMI_BLOCK: + if (!bm_enabled) { + pkt->result = Packet::Success; + return pioDelay; + } + + switch (offset) { + // Bus master IDE command register + case BMIC1: + case BMIC0: + if (pkt->getSize() != sizeof(uint8_t)) + panic("Invalid BMIC write size: %x\n", pkt->getSize()); + + // select the current disk based on DEV bit + disk = getDisk(channel); + + oldVal = bmi_regs.chan[channel].bmic; + newVal = pkt->get<uint8_t>(); + + // if a DMA transfer is in progress, R/W control cannot change + if (oldVal & SSBM) { + if ((oldVal & RWCON) ^ (newVal & RWCON)) { + (oldVal & RWCON) ? newVal |= RWCON : newVal &= ~RWCON; + } + } + + // see if the start/stop bit is being changed + if ((oldVal & SSBM) ^ (newVal & SSBM)) { + if (oldVal & SSBM) { + // stopping DMA transfer + DPRINTF(IdeCtrl, "Stopping DMA transfer\n"); + + // clear the BMIDEA bit + bmi_regs.chan[channel].bmis = + bmi_regs.chan[channel].bmis & ~BMIDEA; + + if (disks[disk] == NULL) + panic("DMA stop for disk %d which does not exist\n", + disk); + + // inform the disk of the DMA transfer abort + disks[disk]->abortDma(); + } else { + // starting DMA transfer + DPRINTF(IdeCtrl, "Starting DMA transfer\n"); + + // set the BMIDEA bit + bmi_regs.chan[channel].bmis = + bmi_regs.chan[channel].bmis | BMIDEA; + + if (disks[disk] == NULL) + panic("DMA start for disk %d which does not exist\n", + disk); + + // inform the disk of the DMA transfer start + disks[disk]->startDma(letoh(bmi_regs.chan[channel].bmidtp)); + } + } + + // update the register value + bmi_regs.chan[channel].bmic = newVal; + break; + + // Bus master IDE status register + case BMIS0: + case BMIS1: + if (pkt->getSize() != sizeof(uint8_t)) + panic("Invalid BMIS write size: %x\n", pkt->getSize()); + + oldVal = bmi_regs.chan[channel].bmis; + newVal = pkt->get<uint8_t>(); + + // the BMIDEA bit is RO + newVal |= (oldVal & BMIDEA); + + // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each + if ((oldVal & IDEINTS) && (newVal & IDEINTS)) + newVal &= ~IDEINTS; // clear the interrupt? + else + (oldVal & IDEINTS) ? newVal |= IDEINTS : newVal &= ~IDEINTS; + + if ((oldVal & IDEDMAE) && (newVal & IDEDMAE)) + newVal &= ~IDEDMAE; + else + (oldVal & IDEDMAE) ? newVal |= IDEDMAE : newVal &= ~IDEDMAE; + + bmi_regs.chan[channel].bmis = newVal; + break; + + // Bus master IDE descriptor table pointer register + case BMIDTP0: + case BMIDTP1: + { + if (pkt->getSize() != sizeof(uint32_t)) + panic("Invalid BMIDTP write size: %x\n", pkt->getSize()); + + bmi_regs.chan[channel].bmidtp = htole(pkt->get<uint32_t>() & ~0x3); + } + break; + + default: + if (pkt->getSize() != sizeof(uint8_t) && + pkt->getSize() != sizeof(uint16_t) && + pkt->getSize() != sizeof(uint32_t)) + panic("IDE controller write of invalid write size: %x\n", + pkt->getSize()); + + // do a default copy of data into the registers + memcpy(&bmi_regs.data[offset], pkt->getPtr<uint8_t>(), pkt->getSize()); + } + break; + case COMMAND_BLOCK: + if (offset == IDE_SELECT_OFFSET) { + uint8_t *devBit = &dev[channel]; + *devBit = (letoh(pkt->get<uint8_t>()) & IDE_SELECT_DEV_BIT) ? 1 : 0; + } + // fall-through ok! + case CONTROL_BLOCK: + disk = getDisk(channel); + + if (disks[disk] == NULL) + break; + + switch (offset) { + case DATA_OFFSET: + switch (pkt->getSize()) { + case sizeof(uint16_t): + disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>()); + break; + + case sizeof(uint32_t): + disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>()); + disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>() + + sizeof(uint16_t)); + break; + default: + panic("IDE write of data reg invalid size: %#x\n", pkt->getSize()); + } + break; + default: + if (pkt->getSize() == sizeof(uint8_t)) { + disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>()); + } else + panic("IDE write of command reg of invalid size: %#x\n", pkt->getSize()); + } + break; + default: + panic("IDE controller write of unknown register block type!\n"); + } + + if (pkt->getSize() == 1) + DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n", + offset, pkt->getSize(), (uint32_t)pkt->get<uint8_t>()); + else if (pkt->getSize() == 2) + DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n", + offset, pkt->getSize(), pkt->get<uint16_t>()); + else + DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n", + offset, pkt->getSize(), pkt->get<uint32_t>()); + + + pkt->result = Packet::Success; + return pioDelay; +} + +//// +// Serialization +//// + +void +IdeController::serialize(std::ostream &os) +{ + // Serialize the PciDev base class + PciDev::serialize(os); + + // Serialize register addresses and sizes + SERIALIZE_SCALAR(pri_cmd_addr); + SERIALIZE_SCALAR(pri_cmd_size); + SERIALIZE_SCALAR(pri_ctrl_addr); + SERIALIZE_SCALAR(pri_ctrl_size); + SERIALIZE_SCALAR(sec_cmd_addr); + SERIALIZE_SCALAR(sec_cmd_size); + SERIALIZE_SCALAR(sec_ctrl_addr); + SERIALIZE_SCALAR(sec_ctrl_size); + SERIALIZE_SCALAR(bmi_addr); + SERIALIZE_SCALAR(bmi_size); + + // Serialize registers + SERIALIZE_ARRAY(bmi_regs.data, + sizeof(bmi_regs.data) / sizeof(bmi_regs.data[0])); + SERIALIZE_ARRAY(dev, sizeof(dev) / sizeof(dev[0])); + SERIALIZE_ARRAY(config_regs.data, + sizeof(config_regs.data) / sizeof(config_regs.data[0])); + + // Serialize internal state + SERIALIZE_SCALAR(io_enabled); + SERIALIZE_SCALAR(bm_enabled); + SERIALIZE_ARRAY(cmd_in_progress, + sizeof(cmd_in_progress) / sizeof(cmd_in_progress[0])); +} + +void +IdeController::unserialize(Checkpoint *cp, const std::string §ion) +{ + // Unserialize the PciDev base class + PciDev::unserialize(cp, section); + + // Unserialize register addresses and sizes + UNSERIALIZE_SCALAR(pri_cmd_addr); + UNSERIALIZE_SCALAR(pri_cmd_size); + UNSERIALIZE_SCALAR(pri_ctrl_addr); + UNSERIALIZE_SCALAR(pri_ctrl_size); + UNSERIALIZE_SCALAR(sec_cmd_addr); + UNSERIALIZE_SCALAR(sec_cmd_size); + UNSERIALIZE_SCALAR(sec_ctrl_addr); + UNSERIALIZE_SCALAR(sec_ctrl_size); + UNSERIALIZE_SCALAR(bmi_addr); + UNSERIALIZE_SCALAR(bmi_size); + + // Unserialize registers + UNSERIALIZE_ARRAY(bmi_regs.data, + sizeof(bmi_regs.data) / sizeof(bmi_regs.data[0])); + UNSERIALIZE_ARRAY(dev, sizeof(dev) / sizeof(dev[0])); + UNSERIALIZE_ARRAY(config_regs.data, + sizeof(config_regs.data) / sizeof(config_regs.data[0])); + + // Unserialize internal state + UNSERIALIZE_SCALAR(io_enabled); + UNSERIALIZE_SCALAR(bm_enabled); + UNSERIALIZE_ARRAY(cmd_in_progress, + sizeof(cmd_in_progress) / sizeof(cmd_in_progress[0])); + pioPort->sendStatusChange(Port::RangeChange); +} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeController) + + SimObjectParam<System *> system; + SimObjectParam<Platform *> platform; + SimObjectParam<PciConfigAll *> configspace; + SimObjectParam<PciConfigData *> configdata; + Param<uint32_t> pci_bus; + Param<uint32_t> pci_dev; + Param<uint32_t> pci_func; + Param<Tick> pio_latency; + SimObjectVectorParam<IdeDisk *> disks; + +END_DECLARE_SIM_OBJECT_PARAMS(IdeController) + +BEGIN_INIT_SIM_OBJECT_PARAMS(IdeController) + + INIT_PARAM(system, "System pointer"), + INIT_PARAM(platform, "Platform pointer"), + INIT_PARAM(configspace, "PCI Configspace"), + INIT_PARAM(configdata, "PCI Config data"), + INIT_PARAM(pci_bus, "PCI bus ID"), + INIT_PARAM(pci_dev, "PCI device number"), + INIT_PARAM(pci_func, "PCI function code"), + INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), + INIT_PARAM(disks, "IDE disks attached to this controller") + +END_INIT_SIM_OBJECT_PARAMS(IdeController) + +CREATE_SIM_OBJECT(IdeController) +{ + IdeController::Params *params = new IdeController::Params; + params->name = getInstanceName(); + params->platform = platform; + params->system = system; + params->configSpace = configspace; + params->configData = configdata; + params->busNum = pci_bus; + params->deviceNum = pci_dev; + params->functionNum = pci_func; + params->pio_delay = pio_latency; + params->disks = disks; + return new IdeController(params); +} + +REGISTER_SIM_OBJECT("IdeController", IdeController) + +#endif //DOXYGEN_SHOULD_SKIP_THIS diff --git a/src/dev/ide_ctrl.hh b/src/dev/ide_ctrl.hh new file mode 100644 index 000000000..1d30c8b31 --- /dev/null +++ b/src/dev/ide_ctrl.hh @@ -0,0 +1,244 @@ +/* + * 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: Andrew Schultz + * Miguel Serrano + */ + +/** @file + * Simple PCI IDE controller with bus mastering capability and UDMA + * modeled after controller in the Intel PIIX4 chip + */ + +#ifndef __IDE_CTRL_HH__ +#define __IDE_CTRL_HH__ + +#include "dev/pcidev.hh" +#include "dev/pcireg.h" +#include "dev/io_device.hh" + +#define BMIC0 0x0 // Bus master IDE command register +#define BMIS0 0x2 // Bus master IDE status register +#define BMIDTP0 0x4 // Bus master IDE descriptor table pointer register +#define BMIC1 0x8 // Bus master IDE command register +#define BMIS1 0xa // Bus master IDE status register +#define BMIDTP1 0xc // Bus master IDE descriptor table pointer register + +// Bus master IDE command register bit fields +#define RWCON 0x08 // Bus master read/write control +#define SSBM 0x01 // Start/stop bus master + +// Bus master IDE status register bit fields +#define DMA1CAP 0x40 // Drive 1 DMA capable +#define DMA0CAP 0x20 // Drive 0 DMA capable +#define IDEINTS 0x04 // IDE Interrupt Status +#define IDEDMAE 0x02 // IDE DMA error +#define BMIDEA 0x01 // Bus master IDE active + +// IDE Command byte fields +#define IDE_SELECT_OFFSET (6) +#define IDE_SELECT_DEV_BIT 0x10 + +#define IDE_FEATURE_OFFSET IDE_ERROR_OFFSET +#define IDE_COMMAND_OFFSET IDE_STATUS_OFFSET + +// IDE Timing Register bit fields +#define IDETIM_DECODE_EN 0x8000 + +// PCI device specific register byte offsets +#define IDE_CTRL_CONF_START 0x40 +#define IDE_CTRL_CONF_END ((IDE_CTRL_CONF_START) + sizeof(config_regs)) + +#define IDE_CTRL_CONF_PRIM_TIMING 0x40 +#define IDE_CTRL_CONF_SEC_TIMING 0x42 +#define IDE_CTRL_CONF_DEV_TIMING 0x44 +#define IDE_CTRL_CONF_UDMA_CNTRL 0x48 +#define IDE_CTRL_CONF_UDMA_TIMING 0x4A +#define IDE_CTRL_CONF_IDE_CONFIG 0x54 + + +enum IdeRegType { + COMMAND_BLOCK, + CONTROL_BLOCK, + BMI_BLOCK +}; + +class IdeDisk; +class IntrControl; +class PciConfigAll; +class Platform; + +/** + * Device model for an Intel PIIX4 IDE controller + */ + +class IdeController : public PciDev +{ + friend class IdeDisk; + + enum IdeChannel { + PRIMARY = 0, + SECONDARY = 1 + }; + + private: + /** Primary command block registers */ + Addr pri_cmd_addr; + Addr pri_cmd_size; + /** Primary control block registers */ + Addr pri_ctrl_addr; + Addr pri_ctrl_size; + /** Secondary command block registers */ + Addr sec_cmd_addr; + Addr sec_cmd_size; + /** Secondary control block registers */ + Addr sec_ctrl_addr; + Addr sec_ctrl_size; + /** Bus master interface (BMI) registers */ + Addr bmi_addr; + Addr bmi_size; + + private: + /** Registers used for bus master interface */ + union { + uint8_t data[16]; + + struct { + uint8_t bmic0; + uint8_t reserved_0; + uint8_t bmis0; + uint8_t reserved_1; + uint32_t bmidtp0; + uint8_t bmic1; + uint8_t reserved_2; + uint8_t bmis1; + uint8_t reserved_3; + uint32_t bmidtp1; + }; + + struct { + uint8_t bmic; + uint8_t reserved_4; + uint8_t bmis; + uint8_t reserved_5; + uint32_t bmidtp; + } chan[2]; + + } bmi_regs; + /** Shadows of the device select bit */ + uint8_t dev[2]; + /** Registers used in device specific PCI configuration */ + union { + uint8_t data[22]; + + struct { + uint16_t idetim0; + uint16_t idetim1; + uint8_t sidetim; + uint8_t reserved_0[3]; + uint8_t udmactl; + uint8_t reserved_1; + uint16_t udmatim; + uint8_t reserved_2[8]; + uint16_t ideconfig; + }; + } config_regs; + + // Internal management variables + bool io_enabled; + bool bm_enabled; + bool cmd_in_progress[4]; + + private: + /** IDE disks connected to controller */ + IdeDisk *disks[4]; + + private: + /** Parse the access address to pass on to device */ + void parseAddr(const Addr &addr, Addr &offset, IdeChannel &channel, + IdeRegType ®_type); + + /** Select the disk based on the channel and device bit */ + int getDisk(IdeChannel channel); + + /** Select the disk based on a pointer */ + int getDisk(IdeDisk *diskPtr); + + public: + /** See if a disk is selected based on its pointer */ + bool isDiskSelected(IdeDisk *diskPtr); + + public: + struct Params : public PciDev::Params + { + /** Array of disk objects */ + std::vector<IdeDisk *> disks; + }; + const Params *params() const { return (const Params *)_params; } + + public: + IdeController(Params *p); + ~IdeController(); + + virtual void writeConfig(int offset, const uint8_t data); + virtual void writeConfig(int offset, const uint16_t data); + virtual void writeConfig(int offset, const uint32_t data); + virtual void readConfig(int offset, uint8_t *data); + virtual void readConfig(int offset, uint16_t *data); + virtual void readConfig(int offset, uint32_t *data); + + void setDmaComplete(IdeDisk *disk); + + /** + * Read a done field for a given target. + * @param pkt Packet describing what is to be read + * @return The amount of time to complete this request + */ + virtual Tick read(Packet *pkt); + + /** + * Write a done field for a given target. + * @param pkt Packet describing what is to be written + * @return The amount of time to complete this request + */ + virtual Tick write(Packet *pkt); + + /** + * Serialize this object to the given output stream. + * @param os The stream to serialize to. + */ + virtual void serialize(std::ostream &os); + + /** + * Reconstruct the state of this object from a checkpoint. + * @param cp The checkpoint use. + * @param section The section name of this object + */ + virtual void unserialize(Checkpoint *cp, const std::string §ion); + +}; +#endif // __IDE_CTRL_HH_ diff --git a/src/dev/ide_disk.cc b/src/dev/ide_disk.cc new file mode 100644 index 000000000..dc78021f8 --- /dev/null +++ b/src/dev/ide_disk.cc @@ -0,0 +1,1149 @@ +/* + * 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: Andrew Schultz + * Ali Saidi + */ + +/** @file + * Device model implementation for an IDE disk + */ + +#include <cerrno> +#include <cstring> +#include <deque> +#include <string> + +#include "base/chunk_generator.hh" +#include "base/cprintf.hh" // csprintf +#include "base/trace.hh" +#include "dev/disk_image.hh" +#include "dev/ide_disk.hh" +#include "dev/ide_ctrl.hh" +#include "dev/tsunami.hh" +#include "dev/tsunami_pchip.hh" +#include "sim/builder.hh" +#include "sim/sim_object.hh" +#include "sim/root.hh" +#include "arch/isa_traits.hh" + +using namespace std; +using namespace TheISA; + +IdeDisk::IdeDisk(const string &name, DiskImage *img, + int id, Tick delay) + : SimObject(name), ctrl(NULL), image(img), diskDelay(delay), + dmaTransferEvent(this), dmaReadCG(NULL), dmaReadWaitEvent(this), + dmaWriteCG(NULL), dmaWriteWaitEvent(this), dmaPrdReadEvent(this), + dmaReadEvent(this), dmaWriteEvent(this) +{ + // Reset the device state + reset(id); + + // fill out the drive ID structure + memset(&driveID, 0, sizeof(struct ataparams)); + + // Calculate LBA and C/H/S values + uint16_t cylinders; + uint8_t heads; + uint8_t sectors; + + uint32_t lba_size = image->size(); + if (lba_size >= 16383*16*63) { + cylinders = 16383; + heads = 16; + sectors = 63; + } else { + if (lba_size >= 63) + sectors = 63; + else + sectors = lba_size; + + if ((lba_size / sectors) >= 16) + heads = 16; + else + heads = (lba_size / sectors); + + cylinders = lba_size / (heads * sectors); + } + + // Setup the model name + strncpy((char *)driveID.atap_model, "5MI EDD si k", + sizeof(driveID.atap_model)); + // Set the maximum multisector transfer size + driveID.atap_multi = MAX_MULTSECT; + // IORDY supported, IORDY disabled, LBA enabled, DMA enabled + driveID.atap_capabilities1 = 0x7; + // UDMA support, EIDE support + driveID.atap_extensions = 0x6; + // Setup default C/H/S settings + driveID.atap_cylinders = cylinders; + driveID.atap_sectors = sectors; + driveID.atap_heads = heads; + // Setup the current multisector transfer size + driveID.atap_curmulti = MAX_MULTSECT; + driveID.atap_curmulti_valid = 0x1; + // Number of sectors on disk + driveID.atap_capacity = lba_size; + // Multiword DMA mode 2 and below supported + driveID.atap_dmamode_supp = 0x400; + // Set PIO mode 4 and 3 supported + driveID.atap_piomode_supp = 0x3; + // Set DMA mode 4 and below supported + driveID.atap_udmamode_supp = 0x1f; + // Statically set hardware config word + driveID.atap_hwreset_res = 0x4001; + + //arbitrary for now... + driveID.atap_ata_major = WDC_VER_ATA7; +} + +IdeDisk::~IdeDisk() +{ + // destroy the data buffer + delete [] dataBuffer; +} + +void +IdeDisk::reset(int id) +{ + // initialize the data buffer and shadow registers + dataBuffer = new uint8_t[MAX_DMA_SIZE]; + + memset(dataBuffer, 0, MAX_DMA_SIZE); + memset(&cmdReg, 0, sizeof(CommandReg_t)); + memset(&curPrd.entry, 0, sizeof(PrdEntry_t)); + + curPrdAddr = 0; + curSector = 0; + cmdBytes = 0; + cmdBytesLeft = 0; + drqBytesLeft = 0; + dmaRead = false; + intrPending = false; + + // set the device state to idle + dmaState = Dma_Idle; + + if (id == DEV0) { + devState = Device_Idle_S; + devID = DEV0; + } else if (id == DEV1) { + devState = Device_Idle_NS; + devID = DEV1; + } else { + panic("Invalid device ID: %#x\n", id); + } + + // set the device ready bit + status = STATUS_DRDY_BIT; + + /* The error register must be set to 0x1 on start-up to + indicate that no diagnostic error was detected */ + cmdReg.error = 0x1; +} + +//// +// Utility functions +//// + +bool +IdeDisk::isDEVSelect() +{ + return ctrl->isDiskSelected(this); +} + +Addr +IdeDisk::pciToDma(Addr pciAddr) +{ + if (ctrl) + return ctrl->plat->pciToDma(pciAddr); + else + panic("Access to unset controller!\n"); +} + +//// +// Device registers read/write +//// + +void +IdeDisk::read(const Addr &offset, IdeRegType reg_type, uint8_t *data) +{ + DevAction_t action = ACT_NONE; + + switch (reg_type) { + case COMMAND_BLOCK: + switch (offset) { + // Data transfers occur two bytes at a time + case DATA_OFFSET: + *(uint16_t*)data = cmdReg.data; + action = ACT_DATA_READ_SHORT; + break; + case ERROR_OFFSET: + *data = cmdReg.error; + break; + case NSECTOR_OFFSET: + *data = cmdReg.sec_count; + break; + case SECTOR_OFFSET: + *data = cmdReg.sec_num; + break; + case LCYL_OFFSET: + *data = cmdReg.cyl_low; + break; + case HCYL_OFFSET: + *data = cmdReg.cyl_high; + break; + case DRIVE_OFFSET: + *data = cmdReg.drive; + break; + case STATUS_OFFSET: + *data = status; + action = ACT_STAT_READ; + break; + default: + panic("Invalid IDE command register offset: %#x\n", offset); + } + break; + case CONTROL_BLOCK: + if (offset == ALTSTAT_OFFSET) + *data = status; + else + panic("Invalid IDE control register offset: %#x\n", offset); + break; + default: + panic("Unknown register block!\n"); + } + DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, + (uint32_t)*data); + + if (action != ACT_NONE) + updateState(action); +} + +void +IdeDisk::write(const Addr &offset, IdeRegType reg_type, const uint8_t *data) +{ + DevAction_t action = ACT_NONE; + + switch (reg_type) { + case COMMAND_BLOCK: + switch (offset) { + case DATA_OFFSET: + cmdReg.data = *(uint16_t*)data; + action = ACT_DATA_WRITE_SHORT; + break; + case FEATURES_OFFSET: + break; + case NSECTOR_OFFSET: + cmdReg.sec_count = *data; + break; + case SECTOR_OFFSET: + cmdReg.sec_num = *data; + break; + case LCYL_OFFSET: + cmdReg.cyl_low = *data; + break; + case HCYL_OFFSET: + cmdReg.cyl_high = *data; + break; + case DRIVE_OFFSET: + cmdReg.drive = *data; + action = ACT_SELECT_WRITE; + break; + case COMMAND_OFFSET: + cmdReg.command = *data; + action = ACT_CMD_WRITE; + break; + default: + panic("Invalid IDE command register offset: %#x\n", offset); + } + break; + case CONTROL_BLOCK: + if (offset == CONTROL_OFFSET) { + if (*data & CONTROL_RST_BIT) { + // force the device into the reset state + devState = Device_Srst; + action = ACT_SRST_SET; + } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT)) + action = ACT_SRST_CLEAR; + + nIENBit = (*data & CONTROL_IEN_BIT) ? true : false; + } + else + panic("Invalid IDE control register offset: %#x\n", offset); + break; + default: + panic("Unknown register block!\n"); + } + + DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset, + (uint32_t)*data); + if (action != ACT_NONE) + updateState(action); +} + +//// +// Perform DMA transactions +//// + +void +IdeDisk::doDmaTransfer() +{ + if (dmaState != Dma_Transfer || devState != Transfer_Data_Dma) + panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n", + dmaState, devState); + + if (ctrl->dmaPending()) { + dmaTransferEvent.schedule(curTick + DMA_BACKOFF_PERIOD); + return; + } else + ctrl->dmaRead(curPrdAddr, sizeof(PrdEntry_t), &dmaPrdReadEvent, + (uint8_t*)&curPrd.entry); +} + +void +IdeDisk::dmaPrdReadDone() +{ + DPRINTF(IdeDisk, + "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n", + curPrd.getBaseAddr(), pciToDma(curPrd.getBaseAddr()), + curPrd.getByteCount(), (cmdBytesLeft/SectorSize), + curPrd.getEOT(), curSector); + + // the prd pointer has already been translated, so just do an increment + curPrdAddr = curPrdAddr + sizeof(PrdEntry_t); + + if (dmaRead) + doDmaDataRead(); + else + doDmaDataWrite(); +} + +void +IdeDisk::doDmaDataRead() +{ + /** @todo we need to figure out what the delay actually will be */ + Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize); + + DPRINTF(IdeDisk, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n", + diskDelay, totalDiskDelay); + + dmaReadWaitEvent.schedule(curTick + totalDiskDelay); +} + +void +IdeDisk::regStats() +{ + using namespace Stats; + dmaReadFullPages + .name(name() + ".dma_read_full_pages") + .desc("Number of full page size DMA reads (not PRD).") + ; + dmaReadBytes + .name(name() + ".dma_read_bytes") + .desc("Number of bytes transfered via DMA reads (not PRD).") + ; + dmaReadTxs + .name(name() + ".dma_read_txs") + .desc("Number of DMA read transactions (not PRD).") + ; + + dmaWriteFullPages + .name(name() + ".dma_write_full_pages") + .desc("Number of full page size DMA writes.") + ; + dmaWriteBytes + .name(name() + ".dma_write_bytes") + .desc("Number of bytes transfered via DMA writes.") + ; + dmaWriteTxs + .name(name() + ".dma_write_txs") + .desc("Number of DMA write transactions.") + ; +} + +void +IdeDisk::doDmaRead() +{ + + if (!dmaReadCG) { + // clear out the data buffer + memset(dataBuffer, 0, MAX_DMA_SIZE); + dmaReadCG = new ChunkGenerator(curPrd.getBaseAddr(), + curPrd.getByteCount(), TheISA::PageBytes); + + } + if (ctrl->dmaPending()) { + panic("shouldn't be reentant??"); + dmaReadWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD); + return; + } else if (!dmaReadCG->done()) { + assert(dmaReadCG->complete() < MAX_DMA_SIZE); + ctrl->dmaRead(pciToDma(dmaReadCG->addr()), dmaReadCG->size(), + &dmaReadWaitEvent, dataBuffer + dmaReadCG->complete()); + dmaReadBytes += dmaReadCG->size(); + dmaReadTxs++; + if (dmaReadCG->size() == TheISA::PageBytes) + dmaReadFullPages++; + dmaReadCG->next(); + } else { + assert(dmaReadCG->done()); + delete dmaReadCG; + dmaReadCG = NULL; + dmaReadDone(); + } +} + +void +IdeDisk::dmaReadDone() +{ + + uint32_t bytesWritten = 0; + + + // write the data to the disk image + for (bytesWritten = 0; bytesWritten < curPrd.getByteCount(); + bytesWritten += SectorSize) { + + cmdBytesLeft -= SectorSize; + writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten)); + } + + // check for the EOT + if (curPrd.getEOT()) { + assert(cmdBytesLeft == 0); + dmaState = Dma_Idle; + updateState(ACT_DMA_DONE); + } else { + doDmaTransfer(); + } +} + +void +IdeDisk::doDmaDataWrite() +{ + /** @todo we need to figure out what the delay actually will be */ + Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize); + uint32_t bytesRead = 0; + + DPRINTF(IdeDisk, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n", + diskDelay, totalDiskDelay); + + memset(dataBuffer, 0, MAX_DMA_SIZE); + assert(cmdBytesLeft <= MAX_DMA_SIZE); + while (bytesRead < curPrd.getByteCount()) { + readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead)); + bytesRead += SectorSize; + cmdBytesLeft -= SectorSize; + } + + dmaWriteWaitEvent.schedule(curTick + totalDiskDelay); +} + +void +IdeDisk::doDmaWrite() +{ + + if (!dmaWriteCG) { + // clear out the data buffer + dmaWriteCG = new ChunkGenerator(curPrd.getBaseAddr(), + curPrd.getByteCount(), TheISA::PageBytes); + } + if (ctrl->dmaPending()) { + panic("shouldn't be reentant??"); + dmaWriteWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD); + return; + } else if (!dmaWriteCG->done()) { + assert(dmaWriteCG->complete() < MAX_DMA_SIZE); + ctrl->dmaWrite(pciToDma(dmaWriteCG->addr()), dmaWriteCG->size(), + &dmaWriteWaitEvent, dataBuffer + dmaWriteCG->complete()); + dmaWriteBytes += dmaWriteCG->size(); + dmaWriteTxs++; + if (dmaWriteCG->size() == TheISA::PageBytes) + dmaWriteFullPages++; + dmaWriteCG->next(); + } else { + assert(dmaWriteCG->done()); + delete dmaWriteCG; + dmaWriteCG = NULL; + dmaWriteDone(); + } +} + +void +IdeDisk::dmaWriteDone() +{ + // check for the EOT + if (curPrd.getEOT()) { + assert(cmdBytesLeft == 0); + dmaState = Dma_Idle; + updateState(ACT_DMA_DONE); + } else { + doDmaTransfer(); + } +} + +//// +// Disk utility routines +/// + +void +IdeDisk::readDisk(uint32_t sector, uint8_t *data) +{ + uint32_t bytesRead = image->read(data, sector); + + if (bytesRead != SectorSize) + panic("Can't read from %s. Only %d of %d read. errno=%d\n", + name(), bytesRead, SectorSize, errno); +} + +void +IdeDisk::writeDisk(uint32_t sector, uint8_t *data) +{ + uint32_t bytesWritten = image->write(data, sector); + + if (bytesWritten != SectorSize) + panic("Can't write to %s. Only %d of %d written. errno=%d\n", + name(), bytesWritten, SectorSize, errno); +} + +//// +// Setup and handle commands +//// + +void +IdeDisk::startDma(const uint32_t &prdTableBase) +{ + if (dmaState != Dma_Start) + panic("Inconsistent DMA state, should be in Dma_Start!\n"); + + if (devState != Transfer_Data_Dma) + panic("Inconsistent device state for DMA start!\n"); + + // PRD base address is given by bits 31:2 + curPrdAddr = pciToDma((Addr)(prdTableBase & ~ULL(0x3))); + + dmaState = Dma_Transfer; + + // schedule dma transfer (doDmaTransfer) + dmaTransferEvent.schedule(curTick + 1); +} + +void +IdeDisk::abortDma() +{ + if (dmaState == Dma_Idle) + panic("Inconsistent DMA state, should be Start or Transfer!"); + + if (devState != Transfer_Data_Dma && devState != Prepare_Data_Dma) + panic("Inconsistent device state, should be Transfer or Prepare!\n"); + + updateState(ACT_CMD_ERROR); +} + +void +IdeDisk::startCommand() +{ + DevAction_t action = ACT_NONE; + uint32_t size = 0; + dmaRead = false; + + // Decode commands + switch (cmdReg.command) { + // Supported non-data commands + case WDSF_READ_NATIVE_MAX: + size = image->size() - 1; + cmdReg.sec_num = (size & 0xff); + cmdReg.cyl_low = ((size & 0xff00) >> 8); + cmdReg.cyl_high = ((size & 0xff0000) >> 16); + cmdReg.head = ((size & 0xf000000) >> 24); + + devState = Command_Execution; + action = ACT_CMD_COMPLETE; + break; + + case WDCC_RECAL: + case WDCC_IDP: + case WDCC_STANDBY_IMMED: + case WDCC_FLUSHCACHE: + case WDSF_VERIFY: + case WDSF_SEEK: + case SET_FEATURES: + case WDCC_SETMULTI: + devState = Command_Execution; + action = ACT_CMD_COMPLETE; + break; + + // Supported PIO data-in commands + case WDCC_IDENTIFY: + cmdBytes = cmdBytesLeft = sizeof(struct ataparams); + devState = Prepare_Data_In; + action = ACT_DATA_READY; + break; + + case WDCC_READMULTI: + case WDCC_READ: + if (!(cmdReg.drive & DRIVE_LBA_BIT)) + panic("Attempt to perform CHS access, only supports LBA\n"); + + if (cmdReg.sec_count == 0) + cmdBytes = cmdBytesLeft = (256 * SectorSize); + else + cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); + + curSector = getLBABase(); + + /** @todo make this a scheduled event to simulate disk delay */ + devState = Prepare_Data_In; + action = ACT_DATA_READY; + break; + + // Supported PIO data-out commands + case WDCC_WRITEMULTI: + case WDCC_WRITE: + if (!(cmdReg.drive & DRIVE_LBA_BIT)) + panic("Attempt to perform CHS access, only supports LBA\n"); + + if (cmdReg.sec_count == 0) + cmdBytes = cmdBytesLeft = (256 * SectorSize); + else + cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); + + curSector = getLBABase(); + + devState = Prepare_Data_Out; + action = ACT_DATA_READY; + break; + + // Supported DMA commands + case WDCC_WRITEDMA: + dmaRead = true; // a write to the disk is a DMA read from memory + case WDCC_READDMA: + if (!(cmdReg.drive & DRIVE_LBA_BIT)) + panic("Attempt to perform CHS access, only supports LBA\n"); + + if (cmdReg.sec_count == 0) + cmdBytes = cmdBytesLeft = (256 * SectorSize); + else + cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); + + curSector = getLBABase(); + + devState = Prepare_Data_Dma; + action = ACT_DMA_READY; + break; + + default: + panic("Unsupported ATA command: %#x\n", cmdReg.command); + } + + if (action != ACT_NONE) { + // set the BSY bit + status |= STATUS_BSY_BIT; + // clear the DRQ bit + status &= ~STATUS_DRQ_BIT; + // clear the DF bit + status &= ~STATUS_DF_BIT; + + updateState(action); + } +} + +//// +// Handle setting and clearing interrupts +//// + +void +IdeDisk::intrPost() +{ + DPRINTF(IdeDisk, "Posting Interrupt\n"); + if (intrPending) + panic("Attempt to post an interrupt with one pending\n"); + + intrPending = true; + + // talk to controller to set interrupt + if (ctrl) { + ctrl->bmi_regs.bmis0 |= IDEINTS; + ctrl->intrPost(); + } +} + +void +IdeDisk::intrClear() +{ + DPRINTF(IdeDisk, "Clearing Interrupt\n"); + if (!intrPending) + panic("Attempt to clear a non-pending interrupt\n"); + + intrPending = false; + + // talk to controller to clear interrupt + if (ctrl) + ctrl->intrClear(); +} + +//// +// Manage the device internal state machine +//// + +void +IdeDisk::updateState(DevAction_t action) +{ + switch (devState) { + case Device_Srst: + if (action == ACT_SRST_SET) { + // set the BSY bit + status |= STATUS_BSY_BIT; + } else if (action == ACT_SRST_CLEAR) { + // clear the BSY bit + status &= ~STATUS_BSY_BIT; + + // reset the device state + reset(devID); + } + break; + + case Device_Idle_S: + if (action == ACT_SELECT_WRITE && !isDEVSelect()) { + devState = Device_Idle_NS; + } else if (action == ACT_CMD_WRITE) { + startCommand(); + } + + break; + + case Device_Idle_SI: + if (action == ACT_SELECT_WRITE && !isDEVSelect()) { + devState = Device_Idle_NS; + intrClear(); + } else if (action == ACT_STAT_READ || isIENSet()) { + devState = Device_Idle_S; + intrClear(); + } else if (action == ACT_CMD_WRITE) { + intrClear(); + startCommand(); + } + + break; + + case Device_Idle_NS: + if (action == ACT_SELECT_WRITE && isDEVSelect()) { + if (!isIENSet() && intrPending) { + devState = Device_Idle_SI; + intrPost(); + } + if (isIENSet() || !intrPending) { + devState = Device_Idle_S; + } + } + break; + + case Command_Execution: + if (action == ACT_CMD_COMPLETE) { + // clear the BSY bit + setComplete(); + + if (!isIENSet()) { + devState = Device_Idle_SI; + intrPost(); + } else { + devState = Device_Idle_S; + } + } + break; + + case Prepare_Data_In: + if (action == ACT_CMD_ERROR) { + // clear the BSY bit + setComplete(); + + if (!isIENSet()) { + devState = Device_Idle_SI; + intrPost(); + } else { + devState = Device_Idle_S; + } + } else if (action == ACT_DATA_READY) { + // clear the BSY bit + status &= ~STATUS_BSY_BIT; + // set the DRQ bit + status |= STATUS_DRQ_BIT; + + // copy the data into the data buffer + if (cmdReg.command == WDCC_IDENTIFY) { + // Reset the drqBytes for this block + drqBytesLeft = sizeof(struct ataparams); + + memcpy((void *)dataBuffer, (void *)&driveID, + sizeof(struct ataparams)); + } else { + // Reset the drqBytes for this block + drqBytesLeft = SectorSize; + + readDisk(curSector++, dataBuffer); + } + + // put the first two bytes into the data register + memcpy((void *)&cmdReg.data, (void *)dataBuffer, + sizeof(uint16_t)); + + if (!isIENSet()) { + devState = Data_Ready_INTRQ_In; + intrPost(); + } else { + devState = Transfer_Data_In; + } + } + break; + + case Data_Ready_INTRQ_In: + if (action == ACT_STAT_READ) { + devState = Transfer_Data_In; + intrClear(); + } + break; + + case Transfer_Data_In: + if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) { + if (action == ACT_DATA_READ_BYTE) { + panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n"); + } else { + drqBytesLeft -= 2; + cmdBytesLeft -= 2; + + // copy next short into data registers + if (drqBytesLeft) + memcpy((void *)&cmdReg.data, + (void *)&dataBuffer[SectorSize - drqBytesLeft], + sizeof(uint16_t)); + } + + if (drqBytesLeft == 0) { + if (cmdBytesLeft == 0) { + // Clear the BSY bit + setComplete(); + devState = Device_Idle_S; + } else { + devState = Prepare_Data_In; + // set the BSY_BIT + status |= STATUS_BSY_BIT; + // clear the DRQ_BIT + status &= ~STATUS_DRQ_BIT; + + /** @todo change this to a scheduled event to simulate + disk delay */ + updateState(ACT_DATA_READY); + } + } + } + break; + + case Prepare_Data_Out: + if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) { + // clear the BSY bit + setComplete(); + + if (!isIENSet()) { + devState = Device_Idle_SI; + intrPost(); + } else { + devState = Device_Idle_S; + } + } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) { + // clear the BSY bit + status &= ~STATUS_BSY_BIT; + // set the DRQ bit + status |= STATUS_DRQ_BIT; + + // clear the data buffer to get it ready for writes + memset(dataBuffer, 0, MAX_DMA_SIZE); + + // reset the drqBytes for this block + drqBytesLeft = SectorSize; + + if (cmdBytesLeft == cmdBytes || isIENSet()) { + devState = Transfer_Data_Out; + } else { + devState = Data_Ready_INTRQ_Out; + intrPost(); + } + } + break; + + case Data_Ready_INTRQ_Out: + if (action == ACT_STAT_READ) { + devState = Transfer_Data_Out; + intrClear(); + } + break; + + case Transfer_Data_Out: + if (action == ACT_DATA_WRITE_BYTE || + action == ACT_DATA_WRITE_SHORT) { + + if (action == ACT_DATA_READ_BYTE) { + panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n"); + } else { + // copy the latest short into the data buffer + memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft], + (void *)&cmdReg.data, + sizeof(uint16_t)); + + drqBytesLeft -= 2; + cmdBytesLeft -= 2; + } + + if (drqBytesLeft == 0) { + // copy the block to the disk + writeDisk(curSector++, dataBuffer); + + // set the BSY bit + status |= STATUS_BSY_BIT; + // set the seek bit + status |= STATUS_SEEK_BIT; + // clear the DRQ bit + status &= ~STATUS_DRQ_BIT; + + devState = Prepare_Data_Out; + + /** @todo change this to a scheduled event to simulate + disk delay */ + updateState(ACT_DATA_READY); + } + } + break; + + case Prepare_Data_Dma: + if (action == ACT_CMD_ERROR) { + // clear the BSY bit + setComplete(); + + if (!isIENSet()) { + devState = Device_Idle_SI; + intrPost(); + } else { + devState = Device_Idle_S; + } + } else if (action == ACT_DMA_READY) { + // clear the BSY bit + status &= ~STATUS_BSY_BIT; + // set the DRQ bit + status |= STATUS_DRQ_BIT; + + devState = Transfer_Data_Dma; + + if (dmaState != Dma_Idle) + panic("Inconsistent DMA state, should be Dma_Idle\n"); + + dmaState = Dma_Start; + // wait for the write to the DMA start bit + } + break; + + case Transfer_Data_Dma: + if (action == ACT_CMD_ERROR || action == ACT_DMA_DONE) { + // clear the BSY bit + setComplete(); + // set the seek bit + status |= STATUS_SEEK_BIT; + // clear the controller state for DMA transfer + ctrl->setDmaComplete(this); + + if (!isIENSet()) { + devState = Device_Idle_SI; + intrPost(); + } else { + devState = Device_Idle_S; + } + } + break; + + default: + panic("Unknown IDE device state: %#x\n", devState); + } +} + +void +IdeDisk::serialize(ostream &os) +{ + // Check all outstanding events to see if they are scheduled + // these are all mutually exclusive + Tick reschedule = 0; + Events_t event = None; + + int eventCount = 0; + + if (dmaTransferEvent.scheduled()) { + reschedule = dmaTransferEvent.when(); + event = Transfer; + eventCount++; + } + if (dmaReadWaitEvent.scheduled()) { + reschedule = dmaReadWaitEvent.when(); + event = ReadWait; + eventCount++; + } + if (dmaWriteWaitEvent.scheduled()) { + reschedule = dmaWriteWaitEvent.when(); + event = WriteWait; + eventCount++; + } + if (dmaPrdReadEvent.scheduled()) { + reschedule = dmaPrdReadEvent.when(); + event = PrdRead; + eventCount++; + } + if (dmaReadEvent.scheduled()) { + reschedule = dmaReadEvent.when(); + event = DmaRead; + eventCount++; + } + if (dmaWriteEvent.scheduled()) { + reschedule = dmaWriteEvent.when(); + event = DmaWrite; + eventCount++; + } + + assert(eventCount <= 1); + + SERIALIZE_SCALAR(reschedule); + SERIALIZE_ENUM(event); + + // Serialize device registers + SERIALIZE_SCALAR(cmdReg.data); + SERIALIZE_SCALAR(cmdReg.sec_count); + SERIALIZE_SCALAR(cmdReg.sec_num); + SERIALIZE_SCALAR(cmdReg.cyl_low); + SERIALIZE_SCALAR(cmdReg.cyl_high); + SERIALIZE_SCALAR(cmdReg.drive); + SERIALIZE_SCALAR(cmdReg.command); + SERIALIZE_SCALAR(status); + SERIALIZE_SCALAR(nIENBit); + SERIALIZE_SCALAR(devID); + + // Serialize the PRD related information + SERIALIZE_SCALAR(curPrd.entry.baseAddr); + SERIALIZE_SCALAR(curPrd.entry.byteCount); + SERIALIZE_SCALAR(curPrd.entry.endOfTable); + SERIALIZE_SCALAR(curPrdAddr); + + /** @todo need to serialized chunk generator stuff!! */ + // Serialize current transfer related information + SERIALIZE_SCALAR(cmdBytesLeft); + SERIALIZE_SCALAR(cmdBytes); + SERIALIZE_SCALAR(drqBytesLeft); + SERIALIZE_SCALAR(curSector); + SERIALIZE_SCALAR(dmaRead); + SERIALIZE_SCALAR(intrPending); + SERIALIZE_ENUM(devState); + SERIALIZE_ENUM(dmaState); + SERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE); +} + +void +IdeDisk::unserialize(Checkpoint *cp, const string §ion) +{ + // Reschedule events that were outstanding + // these are all mutually exclusive + Tick reschedule = 0; + Events_t event = None; + + UNSERIALIZE_SCALAR(reschedule); + UNSERIALIZE_ENUM(event); + + switch (event) { + case None : break; + case Transfer : dmaTransferEvent.schedule(reschedule); break; + case ReadWait : dmaReadWaitEvent.schedule(reschedule); break; + case WriteWait : dmaWriteWaitEvent.schedule(reschedule); break; + case PrdRead : dmaPrdReadEvent.schedule(reschedule); break; + case DmaRead : dmaReadEvent.schedule(reschedule); break; + case DmaWrite : dmaWriteEvent.schedule(reschedule); break; + } + + // Unserialize device registers + UNSERIALIZE_SCALAR(cmdReg.data); + UNSERIALIZE_SCALAR(cmdReg.sec_count); + UNSERIALIZE_SCALAR(cmdReg.sec_num); + UNSERIALIZE_SCALAR(cmdReg.cyl_low); + UNSERIALIZE_SCALAR(cmdReg.cyl_high); + UNSERIALIZE_SCALAR(cmdReg.drive); + UNSERIALIZE_SCALAR(cmdReg.command); + UNSERIALIZE_SCALAR(status); + UNSERIALIZE_SCALAR(nIENBit); + UNSERIALIZE_SCALAR(devID); + + // Unserialize the PRD related information + UNSERIALIZE_SCALAR(curPrd.entry.baseAddr); + UNSERIALIZE_SCALAR(curPrd.entry.byteCount); + UNSERIALIZE_SCALAR(curPrd.entry.endOfTable); + UNSERIALIZE_SCALAR(curPrdAddr); + + /** @todo need to serialized chunk generator stuff!! */ + // Unserialize current transfer related information + UNSERIALIZE_SCALAR(cmdBytes); + UNSERIALIZE_SCALAR(cmdBytesLeft); + UNSERIALIZE_SCALAR(drqBytesLeft); + UNSERIALIZE_SCALAR(curSector); + UNSERIALIZE_SCALAR(dmaRead); + UNSERIALIZE_SCALAR(intrPending); + UNSERIALIZE_ENUM(devState); + UNSERIALIZE_ENUM(dmaState); + UNSERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE); +} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +enum DriveID { master, slave }; +static const char *DriveID_strings[] = { "master", "slave" }; +BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeDisk) + + SimObjectParam<DiskImage *> image; + SimpleEnumParam<DriveID> driveID; + Param<int> delay; + +END_DECLARE_SIM_OBJECT_PARAMS(IdeDisk) + +BEGIN_INIT_SIM_OBJECT_PARAMS(IdeDisk) + + INIT_PARAM(image, "Disk image"), + INIT_ENUM_PARAM(driveID, "Drive ID (0=master 1=slave)", DriveID_strings), + INIT_PARAM_DFLT(delay, "Fixed disk delay in microseconds", 1) + +END_INIT_SIM_OBJECT_PARAMS(IdeDisk) + + +CREATE_SIM_OBJECT(IdeDisk) +{ + return new IdeDisk(getInstanceName(), image, driveID, delay); +} + +REGISTER_SIM_OBJECT("IdeDisk", IdeDisk) + +#endif //DOXYGEN_SHOULD_SKIP_THIS diff --git a/src/dev/ide_disk.hh b/src/dev/ide_disk.hh new file mode 100644 index 000000000..fb0614d4d --- /dev/null +++ b/src/dev/ide_disk.hh @@ -0,0 +1,369 @@ +/* + * 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: Andrew Schultz + */ + +/** @file + * Device model for an IDE disk + */ + +#ifndef __IDE_DISK_HH__ +#define __IDE_DISK_HH__ + +#include "base/statistics.hh" +#include "dev/disk_image.hh" +#include "dev/ide_atareg.h" +#include "dev/ide_ctrl.hh" +#include "dev/ide_wdcreg.h" +#include "dev/io_device.hh" +#include "sim/eventq.hh" + +#define DMA_BACKOFF_PERIOD 200 + +#define MAX_DMA_SIZE (131072) // 128K +#define MAX_MULTSECT (128) + +#define PRD_BASE_MASK 0xfffffffe +#define PRD_COUNT_MASK 0xfffe +#define PRD_EOT_MASK 0x8000 + +typedef struct PrdEntry { + uint32_t baseAddr; + uint16_t byteCount; + uint16_t endOfTable; +} PrdEntry_t; + +class PrdTableEntry { + public: + PrdEntry_t entry; + + uint32_t getBaseAddr() + { + return (entry.baseAddr & PRD_BASE_MASK); + } + + uint32_t getByteCount() + { + return ((entry.byteCount == 0) ? MAX_DMA_SIZE : + (entry.byteCount & PRD_COUNT_MASK)); + } + + uint16_t getEOT() + { + return (entry.endOfTable & PRD_EOT_MASK); + } +}; + +#define DATA_OFFSET (0) +#define ERROR_OFFSET (1) +#define FEATURES_OFFSET (1) +#define NSECTOR_OFFSET (2) +#define SECTOR_OFFSET (3) +#define LCYL_OFFSET (4) +#define HCYL_OFFSET (5) +#define SELECT_OFFSET (6) +#define DRIVE_OFFSET (6) +#define STATUS_OFFSET (7) +#define COMMAND_OFFSET (7) + +#define CONTROL_OFFSET (2) +#define ALTSTAT_OFFSET (2) + +#define SELECT_DEV_BIT 0x10 +#define CONTROL_RST_BIT 0x04 +#define CONTROL_IEN_BIT 0x02 +#define STATUS_BSY_BIT 0x80 +#define STATUS_DRDY_BIT 0x40 +#define STATUS_DRQ_BIT 0x08 +#define STATUS_SEEK_BIT 0x10 +#define STATUS_DF_BIT 0x20 +#define DRIVE_LBA_BIT 0x40 + +#define DEV0 (0) +#define DEV1 (1) + +typedef struct CommandReg { + uint16_t data; + uint8_t error; + uint8_t sec_count; + uint8_t sec_num; + uint8_t cyl_low; + uint8_t cyl_high; + union { + uint8_t drive; + uint8_t head; + }; + uint8_t command; +} CommandReg_t; + +typedef enum Events { + None = 0, + Transfer, + ReadWait, + WriteWait, + PrdRead, + DmaRead, + DmaWrite +} Events_t; + +typedef enum DevAction { + ACT_NONE = 0, + ACT_CMD_WRITE, + ACT_CMD_COMPLETE, + ACT_CMD_ERROR, + ACT_SELECT_WRITE, + ACT_STAT_READ, + ACT_DATA_READY, + ACT_DATA_READ_BYTE, + ACT_DATA_READ_SHORT, + ACT_DATA_WRITE_BYTE, + ACT_DATA_WRITE_SHORT, + ACT_DMA_READY, + ACT_DMA_DONE, + ACT_SRST_SET, + ACT_SRST_CLEAR +} DevAction_t; + +typedef enum DevState { + // Device idle + Device_Idle_S = 0, + Device_Idle_SI, + Device_Idle_NS, + + // Software reset + Device_Srst, + + // Non-data commands + Command_Execution, + + // PIO data-in (data to host) + Prepare_Data_In, + Data_Ready_INTRQ_In, + Transfer_Data_In, + + // PIO data-out (data from host) + Prepare_Data_Out, + Data_Ready_INTRQ_Out, + Transfer_Data_Out, + + // DMA protocol + Prepare_Data_Dma, + Transfer_Data_Dma +} DevState_t; + +typedef enum DmaState { + Dma_Idle = 0, + Dma_Start, + Dma_Transfer +} DmaState_t; + +class PhysicalMemory; +class IdeController; + +/** + * IDE Disk device model + */ +class IdeDisk : public SimObject +{ + protected: + /** The IDE controller for this disk. */ + IdeController *ctrl; + /** The image that contains the data of this disk. */ + DiskImage *image; + + protected: + /** The disk delay in microseconds. */ + int diskDelay; + + private: + /** Drive identification structure for this disk */ + struct ataparams driveID; + /** Data buffer for transfers */ + uint8_t *dataBuffer; + /** Number of bytes in command data transfer */ + uint32_t cmdBytes; + /** Number of bytes left in command data transfer */ + uint32_t cmdBytesLeft; + /** Number of bytes left in DRQ block */ + uint32_t drqBytesLeft; + /** Current sector in access */ + uint32_t curSector; + /** Command block registers */ + CommandReg_t cmdReg; + /** Status register */ + uint8_t status; + /** Interrupt enable bit */ + bool nIENBit; + /** Device state */ + DevState_t devState; + /** Dma state */ + DmaState_t dmaState; + /** Dma transaction is a read */ + bool dmaRead; + /** PRD table base address */ + uint32_t curPrdAddr; + /** PRD entry */ + PrdTableEntry curPrd; + /** Device ID (master=0/slave=1) */ + int devID; + /** Interrupt pending */ + bool intrPending; + + Stats::Scalar<> dmaReadFullPages; + Stats::Scalar<> dmaReadBytes; + Stats::Scalar<> dmaReadTxs; + Stats::Scalar<> dmaWriteFullPages; + Stats::Scalar<> dmaWriteBytes; + Stats::Scalar<> dmaWriteTxs; + + public: + /** + * Create and initialize this Disk. + * @param name The name of this disk. + * @param img The disk image of this disk. + * @param id The disk ID (master=0/slave=1) + * @param disk_delay The disk delay in milliseconds + */ + IdeDisk(const std::string &name, DiskImage *img, int id, Tick disk_delay); + + /** + * Delete the data buffer. + */ + ~IdeDisk(); + + /** + * Reset the device state + */ + void reset(int id); + + /** + * Register Statistics + */ + void regStats(); + + /** + * Set the controller for this device + * @param c The IDE controller + */ + void setController(IdeController *c) { + if (ctrl) panic("Cannot change the controller once set!\n"); + ctrl = c; + } + + // Device register read/write + void read(const Addr &offset, IdeRegType regtype, uint8_t *data); + void write(const Addr &offset, IdeRegType regtype, const uint8_t *data); + + // Start/abort functions + void startDma(const uint32_t &prdTableBase); + void abortDma(); + + private: + void startCommand(); + + // Interrupt management + void intrPost(); + void intrClear(); + + // DMA stuff + void doDmaTransfer(); + friend class EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer>; + EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer> dmaTransferEvent; + + void doDmaDataRead(); + + void doDmaRead(); + ChunkGenerator *dmaReadCG; + friend class EventWrapper<IdeDisk, &IdeDisk::doDmaRead>; + EventWrapper<IdeDisk, &IdeDisk::doDmaRead> dmaReadWaitEvent; + + void doDmaDataWrite(); + + void doDmaWrite(); + ChunkGenerator *dmaWriteCG; + friend class EventWrapper<IdeDisk, &IdeDisk::doDmaWrite>; + EventWrapper<IdeDisk, &IdeDisk::doDmaWrite> dmaWriteWaitEvent; + + void dmaPrdReadDone(); + friend class EventWrapper<IdeDisk, &IdeDisk::dmaPrdReadDone>; + EventWrapper<IdeDisk, &IdeDisk::dmaPrdReadDone> dmaPrdReadEvent; + + void dmaReadDone(); + friend class EventWrapper<IdeDisk, &IdeDisk::dmaReadDone>; + EventWrapper<IdeDisk, &IdeDisk::dmaReadDone> dmaReadEvent; + + void dmaWriteDone(); + friend class EventWrapper<IdeDisk, &IdeDisk::dmaWriteDone>; + EventWrapper<IdeDisk, &IdeDisk::dmaWriteDone> dmaWriteEvent; + + // Disk image read/write + void readDisk(uint32_t sector, uint8_t *data); + void writeDisk(uint32_t sector, uint8_t *data); + + // State machine management + void updateState(DevAction_t action); + + // Utility functions + bool isBSYSet() { return (status & STATUS_BSY_BIT); } + bool isIENSet() { return nIENBit; } + bool isDEVSelect(); + + void setComplete() + { + // clear out the status byte + status = 0; + // set the DRDY bit + status |= STATUS_DRDY_BIT; + // set the SEEK bit + status |= STATUS_SEEK_BIT; + } + + uint32_t getLBABase() + { + return (Addr)(((cmdReg.head & 0xf) << 24) | (cmdReg.cyl_high << 16) | + (cmdReg.cyl_low << 8) | (cmdReg.sec_num)); + } + + inline Addr pciToDma(Addr pciAddr); + + /** + * Serialize this object to the given output stream. + * @param os The stream to serialize to. + */ + void serialize(std::ostream &os); + + /** + * Reconstruct the state of this object from a checkpoint. + * @param cp The checkpoint to use. + * @param section The section name describing this object. + */ + void unserialize(Checkpoint *cp, const std::string §ion); +}; + + +#endif // __IDE_DISK_HH__ diff --git a/dev/ide_wdcreg.h b/src/dev/ide_wdcreg.h index ed7475ec8..ed7475ec8 100644 --- a/dev/ide_wdcreg.h +++ b/src/dev/ide_wdcreg.h diff --git a/src/dev/io_device.cc b/src/dev/io_device.cc new file mode 100644 index 000000000..485216874 --- /dev/null +++ b/src/dev/io_device.cc @@ -0,0 +1,253 @@ +/* + * 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 + * Nathan Binkert + */ + +#include "base/trace.hh" +#include "dev/io_device.hh" +#include "sim/builder.hh" + + +PioPort::PioPort(PioDevice *dev, Platform *p) + : Port(dev->name() + "-pioport"), device(dev), platform(p) +{ } + + +Tick +PioPort::recvAtomic(Packet *pkt) +{ + return device->recvAtomic(pkt); +} + +void +PioPort::recvFunctional(Packet *pkt) +{ + device->recvAtomic(pkt); +} + +void +PioPort::getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop) +{ + snoop.clear(); + device->addressRanges(resp); +} + + +void +PioPort::recvRetry() +{ + Packet* pkt = transmitList.front(); + if (Port::sendTiming(pkt)) { + transmitList.pop_front(); + } +} + + +void +PioPort::SendEvent::process() +{ + if (port->Port::sendTiming(packet)) + return; + + port->transmitList.push_back(packet); +} + + + +bool +PioPort::recvTiming(Packet *pkt) +{ + Tick latency = device->recvAtomic(pkt); + // turn packet around to go back to requester + pkt->makeTimingResponse(); + sendTiming(pkt, latency); + return true; +} + +PioDevice::~PioDevice() +{ + if (pioPort) + delete pioPort; +} + +void +PioDevice::init() +{ + if (!pioPort) + panic("Pio port not connected to anything!"); + pioPort->sendStatusChange(Port::RangeChange); +} + +void +BasicPioDevice::addressRanges(AddrRangeList &range_list) +{ + assert(pioSize != 0); + range_list.clear(); + range_list.push_back(RangeSize(pioAddr, pioSize)); +} + + +DmaPort::DmaPort(DmaDevice *dev, Platform *p) + : Port(dev->name() + "-dmaport"), device(dev), platform(p), pendingCount(0) +{ } + +bool +DmaPort::recvTiming(Packet *pkt) +{ + + + if (pkt->result == Packet::Nacked) { + DPRINTF(DMA, "Received nacked Pkt %#x with State: %#x Addr: %#x\n", + pkt, pkt->senderState, pkt->getAddr()); + pkt->reinitNacked(); + sendDma(pkt, true); + } else if (pkt->senderState) { + DmaReqState *state; + DPRINTF(DMA, "Received response Pkt %#x with State: %#x Addr: %#x\n", + pkt, pkt->senderState, pkt->getAddr()); + state = dynamic_cast<DmaReqState*>(pkt->senderState); + pendingCount--; + + assert(pendingCount >= 0); + assert(state); + + state->numBytes += pkt->req->getSize(); + if (state->totBytes == state->numBytes) { + state->completionEvent->process(); + delete state; + } + delete pkt->req; + delete pkt; + } else { + panic("Got packet without sender state... huh?\n"); + } + + return true; +} + +DmaDevice::DmaDevice(Params *p) + : PioDevice(p), dmaPort(NULL) +{ } + +void +DmaPort::recvRetry() +{ + Packet* pkt = transmitList.front(); + bool result = true; + while (result && transmitList.size()) { + DPRINTF(DMA, "Retry on Packet %#x with senderState: %#x\n", + pkt, pkt->senderState); + result = sendTiming(pkt); + if (result) { + DPRINTF(DMA, "-- Done\n"); + transmitList.pop_front(); + } else { + DPRINTF(DMA, "-- Failed, queued\n"); + } + } +} + + +void +DmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event, + uint8_t *data) +{ + assert(event); + + DmaReqState *reqState = new DmaReqState(event, this, size); + + for (ChunkGenerator gen(addr, size, peerBlockSize()); + !gen.done(); gen.next()) { + Request *req = new Request(gen.addr(), gen.size(), 0); + Packet *pkt = new Packet(req, cmd, Packet::Broadcast); + + // Increment the data pointer on a write + if (data) + pkt->dataStatic(data + gen.complete()); + + pkt->senderState = reqState; + + assert(pendingCount >= 0); + pendingCount++; + sendDma(pkt); + } +} + + +void +DmaPort::sendDma(Packet *pkt, bool front) +{ + // some kind of selction between access methods + // more work is going to have to be done to make + // switching actually work + /* MemState state = device->platform->system->memState; + + if (state == Timing) { */ + DPRINTF(DMA, "Attempting to send Packet %#x with addr: %#x\n", + pkt, pkt->getAddr()); + if (transmitList.size() || !sendTiming(pkt)) { + if (front) + transmitList.push_front(pkt); + else + transmitList.push_back(pkt); + DPRINTF(DMA, "-- Failed: queued\n"); + } else { + DPRINTF(DMA, "-- Done\n"); + } + /* } else if (state == Atomic) { + sendAtomic(pkt); + if (pkt->senderState) { + DmaReqState *state = dynamic_cast<DmaReqState*>(pkt->senderState); + assert(state); + state->completionEvent->schedule(curTick + (pkt->time - + pkt->req->getTime()) +1); + delete state; + } + pendingCount--; + assert(pendingCount >= 0); + delete pkt->req; + delete pkt; + + } else if (state == Functional) { + sendFunctional(pkt); + // Is this correct??? + completionEvent->schedule(pkt->req->responseTime - pkt->req->requestTime); + completionEvent == NULL; + } else + panic("Unknown memory command state."); + */ +} + +DmaDevice::~DmaDevice() +{ + if (dmaPort) + delete dmaPort; +} + + diff --git a/src/dev/io_device.hh b/src/dev/io_device.hh new file mode 100644 index 000000000..195ca0fb7 --- /dev/null +++ b/src/dev/io_device.hh @@ -0,0 +1,332 @@ +/* + * 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: Ali Saidi + * Nathan Binkert + */ + +#ifndef __DEV_IO_DEVICE_HH__ +#define __DEV_IO_DEVICE_HH__ + +#include "base/chunk_generator.hh" +#include "mem/mem_object.hh" +#include "mem/packet_impl.hh" +#include "sim/eventq.hh" +#include "sim/sim_object.hh" + +class Platform; +class PioDevice; +class DmaDevice; +class System; + +/** + * The PioPort class is a programmed i/o port that all devices that are + * sensitive to an address range use. The port takes all the memory + * access types and roles them into one read() and write() call that the device + * must respond to. The device must also provide the addressRanges() function + * with which it returns the address ranges it is interested in. An extra + * sendTiming() function is implemented which takes an delay. In this way the + * device can immediatly call sendTiming(pkt, time) after processing a request + * and the request will be handled by the port even if the port bus the device + * connects to is blocked. + */ +class PioPort : public Port +{ + protected: + /** The device that this port serves. */ + PioDevice *device; + + /** The platform that device/port are in. This is used to select which mode + * we are currently operating in. */ + Platform *platform; + + /** A list of outgoing timing response packets that haven't been serviced + * yet. */ + std::list<Packet*> transmitList; + + /** The current status of the peer(bus) that we are connected to. */ + Status peerStatus; + + virtual bool recvTiming(Packet *pkt); + + virtual Tick recvAtomic(Packet *pkt); + + virtual void recvFunctional(Packet *pkt) ; + + virtual void recvStatusChange(Status status) + { peerStatus = status; } + + virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop); + + /** + * This class is used to implemented sendTiming() with a delay. When a delay + * is requested a new event is created. When the event time expires it + * attempts to send the packet. If it cannot, the packet is pushed onto the + * transmit list to be sent when recvRetry() is called. */ + class SendEvent : public Event + { + PioPort *port; + Packet *packet; + + SendEvent(PioPort *p, Packet *pkt, Tick t) + : Event(&mainEventQueue), port(p), packet(pkt) + { schedule(curTick + t); } + + virtual void process(); + + virtual const char *description() + { return "Future scheduled sendTiming event"; } + + friend class PioPort; + }; + + /** Schedule a sendTiming() event to be called in the future. */ + void sendTiming(Packet *pkt, Tick time) + { new PioPort::SendEvent(this, pkt, time); } + + /** This function is notification that the device should attempt to send a + * packet again. */ + virtual void recvRetry(); + + public: + PioPort(PioDevice *dev, Platform *p); + + friend class PioPort::SendEvent; +}; + + +struct DmaReqState : public Packet::SenderState +{ + /** Event to call on the device when this transaction (all packets) + * complete. */ + Event *completionEvent; + + /** Where we came from for some sanity checking. */ + Port *outPort; + + /** Total number of bytes that this transaction involves. */ + Addr totBytes; + + /** Number of bytes that have been acked for this transaction. */ + Addr numBytes; + + bool final; + DmaReqState(Event *ce, Port *p, Addr tb) + : completionEvent(ce), outPort(p), totBytes(tb), numBytes(0) + {} +}; + +class DmaPort : public Port +{ + protected: + DmaDevice *device; + std::list<Packet*> transmitList; + + /** The platform that device/port are in. This is used to select which mode + * we are currently operating in. */ + Platform *platform; + + /** Number of outstanding packets the dma port has. */ + int pendingCount; + + virtual bool recvTiming(Packet *pkt); + virtual Tick recvAtomic(Packet *pkt) + { panic("dma port shouldn't be used for pio access."); } + virtual void recvFunctional(Packet *pkt) + { panic("dma port shouldn't be used for pio access."); } + + virtual void recvStatusChange(Status status) + { ; } + + virtual void recvRetry() ; + + virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop) + { resp.clear(); snoop.clear(); } + + void sendDma(Packet *pkt, bool front = false); + + public: + DmaPort(DmaDevice *dev, Platform *p); + + void dmaAction(Packet::Command cmd, Addr addr, int size, Event *event, + uint8_t *data = NULL); + + bool dmaPending() { return pendingCount > 0; } + +}; + +/** + * This device is the base class which all devices senstive to an address range + * inherit from. There are three pure virtual functions which all devices must + * implement addressRanges(), read(), and write(). The magic do choose which + * mode we are in, etc is handled by the PioPort so the device doesn't have to + * bother. + */ + +class PioDevice : public MemObject +{ + protected: + + /** The platform we are in. This is used to decide what type of memory + * transaction we should perform. */ + Platform *platform; + + /** The pioPort that handles the requests for us and provides us requests + * that it sees. */ + PioPort *pioPort; + + virtual void addressRanges(AddrRangeList &range_list) = 0; + + /** As far as the devices are concerned they only accept atomic transactions + * which are converted to either a write or a read. */ + Tick recvAtomic(Packet *pkt) + { return pkt->isRead() ? this->read(pkt) : this->write(pkt); } + + /** Pure virtual function that the device must implement. Called when a read + * command is recieved by the port. + * @param pkt Packet describing this request + * @return number of ticks it took to complete + */ + virtual Tick read(Packet *pkt) = 0; + + /** Pure virtual function that the device must implement. Called when a + * write command is recieved by the port. + * @param pkt Packet describing this request + * @return number of ticks it took to complete + */ + virtual Tick write(Packet *pkt) = 0; + + public: + /** Params struct which is extended through each device based on the + * parameters it needs. Since we are re-writing everything, we might as well + * start from the bottom this time. */ + + struct Params + { + std::string name; + Platform *platform; + System *system; + }; + + protected: + Params *_params; + + public: + const Params *params() const { return _params; } + + PioDevice(Params *p) + : MemObject(p->name), platform(p->platform), pioPort(NULL), + _params(p) + {} + + virtual ~PioDevice(); + + virtual void init(); + + virtual Port *getPort(const std::string &if_name) + { + if (if_name == "pio") { + if (pioPort != NULL) + panic("pio port already connected to."); + pioPort = new PioPort(this, params()->platform); + return pioPort; + } else + return NULL; + } + friend class PioPort; + +}; + +class BasicPioDevice : public PioDevice +{ + public: + struct Params : public PioDevice::Params + { + Addr pio_addr; + Tick pio_delay; + }; + + protected: + /** Address that the device listens to. */ + Addr pioAddr; + + /** Size that the device's address range. */ + Addr pioSize; + + /** Delay that the device experinces on an access. */ + Tick pioDelay; + + public: + BasicPioDevice(Params *p) + : PioDevice(p), pioAddr(p->pio_addr), pioSize(0), pioDelay(p->pio_delay) + {} + + /** return the address ranges that this device responds to. + * @params range_list range list to populate with ranges + */ + void addressRanges(AddrRangeList &range_list); + +}; + +class DmaDevice : public PioDevice +{ + protected: + DmaPort *dmaPort; + + public: + DmaDevice(Params *p); + virtual ~DmaDevice(); + + void dmaWrite(Addr addr, int size, Event *event, uint8_t *data) + { dmaPort->dmaAction(Packet::WriteReq, addr, size, event, data) ; } + + void dmaRead(Addr addr, int size, Event *event, uint8_t *data = NULL) + { dmaPort->dmaAction(Packet::ReadReq, addr, size, event, data); } + + bool dmaPending() { return dmaPort->dmaPending(); } + + virtual Port *getPort(const std::string &if_name) + { + if (if_name == "pio") { + if (pioPort != NULL) + panic("pio port already connected to."); + pioPort = new PioPort(this, params()->platform); + return pioPort; + } else if (if_name == "dma") { + if (dmaPort != NULL) + panic("dma port already connected to."); + dmaPort = new DmaPort(this, params()->platform); + return dmaPort; + } else + return NULL; + } + + friend class DmaPort; +}; + + +#endif // __DEV_IO_DEVICE_HH__ diff --git a/src/dev/isa_fake.cc b/src/dev/isa_fake.cc new file mode 100644 index 000000000..9622f015c --- /dev/null +++ b/src/dev/isa_fake.cc @@ -0,0 +1,121 @@ +/* + * 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: Miguel Serrano + * Ali Saidi + */ + +/** @file + * Isa Fake Device implementation + */ + +#include <deque> +#include <string> +#include <vector> + +#include "base/trace.hh" +#include "dev/isa_fake.hh" +#include "mem/packet.hh" +#include "sim/builder.hh" +#include "sim/system.hh" + +using namespace std; + +IsaFake::IsaFake(Params *p) + : BasicPioDevice(p) +{ + pioSize = p->pio_size; +} + +Tick +IsaFake::read(Packet *pkt) +{ + assert(pkt->result == Packet::Unknown); + assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); + + DPRINTF(Tsunami, "read va=%#x size=%d\n", pkt->getAddr(), pkt->getSize()); + + switch (pkt->getSize()) { + pkt->set(0xFFFFFFFFFFFFFFFFULL); + break; + case sizeof(uint32_t): + pkt->set((uint32_t)0xFFFFFFFF); + break; + case sizeof(uint16_t): + pkt->set((uint16_t)0xFFFF); + break; + case sizeof(uint8_t): + pkt->set((uint8_t)0xFF); + break; + default: + panic("invalid access size(?) for PCI configspace!\n"); + } + pkt->result = Packet::Success; + return pioDelay; +} + +Tick +IsaFake::write(Packet *pkt) +{ + DPRINTF(Tsunami, "write - va=%#x size=%d \n", pkt->getAddr(), pkt->getSize()); + pkt->result = Packet::Success; + return pioDelay; +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(IsaFake) + + Param<Addr> pio_addr; + Param<Tick> pio_latency; + Param<Addr> pio_size; + SimObjectParam<Platform *> platform; + SimObjectParam<System *> system; + +END_DECLARE_SIM_OBJECT_PARAMS(IsaFake) + +BEGIN_INIT_SIM_OBJECT_PARAMS(IsaFake) + + INIT_PARAM(pio_addr, "Device Address"), + INIT_PARAM(pio_latency, "Programmed IO latency"), + INIT_PARAM(pio_size, "Size of address range"), + INIT_PARAM(platform, "platform"), + INIT_PARAM(system, "system object") + +END_INIT_SIM_OBJECT_PARAMS(IsaFake) + +CREATE_SIM_OBJECT(IsaFake) +{ + IsaFake::Params *p = new IsaFake::Params; + p->name = getInstanceName(); + p->pio_addr = pio_addr; + p->pio_delay = pio_latency; + p->pio_size = pio_size; + p->platform = platform; + p->system = system; + return new IsaFake(p); +} + +REGISTER_SIM_OBJECT("IsaFake", IsaFake) diff --git a/src/dev/isa_fake.hh b/src/dev/isa_fake.hh new file mode 100644 index 000000000..a7a469e17 --- /dev/null +++ b/src/dev/isa_fake.hh @@ -0,0 +1,81 @@ +/* + * 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: Miguel Serrano + * Ali Saidi + */ + +/** @file + * Declaration of a fake device. + */ + +#ifndef __ISA_FAKE_HH__ +#define __ISA_FAKE_HH__ + +#include "dev/tsunami.hh" +#include "base/range.hh" +#include "dev/io_device.hh" + +/** + * IsaFake is a device that returns -1 on all reads and + * accepts all writes. It is meant to be placed at an address range + * so that an mcheck doesn't occur when an os probes a piece of hw + * that doesn't exist (e.g. UARTs1-3). + */ +class IsaFake : public BasicPioDevice +{ + public: + struct Params : public BasicPioDevice::Params + { + Addr pio_size; + }; + protected: + const Params *params() const { return (const Params*)_params; } + + public: + /** + * The constructor for Tsunmami Fake just registers itself with the MMU. + * @param p params structure + */ + IsaFake(Params *p); + + /** + * This read always returns -1. + * @param req The memory request. + * @param data Where to put the data. + */ + virtual Tick read(Packet *pkt); + + /** + * All writes are simply ignored. + * @param req The memory request. + * @param data the data to not write. + */ + virtual Tick write(Packet *pkt); +}; + +#endif // __TSUNAMI_FAKE_HH__ diff --git a/src/dev/ns_gige.cc b/src/dev/ns_gige.cc new file mode 100644 index 000000000..decffaf73 --- /dev/null +++ b/src/dev/ns_gige.cc @@ -0,0 +1,2913 @@ +/* + * 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: Lisa Hsu + */ + +/** @file + * Device module for modelling the National Semiconductor + * DP83820 ethernet controller. Does not support priority queueing + */ +#include <deque> +#include <string> + +#include "arch/alpha/ev5.hh" +#include "base/inet.hh" +#include "cpu/thread_context.hh" +#include "dev/etherlink.hh" +#include "dev/ns_gige.hh" +#include "dev/pciconfigall.hh" +#include "mem/packet.hh" +#include "sim/builder.hh" +#include "sim/debug.hh" +#include "sim/host.hh" +#include "sim/stats.hh" +#include "sim/system.hh" + +const char *NsRxStateStrings[] = +{ + "rxIdle", + "rxDescRefr", + "rxDescRead", + "rxFifoBlock", + "rxFragWrite", + "rxDescWrite", + "rxAdvance" +}; + +const char *NsTxStateStrings[] = +{ + "txIdle", + "txDescRefr", + "txDescRead", + "txFifoBlock", + "txFragRead", + "txDescWrite", + "txAdvance" +}; + +const char *NsDmaState[] = +{ + "dmaIdle", + "dmaReading", + "dmaWriting", + "dmaReadWaiting", + "dmaWriteWaiting" +}; + +using namespace std; +using namespace Net; +using namespace TheISA; + +/////////////////////////////////////////////////////////////////////// +// +// NSGigE PCI Device +// +NSGigE::NSGigE(Params *p) + : PciDev(p), ioEnable(false), + txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size), + txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL), + txXferLen(0), rxXferLen(0), clock(p->clock), + txState(txIdle), txEnable(false), CTDD(false), + txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle), + rxEnable(false), CRDD(false), rxPktBytes(0), + rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false), + eepromState(eepromStart), rxDmaReadEvent(this), rxDmaWriteEvent(this), + txDmaReadEvent(this), txDmaWriteEvent(this), + dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free), + txDelay(p->tx_delay), rxDelay(p->rx_delay), + rxKickTick(0), rxKickEvent(this), txKickTick(0), txKickEvent(this), + txEvent(this), rxFilterEnable(p->rx_filter), acceptBroadcast(false), + acceptMulticast(false), acceptUnicast(false), + acceptPerfect(false), acceptArp(false), multicastHashEnable(false), + intrTick(0), cpuPendingIntr(false), + intrEvent(0), interface(0) +{ + + intrDelay = p->intr_delay; + dmaReadDelay = p->dma_read_delay; + dmaWriteDelay = p->dma_write_delay; + dmaReadFactor = p->dma_read_factor; + dmaWriteFactor = p->dma_write_factor; + + regsReset(); + memcpy(&rom.perfectMatch, p->eaddr.bytes(), ETH_ADDR_LEN); + + memset(&rxDesc32, 0, sizeof(rxDesc32)); + memset(&txDesc32, 0, sizeof(txDesc32)); + memset(&rxDesc64, 0, sizeof(rxDesc64)); + memset(&txDesc64, 0, sizeof(txDesc64)); +} + +NSGigE::~NSGigE() +{} + +void +NSGigE::regStats() +{ + txBytes + .name(name() + ".txBytes") + .desc("Bytes Transmitted") + .prereq(txBytes) + ; + + rxBytes + .name(name() + ".rxBytes") + .desc("Bytes Received") + .prereq(rxBytes) + ; + + txPackets + .name(name() + ".txPackets") + .desc("Number of Packets Transmitted") + .prereq(txBytes) + ; + + rxPackets + .name(name() + ".rxPackets") + .desc("Number of Packets Received") + .prereq(rxBytes) + ; + + txIpChecksums + .name(name() + ".txIpChecksums") + .desc("Number of tx IP Checksums done by device") + .precision(0) + .prereq(txBytes) + ; + + rxIpChecksums + .name(name() + ".rxIpChecksums") + .desc("Number of rx IP Checksums done by device") + .precision(0) + .prereq(rxBytes) + ; + + txTcpChecksums + .name(name() + ".txTcpChecksums") + .desc("Number of tx TCP Checksums done by device") + .precision(0) + .prereq(txBytes) + ; + + rxTcpChecksums + .name(name() + ".rxTcpChecksums") + .desc("Number of rx TCP Checksums done by device") + .precision(0) + .prereq(rxBytes) + ; + + txUdpChecksums + .name(name() + ".txUdpChecksums") + .desc("Number of tx UDP Checksums done by device") + .precision(0) + .prereq(txBytes) + ; + + rxUdpChecksums + .name(name() + ".rxUdpChecksums") + .desc("Number of rx UDP Checksums done by device") + .precision(0) + .prereq(rxBytes) + ; + + descDmaReads + .name(name() + ".descDMAReads") + .desc("Number of descriptors the device read w/ DMA") + .precision(0) + ; + + descDmaWrites + .name(name() + ".descDMAWrites") + .desc("Number of descriptors the device wrote w/ DMA") + .precision(0) + ; + + descDmaRdBytes + .name(name() + ".descDmaReadBytes") + .desc("number of descriptor bytes read w/ DMA") + .precision(0) + ; + + descDmaWrBytes + .name(name() + ".descDmaWriteBytes") + .desc("number of descriptor bytes write w/ DMA") + .precision(0) + ; + + txBandwidth + .name(name() + ".txBandwidth") + .desc("Transmit Bandwidth (bits/s)") + .precision(0) + .prereq(txBytes) + ; + + rxBandwidth + .name(name() + ".rxBandwidth") + .desc("Receive Bandwidth (bits/s)") + .precision(0) + .prereq(rxBytes) + ; + + totBandwidth + .name(name() + ".totBandwidth") + .desc("Total Bandwidth (bits/s)") + .precision(0) + .prereq(totBytes) + ; + + totPackets + .name(name() + ".totPackets") + .desc("Total Packets") + .precision(0) + .prereq(totBytes) + ; + + totBytes + .name(name() + ".totBytes") + .desc("Total Bytes") + .precision(0) + .prereq(totBytes) + ; + + totPacketRate + .name(name() + ".totPPS") + .desc("Total Tranmission Rate (packets/s)") + .precision(0) + .prereq(totBytes) + ; + + txPacketRate + .name(name() + ".txPPS") + .desc("Packet Tranmission Rate (packets/s)") + .precision(0) + .prereq(txBytes) + ; + + rxPacketRate + .name(name() + ".rxPPS") + .desc("Packet Reception Rate (packets/s)") + .precision(0) + .prereq(rxBytes) + ; + + postedSwi + .name(name() + ".postedSwi") + .desc("number of software interrupts posted to CPU") + .precision(0) + ; + + totalSwi + .name(name() + ".totalSwi") + .desc("total number of Swi written to ISR") + .precision(0) + ; + + coalescedSwi + .name(name() + ".coalescedSwi") + .desc("average number of Swi's coalesced into each post") + .precision(0) + ; + + postedRxIdle + .name(name() + ".postedRxIdle") + .desc("number of rxIdle interrupts posted to CPU") + .precision(0) + ; + + totalRxIdle + .name(name() + ".totalRxIdle") + .desc("total number of RxIdle written to ISR") + .precision(0) + ; + + coalescedRxIdle + .name(name() + ".coalescedRxIdle") + .desc("average number of RxIdle's coalesced into each post") + .precision(0) + ; + + postedRxOk + .name(name() + ".postedRxOk") + .desc("number of RxOk interrupts posted to CPU") + .precision(0) + ; + + totalRxOk + .name(name() + ".totalRxOk") + .desc("total number of RxOk written to ISR") + .precision(0) + ; + + coalescedRxOk + .name(name() + ".coalescedRxOk") + .desc("average number of RxOk's coalesced into each post") + .precision(0) + ; + + postedRxDesc + .name(name() + ".postedRxDesc") + .desc("number of RxDesc interrupts posted to CPU") + .precision(0) + ; + + totalRxDesc + .name(name() + ".totalRxDesc") + .desc("total number of RxDesc written to ISR") + .precision(0) + ; + + coalescedRxDesc + .name(name() + ".coalescedRxDesc") + .desc("average number of RxDesc's coalesced into each post") + .precision(0) + ; + + postedTxOk + .name(name() + ".postedTxOk") + .desc("number of TxOk interrupts posted to CPU") + .precision(0) + ; + + totalTxOk + .name(name() + ".totalTxOk") + .desc("total number of TxOk written to ISR") + .precision(0) + ; + + coalescedTxOk + .name(name() + ".coalescedTxOk") + .desc("average number of TxOk's coalesced into each post") + .precision(0) + ; + + postedTxIdle + .name(name() + ".postedTxIdle") + .desc("number of TxIdle interrupts posted to CPU") + .precision(0) + ; + + totalTxIdle + .name(name() + ".totalTxIdle") + .desc("total number of TxIdle written to ISR") + .precision(0) + ; + + coalescedTxIdle + .name(name() + ".coalescedTxIdle") + .desc("average number of TxIdle's coalesced into each post") + .precision(0) + ; + + postedTxDesc + .name(name() + ".postedTxDesc") + .desc("number of TxDesc interrupts posted to CPU") + .precision(0) + ; + + totalTxDesc + .name(name() + ".totalTxDesc") + .desc("total number of TxDesc written to ISR") + .precision(0) + ; + + coalescedTxDesc + .name(name() + ".coalescedTxDesc") + .desc("average number of TxDesc's coalesced into each post") + .precision(0) + ; + + postedRxOrn + .name(name() + ".postedRxOrn") + .desc("number of RxOrn posted to CPU") + .precision(0) + ; + + totalRxOrn + .name(name() + ".totalRxOrn") + .desc("total number of RxOrn written to ISR") + .precision(0) + ; + + coalescedRxOrn + .name(name() + ".coalescedRxOrn") + .desc("average number of RxOrn's coalesced into each post") + .precision(0) + ; + + coalescedTotal + .name(name() + ".coalescedTotal") + .desc("average number of interrupts coalesced into each post") + .precision(0) + ; + + postedInterrupts + .name(name() + ".postedInterrupts") + .desc("number of posts to CPU") + .precision(0) + ; + + droppedPackets + .name(name() + ".droppedPackets") + .desc("number of packets dropped") + .precision(0) + ; + + coalescedSwi = totalSwi / postedInterrupts; + coalescedRxIdle = totalRxIdle / postedInterrupts; + coalescedRxOk = totalRxOk / postedInterrupts; + coalescedRxDesc = totalRxDesc / postedInterrupts; + coalescedTxOk = totalTxOk / postedInterrupts; + coalescedTxIdle = totalTxIdle / postedInterrupts; + coalescedTxDesc = totalTxDesc / postedInterrupts; + coalescedRxOrn = totalRxOrn / postedInterrupts; + + coalescedTotal = (totalSwi + totalRxIdle + totalRxOk + totalRxDesc + + totalTxOk + totalTxIdle + totalTxDesc + + totalRxOrn) / postedInterrupts; + + txBandwidth = txBytes * Stats::constant(8) / simSeconds; + rxBandwidth = rxBytes * Stats::constant(8) / simSeconds; + totBandwidth = txBandwidth + rxBandwidth; + totBytes = txBytes + rxBytes; + totPackets = txPackets + rxPackets; + + txPacketRate = txPackets / simSeconds; + rxPacketRate = rxPackets / simSeconds; +} + + +/** + * This is to write to the PCI general configuration registers + */ +void +NSGigE::writeConfig(int offset, const uint16_t data) +{ + if (offset < PCI_DEVICE_SPECIFIC) + PciDev::writeConfig(offset, data); + else + panic("Device specific PCI config space not implemented!\n"); + + switch (offset) { + // seems to work fine without all these PCI settings, but i + // put in the IO to double check, an assertion will fail if we + // need to properly implement it + case PCI_COMMAND: + if (config.data[offset] & PCI_CMD_IOSE) + ioEnable = true; + else + ioEnable = false; + break; + } +} + +/** + * This reads the device registers, which are detailed in the NS83820 + * spec sheet + */ +Tick +NSGigE::read(Packet *pkt) +{ + assert(ioEnable); + + pkt->allocate(); + + //The mask is to give you only the offset into the device register file + Addr daddr = pkt->getAddr() & 0xfff; + DPRINTF(EthernetPIO, "read da=%#x pa=%#x size=%d\n", + daddr, pkt->getAddr(), pkt->getSize()); + + + // there are some reserved registers, you can see ns_gige_reg.h and + // the spec sheet for details + if (daddr > LAST && daddr <= RESERVED) { + panic("Accessing reserved register"); + } else if (daddr > RESERVED && daddr <= 0x3FC) { + if (pkt->getSize() == sizeof(uint8_t)) + readConfig(daddr & 0xff, pkt->getPtr<uint8_t>()); + if (pkt->getSize() == sizeof(uint16_t)) + readConfig(daddr & 0xff, pkt->getPtr<uint16_t>()); + if (pkt->getSize() == sizeof(uint32_t)) + readConfig(daddr & 0xff, pkt->getPtr<uint32_t>()); + pkt->result = Packet::Success; + return pioDelay; + } else if (daddr >= MIB_START && daddr <= MIB_END) { + // don't implement all the MIB's. hopefully the kernel + // doesn't actually DEPEND upon their values + // MIB are just hardware stats keepers + pkt->set<uint32_t>(0); + pkt->result = Packet::Success; + return pioDelay; + } else if (daddr > 0x3FC) + panic("Something is messed up!\n"); + + assert(pkt->getSize() == sizeof(uint32_t)); + uint32_t ® = *pkt->getPtr<uint32_t>(); + uint16_t rfaddr; + + switch (daddr) { + case CR: + reg = regs.command; + //these are supposed to be cleared on a read + reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR); + break; + + case CFGR: + reg = regs.config; + break; + + case MEAR: + reg = regs.mear; + break; + + case PTSCR: + reg = regs.ptscr; + break; + + case ISR: + reg = regs.isr; + devIntrClear(ISR_ALL); + break; + + case IMR: + reg = regs.imr; + break; + + case IER: + reg = regs.ier; + break; + + case IHR: + reg = regs.ihr; + break; + + case TXDP: + reg = regs.txdp; + break; + + case TXDP_HI: + reg = regs.txdp_hi; + break; + + case TX_CFG: + reg = regs.txcfg; + break; + + case GPIOR: + reg = regs.gpior; + break; + + case RXDP: + reg = regs.rxdp; + break; + + case RXDP_HI: + reg = regs.rxdp_hi; + break; + + case RX_CFG: + reg = regs.rxcfg; + break; + + case PQCR: + reg = regs.pqcr; + break; + + case WCSR: + reg = regs.wcsr; + break; + + case PCR: + reg = regs.pcr; + break; + + // see the spec sheet for how RFCR and RFDR work + // basically, you write to RFCR to tell the machine + // what you want to do next, then you act upon RFDR, + // and the device will be prepared b/c of what you + // wrote to RFCR + case RFCR: + reg = regs.rfcr; + break; + + case RFDR: + rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR); + switch (rfaddr) { + // Read from perfect match ROM octets + case 0x000: + reg = rom.perfectMatch[1]; + reg = reg << 8; + reg += rom.perfectMatch[0]; + break; + case 0x002: + reg = rom.perfectMatch[3] << 8; + reg += rom.perfectMatch[2]; + break; + case 0x004: + reg = rom.perfectMatch[5] << 8; + reg += rom.perfectMatch[4]; + break; + default: + // Read filter hash table + if (rfaddr >= FHASH_ADDR && + rfaddr < FHASH_ADDR + FHASH_SIZE) { + + // Only word-aligned reads supported + if (rfaddr % 2) + panic("unaligned read from filter hash table!"); + + reg = rom.filterHash[rfaddr - FHASH_ADDR + 1] << 8; + reg += rom.filterHash[rfaddr - FHASH_ADDR]; + break; + } + + panic("reading RFDR for something other than pattern" + " matching or hashing! %#x\n", rfaddr); + } + break; + + case SRR: + reg = regs.srr; + break; + + case MIBC: + reg = regs.mibc; + reg &= ~(MIBC_MIBS | MIBC_ACLR); + break; + + case VRCR: + reg = regs.vrcr; + break; + + case VTCR: + reg = regs.vtcr; + break; + + case VDR: + reg = regs.vdr; + break; + + case CCSR: + reg = regs.ccsr; + break; + + case TBICR: + reg = regs.tbicr; + break; + + case TBISR: + reg = regs.tbisr; + break; + + case TANAR: + reg = regs.tanar; + break; + + case TANLPAR: + reg = regs.tanlpar; + break; + + case TANER: + reg = regs.taner; + break; + + case TESR: + reg = regs.tesr; + break; + + case M5REG: + reg = 0; + if (params()->rx_thread) + reg |= M5REG_RX_THREAD; + if (params()->tx_thread) + reg |= M5REG_TX_THREAD; + if (params()->rss) + reg |= M5REG_RSS; + break; + + default: + panic("reading unimplemented register: addr=%#x", daddr); + } + + DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n", + daddr, reg, reg); + + pkt->result = Packet::Success; + return pioDelay; +} + +Tick +NSGigE::write(Packet *pkt) +{ + assert(ioEnable); + + Addr daddr = pkt->getAddr() & 0xfff; + DPRINTF(EthernetPIO, "write da=%#x pa=%#x size=%d\n", + daddr, pkt->getAddr(), pkt->getSize()); + + if (daddr > LAST && daddr <= RESERVED) { + panic("Accessing reserved register"); + } else if (daddr > RESERVED && daddr <= 0x3FC) { + if (pkt->getSize() == sizeof(uint8_t)) + writeConfig(daddr & 0xff, pkt->get<uint8_t>()); + if (pkt->getSize() == sizeof(uint16_t)) + writeConfig(daddr & 0xff, pkt->get<uint16_t>()); + if (pkt->getSize() == sizeof(uint32_t)) + writeConfig(daddr & 0xff, pkt->get<uint32_t>()); + pkt->result = Packet::Success; + return pioDelay; + } else if (daddr > 0x3FC) + panic("Something is messed up!\n"); + + if (pkt->getSize() == sizeof(uint32_t)) { + uint32_t reg = pkt->get<uint32_t>(); + uint16_t rfaddr; + + DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg); + + switch (daddr) { + case CR: + regs.command = reg; + if (reg & CR_TXD) { + txEnable = false; + } else if (reg & CR_TXE) { + txEnable = true; + + // the kernel is enabling the transmit machine + if (txState == txIdle) + txKick(); + } + + if (reg & CR_RXD) { + rxEnable = false; + } else if (reg & CR_RXE) { + rxEnable = true; + + if (rxState == rxIdle) + rxKick(); + } + + if (reg & CR_TXR) + txReset(); + + if (reg & CR_RXR) + rxReset(); + + if (reg & CR_SWI) + devIntrPost(ISR_SWI); + + if (reg & CR_RST) { + txReset(); + rxReset(); + + regsReset(); + } + break; + + case CFGR: + if (reg & CFGR_LNKSTS || + reg & CFGR_SPDSTS || + reg & CFGR_DUPSTS || + reg & CFGR_RESERVED || + reg & CFGR_T64ADDR || + reg & CFGR_PCI64_DET) + + // First clear all writable bits + regs.config &= CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS | + CFGR_RESERVED | CFGR_T64ADDR | + CFGR_PCI64_DET; + // Now set the appropriate writable bits + regs.config |= reg & ~(CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS | + CFGR_RESERVED | CFGR_T64ADDR | + CFGR_PCI64_DET); + +// all these #if 0's are because i don't THINK the kernel needs to +// have these implemented. if there is a problem relating to one of +// these, you may need to add functionality in. + if (reg & CFGR_TBI_EN) ; + if (reg & CFGR_MODE_1000) ; + + if (reg & CFGR_AUTO_1000) + panic("CFGR_AUTO_1000 not implemented!\n"); + + if (reg & CFGR_PINT_DUPSTS || + reg & CFGR_PINT_LNKSTS || + reg & CFGR_PINT_SPDSTS) + ; + + if (reg & CFGR_TMRTEST) ; + if (reg & CFGR_MRM_DIS) ; + if (reg & CFGR_MWI_DIS) ; + + if (reg & CFGR_T64ADDR) ; + // panic("CFGR_T64ADDR is read only register!\n"); + + if (reg & CFGR_PCI64_DET) + panic("CFGR_PCI64_DET is read only register!\n"); + + if (reg & CFGR_DATA64_EN) ; + if (reg & CFGR_M64ADDR) ; + if (reg & CFGR_PHY_RST) ; + if (reg & CFGR_PHY_DIS) ; + + if (reg & CFGR_EXTSTS_EN) + extstsEnable = true; + else + extstsEnable = false; + + if (reg & CFGR_REQALG) ; + if (reg & CFGR_SB) ; + if (reg & CFGR_POW) ; + if (reg & CFGR_EXD) ; + if (reg & CFGR_PESEL) ; + if (reg & CFGR_BROM_DIS) ; + if (reg & CFGR_EXT_125) ; + if (reg & CFGR_BEM) ; + break; + + case MEAR: + // Clear writable bits + regs.mear &= MEAR_EEDO; + // Set appropriate writable bits + regs.mear |= reg & ~MEAR_EEDO; + + // FreeBSD uses the EEPROM to read PMATCH (for the MAC address) + // even though it could get it through RFDR + if (reg & MEAR_EESEL) { + // Rising edge of clock + if (reg & MEAR_EECLK && !eepromClk) + eepromKick(); + } + else { + eepromState = eepromStart; + regs.mear &= ~MEAR_EEDI; + } + + eepromClk = reg & MEAR_EECLK; + + // since phy is completely faked, MEAR_MD* don't matter + if (reg & MEAR_MDIO) ; + if (reg & MEAR_MDDIR) ; + if (reg & MEAR_MDC) ; + break; + + case PTSCR: + regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY); + // these control BISTs for various parts of chip - we + // don't care or do just fake that the BIST is done + if (reg & PTSCR_RBIST_EN) + regs.ptscr |= PTSCR_RBIST_DONE; + if (reg & PTSCR_EEBIST_EN) + regs.ptscr &= ~PTSCR_EEBIST_EN; + if (reg & PTSCR_EELOAD_EN) + regs.ptscr &= ~PTSCR_EELOAD_EN; + break; + + case ISR: /* writing to the ISR has no effect */ + panic("ISR is a read only register!\n"); + + case IMR: + regs.imr = reg; + devIntrChangeMask(); + break; + + case IER: + regs.ier = reg; + break; + + case IHR: + regs.ihr = reg; + /* not going to implement real interrupt holdoff */ + break; + + case TXDP: + regs.txdp = (reg & 0xFFFFFFFC); + assert(txState == txIdle); + CTDD = false; + break; + + case TXDP_HI: + regs.txdp_hi = reg; + break; + + case TX_CFG: + regs.txcfg = reg; +#if 0 + if (reg & TX_CFG_CSI) ; + if (reg & TX_CFG_HBI) ; + if (reg & TX_CFG_MLB) ; + if (reg & TX_CFG_ATP) ; + if (reg & TX_CFG_ECRETRY) { + /* + * this could easily be implemented, but considering + * the network is just a fake pipe, wouldn't make + * sense to do this + */ + } + + if (reg & TX_CFG_BRST_DIS) ; +#endif + +#if 0 + /* we handle our own DMA, ignore the kernel's exhortations */ + if (reg & TX_CFG_MXDMA) ; +#endif + + // also, we currently don't care about fill/drain + // thresholds though this may change in the future with + // more realistic networks or a driver which changes it + // according to feedback + + break; + + case GPIOR: + // Only write writable bits + regs.gpior &= GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN + | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN; + regs.gpior |= reg & ~(GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN + | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN); + /* these just control general purpose i/o pins, don't matter */ + break; + + case RXDP: + regs.rxdp = reg; + CRDD = false; + break; + + case RXDP_HI: + regs.rxdp_hi = reg; + break; + + case RX_CFG: + regs.rxcfg = reg; +#if 0 + if (reg & RX_CFG_AEP) ; + if (reg & RX_CFG_ARP) ; + if (reg & RX_CFG_STRIPCRC) ; + if (reg & RX_CFG_RX_RD) ; + if (reg & RX_CFG_ALP) ; + if (reg & RX_CFG_AIRL) ; + + /* we handle our own DMA, ignore what kernel says about it */ + if (reg & RX_CFG_MXDMA) ; + + //also, we currently don't care about fill/drain thresholds + //though this may change in the future with more realistic + //networks or a driver which changes it according to feedback + if (reg & (RX_CFG_DRTH | RX_CFG_DRTH0)) ; +#endif + break; + + case PQCR: + /* there is no priority queueing used in the linux 2.6 driver */ + regs.pqcr = reg; + break; + + case WCSR: + /* not going to implement wake on LAN */ + regs.wcsr = reg; + break; + + case PCR: + /* not going to implement pause control */ + regs.pcr = reg; + break; + + case RFCR: + regs.rfcr = reg; + + rxFilterEnable = (reg & RFCR_RFEN) ? true : false; + acceptBroadcast = (reg & RFCR_AAB) ? true : false; + acceptMulticast = (reg & RFCR_AAM) ? true : false; + acceptUnicast = (reg & RFCR_AAU) ? true : false; + acceptPerfect = (reg & RFCR_APM) ? true : false; + acceptArp = (reg & RFCR_AARP) ? true : false; + multicastHashEnable = (reg & RFCR_MHEN) ? true : false; + +#if 0 + if (reg & RFCR_APAT) + panic("RFCR_APAT not implemented!\n"); +#endif + if (reg & RFCR_UHEN) + panic("Unicast hash filtering not used by drivers!\n"); + + if (reg & RFCR_ULM) + panic("RFCR_ULM not implemented!\n"); + + break; + + case RFDR: + rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR); + switch (rfaddr) { + case 0x000: + rom.perfectMatch[0] = (uint8_t)reg; + rom.perfectMatch[1] = (uint8_t)(reg >> 8); + break; + case 0x002: + rom.perfectMatch[2] = (uint8_t)reg; + rom.perfectMatch[3] = (uint8_t)(reg >> 8); + break; + case 0x004: + rom.perfectMatch[4] = (uint8_t)reg; + rom.perfectMatch[5] = (uint8_t)(reg >> 8); + break; + default: + + if (rfaddr >= FHASH_ADDR && + rfaddr < FHASH_ADDR + FHASH_SIZE) { + + // Only word-aligned writes supported + if (rfaddr % 2) + panic("unaligned write to filter hash table!"); + + rom.filterHash[rfaddr - FHASH_ADDR] = (uint8_t)reg; + rom.filterHash[rfaddr - FHASH_ADDR + 1] + = (uint8_t)(reg >> 8); + break; + } + panic("writing RFDR for something other than pattern matching\ + or hashing! %#x\n", rfaddr); + } + + case BRAR: + regs.brar = reg; + break; + + case BRDR: + panic("the driver never uses BRDR, something is wrong!\n"); + + case SRR: + panic("SRR is read only register!\n"); + + case MIBC: + panic("the driver never uses MIBC, something is wrong!\n"); + + case VRCR: + regs.vrcr = reg; + break; + + case VTCR: + regs.vtcr = reg; + break; + + case VDR: + panic("the driver never uses VDR, something is wrong!\n"); + + case CCSR: + /* not going to implement clockrun stuff */ + regs.ccsr = reg; + break; + + case TBICR: + regs.tbicr = reg; + if (reg & TBICR_MR_LOOPBACK) + panic("TBICR_MR_LOOPBACK never used, something wrong!\n"); + + if (reg & TBICR_MR_AN_ENABLE) { + regs.tanlpar = regs.tanar; + regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS); + } + +#if 0 + if (reg & TBICR_MR_RESTART_AN) ; +#endif + + break; + + case TBISR: + panic("TBISR is read only register!\n"); + + case TANAR: + // Only write the writable bits + regs.tanar &= TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED; + regs.tanar |= reg & ~(TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED); + + // Pause capability unimplemented +#if 0 + if (reg & TANAR_PS2) ; + if (reg & TANAR_PS1) ; +#endif + + break; + + case TANLPAR: + panic("this should only be written to by the fake phy!\n"); + + case TANER: + panic("TANER is read only register!\n"); + + case TESR: + regs.tesr = reg; + break; + + default: + panic("invalid register access daddr=%#x", daddr); + } + } else { + panic("Invalid Request Size"); + } + pkt->result = Packet::Success; + return pioDelay; +} + +void +NSGigE::devIntrPost(uint32_t interrupts) +{ + if (interrupts & ISR_RESERVE) + panic("Cannot set a reserved interrupt"); + + if (interrupts & ISR_NOIMPL) + warn("interrupt not implemented %#x\n", interrupts); + + interrupts &= ISR_IMPL; + regs.isr |= interrupts; + + if (interrupts & regs.imr) { + if (interrupts & ISR_SWI) { + totalSwi++; + } + if (interrupts & ISR_RXIDLE) { + totalRxIdle++; + } + if (interrupts & ISR_RXOK) { + totalRxOk++; + } + if (interrupts & ISR_RXDESC) { + totalRxDesc++; + } + if (interrupts & ISR_TXOK) { + totalTxOk++; + } + if (interrupts & ISR_TXIDLE) { + totalTxIdle++; + } + if (interrupts & ISR_TXDESC) { + totalTxDesc++; + } + if (interrupts & ISR_RXORN) { + totalRxOrn++; + } + } + + DPRINTF(EthernetIntr, + "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n", + interrupts, regs.isr, regs.imr); + + if ((regs.isr & regs.imr)) { + Tick when = curTick; + if ((regs.isr & regs.imr & ISR_NODELAY) == 0) + when += intrDelay; + cpuIntrPost(when); + } +} + +/* writing this interrupt counting stats inside this means that this function + is now limited to being used to clear all interrupts upon the kernel + reading isr and servicing. just telling you in case you were thinking + of expanding use. +*/ +void +NSGigE::devIntrClear(uint32_t interrupts) +{ + if (interrupts & ISR_RESERVE) + panic("Cannot clear a reserved interrupt"); + + if (regs.isr & regs.imr & ISR_SWI) { + postedSwi++; + } + if (regs.isr & regs.imr & ISR_RXIDLE) { + postedRxIdle++; + } + if (regs.isr & regs.imr & ISR_RXOK) { + postedRxOk++; + } + if (regs.isr & regs.imr & ISR_RXDESC) { + postedRxDesc++; + } + if (regs.isr & regs.imr & ISR_TXOK) { + postedTxOk++; + } + if (regs.isr & regs.imr & ISR_TXIDLE) { + postedTxIdle++; + } + if (regs.isr & regs.imr & ISR_TXDESC) { + postedTxDesc++; + } + if (regs.isr & regs.imr & ISR_RXORN) { + postedRxOrn++; + } + + if (regs.isr & regs.imr & ISR_IMPL) + postedInterrupts++; + + interrupts &= ~ISR_NOIMPL; + regs.isr &= ~interrupts; + + DPRINTF(EthernetIntr, + "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n", + interrupts, regs.isr, regs.imr); + + if (!(regs.isr & regs.imr)) + cpuIntrClear(); +} + +void +NSGigE::devIntrChangeMask() +{ + DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n", + regs.isr, regs.imr, regs.isr & regs.imr); + + if (regs.isr & regs.imr) + cpuIntrPost(curTick); + else + cpuIntrClear(); +} + +void +NSGigE::cpuIntrPost(Tick when) +{ + // If the interrupt you want to post is later than an interrupt + // already scheduled, just let it post in the coming one and don't + // schedule another. + // HOWEVER, must be sure that the scheduled intrTick is in the + // future (this was formerly the source of a bug) + /** + * @todo this warning should be removed and the intrTick code should + * be fixed. + */ + assert(when >= curTick); + assert(intrTick >= curTick || intrTick == 0); + if (when > intrTick && intrTick != 0) { + DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n", + intrTick); + return; + } + + intrTick = when; + if (intrTick < curTick) { + debug_break(); + intrTick = curTick; + } + + DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", + intrTick); + + if (intrEvent) + intrEvent->squash(); + intrEvent = new IntrEvent(this, true); + intrEvent->schedule(intrTick); +} + +void +NSGigE::cpuInterrupt() +{ + assert(intrTick == curTick); + + // Whether or not there's a pending interrupt, we don't care about + // it anymore + intrEvent = 0; + intrTick = 0; + + // Don't send an interrupt if there's already one + if (cpuPendingIntr) { + DPRINTF(EthernetIntr, + "would send an interrupt now, but there's already pending\n"); + } else { + // Send interrupt + cpuPendingIntr = true; + + DPRINTF(EthernetIntr, "posting interrupt\n"); + intrPost(); + } +} + +void +NSGigE::cpuIntrClear() +{ + if (!cpuPendingIntr) + return; + + if (intrEvent) { + intrEvent->squash(); + intrEvent = 0; + } + + intrTick = 0; + + cpuPendingIntr = false; + + DPRINTF(EthernetIntr, "clearing interrupt\n"); + intrClear(); +} + +bool +NSGigE::cpuIntrPending() const +{ return cpuPendingIntr; } + +void +NSGigE::txReset() +{ + + DPRINTF(Ethernet, "transmit reset\n"); + + CTDD = false; + txEnable = false;; + txFragPtr = 0; + assert(txDescCnt == 0); + txFifo.clear(); + txState = txIdle; + assert(txDmaState == dmaIdle); +} + +void +NSGigE::rxReset() +{ + DPRINTF(Ethernet, "receive reset\n"); + + CRDD = false; + assert(rxPktBytes == 0); + rxEnable = false; + rxFragPtr = 0; + assert(rxDescCnt == 0); + assert(rxDmaState == dmaIdle); + rxFifo.clear(); + rxState = rxIdle; +} + +void +NSGigE::regsReset() +{ + memset(®s, 0, sizeof(regs)); + regs.config = (CFGR_LNKSTS | CFGR_TBI_EN | CFGR_MODE_1000); + regs.mear = 0x12; + regs.txcfg = 0x120; // set drain threshold to 1024 bytes and + // fill threshold to 32 bytes + regs.rxcfg = 0x4; // set drain threshold to 16 bytes + regs.srr = 0x0103; // set the silicon revision to rev B or 0x103 + regs.mibc = MIBC_FRZ; + regs.vdr = 0x81; // set the vlan tag type to 802.1q + regs.tesr = 0xc000; // TBI capable of both full and half duplex + regs.brar = 0xffffffff; + + extstsEnable = false; + acceptBroadcast = false; + acceptMulticast = false; + acceptUnicast = false; + acceptPerfect = false; + acceptArp = false; +} + +bool +NSGigE::doRxDmaRead() +{ + assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting); + rxDmaState = dmaReading; + + if (dmaPending()) + rxDmaState = dmaReadWaiting; + else + dmaRead(rxDmaAddr, rxDmaLen, &rxDmaReadEvent, (uint8_t*)rxDmaData); + + return true; +} + +void +NSGigE::rxDmaReadDone() +{ + assert(rxDmaState == dmaReading); + rxDmaState = dmaIdle; + + DPRINTF(EthernetDMA, "rx dma read paddr=%#x len=%d\n", + rxDmaAddr, rxDmaLen); + DDUMP(EthernetDMA, rxDmaData, rxDmaLen); + + // If the transmit state machine has a pending DMA, let it go first + if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) + txKick(); + + rxKick(); +} + +bool +NSGigE::doRxDmaWrite() +{ + assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting); + rxDmaState = dmaWriting; + + if (dmaPending()) + rxDmaState = dmaWriteWaiting; + else + dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaWriteEvent, (uint8_t*)rxDmaData); + return true; +} + +void +NSGigE::rxDmaWriteDone() +{ + assert(rxDmaState == dmaWriting); + rxDmaState = dmaIdle; + + DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n", + rxDmaAddr, rxDmaLen); + DDUMP(EthernetDMA, rxDmaData, rxDmaLen); + + // If the transmit state machine has a pending DMA, let it go first + if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) + txKick(); + + rxKick(); +} + +void +NSGigE::rxKick() +{ + bool is64bit = (bool)(regs.config & CFGR_M64ADDR); + + DPRINTF(EthernetSM, + "receive kick rxState=%s (rxBuf.size=%d) %d-bit\n", + NsRxStateStrings[rxState], rxFifo.size(), is64bit ? 64 : 32); + + Addr link, bufptr; + uint32_t &cmdsts = is64bit ? rxDesc64.cmdsts : rxDesc32.cmdsts; + uint32_t &extsts = is64bit ? rxDesc64.extsts : rxDesc32.extsts; + + next: + if (clock) { + if (rxKickTick > curTick) { + DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n", + rxKickTick); + + goto exit; + } + + // Go to the next state machine clock tick. + rxKickTick = curTick + cycles(1); + } + + switch(rxDmaState) { + case dmaReadWaiting: + if (doRxDmaRead()) + goto exit; + break; + case dmaWriteWaiting: + if (doRxDmaWrite()) + goto exit; + break; + default: + break; + } + + link = is64bit ? (Addr)rxDesc64.link : (Addr)rxDesc32.link; + bufptr = is64bit ? (Addr)rxDesc64.bufptr : (Addr)rxDesc32.bufptr; + + // see state machine from spec for details + // the way this works is, if you finish work on one state and can + // go directly to another, you do that through jumping to the + // label "next". however, if you have intermediate work, like DMA + // so that you can't go to the next state yet, you go to exit and + // exit the loop. however, when the DMA is done it will trigger + // an event and come back to this loop. + switch (rxState) { + case rxIdle: + if (!rxEnable) { + DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n"); + goto exit; + } + + if (CRDD) { + rxState = rxDescRefr; + + rxDmaAddr = regs.rxdp & 0x3fffffff; + rxDmaData = + is64bit ? (void *)&rxDesc64.link : (void *)&rxDesc32.link; + rxDmaLen = is64bit ? sizeof(rxDesc64.link) : sizeof(rxDesc32.link); + rxDmaFree = dmaDescFree; + + descDmaReads++; + descDmaRdBytes += rxDmaLen; + + if (doRxDmaRead()) + goto exit; + } else { + rxState = rxDescRead; + + rxDmaAddr = regs.rxdp & 0x3fffffff; + rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32; + rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32); + rxDmaFree = dmaDescFree; + + descDmaReads++; + descDmaRdBytes += rxDmaLen; + + if (doRxDmaRead()) + goto exit; + } + break; + + case rxDescRefr: + if (rxDmaState != dmaIdle) + goto exit; + + rxState = rxAdvance; + break; + + case rxDescRead: + if (rxDmaState != dmaIdle) + goto exit; + + DPRINTF(EthernetDesc, "rxDesc: addr=%08x read descriptor\n", + regs.rxdp & 0x3fffffff); + DPRINTF(EthernetDesc, + "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n", + link, bufptr, cmdsts, extsts); + + if (cmdsts & CMDSTS_OWN) { + devIntrPost(ISR_RXIDLE); + rxState = rxIdle; + goto exit; + } else { + rxState = rxFifoBlock; + rxFragPtr = bufptr; + rxDescCnt = cmdsts & CMDSTS_LEN_MASK; + } + break; + + case rxFifoBlock: + if (!rxPacket) { + /** + * @todo in reality, we should be able to start processing + * the packet as it arrives, and not have to wait for the + * full packet ot be in the receive fifo. + */ + if (rxFifo.empty()) + goto exit; + + DPRINTF(EthernetSM, "****processing receive of new packet****\n"); + + // If we don't have a packet, grab a new one from the fifo. + rxPacket = rxFifo.front(); + rxPktBytes = rxPacket->length; + rxPacketBufPtr = rxPacket->data; + +#if TRACING_ON + if (DTRACE(Ethernet)) { + IpPtr ip(rxPacket); + if (ip) { + DPRINTF(Ethernet, "ID is %d\n", ip->id()); + TcpPtr tcp(ip); + if (tcp) { + DPRINTF(Ethernet, + "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", + tcp->sport(), tcp->dport(), tcp->seq(), + tcp->ack()); + } + } + } +#endif + + // sanity check - i think the driver behaves like this + assert(rxDescCnt >= rxPktBytes); + rxFifo.pop(); + } + + + // dont' need the && rxDescCnt > 0 if driver sanity check + // above holds + if (rxPktBytes > 0) { + rxState = rxFragWrite; + // don't need min<>(rxPktBytes,rxDescCnt) if above sanity + // check holds + rxXferLen = rxPktBytes; + + rxDmaAddr = rxFragPtr & 0x3fffffff; + rxDmaData = rxPacketBufPtr; + rxDmaLen = rxXferLen; + rxDmaFree = dmaDataFree; + + if (doRxDmaWrite()) + goto exit; + + } else { + rxState = rxDescWrite; + + //if (rxPktBytes == 0) { /* packet is done */ + assert(rxPktBytes == 0); + DPRINTF(EthernetSM, "done with receiving packet\n"); + + cmdsts |= CMDSTS_OWN; + cmdsts &= ~CMDSTS_MORE; + cmdsts |= CMDSTS_OK; + cmdsts &= 0xffff0000; + cmdsts += rxPacket->length; //i.e. set CMDSTS_SIZE + +#if 0 + /* + * all the driver uses these are for its own stats keeping + * which we don't care about, aren't necessary for + * functionality and doing this would just slow us down. + * if they end up using this in a later version for + * functional purposes, just undef + */ + if (rxFilterEnable) { + cmdsts &= ~CMDSTS_DEST_MASK; + const EthAddr &dst = rxFifoFront()->dst(); + if (dst->unicast()) + cmdsts |= CMDSTS_DEST_SELF; + if (dst->multicast()) + cmdsts |= CMDSTS_DEST_MULTI; + if (dst->broadcast()) + cmdsts |= CMDSTS_DEST_MASK; + } +#endif + + IpPtr ip(rxPacket); + if (extstsEnable && ip) { + extsts |= EXTSTS_IPPKT; + rxIpChecksums++; + if (cksum(ip) != 0) { + DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); + extsts |= EXTSTS_IPERR; + } + TcpPtr tcp(ip); + UdpPtr udp(ip); + if (tcp) { + extsts |= EXTSTS_TCPPKT; + rxTcpChecksums++; + if (cksum(tcp) != 0) { + DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); + extsts |= EXTSTS_TCPERR; + + } + } else if (udp) { + extsts |= EXTSTS_UDPPKT; + rxUdpChecksums++; + if (cksum(udp) != 0) { + DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); + extsts |= EXTSTS_UDPERR; + } + } + } + rxPacket = 0; + + /* + * the driver seems to always receive into desc buffers + * of size 1514, so you never have a pkt that is split + * into multiple descriptors on the receive side, so + * i don't implement that case, hence the assert above. + */ + + DPRINTF(EthernetDesc, + "rxDesc: addr=%08x writeback cmdsts extsts\n", + regs.rxdp & 0x3fffffff); + DPRINTF(EthernetDesc, + "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n", + link, bufptr, cmdsts, extsts); + + rxDmaAddr = regs.rxdp & 0x3fffffff; + rxDmaData = &cmdsts; + if (is64bit) { + rxDmaAddr += offsetof(ns_desc64, cmdsts); + rxDmaLen = sizeof(rxDesc64.cmdsts) + sizeof(rxDesc64.extsts); + } else { + rxDmaAddr += offsetof(ns_desc32, cmdsts); + rxDmaLen = sizeof(rxDesc32.cmdsts) + sizeof(rxDesc32.extsts); + } + rxDmaFree = dmaDescFree; + + descDmaWrites++; + descDmaWrBytes += rxDmaLen; + + if (doRxDmaWrite()) + goto exit; + } + break; + + case rxFragWrite: + if (rxDmaState != dmaIdle) + goto exit; + + rxPacketBufPtr += rxXferLen; + rxFragPtr += rxXferLen; + rxPktBytes -= rxXferLen; + + rxState = rxFifoBlock; + break; + + case rxDescWrite: + if (rxDmaState != dmaIdle) + goto exit; + + assert(cmdsts & CMDSTS_OWN); + + assert(rxPacket == 0); + devIntrPost(ISR_RXOK); + + if (cmdsts & CMDSTS_INTR) + devIntrPost(ISR_RXDESC); + + if (!rxEnable) { + DPRINTF(EthernetSM, "Halting the RX state machine\n"); + rxState = rxIdle; + goto exit; + } else + rxState = rxAdvance; + break; + + case rxAdvance: + if (link == 0) { + devIntrPost(ISR_RXIDLE); + rxState = rxIdle; + CRDD = true; + goto exit; + } else { + if (rxDmaState != dmaIdle) + goto exit; + rxState = rxDescRead; + regs.rxdp = link; + CRDD = false; + + rxDmaAddr = regs.rxdp & 0x3fffffff; + rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32; + rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32); + rxDmaFree = dmaDescFree; + + if (doRxDmaRead()) + goto exit; + } + break; + + default: + panic("Invalid rxState!"); + } + + DPRINTF(EthernetSM, "entering next rxState=%s\n", + NsRxStateStrings[rxState]); + goto next; + + exit: + /** + * @todo do we want to schedule a future kick? + */ + DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", + NsRxStateStrings[rxState]); + + if (clock && !rxKickEvent.scheduled()) + rxKickEvent.schedule(rxKickTick); +} + +void +NSGigE::transmit() +{ + if (txFifo.empty()) { + DPRINTF(Ethernet, "nothing to transmit\n"); + return; + } + + DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n", + txFifo.size()); + if (interface->sendPacket(txFifo.front())) { +#if TRACING_ON + if (DTRACE(Ethernet)) { + IpPtr ip(txFifo.front()); + if (ip) { + DPRINTF(Ethernet, "ID is %d\n", ip->id()); + TcpPtr tcp(ip); + if (tcp) { + DPRINTF(Ethernet, + "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", + tcp->sport(), tcp->dport(), tcp->seq(), + tcp->ack()); + } + } + } +#endif + + DDUMP(EthernetData, txFifo.front()->data, txFifo.front()->length); + txBytes += txFifo.front()->length; + txPackets++; + + DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n", + txFifo.avail()); + txFifo.pop(); + + /* + * normally do a writeback of the descriptor here, and ONLY + * after that is done, send this interrupt. but since our + * stuff never actually fails, just do this interrupt here, + * otherwise the code has to stray from this nice format. + * besides, it's functionally the same. + */ + devIntrPost(ISR_TXOK); + } + + if (!txFifo.empty() && !txEvent.scheduled()) { + DPRINTF(Ethernet, "reschedule transmit\n"); + txEvent.schedule(curTick + retryTime); + } +} + +bool +NSGigE::doTxDmaRead() +{ + assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting); + txDmaState = dmaReading; + + if (dmaPending()) + txDmaState = dmaReadWaiting; + else + dmaRead(txDmaAddr, txDmaLen, &txDmaReadEvent, (uint8_t*)txDmaData); + + return true; +} + +void +NSGigE::txDmaReadDone() +{ + assert(txDmaState == dmaReading); + txDmaState = dmaIdle; + + DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", + txDmaAddr, txDmaLen); + DDUMP(EthernetDMA, txDmaData, txDmaLen); + + // If the receive state machine has a pending DMA, let it go first + if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) + rxKick(); + + txKick(); +} + +bool +NSGigE::doTxDmaWrite() +{ + assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting); + txDmaState = dmaWriting; + + if (dmaPending()) + txDmaState = dmaWriteWaiting; + else + dmaWrite(txDmaAddr, txDmaLen, &txDmaWriteEvent, (uint8_t*)txDmaData); + return true; +} + +void +NSGigE::txDmaWriteDone() +{ + assert(txDmaState == dmaWriting); + txDmaState = dmaIdle; + + DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n", + txDmaAddr, txDmaLen); + DDUMP(EthernetDMA, txDmaData, txDmaLen); + + // If the receive state machine has a pending DMA, let it go first + if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) + rxKick(); + + txKick(); +} + +void +NSGigE::txKick() +{ + bool is64bit = (bool)(regs.config & CFGR_M64ADDR); + + DPRINTF(EthernetSM, "transmit kick txState=%s %d-bit\n", + NsTxStateStrings[txState], is64bit ? 64 : 32); + + Addr link, bufptr; + uint32_t &cmdsts = is64bit ? txDesc64.cmdsts : txDesc32.cmdsts; + uint32_t &extsts = is64bit ? txDesc64.extsts : txDesc32.extsts; + + next: + if (clock) { + if (txKickTick > curTick) { + DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n", + txKickTick); + goto exit; + } + + // Go to the next state machine clock tick. + txKickTick = curTick + cycles(1); + } + + switch(txDmaState) { + case dmaReadWaiting: + if (doTxDmaRead()) + goto exit; + break; + case dmaWriteWaiting: + if (doTxDmaWrite()) + goto exit; + break; + default: + break; + } + + link = is64bit ? (Addr)txDesc64.link : (Addr)txDesc32.link; + bufptr = is64bit ? (Addr)txDesc64.bufptr : (Addr)txDesc32.bufptr; + switch (txState) { + case txIdle: + if (!txEnable) { + DPRINTF(EthernetSM, "Transmit disabled. Nothing to do.\n"); + goto exit; + } + + if (CTDD) { + txState = txDescRefr; + + txDmaAddr = regs.txdp & 0x3fffffff; + txDmaData = + is64bit ? (void *)&txDesc64.link : (void *)&txDesc32.link; + txDmaLen = is64bit ? sizeof(txDesc64.link) : sizeof(txDesc32.link); + txDmaFree = dmaDescFree; + + descDmaReads++; + descDmaRdBytes += txDmaLen; + + if (doTxDmaRead()) + goto exit; + + } else { + txState = txDescRead; + + txDmaAddr = regs.txdp & 0x3fffffff; + txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32; + txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32); + txDmaFree = dmaDescFree; + + descDmaReads++; + descDmaRdBytes += txDmaLen; + + if (doTxDmaRead()) + goto exit; + } + break; + + case txDescRefr: + if (txDmaState != dmaIdle) + goto exit; + + txState = txAdvance; + break; + + case txDescRead: + if (txDmaState != dmaIdle) + goto exit; + + DPRINTF(EthernetDesc, "txDesc: addr=%08x read descriptor\n", + regs.txdp & 0x3fffffff); + DPRINTF(EthernetDesc, + "txDesc: link=%#x bufptr=%#x cmdsts=%#08x extsts=%#08x\n", + link, bufptr, cmdsts, extsts); + + if (cmdsts & CMDSTS_OWN) { + txState = txFifoBlock; + txFragPtr = bufptr; + txDescCnt = cmdsts & CMDSTS_LEN_MASK; + } else { + devIntrPost(ISR_TXIDLE); + txState = txIdle; + goto exit; + } + break; + + case txFifoBlock: + if (!txPacket) { + DPRINTF(EthernetSM, "****starting the tx of a new packet****\n"); + txPacket = new EthPacketData(16384); + txPacketBufPtr = txPacket->data; + } + + if (txDescCnt == 0) { + DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n"); + if (cmdsts & CMDSTS_MORE) { + DPRINTF(EthernetSM, "there are more descriptors to come\n"); + txState = txDescWrite; + + cmdsts &= ~CMDSTS_OWN; + + txDmaAddr = regs.txdp & 0x3fffffff; + txDmaData = &cmdsts; + if (is64bit) { + txDmaAddr += offsetof(ns_desc64, cmdsts); + txDmaLen = sizeof(txDesc64.cmdsts); + } else { + txDmaAddr += offsetof(ns_desc32, cmdsts); + txDmaLen = sizeof(txDesc32.cmdsts); + } + txDmaFree = dmaDescFree; + + if (doTxDmaWrite()) + goto exit; + + } else { /* this packet is totally done */ + DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n"); + /* deal with the the packet that just finished */ + if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) { + IpPtr ip(txPacket); + if (extsts & EXTSTS_UDPPKT) { + UdpPtr udp(ip); + udp->sum(0); + udp->sum(cksum(udp)); + txUdpChecksums++; + } else if (extsts & EXTSTS_TCPPKT) { + TcpPtr tcp(ip); + tcp->sum(0); + tcp->sum(cksum(tcp)); + txTcpChecksums++; + } + if (extsts & EXTSTS_IPPKT) { + ip->sum(0); + ip->sum(cksum(ip)); + txIpChecksums++; + } + } + + txPacket->length = txPacketBufPtr - txPacket->data; + // this is just because the receive can't handle a + // packet bigger want to make sure + if (txPacket->length > 1514) + panic("transmit packet too large, %s > 1514\n", + txPacket->length); + +#ifndef NDEBUG + bool success = +#endif + txFifo.push(txPacket); + assert(success); + + /* + * this following section is not tqo spec, but + * functionally shouldn't be any different. normally, + * the chip will wait til the transmit has occurred + * before writing back the descriptor because it has + * to wait to see that it was successfully transmitted + * to decide whether to set CMDSTS_OK or not. + * however, in the simulator since it is always + * successfully transmitted, and writing it exactly to + * spec would complicate the code, we just do it here + */ + + cmdsts &= ~CMDSTS_OWN; + cmdsts |= CMDSTS_OK; + + DPRINTF(EthernetDesc, + "txDesc writeback: cmdsts=%08x extsts=%08x\n", + cmdsts, extsts); + + txDmaFree = dmaDescFree; + txDmaAddr = regs.txdp & 0x3fffffff; + txDmaData = &cmdsts; + if (is64bit) { + txDmaAddr += offsetof(ns_desc64, cmdsts); + txDmaLen = + sizeof(txDesc64.cmdsts) + sizeof(txDesc64.extsts); + } else { + txDmaAddr += offsetof(ns_desc32, cmdsts); + txDmaLen = + sizeof(txDesc32.cmdsts) + sizeof(txDesc32.extsts); + } + + descDmaWrites++; + descDmaWrBytes += txDmaLen; + + transmit(); + txPacket = 0; + + if (!txEnable) { + DPRINTF(EthernetSM, "halting TX state machine\n"); + txState = txIdle; + goto exit; + } else + txState = txAdvance; + + if (doTxDmaWrite()) + goto exit; + } + } else { + DPRINTF(EthernetSM, "this descriptor isn't done yet\n"); + if (!txFifo.full()) { + txState = txFragRead; + + /* + * The number of bytes transferred is either whatever + * is left in the descriptor (txDescCnt), or if there + * is not enough room in the fifo, just whatever room + * is left in the fifo + */ + txXferLen = min<uint32_t>(txDescCnt, txFifo.avail()); + + txDmaAddr = txFragPtr & 0x3fffffff; + txDmaData = txPacketBufPtr; + txDmaLen = txXferLen; + txDmaFree = dmaDataFree; + + if (doTxDmaRead()) + goto exit; + } else { + txState = txFifoBlock; + transmit(); + + goto exit; + } + + } + break; + + case txFragRead: + if (txDmaState != dmaIdle) + goto exit; + + txPacketBufPtr += txXferLen; + txFragPtr += txXferLen; + txDescCnt -= txXferLen; + txFifo.reserve(txXferLen); + + txState = txFifoBlock; + break; + + case txDescWrite: + if (txDmaState != dmaIdle) + goto exit; + + if (cmdsts & CMDSTS_INTR) + devIntrPost(ISR_TXDESC); + + if (!txEnable) { + DPRINTF(EthernetSM, "halting TX state machine\n"); + txState = txIdle; + goto exit; + } else + txState = txAdvance; + break; + + case txAdvance: + if (link == 0) { + devIntrPost(ISR_TXIDLE); + txState = txIdle; + goto exit; + } else { + if (txDmaState != dmaIdle) + goto exit; + txState = txDescRead; + regs.txdp = link; + CTDD = false; + + txDmaAddr = link & 0x3fffffff; + txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32; + txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32); + txDmaFree = dmaDescFree; + + if (doTxDmaRead()) + goto exit; + } + break; + + default: + panic("invalid state"); + } + + DPRINTF(EthernetSM, "entering next txState=%s\n", + NsTxStateStrings[txState]); + goto next; + + exit: + /** + * @todo do we want to schedule a future kick? + */ + DPRINTF(EthernetSM, "tx state machine exited txState=%s\n", + NsTxStateStrings[txState]); + + if (clock && !txKickEvent.scheduled()) + txKickEvent.schedule(txKickTick); +} + +/** + * Advance the EEPROM state machine + * Called on rising edge of EEPROM clock bit in MEAR + */ +void +NSGigE::eepromKick() +{ + switch (eepromState) { + + case eepromStart: + + // Wait for start bit + if (regs.mear & MEAR_EEDI) { + // Set up to get 2 opcode bits + eepromState = eepromGetOpcode; + eepromBitsToRx = 2; + eepromOpcode = 0; + } + break; + + case eepromGetOpcode: + eepromOpcode <<= 1; + eepromOpcode += (regs.mear & MEAR_EEDI) ? 1 : 0; + --eepromBitsToRx; + + // Done getting opcode + if (eepromBitsToRx == 0) { + if (eepromOpcode != EEPROM_READ) + panic("only EEPROM reads are implemented!"); + + // Set up to get address + eepromState = eepromGetAddress; + eepromBitsToRx = 6; + eepromAddress = 0; + } + break; + + case eepromGetAddress: + eepromAddress <<= 1; + eepromAddress += (regs.mear & MEAR_EEDI) ? 1 : 0; + --eepromBitsToRx; + + // Done getting address + if (eepromBitsToRx == 0) { + + if (eepromAddress >= EEPROM_SIZE) + panic("EEPROM read access out of range!"); + + switch (eepromAddress) { + + case EEPROM_PMATCH2_ADDR: + eepromData = rom.perfectMatch[5]; + eepromData <<= 8; + eepromData += rom.perfectMatch[4]; + break; + + case EEPROM_PMATCH1_ADDR: + eepromData = rom.perfectMatch[3]; + eepromData <<= 8; + eepromData += rom.perfectMatch[2]; + break; + + case EEPROM_PMATCH0_ADDR: + eepromData = rom.perfectMatch[1]; + eepromData <<= 8; + eepromData += rom.perfectMatch[0]; + break; + + default: + panic("FreeBSD driver only uses EEPROM to read PMATCH!"); + } + // Set up to read data + eepromState = eepromRead; + eepromBitsToRx = 16; + + // Clear data in bit + regs.mear &= ~MEAR_EEDI; + } + break; + + case eepromRead: + // Clear Data Out bit + regs.mear &= ~MEAR_EEDO; + // Set bit to value of current EEPROM bit + regs.mear |= (eepromData & 0x8000) ? MEAR_EEDO : 0x0; + + eepromData <<= 1; + --eepromBitsToRx; + + // All done + if (eepromBitsToRx == 0) { + eepromState = eepromStart; + } + break; + + default: + panic("invalid EEPROM state"); + } + +} + +void +NSGigE::transferDone() +{ + if (txFifo.empty()) { + DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n"); + return; + } + + DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); + + if (txEvent.scheduled()) + txEvent.reschedule(curTick + cycles(1)); + else + txEvent.schedule(curTick + cycles(1)); +} + +bool +NSGigE::rxFilter(const EthPacketPtr &packet) +{ + EthPtr eth = packet; + bool drop = true; + string type; + + const EthAddr &dst = eth->dst(); + if (dst.unicast()) { + // If we're accepting all unicast addresses + if (acceptUnicast) + drop = false; + + // If we make a perfect match + if (acceptPerfect && dst == rom.perfectMatch) + drop = false; + + if (acceptArp && eth->type() == ETH_TYPE_ARP) + drop = false; + + } else if (dst.broadcast()) { + // if we're accepting broadcasts + if (acceptBroadcast) + drop = false; + + } else if (dst.multicast()) { + // if we're accepting all multicasts + if (acceptMulticast) + drop = false; + + // Multicast hashing faked - all packets accepted + if (multicastHashEnable) + drop = false; + } + + if (drop) { + DPRINTF(Ethernet, "rxFilter drop\n"); + DDUMP(EthernetData, packet->data, packet->length); + } + + return drop; +} + +bool +NSGigE::recvPacket(EthPacketPtr packet) +{ + rxBytes += packet->length; + rxPackets++; + + DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n", + rxFifo.avail()); + + if (!rxEnable) { + DPRINTF(Ethernet, "receive disabled...packet dropped\n"); + return true; + } + + if (!rxFilterEnable) { + DPRINTF(Ethernet, + "receive packet filtering disabled . . . packet dropped\n"); + return true; + } + + if (rxFilter(packet)) { + DPRINTF(Ethernet, "packet filtered...dropped\n"); + return true; + } + + if (rxFifo.avail() < packet->length) { +#if TRACING_ON + IpPtr ip(packet); + TcpPtr tcp(ip); + if (ip) { + DPRINTF(Ethernet, + "packet won't fit in receive buffer...pkt ID %d dropped\n", + ip->id()); + if (tcp) { + DPRINTF(Ethernet, "Seq=%d\n", tcp->seq()); + } + } +#endif + droppedPackets++; + devIntrPost(ISR_RXORN); + return false; + } + + rxFifo.push(packet); + + rxKick(); + return true; +} + +//===================================================================== +// +// +void +NSGigE::serialize(ostream &os) +{ + // Serialize the PciDev base class + PciDev::serialize(os); + + /* + * Finalize any DMA events now. + */ + // @todo will mem system save pending dma? + + /* + * Serialize the device registers + */ + SERIALIZE_SCALAR(regs.command); + SERIALIZE_SCALAR(regs.config); + SERIALIZE_SCALAR(regs.mear); + SERIALIZE_SCALAR(regs.ptscr); + SERIALIZE_SCALAR(regs.isr); + SERIALIZE_SCALAR(regs.imr); + SERIALIZE_SCALAR(regs.ier); + SERIALIZE_SCALAR(regs.ihr); + SERIALIZE_SCALAR(regs.txdp); + SERIALIZE_SCALAR(regs.txdp_hi); + SERIALIZE_SCALAR(regs.txcfg); + SERIALIZE_SCALAR(regs.gpior); + SERIALIZE_SCALAR(regs.rxdp); + SERIALIZE_SCALAR(regs.rxdp_hi); + SERIALIZE_SCALAR(regs.rxcfg); + SERIALIZE_SCALAR(regs.pqcr); + SERIALIZE_SCALAR(regs.wcsr); + SERIALIZE_SCALAR(regs.pcr); + SERIALIZE_SCALAR(regs.rfcr); + SERIALIZE_SCALAR(regs.rfdr); + SERIALIZE_SCALAR(regs.brar); + SERIALIZE_SCALAR(regs.brdr); + SERIALIZE_SCALAR(regs.srr); + SERIALIZE_SCALAR(regs.mibc); + SERIALIZE_SCALAR(regs.vrcr); + SERIALIZE_SCALAR(regs.vtcr); + SERIALIZE_SCALAR(regs.vdr); + SERIALIZE_SCALAR(regs.ccsr); + SERIALIZE_SCALAR(regs.tbicr); + SERIALIZE_SCALAR(regs.tbisr); + SERIALIZE_SCALAR(regs.tanar); + SERIALIZE_SCALAR(regs.tanlpar); + SERIALIZE_SCALAR(regs.taner); + SERIALIZE_SCALAR(regs.tesr); + + SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); + SERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE); + + SERIALIZE_SCALAR(ioEnable); + + /* + * Serialize the data Fifos + */ + rxFifo.serialize("rxFifo", os); + txFifo.serialize("txFifo", os); + + /* + * Serialize the various helper variables + */ + bool txPacketExists = txPacket; + SERIALIZE_SCALAR(txPacketExists); + if (txPacketExists) { + txPacket->length = txPacketBufPtr - txPacket->data; + txPacket->serialize("txPacket", os); + uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data); + SERIALIZE_SCALAR(txPktBufPtr); + } + + bool rxPacketExists = rxPacket; + SERIALIZE_SCALAR(rxPacketExists); + if (rxPacketExists) { + rxPacket->serialize("rxPacket", os); + uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data); + SERIALIZE_SCALAR(rxPktBufPtr); + } + + SERIALIZE_SCALAR(txXferLen); + SERIALIZE_SCALAR(rxXferLen); + + /* + * Serialize Cached Descriptors + */ + SERIALIZE_SCALAR(rxDesc64.link); + SERIALIZE_SCALAR(rxDesc64.bufptr); + SERIALIZE_SCALAR(rxDesc64.cmdsts); + SERIALIZE_SCALAR(rxDesc64.extsts); + SERIALIZE_SCALAR(txDesc64.link); + SERIALIZE_SCALAR(txDesc64.bufptr); + SERIALIZE_SCALAR(txDesc64.cmdsts); + SERIALIZE_SCALAR(txDesc64.extsts); + SERIALIZE_SCALAR(rxDesc32.link); + SERIALIZE_SCALAR(rxDesc32.bufptr); + SERIALIZE_SCALAR(rxDesc32.cmdsts); + SERIALIZE_SCALAR(rxDesc32.extsts); + SERIALIZE_SCALAR(txDesc32.link); + SERIALIZE_SCALAR(txDesc32.bufptr); + SERIALIZE_SCALAR(txDesc32.cmdsts); + SERIALIZE_SCALAR(txDesc32.extsts); + SERIALIZE_SCALAR(extstsEnable); + + /* + * Serialize tx state machine + */ + int txState = this->txState; + SERIALIZE_SCALAR(txState); + SERIALIZE_SCALAR(txEnable); + SERIALIZE_SCALAR(CTDD); + SERIALIZE_SCALAR(txFragPtr); + SERIALIZE_SCALAR(txDescCnt); + int txDmaState = this->txDmaState; + SERIALIZE_SCALAR(txDmaState); + SERIALIZE_SCALAR(txKickTick); + + /* + * Serialize rx state machine + */ + int rxState = this->rxState; + SERIALIZE_SCALAR(rxState); + SERIALIZE_SCALAR(rxEnable); + SERIALIZE_SCALAR(CRDD); + SERIALIZE_SCALAR(rxPktBytes); + SERIALIZE_SCALAR(rxFragPtr); + SERIALIZE_SCALAR(rxDescCnt); + int rxDmaState = this->rxDmaState; + SERIALIZE_SCALAR(rxDmaState); + SERIALIZE_SCALAR(rxKickTick); + + /* + * Serialize EEPROM state machine + */ + int eepromState = this->eepromState; + SERIALIZE_SCALAR(eepromState); + SERIALIZE_SCALAR(eepromClk); + SERIALIZE_SCALAR(eepromBitsToRx); + SERIALIZE_SCALAR(eepromOpcode); + SERIALIZE_SCALAR(eepromAddress); + SERIALIZE_SCALAR(eepromData); + + /* + * If there's a pending transmit, store the time so we can + * reschedule it later + */ + Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0; + SERIALIZE_SCALAR(transmitTick); + + /* + * receive address filter settings + */ + SERIALIZE_SCALAR(rxFilterEnable); + SERIALIZE_SCALAR(acceptBroadcast); + SERIALIZE_SCALAR(acceptMulticast); + SERIALIZE_SCALAR(acceptUnicast); + SERIALIZE_SCALAR(acceptPerfect); + SERIALIZE_SCALAR(acceptArp); + SERIALIZE_SCALAR(multicastHashEnable); + + /* + * Keep track of pending interrupt status. + */ + SERIALIZE_SCALAR(intrTick); + SERIALIZE_SCALAR(cpuPendingIntr); + Tick intrEventTick = 0; + if (intrEvent) + intrEventTick = intrEvent->when(); + SERIALIZE_SCALAR(intrEventTick); + +} + +void +NSGigE::unserialize(Checkpoint *cp, const std::string §ion) +{ + // Unserialize the PciDev base class + PciDev::unserialize(cp, section); + + UNSERIALIZE_SCALAR(regs.command); + UNSERIALIZE_SCALAR(regs.config); + UNSERIALIZE_SCALAR(regs.mear); + UNSERIALIZE_SCALAR(regs.ptscr); + UNSERIALIZE_SCALAR(regs.isr); + UNSERIALIZE_SCALAR(regs.imr); + UNSERIALIZE_SCALAR(regs.ier); + UNSERIALIZE_SCALAR(regs.ihr); + UNSERIALIZE_SCALAR(regs.txdp); + UNSERIALIZE_SCALAR(regs.txdp_hi); + UNSERIALIZE_SCALAR(regs.txcfg); + UNSERIALIZE_SCALAR(regs.gpior); + UNSERIALIZE_SCALAR(regs.rxdp); + UNSERIALIZE_SCALAR(regs.rxdp_hi); + UNSERIALIZE_SCALAR(regs.rxcfg); + UNSERIALIZE_SCALAR(regs.pqcr); + UNSERIALIZE_SCALAR(regs.wcsr); + UNSERIALIZE_SCALAR(regs.pcr); + UNSERIALIZE_SCALAR(regs.rfcr); + UNSERIALIZE_SCALAR(regs.rfdr); + UNSERIALIZE_SCALAR(regs.brar); + UNSERIALIZE_SCALAR(regs.brdr); + UNSERIALIZE_SCALAR(regs.srr); + UNSERIALIZE_SCALAR(regs.mibc); + UNSERIALIZE_SCALAR(regs.vrcr); + UNSERIALIZE_SCALAR(regs.vtcr); + UNSERIALIZE_SCALAR(regs.vdr); + UNSERIALIZE_SCALAR(regs.ccsr); + UNSERIALIZE_SCALAR(regs.tbicr); + UNSERIALIZE_SCALAR(regs.tbisr); + UNSERIALIZE_SCALAR(regs.tanar); + UNSERIALIZE_SCALAR(regs.tanlpar); + UNSERIALIZE_SCALAR(regs.taner); + UNSERIALIZE_SCALAR(regs.tesr); + + UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); + UNSERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE); + + UNSERIALIZE_SCALAR(ioEnable); + + /* + * unserialize the data fifos + */ + rxFifo.unserialize("rxFifo", cp, section); + txFifo.unserialize("txFifo", cp, section); + + /* + * unserialize the various helper variables + */ + bool txPacketExists; + UNSERIALIZE_SCALAR(txPacketExists); + if (txPacketExists) { + txPacket = new EthPacketData(16384); + txPacket->unserialize("txPacket", cp, section); + uint32_t txPktBufPtr; + UNSERIALIZE_SCALAR(txPktBufPtr); + txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr; + } else + txPacket = 0; + + bool rxPacketExists; + UNSERIALIZE_SCALAR(rxPacketExists); + rxPacket = 0; + if (rxPacketExists) { + rxPacket = new EthPacketData(16384); + rxPacket->unserialize("rxPacket", cp, section); + uint32_t rxPktBufPtr; + UNSERIALIZE_SCALAR(rxPktBufPtr); + rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr; + } else + rxPacket = 0; + + UNSERIALIZE_SCALAR(txXferLen); + UNSERIALIZE_SCALAR(rxXferLen); + + /* + * Unserialize Cached Descriptors + */ + UNSERIALIZE_SCALAR(rxDesc64.link); + UNSERIALIZE_SCALAR(rxDesc64.bufptr); + UNSERIALIZE_SCALAR(rxDesc64.cmdsts); + UNSERIALIZE_SCALAR(rxDesc64.extsts); + UNSERIALIZE_SCALAR(txDesc64.link); + UNSERIALIZE_SCALAR(txDesc64.bufptr); + UNSERIALIZE_SCALAR(txDesc64.cmdsts); + UNSERIALIZE_SCALAR(txDesc64.extsts); + UNSERIALIZE_SCALAR(rxDesc32.link); + UNSERIALIZE_SCALAR(rxDesc32.bufptr); + UNSERIALIZE_SCALAR(rxDesc32.cmdsts); + UNSERIALIZE_SCALAR(rxDesc32.extsts); + UNSERIALIZE_SCALAR(txDesc32.link); + UNSERIALIZE_SCALAR(txDesc32.bufptr); + UNSERIALIZE_SCALAR(txDesc32.cmdsts); + UNSERIALIZE_SCALAR(txDesc32.extsts); + UNSERIALIZE_SCALAR(extstsEnable); + + /* + * unserialize tx state machine + */ + int txState; + UNSERIALIZE_SCALAR(txState); + this->txState = (TxState) txState; + UNSERIALIZE_SCALAR(txEnable); + UNSERIALIZE_SCALAR(CTDD); + UNSERIALIZE_SCALAR(txFragPtr); + UNSERIALIZE_SCALAR(txDescCnt); + int txDmaState; + UNSERIALIZE_SCALAR(txDmaState); + this->txDmaState = (DmaState) txDmaState; + UNSERIALIZE_SCALAR(txKickTick); + if (txKickTick) + txKickEvent.schedule(txKickTick); + + /* + * unserialize rx state machine + */ + int rxState; + UNSERIALIZE_SCALAR(rxState); + this->rxState = (RxState) rxState; + UNSERIALIZE_SCALAR(rxEnable); + UNSERIALIZE_SCALAR(CRDD); + UNSERIALIZE_SCALAR(rxPktBytes); + UNSERIALIZE_SCALAR(rxFragPtr); + UNSERIALIZE_SCALAR(rxDescCnt); + int rxDmaState; + UNSERIALIZE_SCALAR(rxDmaState); + this->rxDmaState = (DmaState) rxDmaState; + UNSERIALIZE_SCALAR(rxKickTick); + if (rxKickTick) + rxKickEvent.schedule(rxKickTick); + + /* + * Unserialize EEPROM state machine + */ + int eepromState; + UNSERIALIZE_SCALAR(eepromState); + this->eepromState = (EEPROMState) eepromState; + UNSERIALIZE_SCALAR(eepromClk); + UNSERIALIZE_SCALAR(eepromBitsToRx); + UNSERIALIZE_SCALAR(eepromOpcode); + UNSERIALIZE_SCALAR(eepromAddress); + UNSERIALIZE_SCALAR(eepromData); + + /* + * If there's a pending transmit, reschedule it now + */ + Tick transmitTick; + UNSERIALIZE_SCALAR(transmitTick); + if (transmitTick) + txEvent.schedule(curTick + transmitTick); + + /* + * unserialize receive address filter settings + */ + UNSERIALIZE_SCALAR(rxFilterEnable); + UNSERIALIZE_SCALAR(acceptBroadcast); + UNSERIALIZE_SCALAR(acceptMulticast); + UNSERIALIZE_SCALAR(acceptUnicast); + UNSERIALIZE_SCALAR(acceptPerfect); + UNSERIALIZE_SCALAR(acceptArp); + UNSERIALIZE_SCALAR(multicastHashEnable); + + /* + * Keep track of pending interrupt status. + */ + UNSERIALIZE_SCALAR(intrTick); + UNSERIALIZE_SCALAR(cpuPendingIntr); + Tick intrEventTick; + UNSERIALIZE_SCALAR(intrEventTick); + if (intrEventTick) { + intrEvent = new IntrEvent(this, true); + intrEvent->schedule(intrEventTick); + } +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) + + SimObjectParam<EtherInt *> peer; + SimObjectParam<NSGigE *> device; + +END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) + +BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt) + + INIT_PARAM_DFLT(peer, "peer interface", NULL), + INIT_PARAM(device, "Ethernet device of this interface") + +END_INIT_SIM_OBJECT_PARAMS(NSGigEInt) + +CREATE_SIM_OBJECT(NSGigEInt) +{ + NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device); + + EtherInt *p = (EtherInt *)peer; + if (p) { + dev_int->setPeer(p); + p->setPeer(dev_int); + } + + return dev_int; +} + +REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt) + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE) + + SimObjectParam<System *> system; + SimObjectParam<Platform *> platform; + SimObjectParam<PciConfigAll *> configspace; + SimObjectParam<PciConfigData *> configdata; + Param<uint32_t> pci_bus; + Param<uint32_t> pci_dev; + Param<uint32_t> pci_func; + Param<Tick> pio_latency; + + Param<Tick> clock; + Param<bool> dma_desc_free; + Param<bool> dma_data_free; + Param<Tick> dma_read_delay; + Param<Tick> dma_write_delay; + Param<Tick> dma_read_factor; + Param<Tick> dma_write_factor; + Param<bool> dma_no_allocate; + Param<Tick> intr_delay; + + Param<Tick> rx_delay; + Param<Tick> tx_delay; + Param<uint32_t> rx_fifo_size; + Param<uint32_t> tx_fifo_size; + + Param<bool> rx_filter; + Param<string> hardware_address; + Param<bool> rx_thread; + Param<bool> tx_thread; + Param<bool> rss; + +END_DECLARE_SIM_OBJECT_PARAMS(NSGigE) + +BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE) + + INIT_PARAM(system, "System pointer"), + INIT_PARAM(platform, "Platform pointer"), + INIT_PARAM(configspace, "PCI Configspace"), + INIT_PARAM(configdata, "PCI Config data"), + INIT_PARAM(pci_bus, "PCI bus ID"), + INIT_PARAM(pci_dev, "PCI device number"), + INIT_PARAM(pci_func, "PCI function code"), + INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), + INIT_PARAM(clock, "State machine cycle time"), + + INIT_PARAM(dma_desc_free, "DMA of Descriptors is free"), + INIT_PARAM(dma_data_free, "DMA of Data is free"), + INIT_PARAM(dma_read_delay, "fixed delay for dma reads"), + INIT_PARAM(dma_write_delay, "fixed delay for dma writes"), + INIT_PARAM(dma_read_factor, "multiplier for dma reads"), + INIT_PARAM(dma_write_factor, "multiplier for dma writes"), + INIT_PARAM(dma_no_allocate, "Should DMA reads allocate cache lines"), + INIT_PARAM(intr_delay, "Interrupt Delay in microseconds"), + + INIT_PARAM(rx_delay, "Receive Delay"), + INIT_PARAM(tx_delay, "Transmit Delay"), + INIT_PARAM(rx_fifo_size, "max size in bytes of rxFifo"), + INIT_PARAM(tx_fifo_size, "max size in bytes of txFifo"), + + INIT_PARAM(rx_filter, "Enable Receive Filter"), + INIT_PARAM(hardware_address, "Ethernet Hardware Address"), + INIT_PARAM(rx_thread, ""), + INIT_PARAM(tx_thread, ""), + INIT_PARAM(rss, "") + +END_INIT_SIM_OBJECT_PARAMS(NSGigE) + + +CREATE_SIM_OBJECT(NSGigE) +{ + NSGigE::Params *params = new NSGigE::Params; + + params->name = getInstanceName(); + params->platform = platform; + params->system = system; + params->configSpace = configspace; + params->configData = configdata; + params->busNum = pci_bus; + params->deviceNum = pci_dev; + params->functionNum = pci_func; + params->pio_delay = pio_latency; + + params->clock = clock; + params->dma_desc_free = dma_desc_free; + params->dma_data_free = dma_data_free; + params->dma_read_delay = dma_read_delay; + params->dma_write_delay = dma_write_delay; + params->dma_read_factor = dma_read_factor; + params->dma_write_factor = dma_write_factor; + params->dma_no_allocate = dma_no_allocate; + params->pio_delay = pio_latency; + params->intr_delay = intr_delay; + + params->rx_delay = rx_delay; + params->tx_delay = tx_delay; + params->rx_fifo_size = rx_fifo_size; + params->tx_fifo_size = tx_fifo_size; + + params->rx_filter = rx_filter; + params->eaddr = hardware_address; + params->rx_thread = rx_thread; + params->tx_thread = tx_thread; + params->rss = rss; + + return new NSGigE(params); +} + +REGISTER_SIM_OBJECT("NSGigE", NSGigE) diff --git a/src/dev/ns_gige.hh b/src/dev/ns_gige.hh new file mode 100644 index 000000000..2de11c951 --- /dev/null +++ b/src/dev/ns_gige.hh @@ -0,0 +1,465 @@ +/* + * 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: Lisa Hsu + */ + +/** @file + * Device module for modelling the National Semiconductor + * DP83820 ethernet controller + */ + +#ifndef __DEV_NS_GIGE_HH__ +#define __DEV_NS_GIGE_HH__ + +#include "base/inet.hh" +#include "base/statistics.hh" +#include "dev/etherint.hh" +#include "dev/etherpkt.hh" +#include "dev/io_device.hh" +#include "dev/ns_gige_reg.h" +#include "dev/pcidev.hh" +#include "dev/pktfifo.hh" +#include "sim/eventq.hh" + +// Hash filtering constants +const uint16_t FHASH_ADDR = 0x100; +const uint16_t FHASH_SIZE = 0x100; + +// EEPROM constants +const uint8_t EEPROM_READ = 0x2; +const uint8_t EEPROM_SIZE = 64; // Size in words of NSC93C46 EEPROM +const uint8_t EEPROM_PMATCH2_ADDR = 0xA; // EEPROM Address of PMATCH word 2 +const uint8_t EEPROM_PMATCH1_ADDR = 0xB; // EEPROM Address of PMATCH word 1 +const uint8_t EEPROM_PMATCH0_ADDR = 0xC; // EEPROM Address of PMATCH word 0 + +/** + * Ethernet device registers + */ +struct dp_regs { + uint32_t command; + uint32_t config; + uint32_t mear; + uint32_t ptscr; + uint32_t isr; + uint32_t imr; + uint32_t ier; + uint32_t ihr; + uint32_t txdp; + uint32_t txdp_hi; + uint32_t txcfg; + uint32_t gpior; + uint32_t rxdp; + uint32_t rxdp_hi; + uint32_t rxcfg; + uint32_t pqcr; + uint32_t wcsr; + uint32_t pcr; + uint32_t rfcr; + uint32_t rfdr; + uint32_t brar; + uint32_t brdr; + uint32_t srr; + uint32_t mibc; + uint32_t vrcr; + uint32_t vtcr; + uint32_t vdr; + uint32_t ccsr; + uint32_t tbicr; + uint32_t tbisr; + uint32_t tanar; + uint32_t tanlpar; + uint32_t taner; + uint32_t tesr; +}; + +struct dp_rom { + /** + * for perfect match memory. + * the linux driver doesn't use any other ROM + */ + uint8_t perfectMatch[ETH_ADDR_LEN]; + + /** + * for hash table memory. + * used by the freebsd driver + */ + uint8_t filterHash[FHASH_SIZE]; +}; + +class NSGigEInt; +class Packet; +class PciConfigAll; + +/** + * NS DP83820 Ethernet device model + */ +class NSGigE : public PciDev +{ + public: + /** Transmit State Machine states */ + enum TxState + { + txIdle, + txDescRefr, + txDescRead, + txFifoBlock, + txFragRead, + txDescWrite, + txAdvance + }; + + /** Receive State Machine States */ + enum RxState + { + rxIdle, + rxDescRefr, + rxDescRead, + rxFifoBlock, + rxFragWrite, + rxDescWrite, + rxAdvance + }; + + enum DmaState + { + dmaIdle, + dmaReading, + dmaWriting, + dmaReadWaiting, + dmaWriteWaiting + }; + + /** EEPROM State Machine States */ + enum EEPROMState + { + eepromStart, + eepromGetOpcode, + eepromGetAddress, + eepromRead + }; + + protected: + /** device register file */ + dp_regs regs; + dp_rom rom; + + /** pci settings */ + bool ioEnable; +#if 0 + bool memEnable; + bool bmEnable; +#endif + + /*** BASIC STRUCTURES FOR TX/RX ***/ + /* Data FIFOs */ + PacketFifo txFifo; + PacketFifo rxFifo; + + /** various helper vars */ + EthPacketPtr txPacket; + EthPacketPtr rxPacket; + uint8_t *txPacketBufPtr; + uint8_t *rxPacketBufPtr; + uint32_t txXferLen; + uint32_t rxXferLen; + bool rxDmaFree; + bool txDmaFree; + + /** DescCaches */ + ns_desc32 txDesc32; + ns_desc32 rxDesc32; + ns_desc64 txDesc64; + ns_desc64 rxDesc64; + + /* state machine cycle time */ + Tick clock; + inline Tick cycles(int numCycles) const { return numCycles * clock; } + + /* tx State Machine */ + TxState txState; + bool txEnable; + + /** Current Transmit Descriptor Done */ + bool CTDD; + /** halt the tx state machine after next packet */ + bool txHalt; + /** ptr to the next byte in the current fragment */ + Addr txFragPtr; + /** count of bytes remaining in the current descriptor */ + uint32_t txDescCnt; + DmaState txDmaState; + + /** rx State Machine */ + RxState rxState; + bool rxEnable; + + /** Current Receive Descriptor Done */ + bool CRDD; + /** num of bytes in the current packet being drained from rxDataFifo */ + uint32_t rxPktBytes; + /** halt the rx state machine after current packet */ + bool rxHalt; + /** ptr to the next byte in current fragment */ + Addr rxFragPtr; + /** count of bytes remaining in the current descriptor */ + uint32_t rxDescCnt; + DmaState rxDmaState; + + bool extstsEnable; + + /** EEPROM State Machine */ + EEPROMState eepromState; + bool eepromClk; + uint8_t eepromBitsToRx; + uint8_t eepromOpcode; + uint8_t eepromAddress; + uint16_t eepromData; + + protected: + Tick dmaReadDelay; + Tick dmaWriteDelay; + + Tick dmaReadFactor; + Tick dmaWriteFactor; + + void *rxDmaData; + Addr rxDmaAddr; + int rxDmaLen; + bool doRxDmaRead(); + bool doRxDmaWrite(); + + void *txDmaData; + Addr txDmaAddr; + int txDmaLen; + bool doTxDmaRead(); + bool doTxDmaWrite(); + + void rxDmaReadDone(); + friend class EventWrapper<NSGigE, &NSGigE::rxDmaReadDone>; + EventWrapper<NSGigE, &NSGigE::rxDmaReadDone> rxDmaReadEvent; + + void rxDmaWriteDone(); + friend class EventWrapper<NSGigE, &NSGigE::rxDmaWriteDone>; + EventWrapper<NSGigE, &NSGigE::rxDmaWriteDone> rxDmaWriteEvent; + + void txDmaReadDone(); + friend class EventWrapper<NSGigE, &NSGigE::txDmaReadDone>; + EventWrapper<NSGigE, &NSGigE::txDmaReadDone> txDmaReadEvent; + + void txDmaWriteDone(); + friend class EventWrapper<NSGigE, &NSGigE::txDmaWriteDone>; + EventWrapper<NSGigE, &NSGigE::txDmaWriteDone> txDmaWriteEvent; + + bool dmaDescFree; + bool dmaDataFree; + + protected: + Tick txDelay; + Tick rxDelay; + + void txReset(); + void rxReset(); + void regsReset(); + + void rxKick(); + Tick rxKickTick; + typedef EventWrapper<NSGigE, &NSGigE::rxKick> RxKickEvent; + friend void RxKickEvent::process(); + RxKickEvent rxKickEvent; + + void txKick(); + Tick txKickTick; + typedef EventWrapper<NSGigE, &NSGigE::txKick> TxKickEvent; + friend void TxKickEvent::process(); + TxKickEvent txKickEvent; + + void eepromKick(); + + /** + * Retransmit event + */ + void transmit(); + void txEventTransmit() + { + transmit(); + if (txState == txFifoBlock) + txKick(); + } + typedef EventWrapper<NSGigE, &NSGigE::txEventTransmit> TxEvent; + friend void TxEvent::process(); + TxEvent txEvent; + + void txDump() const; + void rxDump() const; + + /** + * receive address filter + */ + bool rxFilterEnable; + bool rxFilter(const EthPacketPtr &packet); + bool acceptBroadcast; + bool acceptMulticast; + bool acceptUnicast; + bool acceptPerfect; + bool acceptArp; + bool multicastHashEnable; + + /** + * Interrupt management + */ + void devIntrPost(uint32_t interrupts); + void devIntrClear(uint32_t interrupts); + void devIntrChangeMask(); + + Tick intrDelay; + Tick intrTick; + bool cpuPendingIntr; + void cpuIntrPost(Tick when); + void cpuInterrupt(); + void cpuIntrClear(); + + typedef EventWrapper<NSGigE, &NSGigE::cpuInterrupt> IntrEvent; + friend void IntrEvent::process(); + IntrEvent *intrEvent; + NSGigEInt *interface; + + public: + struct Params : public PciDev::Params + { + Tick clock; + Tick intr_delay; + Tick tx_delay; + Tick rx_delay; + bool dma_desc_free; + bool dma_data_free; + Tick dma_read_delay; + Tick dma_write_delay; + Tick dma_read_factor; + Tick dma_write_factor; + bool rx_filter; + Net::EthAddr eaddr; + uint32_t tx_fifo_size; + uint32_t rx_fifo_size; + bool rx_thread; + bool tx_thread; + bool rss; + bool dma_no_allocate; + }; + + NSGigE(Params *params); + ~NSGigE(); + const Params *params() const { return (const Params *)_params; } + + virtual void writeConfig(int offset, const uint16_t data); + + virtual Tick read(Packet *pkt); + virtual Tick write(Packet *pkt); + + bool cpuIntrPending() const; + void cpuIntrAck() { cpuIntrClear(); } + + bool recvPacket(EthPacketPtr packet); + void transferDone(); + + void setInterface(NSGigEInt *i) { assert(!interface); interface = i; } + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + + public: + void regStats(); + + private: + Stats::Scalar<> txBytes; + Stats::Scalar<> rxBytes; + Stats::Scalar<> txPackets; + Stats::Scalar<> rxPackets; + Stats::Scalar<> txIpChecksums; + Stats::Scalar<> rxIpChecksums; + Stats::Scalar<> txTcpChecksums; + Stats::Scalar<> rxTcpChecksums; + Stats::Scalar<> txUdpChecksums; + Stats::Scalar<> rxUdpChecksums; + Stats::Scalar<> descDmaReads; + Stats::Scalar<> descDmaWrites; + Stats::Scalar<> descDmaRdBytes; + Stats::Scalar<> descDmaWrBytes; + Stats::Formula totBandwidth; + Stats::Formula totPackets; + Stats::Formula totBytes; + Stats::Formula totPacketRate; + Stats::Formula txBandwidth; + Stats::Formula rxBandwidth; + Stats::Formula txPacketRate; + Stats::Formula rxPacketRate; + Stats::Scalar<> postedSwi; + Stats::Formula coalescedSwi; + Stats::Scalar<> totalSwi; + Stats::Scalar<> postedRxIdle; + Stats::Formula coalescedRxIdle; + Stats::Scalar<> totalRxIdle; + Stats::Scalar<> postedRxOk; + Stats::Formula coalescedRxOk; + Stats::Scalar<> totalRxOk; + Stats::Scalar<> postedRxDesc; + Stats::Formula coalescedRxDesc; + Stats::Scalar<> totalRxDesc; + Stats::Scalar<> postedTxOk; + Stats::Formula coalescedTxOk; + Stats::Scalar<> totalTxOk; + Stats::Scalar<> postedTxIdle; + Stats::Formula coalescedTxIdle; + Stats::Scalar<> totalTxIdle; + Stats::Scalar<> postedTxDesc; + Stats::Formula coalescedTxDesc; + Stats::Scalar<> totalTxDesc; + Stats::Scalar<> postedRxOrn; + Stats::Formula coalescedRxOrn; + Stats::Scalar<> totalRxOrn; + Stats::Formula coalescedTotal; + Stats::Scalar<> postedInterrupts; + Stats::Scalar<> droppedPackets; +}; + +/* + * Ethernet Interface for an Ethernet Device + */ +class NSGigEInt : public EtherInt +{ + private: + NSGigE *dev; + + public: + NSGigEInt(const std::string &name, NSGigE *d) + : EtherInt(name), dev(d) { dev->setInterface(this); } + + virtual bool recvPacket(EthPacketPtr pkt) { return dev->recvPacket(pkt); } + virtual void sendDone() { dev->transferDone(); } +}; + +#endif // __DEV_NS_GIGE_HH__ diff --git a/src/dev/ns_gige_reg.h b/src/dev/ns_gige_reg.h new file mode 100644 index 000000000..80ac5800d --- /dev/null +++ b/src/dev/ns_gige_reg.h @@ -0,0 +1,353 @@ +/* + * 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: Lisa Hsu + */ + +/** @file + * Ethernet device register definitions for the National + * Semiconductor DP83820 Ethernet controller + */ + +#ifndef __DEV_NS_GIGE_REG_H__ +#define __DEV_NS_GIGE_REG_H__ + +/* Device Register Address Map */ +#define CR 0x00 +#define CFGR 0x04 +#define MEAR 0x08 +#define PTSCR 0x0c +#define ISR 0x10 +#define IMR 0x14 +#define IER 0x18 +#define IHR 0x1c +#define TXDP 0x20 +#define TXDP_HI 0x24 +#define TX_CFG 0x28 +#define GPIOR 0x2c +#define RXDP 0x30 +#define RXDP_HI 0x34 +#define RX_CFG 0x38 +#define PQCR 0x3c +#define WCSR 0x40 +#define PCR 0x44 +#define RFCR 0x48 +#define RFDR 0x4c +#define BRAR 0x50 +#define BRDR 0x54 +#define SRR 0x58 +#define MIBC 0x5c +#define MIB_START 0x60 +#define MIB_END 0x88 +#define VRCR 0xbc +#define VTCR 0xc0 +#define VDR 0xc4 +#define CCSR 0xcc +#define TBICR 0xe0 +#define TBISR 0xe4 +#define TANAR 0xe8 +#define TANLPAR 0xec +#define TANER 0xf0 +#define TESR 0xf4 +#define M5REG 0xf8 +#define LAST 0xf8 +#define RESERVED 0xfc + +/* Chip Command Register */ +#define CR_TXE 0x00000001 +#define CR_TXD 0x00000002 +#define CR_RXE 0x00000004 +#define CR_RXD 0x00000008 +#define CR_TXR 0x00000010 +#define CR_RXR 0x00000020 +#define CR_SWI 0x00000080 +#define CR_RST 0x00000100 + +/* configuration register */ +#define CFGR_LNKSTS 0x80000000 +#define CFGR_SPDSTS 0x60000000 +#define CFGR_SPDSTS1 0x40000000 +#define CFGR_SPDSTS0 0x20000000 +#define CFGR_DUPSTS 0x10000000 +#define CFGR_TBI_EN 0x01000000 +#define CFGR_RESERVED 0x0e000000 +#define CFGR_MODE_1000 0x00400000 +#define CFGR_AUTO_1000 0x00200000 +#define CFGR_PINT_CTL 0x001c0000 +#define CFGR_PINT_DUPSTS 0x00100000 +#define CFGR_PINT_LNKSTS 0x00080000 +#define CFGR_PINT_SPDSTS 0x00040000 +#define CFGR_TMRTEST 0x00020000 +#define CFGR_MRM_DIS 0x00010000 +#define CFGR_MWI_DIS 0x00008000 +#define CFGR_T64ADDR 0x00004000 +#define CFGR_PCI64_DET 0x00002000 +#define CFGR_DATA64_EN 0x00001000 +#define CFGR_M64ADDR 0x00000800 +#define CFGR_PHY_RST 0x00000400 +#define CFGR_PHY_DIS 0x00000200 +#define CFGR_EXTSTS_EN 0x00000100 +#define CFGR_REQALG 0x00000080 +#define CFGR_SB 0x00000040 +#define CFGR_POW 0x00000020 +#define CFGR_EXD 0x00000010 +#define CFGR_PESEL 0x00000008 +#define CFGR_BROM_DIS 0x00000004 +#define CFGR_EXT_125 0x00000002 +#define CFGR_BEM 0x00000001 + +/* EEPROM access register */ +#define MEAR_EEDI 0x00000001 +#define MEAR_EEDO 0x00000002 +#define MEAR_EECLK 0x00000004 +#define MEAR_EESEL 0x00000008 +#define MEAR_MDIO 0x00000010 +#define MEAR_MDDIR 0x00000020 +#define MEAR_MDC 0x00000040 + +/* PCI test control register */ +#define PTSCR_EEBIST_FAIL 0x00000001 +#define PTSCR_EEBIST_EN 0x00000002 +#define PTSCR_EELOAD_EN 0x00000004 +#define PTSCR_RBIST_FAIL 0x000001b8 +#define PTSCR_RBIST_DONE 0x00000200 +#define PTSCR_RBIST_EN 0x00000400 +#define PTSCR_RBIST_RST 0x00002000 +#define PTSCR_RBIST_RDONLY 0x000003f9 + +/* interrupt status register */ +#define ISR_RESERVE 0x80000000 +#define ISR_TXDESC3 0x40000000 +#define ISR_TXDESC2 0x20000000 +#define ISR_TXDESC1 0x10000000 +#define ISR_TXDESC0 0x08000000 +#define ISR_RXDESC3 0x04000000 +#define ISR_RXDESC2 0x02000000 +#define ISR_RXDESC1 0x01000000 +#define ISR_RXDESC0 0x00800000 +#define ISR_TXRCMP 0x00400000 +#define ISR_RXRCMP 0x00200000 +#define ISR_DPERR 0x00100000 +#define ISR_SSERR 0x00080000 +#define ISR_RMABT 0x00040000 +#define ISR_RTABT 0x00020000 +#define ISR_RXSOVR 0x00010000 +#define ISR_HIBINT 0x00008000 +#define ISR_PHY 0x00004000 +#define ISR_PME 0x00002000 +#define ISR_SWI 0x00001000 +#define ISR_MIB 0x00000800 +#define ISR_TXURN 0x00000400 +#define ISR_TXIDLE 0x00000200 +#define ISR_TXERR 0x00000100 +#define ISR_TXDESC 0x00000080 +#define ISR_TXOK 0x00000040 +#define ISR_RXORN 0x00000020 +#define ISR_RXIDLE 0x00000010 +#define ISR_RXEARLY 0x00000008 +#define ISR_RXERR 0x00000004 +#define ISR_RXDESC 0x00000002 +#define ISR_RXOK 0x00000001 +#define ISR_ALL 0x7FFFFFFF +#define ISR_DELAY (ISR_TXIDLE|ISR_TXDESC|ISR_TXOK| \ + ISR_RXIDLE|ISR_RXDESC|ISR_RXOK) +#define ISR_NODELAY (ISR_ALL & ~ISR_DELAY) +#define ISR_IMPL (ISR_SWI|ISR_TXIDLE|ISR_TXDESC|ISR_TXOK|ISR_RXORN| \ + ISR_RXIDLE|ISR_RXDESC|ISR_RXOK) +#define ISR_NOIMPL (ISR_ALL & ~ISR_IMPL) + +/* transmit configuration register */ +#define TX_CFG_CSI 0x80000000 +#define TX_CFG_HBI 0x40000000 +#define TX_CFG_MLB 0x20000000 +#define TX_CFG_ATP 0x10000000 +#define TX_CFG_ECRETRY 0x00800000 +#define TX_CFG_BRST_DIS 0x00080000 +#define TX_CFG_MXDMA1024 0x00000000 +#define TX_CFG_MXDMA512 0x00700000 +#define TX_CFG_MXDMA256 0x00600000 +#define TX_CFG_MXDMA128 0x00500000 +#define TX_CFG_MXDMA64 0x00400000 +#define TX_CFG_MXDMA32 0x00300000 +#define TX_CFG_MXDMA16 0x00200000 +#define TX_CFG_MXDMA8 0x00100000 +#define TX_CFG_MXDMA 0x00700000 + +#define TX_CFG_FLTH_MASK 0x0000ff00 +#define TX_CFG_DRTH_MASK 0x000000ff + +/*general purpose I/O control register */ +#define GPIOR_UNUSED 0xffff8000 +#define GPIOR_GP5_IN 0x00004000 +#define GPIOR_GP4_IN 0x00002000 +#define GPIOR_GP3_IN 0x00001000 +#define GPIOR_GP2_IN 0x00000800 +#define GPIOR_GP1_IN 0x00000400 +#define GPIOR_GP5_OE 0x00000200 +#define GPIOR_GP4_OE 0x00000100 +#define GPIOR_GP3_OE 0x00000080 +#define GPIOR_GP2_OE 0x00000040 +#define GPIOR_GP1_OE 0x00000020 +#define GPIOR_GP5_OUT 0x00000010 +#define GPIOR_GP4_OUT 0x00000008 +#define GPIOR_GP3_OUT 0x00000004 +#define GPIOR_GP2_OUT 0x00000002 +#define GPIOR_GP1_OUT 0x00000001 + +/* receive configuration register */ +#define RX_CFG_AEP 0x80000000 +#define RX_CFG_ARP 0x40000000 +#define RX_CFG_STRIPCRC 0x20000000 +#define RX_CFG_RX_FD 0x10000000 +#define RX_CFG_ALP 0x08000000 +#define RX_CFG_AIRL 0x04000000 +#define RX_CFG_MXDMA512 0x00700000 +#define RX_CFG_MXDMA 0x00700000 +#define RX_CFG_DRTH 0x0000003e +#define RX_CFG_DRTH0 0x00000002 + +/* pause control status register */ +#define PCR_PSEN (1 << 31) +#define PCR_PS_MCAST (1 << 30) +#define PCR_PS_DA (1 << 29) +#define PCR_STHI_8 (3 << 23) +#define PCR_STLO_4 (1 << 23) +#define PCR_FFHI_8K (3 << 21) +#define PCR_FFLO_4K (1 << 21) +#define PCR_PAUSE_CNT 0xFFFE + +/*receive filter/match control register */ +#define RFCR_RFEN 0x80000000 +#define RFCR_AAB 0x40000000 +#define RFCR_AAM 0x20000000 +#define RFCR_AAU 0x10000000 +#define RFCR_APM 0x08000000 +#define RFCR_APAT 0x07800000 +#define RFCR_APAT3 0x04000000 +#define RFCR_APAT2 0x02000000 +#define RFCR_APAT1 0x01000000 +#define RFCR_APAT0 0x00800000 +#define RFCR_AARP 0x00400000 +#define RFCR_MHEN 0x00200000 +#define RFCR_UHEN 0x00100000 +#define RFCR_ULM 0x00080000 +#define RFCR_RFADDR 0x000003ff + +/* receive filter/match data register */ +#define RFDR_BMASK 0x00030000 +#define RFDR_RFDATA0 0x000000ff +#define RFDR_RFDATA1 0x0000ff00 + +/* management information base control register */ +#define MIBC_MIBS 0x00000008 +#define MIBC_ACLR 0x00000004 +#define MIBC_FRZ 0x00000002 +#define MIBC_WRN 0x00000001 + +/* VLAN/IP receive control register */ +#define VRCR_RUDPE 0x00000080 +#define VRCR_RTCPE 0x00000040 +#define VRCR_RIPE 0x00000020 +#define VRCR_IPEN 0x00000010 +#define VRCR_DUTF 0x00000008 +#define VRCR_DVTF 0x00000004 +#define VRCR_VTREN 0x00000002 +#define VRCR_VTDEN 0x00000001 + +/* VLAN/IP transmit control register */ +#define VTCR_PPCHK 0x00000008 +#define VTCR_GCHK 0x00000004 +#define VTCR_VPPTI 0x00000002 +#define VTCR_VGTI 0x00000001 + +/* Clockrun Control/Status Register */ +#define CCSR_CLKRUN_EN 0x00000001 + +/* TBI control register */ +#define TBICR_MR_LOOPBACK 0x00004000 +#define TBICR_MR_AN_ENABLE 0x00001000 +#define TBICR_MR_RESTART_AN 0x00000200 + +/* TBI status register */ +#define TBISR_MR_LINK_STATUS 0x00000020 +#define TBISR_MR_AN_COMPLETE 0x00000004 + +/* TBI auto-negotiation advertisement register */ +#define TANAR_NP 0x00008000 +#define TANAR_RF2 0x00002000 +#define TANAR_RF1 0x00001000 +#define TANAR_PS2 0x00000100 +#define TANAR_PS1 0x00000080 +#define TANAR_HALF_DUP 0x00000040 +#define TANAR_FULL_DUP 0x00000020 +#define TANAR_UNUSED 0x00000E1F + +/* M5 control register */ +#define M5REG_RESERVED 0xfffffffc +#define M5REG_RSS 0x00000004 +#define M5REG_RX_THREAD 0x00000002 +#define M5REG_TX_THREAD 0x00000001 + +struct ns_desc32 { + uint32_t link; /* link field to next descriptor in linked list */ + uint32_t bufptr; /* pointer to the first fragment or buffer */ + uint32_t cmdsts; /* command/status field */ + uint32_t extsts; /* extended status field for VLAN and IP info */ +}; + +struct ns_desc64 { + uint64_t link; /* link field to next descriptor in linked list */ + uint64_t bufptr; /* pointer to the first fragment or buffer */ + uint32_t cmdsts; /* command/status field */ + uint32_t extsts; /* extended status field for VLAN and IP info */ +}; + +/* cmdsts flags for descriptors */ +#define CMDSTS_OWN 0x80000000 +#define CMDSTS_MORE 0x40000000 +#define CMDSTS_INTR 0x20000000 +#define CMDSTS_ERR 0x10000000 +#define CMDSTS_OK 0x08000000 +#define CMDSTS_LEN_MASK 0x0000ffff + +#define CMDSTS_DEST_MASK 0x01800000 +#define CMDSTS_DEST_SELF 0x00800000 +#define CMDSTS_DEST_MULTI 0x01000000 + +/* extended flags for descriptors */ +#define EXTSTS_UDPERR 0x00400000 +#define EXTSTS_UDPPKT 0x00200000 +#define EXTSTS_TCPERR 0x00100000 +#define EXTSTS_TCPPKT 0x00080000 +#define EXTSTS_IPERR 0x00040000 +#define EXTSTS_IPPKT 0x00020000 + + +/* speed status */ +#define SPDSTS_POLARITY (CFGR_SPDSTS1 | CFGR_SPDSTS0 | CFGR_DUPSTS | (lnksts ? CFGR_LNKSTS : 0)) + +#endif /* __DEV_NS_GIGE_REG_H__ */ diff --git a/src/dev/pciconfigall.cc b/src/dev/pciconfigall.cc new file mode 100644 index 000000000..785774ff4 --- /dev/null +++ b/src/dev/pciconfigall.cc @@ -0,0 +1,224 @@ +/* + * 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: Andrew Schultz + * Ali Saidi + */ + +/* @file + * PCI Configspace implementation + */ + +#include <deque> +#include <string> +#include <vector> +#include <bitset> + +#include "base/trace.hh" +#include "dev/pciconfigall.hh" +#include "dev/pcidev.hh" +#include "dev/pcireg.h" +#include "dev/platform.hh" +#include "mem/packet.hh" +#include "sim/builder.hh" +#include "sim/system.hh" + +using namespace std; + +PciConfigAll::PciConfigAll(Params *p) + : BasicPioDevice(p) +{ + pioSize = 0xffffff; + + // Set backpointer for pci config. Really the config stuff should be able to + // automagically do this + p->platform->pciconfig = this; + + // Make all the pointers to devices null + for(int x=0; x < MAX_PCI_DEV; x++) + for(int y=0; y < MAX_PCI_FUNC; y++) + devices[x][y] = NULL; +} + +// If two interrupts share the same line largely bad things will happen. +// Since we don't track how many times an interrupt was set and correspondingly +// cleared two devices on the same interrupt line and assert and deassert each +// others interrupt "line". Interrupts will not work correctly. +void +PciConfigAll::startup() +{ + bitset<256> intLines; + PciDev *tempDev; + uint8_t intline; + + for (int x = 0; x < MAX_PCI_DEV; x++) { + for (int y = 0; y < MAX_PCI_FUNC; y++) { + if (devices[x][y] != NULL) { + tempDev = devices[x][y]; + intline = tempDev->interruptLine(); + if (intLines.test(intline)) + warn("Interrupt line %#X is used multiple times" + "(You probably want to fix this).\n", (uint32_t)intline); + else + intLines.set(intline); + } // devices != NULL + } // PCI_FUNC + } // PCI_DEV + +} + +Tick +PciConfigAll::read(Packet *pkt) +{ + assert(pkt->result == Packet::Unknown); + assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); + + Addr daddr = pkt->getAddr() - pioAddr; + int device = (daddr >> 11) & 0x1F; + int func = (daddr >> 8) & 0x7; + int reg = daddr & 0xFF; + + pkt->allocate(); + + DPRINTF(PciConfigAll, "read va=%#x da=%#x size=%d\n", pkt->getAddr(), daddr, + pkt->getSize()); + + switch (pkt->getSize()) { + case sizeof(uint32_t): + if (devices[device][func] == NULL) + pkt->set<uint32_t>(0xFFFFFFFF); + else + devices[device][func]->readConfig(reg, pkt->getPtr<uint32_t>()); + break; + case sizeof(uint16_t): + if (devices[device][func] == NULL) + pkt->set<uint16_t>(0xFFFF); + else + devices[device][func]->readConfig(reg, pkt->getPtr<uint16_t>()); + break; + case sizeof(uint8_t): + if (devices[device][func] == NULL) + pkt->set<uint8_t>(0xFF); + else + devices[device][func]->readConfig(reg, pkt->getPtr<uint8_t>()); + break; + default: + panic("invalid access size(?) for PCI configspace!\n"); + } + pkt->result = Packet::Success; + return pioDelay; +} + +Tick +PciConfigAll::write(Packet *pkt) +{ + assert(pkt->result == Packet::Unknown); + assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); + assert(pkt->getSize() == sizeof(uint8_t) || pkt->getSize() == sizeof(uint16_t) || + pkt->getSize() == sizeof(uint32_t)); + Addr daddr = pkt->getAddr() - pioAddr; + + int device = (daddr >> 11) & 0x1F; + int func = (daddr >> 8) & 0x7; + int reg = daddr & 0xFF; + + if (devices[device][func] == NULL) + panic("Attempting to write to config space on non-existant device\n"); + + DPRINTF(PciConfigAll, "write - va=%#x size=%d data=%#x\n", + pkt->getAddr(), pkt->getSize(), pkt->get<uint32_t>()); + + switch (pkt->getSize()) { + case sizeof(uint8_t): + devices[device][func]->writeConfig(reg, pkt->get<uint8_t>()); + break; + case sizeof(uint16_t): + devices[device][func]->writeConfig(reg, pkt->get<uint16_t>()); + break; + case sizeof(uint32_t): + devices[device][func]->writeConfig(reg, pkt->get<uint32_t>()); + break; + default: + panic("invalid pci config write size\n"); + } + pkt->result = Packet::Success; + return pioDelay; +} + +void +PciConfigAll::serialize(std::ostream &os) +{ + /* + * There is no state associated with this object that requires + * serialization. The only real state are the device pointers + * which are all setup by the constructor of the PciDev class + */ +} + +void +PciConfigAll::unserialize(Checkpoint *cp, const std::string §ion) +{ + /* + * There is no state associated with this object that requires + * serialization. The only real state are the device pointers + * which are all setup by the constructor of the PciDev class + */ +} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(PciConfigAll) + + Param<Addr> pio_addr; + Param<Tick> pio_latency; + SimObjectParam<Platform *> platform; + SimObjectParam<System *> system; + +END_DECLARE_SIM_OBJECT_PARAMS(PciConfigAll) + +BEGIN_INIT_SIM_OBJECT_PARAMS(PciConfigAll) + + INIT_PARAM(pio_addr, "Device Address"), + INIT_PARAM(pio_latency, "Programmed IO latency"), + INIT_PARAM(platform, "platform"), + INIT_PARAM(system, "system object") + +END_INIT_SIM_OBJECT_PARAMS(PciConfigAll) + +CREATE_SIM_OBJECT(PciConfigAll) +{ + BasicPioDevice::Params *p = new BasicPioDevice::Params; + p->pio_addr = pio_addr; + p->pio_delay = pio_latency; + p->platform = platform; + p->system = system; + return new PciConfigAll(p); +} + +REGISTER_SIM_OBJECT("PciConfigAll", PciConfigAll) + +#endif // DOXYGEN_SHOULD_SKIP_THIS diff --git a/src/dev/pciconfigall.hh b/src/dev/pciconfigall.hh new file mode 100644 index 000000000..e60fd949b --- /dev/null +++ b/src/dev/pciconfigall.hh @@ -0,0 +1,131 @@ +/* + * 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: Andrew Schultz + * Ali Saidi + */ + +/* + * @file + * PCI Config space implementation. + */ + +#ifndef __PCICONFIGALL_HH__ +#define __PCICONFIGALL_HH__ + +#include "dev/pcireg.h" +#include "base/range.hh" +#include "dev/io_device.hh" + + +static const uint32_t MAX_PCI_DEV = 32; +static const uint32_t MAX_PCI_FUNC = 8; + +class PciDev; + +/** + * PCI Config Space + * All of PCI config space needs to return -1 on Tsunami, except + * the devices that exist. This device maps the entire bus config + * space and passes the requests on to TsunamiPCIDev devices as + * appropriate. + */ +class PciConfigAll : public BasicPioDevice +{ + private: + /** + * Pointers to all the devices that are registered with this + * particular config space. + */ + PciDev* devices[MAX_PCI_DEV][MAX_PCI_FUNC]; + + public: + /** + * Constructor for PCIConfigAll + * @param p parameters structure + */ + PciConfigAll(Params *p); + + /** + * Check if a device exists. + * @param pcidev PCI device to check + * @param pcifunc PCI function to check + * @return true if device exists, false otherwise + */ + bool deviceExists(uint32_t pcidev, uint32_t pcifunc) + { return devices[pcidev][pcifunc] != NULL ? true : false; } + + /** + * Registers a device with the config space object. + * @param pcidev PCI device to register + * @param pcifunc PCI function to register + * @param device device to register + */ + void registerDevice(uint8_t pcidev, uint8_t pcifunc, PciDev *device) + { devices[pcidev][pcifunc] = device; } + + /** + * Read something in PCI config space. If the device does not exist + * -1 is returned, if the device does exist its PciDev::ReadConfig (or the + * virtual function that overrides) it is called. + * @param pkt Contains the address of the field to read. + * @return Amount of time to do the read + */ + virtual Tick read(Packet *pkt); + + /** + * Write to PCI config spcae. If the device does not exit the simulator + * panics. If it does it is passed on the PciDev::WriteConfig (or the virtual + * function that overrides it). + * @param req Contains the address to write to. + * @param data The data to write. + * @return The fault condition of the access. + */ + + virtual Tick write(Packet *pkt); + + /** + * Start up function to check if more than one person is using an interrupt line + * and print a warning if such a case exists + */ + virtual void startup(); + + /** + * Serialize this object to the given output stream. + * @param os The stream to serialize to. + */ + virtual void serialize(std::ostream &os); + + /** + * Reconstruct the state of this object from a checkpoint. + * @param cp The checkpoint use. + * @param section The section name of this object + */ + virtual void unserialize(Checkpoint *cp, const std::string §ion); +}; + +#endif // __PCICONFIGALL_HH__ diff --git a/src/dev/pcidev.cc b/src/dev/pcidev.cc new file mode 100644 index 000000000..f8db2efbc --- /dev/null +++ b/src/dev/pcidev.cc @@ -0,0 +1,390 @@ +/* + * 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: Ali Saidi + * Andrew Schultz + * Miguel Serrano + */ + +/* @file + * A single PCI device configuration space entry. + */ + +#include <list> +#include <string> +#include <vector> + +#include "base/inifile.hh" +#include "base/misc.hh" +#include "base/str.hh" // for to_number +#include "base/trace.hh" +#include "dev/pciconfigall.hh" +#include "dev/pcidev.hh" +#include "dev/tsunamireg.h" +#include "mem/packet.hh" +#include "sim/builder.hh" +#include "sim/byteswap.hh" +#include "sim/param.hh" +#include "sim/root.hh" + +using namespace std; + +PciDev::PciDev(Params *p) + : DmaDevice(p), plat(p->platform), configData(p->configData), + pioDelay(p->pio_delay) +{ + // copy the config data from the PciConfigData object + if (configData) { + memcpy(config.data, configData->config.data, sizeof(config.data)); + memcpy(BARSize, configData->BARSize, sizeof(BARSize)); + memcpy(BARAddrs, configData->BARAddrs, sizeof(BARAddrs)); + } else + panic("NULL pointer to configuration data"); + + // Setup pointer in config space to point to this entry + if (p->configSpace->deviceExists(p->deviceNum, p->functionNum)) + panic("Two PCI devices occuping same dev: %#x func: %#x", + p->deviceNum, p->functionNum); + else + p->configSpace->registerDevice(p->deviceNum, p->functionNum, this); +} + +void +PciDev::readConfig(int offset, uint8_t *data) +{ + if (offset >= PCI_DEVICE_SPECIFIC) + panic("Device specific PCI config space not implemented!\n"); + + *data = config.data[offset]; + + DPRINTF(PCIDEV, + "read device: %#x function: %#x register: %#x 1 bytes: data: %#x\n", + params()->deviceNum, params()->functionNum, offset, *data); +} + +void +PciDev::addressRanges(AddrRangeList &range_list) +{ + int x = 0; + range_list.clear(); + for (x = 0; x < 6; x++) + if (BARAddrs[x] != 0) + range_list.push_back(RangeSize(BARAddrs[x],BARSize[x])); +} + +void +PciDev::readConfig(int offset, uint16_t *data) +{ + if (offset >= PCI_DEVICE_SPECIFIC) + panic("Device specific PCI config space not implemented!\n"); + + *data = *(uint16_t*)&config.data[offset]; + + DPRINTF(PCIDEV, + "read device: %#x function: %#x register: %#x 2 bytes: data: %#x\n", + params()->deviceNum, params()->functionNum, offset, *data); +} + +void +PciDev::readConfig(int offset, uint32_t *data) +{ + if (offset >= PCI_DEVICE_SPECIFIC) + panic("Device specific PCI config space not implemented!\n"); + + *data = *(uint32_t*)&config.data[offset]; + + DPRINTF(PCIDEV, + "read device: %#x function: %#x register: %#x 4 bytes: data: %#x\n", + params()->deviceNum, params()->functionNum, offset, *data); +} + + +void +PciDev::writeConfig(int offset, const uint8_t data) +{ + if (offset >= PCI_DEVICE_SPECIFIC) + panic("Device specific PCI config space not implemented!\n"); + + DPRINTF(PCIDEV, + "write device: %#x function: %#x reg: %#x size: 1 data: %#x\n", + params()->deviceNum, params()->functionNum, offset, data); + + switch (offset) { + case PCI0_INTERRUPT_LINE: + config.interruptLine = data; + case PCI_CACHE_LINE_SIZE: + config.cacheLineSize = data; + case PCI_LATENCY_TIMER: + config.latencyTimer = data; + break; + /* Do nothing for these read-only registers */ + case PCI0_INTERRUPT_PIN: + case PCI0_MINIMUM_GRANT: + case PCI0_MAXIMUM_LATENCY: + case PCI_CLASS_CODE: + case PCI_REVISION_ID: + break; + default: + panic("writing to a read only register"); + } +} + +void +PciDev::writeConfig(int offset, const uint16_t data) +{ + if (offset >= PCI_DEVICE_SPECIFIC) + panic("Device specific PCI config space not implemented!\n"); + + DPRINTF(PCIDEV, + "write device: %#x function: %#x reg: %#x size: 2 data: %#x\n", + params()->deviceNum, params()->functionNum, offset, data); + + switch (offset) { + case PCI_COMMAND: + config.command = data; + case PCI_STATUS: + config.status = data; + case PCI_CACHE_LINE_SIZE: + config.cacheLineSize = data; + break; + default: + panic("writing to a read only register"); + } +} + + +void +PciDev::writeConfig(int offset, const uint32_t data) +{ + if (offset >= PCI_DEVICE_SPECIFIC) + panic("Device specific PCI config space not implemented!\n"); + + DPRINTF(PCIDEV, + "write device: %#x function: %#x reg: %#x size: 4 data: %#x\n", + params()->deviceNum, params()->functionNum, offset, data); + + switch (offset) { + case PCI0_BASE_ADDR0: + case PCI0_BASE_ADDR1: + case PCI0_BASE_ADDR2: + case PCI0_BASE_ADDR3: + case PCI0_BASE_ADDR4: + case PCI0_BASE_ADDR5: + + uint32_t barnum, bar_mask; + Addr base_addr, base_size, space_base; + + barnum = BAR_NUMBER(offset); + + if (BAR_IO_SPACE(letoh(config.baseAddr[barnum]))) { + bar_mask = BAR_IO_MASK; + space_base = TSUNAMI_PCI0_IO; + } else { + bar_mask = BAR_MEM_MASK; + space_base = TSUNAMI_PCI0_MEMORY; + } + + // Writing 0xffffffff to a BAR tells the card to set the + // value of the bar to size of memory it needs + if (letoh(data) == 0xffffffff) { + // This is I/O Space, bottom two bits are read only + + config.baseAddr[barnum] = letoh( + (~(BARSize[barnum] - 1) & ~bar_mask) | + (letoh(config.baseAddr[barnum]) & bar_mask)); + } else { + config.baseAddr[barnum] = letoh( + (letoh(data) & ~bar_mask) | + (letoh(config.baseAddr[barnum]) & bar_mask)); + + if (letoh(config.baseAddr[barnum]) & ~bar_mask) { + base_addr = (letoh(data) & ~bar_mask) + space_base; + base_size = BARSize[barnum]; + BARAddrs[barnum] = base_addr; + + pioPort->sendStatusChange(Port::RangeChange); + } + } + break; + + case PCI0_ROM_BASE_ADDR: + if (letoh(data) == 0xfffffffe) + config.expansionROM = htole((uint32_t)0xffffffff); + else + config.expansionROM = data; + break; + + case PCI_COMMAND: + // This could also clear some of the error bits in the Status + // register. However they should never get set, so lets ignore + // it for now + config.command = data; + break; + + default: + DPRINTF(PCIDEV, "Writing to a read only register"); + } +} + +void +PciDev::serialize(ostream &os) +{ + SERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0])); + SERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0])); + SERIALIZE_ARRAY(config.data, sizeof(config.data) / sizeof(config.data[0])); +} + +void +PciDev::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_ARRAY(BARSize, sizeof(BARSize) / sizeof(BARSize[0])); + UNSERIALIZE_ARRAY(BARAddrs, sizeof(BARAddrs) / sizeof(BARAddrs[0])); + UNSERIALIZE_ARRAY(config.data, + sizeof(config.data) / sizeof(config.data[0])); +} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(PciConfigData) + + Param<uint16_t> VendorID; + Param<uint16_t> DeviceID; + Param<uint16_t> Command; + Param<uint16_t> Status; + Param<uint8_t> Revision; + Param<uint8_t> ProgIF; + Param<uint8_t> SubClassCode; + Param<uint8_t> ClassCode; + Param<uint8_t> CacheLineSize; + Param<uint8_t> LatencyTimer; + Param<uint8_t> HeaderType; + Param<uint8_t> BIST; + Param<uint32_t> BAR0; + Param<uint32_t> BAR1; + Param<uint32_t> BAR2; + Param<uint32_t> BAR3; + Param<uint32_t> BAR4; + Param<uint32_t> BAR5; + Param<uint32_t> CardbusCIS; + Param<uint16_t> SubsystemVendorID; + Param<uint16_t> SubsystemID; + Param<uint32_t> ExpansionROM; + Param<uint8_t> InterruptLine; + Param<uint8_t> InterruptPin; + Param<uint8_t> MinimumGrant; + Param<uint8_t> MaximumLatency; + Param<uint32_t> BAR0Size; + Param<uint32_t> BAR1Size; + Param<uint32_t> BAR2Size; + Param<uint32_t> BAR3Size; + Param<uint32_t> BAR4Size; + Param<uint32_t> BAR5Size; + +END_DECLARE_SIM_OBJECT_PARAMS(PciConfigData) + +BEGIN_INIT_SIM_OBJECT_PARAMS(PciConfigData) + + INIT_PARAM(VendorID, "Vendor ID"), + INIT_PARAM(DeviceID, "Device ID"), + INIT_PARAM_DFLT(Command, "Command Register", 0x00), + INIT_PARAM_DFLT(Status, "Status Register", 0x00), + INIT_PARAM_DFLT(Revision, "Device Revision", 0x00), + INIT_PARAM_DFLT(ProgIF, "Programming Interface", 0x00), + INIT_PARAM(SubClassCode, "Sub-Class Code"), + INIT_PARAM(ClassCode, "Class Code"), + INIT_PARAM_DFLT(CacheLineSize, "System Cacheline Size", 0x00), + INIT_PARAM_DFLT(LatencyTimer, "PCI Latency Timer", 0x00), + INIT_PARAM_DFLT(HeaderType, "PCI Header Type", 0x00), + INIT_PARAM_DFLT(BIST, "Built In Self Test", 0x00), + INIT_PARAM_DFLT(BAR0, "Base Address Register 0", 0x00), + INIT_PARAM_DFLT(BAR1, "Base Address Register 1", 0x00), + INIT_PARAM_DFLT(BAR2, "Base Address Register 2", 0x00), + INIT_PARAM_DFLT(BAR3, "Base Address Register 3", 0x00), + INIT_PARAM_DFLT(BAR4, "Base Address Register 4", 0x00), + INIT_PARAM_DFLT(BAR5, "Base Address Register 5", 0x00), + INIT_PARAM_DFLT(CardbusCIS, "Cardbus Card Information Structure", 0x00), + INIT_PARAM_DFLT(SubsystemVendorID, "Subsystem Vendor ID", 0x00), + INIT_PARAM_DFLT(SubsystemID, "Subsystem ID", 0x00), + INIT_PARAM_DFLT(ExpansionROM, "Expansion ROM Base Address Register", 0x00), + INIT_PARAM(InterruptLine, "Interrupt Line Register"), + INIT_PARAM(InterruptPin, "Interrupt Pin Register"), + INIT_PARAM_DFLT(MinimumGrant, "Minimum Grant", 0x00), + INIT_PARAM_DFLT(MaximumLatency, "Maximum Latency", 0x00), + INIT_PARAM_DFLT(BAR0Size, "Base Address Register 0 Size", 0x00), + INIT_PARAM_DFLT(BAR1Size, "Base Address Register 1 Size", 0x00), + INIT_PARAM_DFLT(BAR2Size, "Base Address Register 2 Size", 0x00), + INIT_PARAM_DFLT(BAR3Size, "Base Address Register 3 Size", 0x00), + INIT_PARAM_DFLT(BAR4Size, "Base Address Register 4 Size", 0x00), + INIT_PARAM_DFLT(BAR5Size, "Base Address Register 5 Size", 0x00) + +END_INIT_SIM_OBJECT_PARAMS(PciConfigData) + +CREATE_SIM_OBJECT(PciConfigData) +{ + PciConfigData *data = new PciConfigData(getInstanceName()); + + data->config.vendor = htole(VendorID); + data->config.device = htole(DeviceID); + data->config.command = htole(Command); + data->config.status = htole(Status); + data->config.revision = htole(Revision); + data->config.progIF = htole(ProgIF); + data->config.subClassCode = htole(SubClassCode); + data->config.classCode = htole(ClassCode); + data->config.cacheLineSize = htole(CacheLineSize); + data->config.latencyTimer = htole(LatencyTimer); + data->config.headerType = htole(HeaderType); + data->config.bist = htole(BIST); + + data->config.baseAddr0 = htole(BAR0); + data->config.baseAddr1 = htole(BAR1); + data->config.baseAddr2 = htole(BAR2); + data->config.baseAddr3 = htole(BAR3); + data->config.baseAddr4 = htole(BAR4); + data->config.baseAddr5 = htole(BAR5); + data->config.cardbusCIS = htole(CardbusCIS); + data->config.subsystemVendorID = htole(SubsystemVendorID); + data->config.subsystemID = htole(SubsystemVendorID); + data->config.expansionROM = htole(ExpansionROM); + data->config.interruptLine = htole(InterruptLine); + data->config.interruptPin = htole(InterruptPin); + data->config.minimumGrant = htole(MinimumGrant); + data->config.maximumLatency = htole(MaximumLatency); + + data->BARSize[0] = BAR0Size; + data->BARSize[1] = BAR1Size; + data->BARSize[2] = BAR2Size; + data->BARSize[3] = BAR3Size; + data->BARSize[4] = BAR4Size; + data->BARSize[5] = BAR5Size; + + return data; +} + +REGISTER_SIM_OBJECT("PciConfigData", PciConfigData) + +#endif // DOXYGEN_SHOULD_SKIP_THIS diff --git a/src/dev/pcidev.hh b/src/dev/pcidev.hh new file mode 100644 index 000000000..92786427b --- /dev/null +++ b/src/dev/pcidev.hh @@ -0,0 +1,234 @@ +/* + * 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: Ali Saidi + * Andrew Schultz + * Nathan Binkert + */ + +/* @file + * Interface for devices using PCI configuration + */ + +#ifndef __DEV_PCIDEV_HH__ +#define __DEV_PCIDEV_HH__ + +#include "dev/io_device.hh" +#include "dev/pcireg.h" +#include "dev/platform.hh" + +#define BAR_IO_MASK 0x3 +#define BAR_MEM_MASK 0xF +#define BAR_IO_SPACE_BIT 0x1 +#define BAR_IO_SPACE(x) ((x) & BAR_IO_SPACE_BIT) +#define BAR_NUMBER(x) (((x) - PCI0_BASE_ADDR0) >> 0x2); + +class PciConfigAll; + + +/** + * This class encapulates the first 64 bytes of a singles PCI + * devices config space that in configured by the configuration file. + */ +class PciConfigData : public SimObject +{ + public: + /** + * Constructor to initialize the devices config space to 0. + */ + PciConfigData(const std::string &name) + : SimObject(name) + { + memset(config.data, 0, sizeof(config.data)); + memset(BARAddrs, 0, sizeof(BARAddrs)); + memset(BARSize, 0, sizeof(BARSize)); + } + + /** The first 64 bytes */ + PCIConfig config; + + /** The size of the BARs */ + uint32_t BARSize[6]; + + /** The addresses of the BARs */ + Addr BARAddrs[6]; +}; + +/** + * PCI device, base implemnation is only config space. + * Each device is connected to a PCIConfigSpace device + * which returns -1 for everything but the pcidevs that + * register with it. This object registers with the PCIConfig space + * object. + */ +class PciDev : public DmaDevice +{ + public: + struct Params : public ::PioDevice::Params + { + /** + * A pointer to the configspace all object that calls us when + * a read comes to this particular device/function. + */ + PciConfigAll *configSpace; + + /** + * A pointer to the object that contains the first 64 bytes of + * config space + */ + PciConfigData *configData; + + /** The bus number we are on */ + uint32_t busNum; + + /** The device number we have */ + uint32_t deviceNum; + + /** The function number */ + uint32_t functionNum; + + /** The latency for pio accesses. */ + Tick pio_delay; + }; + + public: + const Params *params() const { return (const Params *)_params; } + + protected: + /** The current config space. Unlike the PciConfigData this is + * updated during simulation while continues to reflect what was + * in the config file. + */ + PCIConfig config; + + /** The size of the BARs */ + uint32_t BARSize[6]; + + /** The current address mapping of the BARs */ + Addr BARAddrs[6]; + + bool + isBAR(Addr addr, int bar) const + { + assert(bar >= 0 && bar < 6); + return BARAddrs[bar] <= addr && addr < BARAddrs[bar] + BARSize[bar]; + } + + int + getBAR(Addr addr) + { + for (int i = 0; i <= 5; ++i) + if (isBAR(addr, i)) + return i; + + return -1; + } + + bool + getBAR(Addr paddr, Addr &daddr, int &bar) + { + int b = getBAR(paddr); + if (b < 0) + return false; + + daddr = paddr - BARAddrs[b]; + bar = b; + return true; + } + + protected: + Platform *plat; + PciConfigData *configData; + Tick pioDelay; + + public: + Addr pciToDma(Addr pciAddr) const + { return plat->pciToDma(pciAddr); } + + void + intrPost() + { plat->postPciInt(configData->config.interruptLine); } + + void + intrClear() + { plat->clearPciInt(configData->config.interruptLine); } + + uint8_t + interruptLine() + { return configData->config.interruptLine; } + + /** return the address ranges that this device responds to. + * @params range_list range list to populate with ranges + */ + void addressRanges(AddrRangeList &range_list); + + /** + * Constructor for PCI Dev. This function copies data from the + * config file object PCIConfigData and registers the device with + * a PciConfigAll object. + */ + PciDev(Params *params); + + /** + * Write to the PCI config space data that is stored locally. This may be + * overridden by the device but at some point it will eventually call this + * for normal operations that it does not need to override. + * @param offset the offset into config space + * @param size the size of the write + * @param data the data to write + */ + virtual void writeConfig(int offset, const uint8_t data); + virtual void writeConfig(int offset, const uint16_t data); + virtual void writeConfig(int offset, const uint32_t data); + + + /** + * Read from the PCI config space data that is stored locally. This may be + * overridden by the device but at some point it will eventually call this + * for normal operations that it does not need to override. + * @param offset the offset into config space + * @param size the size of the read + * @param data pointer to the location where the read value should be stored + */ + virtual void readConfig(int offset, uint8_t *data); + virtual void readConfig(int offset, uint16_t *data); + virtual void readConfig(int offset, uint32_t *data); + + /** + * Serialize this object to the given output stream. + * @param os The stream to serialize to. + */ + virtual void serialize(std::ostream &os); + + /** + * Reconstruct the state of this object from a checkpoint. + * @param cp The checkpoint use. + * @param section The section name of this object + */ + virtual void unserialize(Checkpoint *cp, const std::string §ion); +}; +#endif // __DEV_PCIDEV_HH__ diff --git a/src/dev/pcireg.h b/src/dev/pcireg.h new file mode 100644 index 000000000..0aa4ba8ef --- /dev/null +++ b/src/dev/pcireg.h @@ -0,0 +1,159 @@ +/* + * 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 + * Miguel Serrano + */ + +/* @file + * Device register definitions for a device's PCI config space + */ + +#ifndef __PCIREG_H__ +#define __PCIREG_H__ + +#include <sys/types.h> + +union PCIConfig { + uint8_t data[64]; + + struct { + uint16_t vendor; + uint16_t device; + uint16_t command; + uint16_t status; + uint8_t revision; + uint8_t progIF; + uint8_t subClassCode; + uint8_t classCode; + uint8_t cacheLineSize; + uint8_t latencyTimer; + uint8_t headerType; + uint8_t bist; + union { + uint32_t baseAddr[6]; + + struct { + uint32_t baseAddr0; + uint32_t baseAddr1; + uint32_t baseAddr2; + uint32_t baseAddr3; + uint32_t baseAddr4; + uint32_t baseAddr5; + }; + }; + uint32_t cardbusCIS; + uint16_t subsystemVendorID; + uint16_t subsystemID; + uint32_t expansionROM; + uint32_t reserved0; + uint32_t reserved1; + uint8_t interruptLine; + uint8_t interruptPin; + uint8_t minimumGrant; + uint8_t maximumLatency; + }; +}; + +// Common PCI offsets +#define PCI_VENDOR_ID 0x00 // Vendor ID ro +#define PCI_DEVICE_ID 0x02 // Device ID ro +#define PCI_COMMAND 0x04 // Command rw +#define PCI_STATUS 0x06 // Status rw +#define PCI_REVISION_ID 0x08 // Revision ID ro +#define PCI_CLASS_CODE 0x09 // Class Code ro +#define PCI_SUB_CLASS_CODE 0x0A // Sub Class Code ro +#define PCI_BASE_CLASS_CODE 0x0B // Base Class Code ro +#define PCI_CACHE_LINE_SIZE 0x0C // Cache Line Size ro+ +#define PCI_LATENCY_TIMER 0x0D // Latency Timer ro+ +#define PCI_HEADER_TYPE 0x0E // Header Type ro +#define PCI_BIST 0x0F // Built in self test rw + +// some pci command reg bitfields +#define PCI_CMD_BME 0x04 // Bus master function enable +#define PCI_CMD_MSE 0x02 // Memory Space Access enable +#define PCI_CMD_IOSE 0x01 // I/O space enable + +// Type 0 PCI offsets +#define PCI0_BASE_ADDR0 0x10 // Base Address 0 rw +#define PCI0_BASE_ADDR1 0x14 // Base Address 1 rw +#define PCI0_BASE_ADDR2 0x18 // Base Address 2 rw +#define PCI0_BASE_ADDR3 0x1C // Base Address 3 rw +#define PCI0_BASE_ADDR4 0x20 // Base Address 4 rw +#define PCI0_BASE_ADDR5 0x24 // Base Address 5 rw +#define PCI0_CIS 0x28 // CardBus CIS Pointer ro +#define PCI0_SUB_VENDOR_ID 0x2C // Sub-Vendor ID ro +#define PCI0_SUB_SYSTEM_ID 0x2E // Sub-System ID ro +#define PCI0_ROM_BASE_ADDR 0x30 // Expansion ROM Base Address rw +#define PCI0_RESERVED0 0x34 +#define PCI0_RESERVED1 0x38 +#define PCI0_INTERRUPT_LINE 0x3C // Interrupt Line rw +#define PCI0_INTERRUPT_PIN 0x3D // Interrupt Pin ro +#define PCI0_MINIMUM_GRANT 0x3E // Maximum Grant ro +#define PCI0_MAXIMUM_LATENCY 0x3F // Maximum Latency ro + +// Type 1 PCI offsets +#define PCI1_BASE_ADDR0 0x10 // Base Address 0 rw +#define PCI1_BASE_ADDR1 0x14 // Base Address 1 rw +#define PCI1_PRI_BUS_NUM 0x18 // Primary Bus Number rw +#define PCI1_SEC_BUS_NUM 0x19 // Secondary Bus Number rw +#define PCI1_SUB_BUS_NUM 0x1A // Subordinate Bus Number rw +#define PCI1_SEC_LAT_TIMER 0x1B // Secondary Latency Timer ro+ +#define PCI1_IO_BASE 0x1C // I/O Base rw +#define PCI1_IO_LIMIT 0x1D // I/O Limit rw +#define PCI1_SECONDARY_STATUS 0x1E // Secondary Status rw +#define PCI1_MEM_BASE 0x20 // Memory Base rw +#define PCI1_MEM_LIMIT 0x22 // Memory Limit rw +#define PCI1_PRF_MEM_BASE 0x24 // Prefetchable Memory Base rw +#define PCI1_PRF_MEM_LIMIT 0x26 // Prefetchable Memory Limit rw +#define PCI1_PRF_BASE_UPPER 0x28 // Prefetchable Base Upper 32 rw +#define PCI1_PRF_LIMIT_UPPER 0x2C // Prefetchable Limit Upper 32 rw +#define PCI1_IO_BASE_UPPER 0x30 // I/O Base Upper 16 bits rw +#define PCI1_IO_LIMIT_UPPER 0x32 // I/O Limit Upper 16 bits rw +#define PCI1_RESERVED 0x34 // Reserved ro +#define PCI1_ROM_BASE_ADDR 0x38 // Expansion ROM Base Address rw +#define PCI1_INTR_LINE 0x3C // Interrupt Line rw +#define PCI1_INTR_PIN 0x3D // Interrupt Pin ro +#define PCI1_BRIDGE_CTRL 0x3E // Bridge Control rw + +// Device specific offsets +#define PCI_DEVICE_SPECIFIC 0x40 // 192 bytes + +// Some Vendor IDs +#define PCI_VENDOR_DEC 0x1011 +#define PCI_VENDOR_NCR 0x101A +#define PCI_VENDOR_QLOGIC 0x1077 +#define PCI_VENDOR_SIMOS 0x1291 + +// Some Product IDs +#define PCI_PRODUCT_DEC_PZA 0x0008 +#define PCI_PRODUCT_NCR_810 0x0001 +#define PCI_PRODUCT_QLOGIC_ISP1020 0x1020 +#define PCI_PRODUCT_SIMOS_SIMOS 0x1291 +#define PCI_PRODUCT_SIMOS_ETHER 0x1292 + +#endif // __PCIREG_H__ diff --git a/src/dev/pitreg.h b/src/dev/pitreg.h new file mode 100644 index 000000000..d42925a41 --- /dev/null +++ b/src/dev/pitreg.h @@ -0,0 +1,75 @@ +/* + * 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: Miguel Serrano + */ + +/* @file + * Device register definitions for a device's PCI config space + */ + +#ifndef __PITREG_H__ +#define __PITREG_H__ + +#include <sys/types.h> + +// Control Word Format + +#define PIT_SEL_SHFT 0x6 +#define PIT_RW_SHFT 0x4 +#define PIT_MODE_SHFT 0x1 +#define PIT_BCD_SHFT 0x0 + +#define PIT_SEL_MASK 0x3 +#define PIT_RW_MASK 0x3 +#define PIT_MODE_MASK 0x7 +#define PIT_BCD_MASK 0x1 + +#define GET_CTRL_FIELD(x, s, m) (((x) >> s) & m) +#define GET_CTRL_SEL(x) GET_CTRL_FIELD(x, PIT_SEL_SHFT, PIT_SEL_MASK) +#define GET_CTRL_RW(x) GET_CTRL_FIELD(x, PIT_RW_SHFT, PIT_RW_MASK) +#define GET_CTRL_MODE(x) GET_CTRL_FIELD(x, PIT_MODE_SHFT, PIT_MODE_MASK) +#define GET_CTRL_BCD(x) GET_CTRL_FIELD(x, PIT_BCD_SHFT, PIT_BCD_MASK) + +#define PIT_READ_BACK 0x3 + +#define PIT_RW_LATCH_COMMAND 0x0 +#define PIT_RW_LSB_ONLY 0x1 +#define PIT_RW_MSB_ONLY 0x2 +#define PIT_RW_16BIT 0x3 + +#define PIT_MODE_INTTC 0x0 +#define PIT_MODE_ONESHOT 0x1 +#define PIT_MODE_RATEGEN 0x2 +#define PIT_MODE_SQWAVE 0x3 +#define PIT_MODE_SWSTROBE 0x4 +#define PIT_MODE_HWSTROBE 0x5 + +#define PIT_BCD_FALSE 0x0 +#define PIT_BCD_TRUE 0x1 + +#endif // __PITREG_H__ diff --git a/src/dev/pktfifo.cc b/src/dev/pktfifo.cc new file mode 100644 index 000000000..37f7ff680 --- /dev/null +++ b/src/dev/pktfifo.cc @@ -0,0 +1,101 @@ +/* + * 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: Nathan Binkert + */ + +#include "base/misc.hh" +#include "dev/pktfifo.hh" + +using namespace std; + +bool +PacketFifo::copyout(void *dest, int offset, int len) +{ + char *data = (char *)dest; + if (offset + len >= size()) + return false; + + list<EthPacketPtr>::iterator p = fifo.begin(); + list<EthPacketPtr>::iterator end = fifo.end(); + while (len > 0) { + while (offset >= (*p)->length) { + offset -= (*p)->length; + ++p; + } + + if (p == end) + panic("invalid fifo"); + + int size = min((*p)->length - offset, len); + memcpy(data, (*p)->data, size); + offset = 0; + len -= size; + data += size; + ++p; + } + + return true; +} + + +void +PacketFifo::serialize(const string &base, ostream &os) +{ + paramOut(os, base + ".size", _size); + paramOut(os, base + ".maxsize", _maxsize); + paramOut(os, base + ".reserved", _reserved); + paramOut(os, base + ".packets", fifo.size()); + + int i = 0; + list<EthPacketPtr>::iterator p = fifo.begin(); + list<EthPacketPtr>::iterator end = fifo.end(); + while (p != end) { + (*p)->serialize(csprintf("%s.packet%d", base, i), os); + ++p; + ++i; + } +} + +void +PacketFifo::unserialize(const string &base, Checkpoint *cp, + const string §ion) +{ + paramIn(cp, section, base + ".size", _size); +// paramIn(cp, section, base + ".maxsize", _maxsize); + paramIn(cp, section, base + ".reserved", _reserved); + int fifosize; + paramIn(cp, section, base + ".packets", fifosize); + + fifo.clear(); + + for (int i = 0; i < fifosize; ++i) { + EthPacketPtr p = new EthPacketData(16384); + p->unserialize(csprintf("%s.packet%d", base, i), cp, section); + fifo.push_back(p); + } +} diff --git a/src/dev/pktfifo.hh b/src/dev/pktfifo.hh new file mode 100644 index 000000000..45157ba41 --- /dev/null +++ b/src/dev/pktfifo.hh @@ -0,0 +1,170 @@ +/* + * 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: Nathan Binkert + */ + +#ifndef __DEV_PKTFIFO_HH__ +#define __DEV_PKTFIFO_HH__ + +#include <iosfwd> +#include <list> +#include <string> + +#include "dev/etherpkt.hh" +#include "sim/serialize.hh" + +class Checkpoint; +class PacketFifo +{ + public: + typedef std::list<EthPacketPtr> fifo_list; + typedef fifo_list::iterator iterator; + + protected: + std::list<EthPacketPtr> fifo; + int _maxsize; + int _size; + int _reserved; + + public: + explicit PacketFifo(int max) : _maxsize(max), _size(0), _reserved(0) {} + virtual ~PacketFifo() {} + + int packets() const { return fifo.size(); } + int maxsize() const { return _maxsize; } + int size() const { return _size; } + int reserved() const { return _reserved; } + int avail() const { return _maxsize - _size - _reserved; } + bool empty() const { return size() <= 0; } + bool full() const { return avail() <= 0; } + + int reserve(int len = 0) + { + _reserved += len; + assert(avail() >= 0); + return _reserved; + } + + iterator begin() { return fifo.begin(); } + iterator end() { return fifo.end(); } + + EthPacketPtr front() { return fifo.front(); } + + bool push(EthPacketPtr ptr) + { + assert(ptr->length); + assert(_reserved <= ptr->length); + assert(ptr->slack == 0); + if (avail() < ptr->length - _reserved) + return false; + + _size += ptr->length; + fifo.push_back(ptr); + _reserved = 0; + return true; + } + + void pop() + { + if (empty()) + return; + + EthPacketPtr &packet = fifo.front(); + _size -= packet->length; + _size -= packet->slack; + packet->slack = 0; + packet = NULL; + fifo.pop_front(); + } + + void clear() + { + for (iterator i = begin(); i != end(); ++i) + (*i)->slack = 0; + fifo.clear(); + _size = 0; + _reserved = 0; + } + + void remove(iterator i) + { + EthPacketPtr &packet = *i; + if (i != fifo.begin()) { + iterator prev = i; + --prev; + assert(prev != fifo.end()); + (*prev)->slack += packet->length; + } else { + _size -= packet->length; + _size -= packet->slack; + } + + packet->slack = 0; + packet = NULL; + fifo.erase(i); + } + + bool copyout(void *dest, int offset, int len); + + int countPacketsBefore(iterator end) + { + iterator i = fifo.begin(); + int count = 0; + + while (i != end) { + ++count; + ++i; + } + + return count; + } + + int countPacketsAfter(iterator i) + { + iterator end = fifo.end(); + int count = 0; + + while (i != end) { + ++count; + ++i; + } + + return count; + } + + +/** + * Serialization stuff + */ + public: + void serialize(const std::string &base, std::ostream &os); + void unserialize(const std::string &base, + Checkpoint *cp, const std::string §ion); +}; + +#endif // __DEV_PKTFIFO_HH__ diff --git a/src/dev/platform.cc b/src/dev/platform.cc new file mode 100644 index 000000000..ed021e3b6 --- /dev/null +++ b/src/dev/platform.cc @@ -0,0 +1,67 @@ +/* + * 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: Ali Saidi + * Nathan Binkert + */ + +#include "dev/platform.hh" +#include "sim/builder.hh" +#include "sim/sim_exit.hh" + +using namespace std; +using namespace TheISA; + +Platform::Platform(const string &name, IntrControl *intctrl) + : SimObject(name), intrctrl(intctrl) +{ +} + +Platform::~Platform() +{ +} + +void +Platform::postPciInt(int line) +{ + panic("No PCI interrupt support in platform."); +} + +void +Platform::clearPciInt(int line) +{ + panic("No PCI interrupt support in platform."); +} + +Addr +Platform::pciToDma(Addr pciAddr) const +{ + panic("No PCI dma support in platform."); +} + +DEFINE_SIM_OBJECT_CLASS_NAME("Platform", Platform) + diff --git a/src/dev/platform.hh b/src/dev/platform.hh new file mode 100644 index 000000000..bfc229748 --- /dev/null +++ b/src/dev/platform.hh @@ -0,0 +1,75 @@ +/* + * 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: Andrew Schultz + */ + +/** + * @file + * Generic interface for platforms + */ + +#ifndef __DEV_PLATFORM_HH__ +#define __DEV_PLATFORM_HH__ + +#include "sim/sim_object.hh" +#include "arch/isa_traits.hh" + +class PciConfigAll; +class IntrControl; +class SimConsole; +class Uart; +class System; + +class Platform : public SimObject +{ + public: + /** Pointer to the interrupt controller */ + IntrControl *intrctrl; + + /** Pointer to the PCI configuration space */ + PciConfigAll *pciconfig; + + /** Pointer to the UART, set by the uart */ + Uart *uart; + + /** Pointer to the system for info about the memory system. */ + System *system; + + public: + Platform(const std::string &name, IntrControl *intctrl); + virtual ~Platform(); + virtual void init() { if (pciconfig == NULL) panic("PCI Config not set"); } + virtual void postConsoleInt() = 0; + virtual void clearConsoleInt() = 0; + virtual Tick intrFrequency() = 0; + virtual void postPciInt(int line); + virtual void clearPciInt(int line); + virtual Addr pciToDma(Addr pciAddr) const; +}; + +#endif // __DEV_PLATFORM_HH__ diff --git a/src/dev/rtcreg.h b/src/dev/rtcreg.h new file mode 100644 index 000000000..37255777b --- /dev/null +++ b/src/dev/rtcreg.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 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: Ali Saidi + * Miguel Serrano + * Nathan Binkert + */ + +#define RTC_SEC 0x00 +#define RTC_SEC_ALRM 0x01 +#define RTC_MIN 0x02 +#define RTC_MIN_ALRM 0x03 +#define RTC_HR 0x04 +#define RTC_HR_ALRM 0x05 +#define RTC_DOW 0x06 +#define RTC_DOM 0x07 +#define RTC_MON 0x08 +#define RTC_YEAR 0x09 + +#define RTC_STAT_REGA 0x0A +#define RTCA_1024HZ 0x06 /* 1024Hz periodic interrupt frequency */ +#define RTCA_32768HZ 0x20 /* 22-stage divider, 32.768KHz timebase */ +#define RTCA_UIP 0x80 /* 1 = date and time update in progress */ + +#define RTC_STAT_REGB 0x0B +#define RTCB_DST 0x01 /* USA Daylight Savings Time enable */ +#define RTCB_24HR 0x02 /* 0 = 12 hours, 1 = 24 hours */ +#define RTCB_BIN 0x04 /* 0 = BCD, 1 = Binary coded time */ +#define RTCB_SQWE 0x08 /* 1 = output sqare wave at SQW pin */ +#define RTCB_UPDT_IE 0x10 /* 1 = enable update-ended interrupt */ +#define RTCB_ALRM_IE 0x20 /* 1 = enable alarm interrupt */ +#define RTCB_PRDC_IE 0x40 /* 1 = enable periodic clock interrupt */ +#define RTCB_NO_UPDT 0x80 /* stop clock updates */ + +#define RTC_STAT_REGC 0x0C +#define RTC_STAT_REGD 0x0D + diff --git a/src/dev/simconsole.cc b/src/dev/simconsole.cc new file mode 100644 index 000000000..77aafd9fa --- /dev/null +++ b/src/dev/simconsole.cc @@ -0,0 +1,416 @@ +/* + * 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 + * Ali Saidi + */ + +/* @file + * Implements the user interface to a serial console + */ + +#include <sys/ioctl.h> +#include <sys/termios.h> +#include <sys/types.h> +#include <errno.h> +#include <poll.h> +#include <unistd.h> + +#include <iostream> +#include <fstream> +#include <sstream> +#include <string> + +#include "base/misc.hh" +#include "base/output.hh" +#include "base/socket.hh" +#include "base/trace.hh" +#include "dev/platform.hh" +#include "dev/simconsole.hh" +#include "dev/uart.hh" +#include "sim/builder.hh" + +using namespace std; + +//////////////////////////////////////////////////////////////////////// +// +// + +SimConsole::Event::Event(SimConsole *c, int fd, int e) + : PollEvent(fd, e), cons(c) +{ +} + +void +SimConsole::Event::process(int revent) +{ + if (revent & POLLIN) + cons->data(); + else if (revent & POLLNVAL) + cons->detach(); +} + +SimConsole::SimConsole(const string &name, ostream *os, int num) + : SimObject(name), event(NULL), number(num), in_fd(-1), out_fd(-1), + listener(NULL), txbuf(16384), rxbuf(16384), outfile(os) +#if TRACING_ON == 1 + , linebuf(16384) +#endif +{ + if (outfile) + outfile->setf(ios::unitbuf); +} + +SimConsole::~SimConsole() +{ + close(); +} + +void +SimConsole::close() +{ + if (in_fd != -1) + ::close(in_fd); + + if (out_fd != in_fd && out_fd != -1) + ::close(out_fd); +} + +void +SimConsole::attach(int in, int out, ConsoleListener *l) +{ + in_fd = in; + out_fd = out; + listener = l; + + event = new Event(this, in, POLLIN); + pollQueue.schedule(event); + + stringstream stream; + ccprintf(stream, "==== m5 slave console: Console %d ====", number); + + // we need an actual carriage return followed by a newline for the + // terminal + stream << "\r\n"; + + write((const uint8_t *)stream.str().c_str(), stream.str().size()); + + + DPRINTFN("attach console %d\n", number); + + txbuf.readall(out); +} + +void +SimConsole::detach() +{ + close(); + in_fd = -1; + out_fd = -1; + + pollQueue.remove(event); + + if (listener) { + listener->add(this); + listener = NULL; + } + + DPRINTFN("detach console %d\n", number); +} + +void +SimConsole::data() +{ + uint8_t buf[1024]; + int len; + + len = read(buf, sizeof(buf)); + if (len) { + rxbuf.write((char *)buf, len); + // Inform the UART there is data available + uart->dataAvailable(); + } +} + +size_t +SimConsole::read(uint8_t *buf, size_t len) +{ + if (in_fd < 0) + panic("Console not properly attached.\n"); + + size_t ret; + do { + ret = ::read(in_fd, buf, len); + } while (ret == -1 && errno == EINTR); + + + if (ret < 0) + DPRINTFN("Read failed.\n"); + + if (ret <= 0) { + detach(); + return 0; + } + + return ret; +} + +// Console output. +size_t +SimConsole::write(const uint8_t *buf, size_t len) +{ + if (out_fd < 0) + panic("Console not properly attached.\n"); + + size_t ret; + for (;;) { + ret = ::write(out_fd, buf, len); + + if (ret >= 0) + break; + + if (errno != EINTR) + detach(); + } + + return ret; +} + +#define MORE_PENDING (ULL(1) << 61) +#define RECEIVE_SUCCESS (ULL(0) << 62) +#define RECEIVE_NONE (ULL(2) << 62) +#define RECEIVE_ERROR (ULL(3) << 62) + +uint8_t +SimConsole::in() +{ + bool empty; + uint8_t c; + + empty = rxbuf.empty(); + assert(!empty); + rxbuf.read((char *)&c, 1); + empty = rxbuf.empty(); + + + DPRINTF(ConsoleVerbose, "in: \'%c\' %#02x more: %d\n", + isprint(c) ? c : ' ', c, !empty); + + return c; +} + +uint64_t +SimConsole::console_in() +{ + uint64_t value; + + if (dataAvailable()) { + value = RECEIVE_SUCCESS | in(); + if (!rxbuf.empty()) + value |= MORE_PENDING; + } else { + value = RECEIVE_NONE; + } + + DPRINTF(ConsoleVerbose, "console_in: return: %#x\n", value); + + return value; +} + +void +SimConsole::out(char c) +{ +#if TRACING_ON == 1 + if (DTRACE(Console)) { + static char last = '\0'; + + if (c != '\n' && c != '\r' || + last != '\n' && last != '\r') { + if (c == '\n' || c == '\r') { + int size = linebuf.size(); + char *buffer = new char[size + 1]; + linebuf.read(buffer, size); + buffer[size] = '\0'; + DPRINTF(Console, "%s\n", buffer); + delete [] buffer; + } else { + linebuf.write(c); + } + } + + last = c; + } +#endif + + txbuf.write(c); + + if (out_fd >= 0) + write(c); + + if (outfile) + outfile->write(&c, 1); + + DPRINTF(ConsoleVerbose, "out: \'%c\' %#02x\n", + isprint(c) ? c : ' ', (int)c); + +} + + +void +SimConsole::serialize(ostream &os) +{ +} + +void +SimConsole::unserialize(Checkpoint *cp, const std::string §ion) +{ +} + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimConsole) + + SimObjectParam<ConsoleListener *> listener; + SimObjectParam<IntrControl *> intr_control; + Param<string> output; + Param<bool> append_name; + Param<int> number; + +END_DECLARE_SIM_OBJECT_PARAMS(SimConsole) + +BEGIN_INIT_SIM_OBJECT_PARAMS(SimConsole) + + INIT_PARAM(listener, "console listener"), + INIT_PARAM(intr_control, "interrupt controller"), + INIT_PARAM(output, "file to dump output to"), + INIT_PARAM_DFLT(append_name, "append name() to filename", true), + INIT_PARAM_DFLT(number, "console number", 0) + +END_INIT_SIM_OBJECT_PARAMS(SimConsole) + +CREATE_SIM_OBJECT(SimConsole) +{ + string filename = output; + ostream *stream = NULL; + + if (!filename.empty()) { + if (append_name) + filename += "." + getInstanceName(); + stream = simout.find(filename); + } + + SimConsole *console = new SimConsole(getInstanceName(), stream, number); + ((ConsoleListener *)listener)->add(console); + + return console; +} + +REGISTER_SIM_OBJECT("SimConsole", SimConsole) + +//////////////////////////////////////////////////////////////////////// +// +// + +ConsoleListener::ConsoleListener(const string &name) + : SimObject(name), event(NULL) +{} + +ConsoleListener::~ConsoleListener() +{ + if (event) + delete event; +} + +void +ConsoleListener::Event::process(int revent) +{ + listener->accept(); +} + +/////////////////////////////////////////////////////////////////////// +// socket creation and console attach +// + +void +ConsoleListener::listen(int port) +{ + while (!listener.listen(port, true)) { + DPRINTF(Console, + ": can't bind address console port %d inuse PID %d\n", + port, getpid()); + port++; + } + + ccprintf(cerr, "Listening for console connection on port %d\n", port); + + event = new Event(this, listener.getfd(), POLLIN); + pollQueue.schedule(event); +} + +void +ConsoleListener::add(SimConsole *cons) +{ ConsoleList.push_back(cons);} + +void +ConsoleListener::accept() +{ + if (!listener.islistening()) + panic("%s: cannot accept a connection if not listening!", name()); + + int sfd = listener.accept(true); + if (sfd != -1) { + iter_t i = ConsoleList.begin(); + iter_t end = ConsoleList.end(); + if (i == end) { + close(sfd); + } else { + (*i)->attach(sfd, this); + i = ConsoleList.erase(i); + } + } +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(ConsoleListener) + + Param<int> port; + +END_DECLARE_SIM_OBJECT_PARAMS(ConsoleListener) + +BEGIN_INIT_SIM_OBJECT_PARAMS(ConsoleListener) + + INIT_PARAM_DFLT(port, "listen port", 3456) + +END_INIT_SIM_OBJECT_PARAMS(ConsoleListener) + +CREATE_SIM_OBJECT(ConsoleListener) +{ + ConsoleListener *listener = new ConsoleListener(getInstanceName()); + listener->listen(port); + + return listener; +} + +REGISTER_SIM_OBJECT("ConsoleListener", ConsoleListener) diff --git a/src/dev/simconsole.hh b/src/dev/simconsole.hh new file mode 100644 index 000000000..ec99c6028 --- /dev/null +++ b/src/dev/simconsole.hh @@ -0,0 +1,168 @@ +/* + * 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 + * Ali Saidi + */ + +/* @file + * User Console Interface + */ + +#ifndef __CONSOLE_HH__ +#define __CONSOLE_HH__ + +#include <iostream> + +#include "base/circlebuf.hh" +#include "cpu/intr_control.hh" +#include "base/pollevent.hh" +#include "base/socket.hh" +#include "sim/sim_object.hh" + +class ConsoleListener; +class Uart; + +class SimConsole : public SimObject +{ + public: + Uart *uart; + + protected: + class Event : public PollEvent + { + protected: + SimConsole *cons; + + public: + Event(SimConsole *c, int fd, int e); + void process(int revent); + }; + + friend class Event; + Event *event; + + protected: + int number; + int in_fd; + int out_fd; + ConsoleListener *listener; + + public: + SimConsole(const std::string &name, std::ostream *os, int num); + ~SimConsole(); + + protected: + CircleBuf txbuf; + CircleBuf rxbuf; + std::ostream *outfile; +#if TRACING_ON == 1 + CircleBuf linebuf; +#endif + + public: + /////////////////////// + // Terminal Interface + + void attach(int fd, ConsoleListener *l = NULL) { attach(fd, fd, l); } + void attach(int in, int out, ConsoleListener *l = NULL); + void detach(); + + void data(); + + void close(); + void read(uint8_t &c) { read(&c, 1); } + size_t read(uint8_t *buf, size_t len); + void write(uint8_t c) { write(&c, 1); } + size_t write(const uint8_t *buf, size_t len); + + public: + ///////////////// + // OS interface + + // Get a character from the console. + uint8_t in(); + + // get a character from the console in the console specific format + // corresponds to GETC: + // retval<63:61> + // 000: success: character received + // 001: success: character received, more pending + // 100: failure: no character ready + // 110: failure: character received with error + // 111: failure: character received with error, more pending + // retval<31:0> + // character read from console + // + // Interrupts are cleared when the buffer is empty. + uint64_t console_in(); + + // Send a character to the console + void out(char c); + + //Ask the console if data is available + bool dataAvailable() { return !rxbuf.empty(); } + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); +}; + +class ConsoleListener : public SimObject +{ + protected: + class Event : public PollEvent + { + protected: + ConsoleListener *listener; + + public: + Event(ConsoleListener *l, int fd, int e) + : PollEvent(fd, e), listener(l) {} + void process(int revent); + }; + + friend class Event; + Event *event; + + typedef std::list<SimConsole *> list_t; + typedef list_t::iterator iter_t; + list_t ConsoleList; + + protected: + ListenSocket listener; + + public: + ConsoleListener(const std::string &name); + ~ConsoleListener(); + + void add(SimConsole *cons); + + void accept(); + void listen(int port); +}; + +#endif // __CONSOLE_HH__ diff --git a/src/dev/simple_disk.cc b/src/dev/simple_disk.cc new file mode 100644 index 000000000..e29bfa726 --- /dev/null +++ b/src/dev/simple_disk.cc @@ -0,0 +1,113 @@ +/* + * 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 + */ + +/* @file + * Simple disk interface for the system console + */ + +#include <sys/types.h> +#include <sys/uio.h> +#include <fcntl.h> +#include <unistd.h> + +#include <cstring> +#include <string> + +#include "base/misc.hh" +#include "base/trace.hh" +#include "dev/disk_image.hh" +#include "dev/simple_disk.hh" +#include "mem/port.hh" +#include "sim/builder.hh" +#include "sim/system.hh" + +using namespace std; + +SimpleDisk::SimpleDisk(const string &name, System *sys, DiskImage *img) + : SimObject(name), system(sys), image(img) +{} + +SimpleDisk::~SimpleDisk() +{} + + +void +SimpleDisk::read(Addr addr, baddr_t block, int count) const +{ + uint8_t *data = new uint8_t[SectorSize * count]; + + if (count & (SectorSize - 1)) + panic("Not reading a multiple of a sector (count = %d)", count); + + for (int i = 0, j = 0; i < count; i += SectorSize, j++) + image->read(data + i, block + j); + + system->functionalPort.writeBlob(addr, data, count); + + DPRINTF(SimpleDisk, "read block=%#x len=%d\n", (uint64_t)block, count); + DDUMP(SimpleDiskData, data, count); + + delete data; +} + +void +SimpleDisk::write(Addr addr, baddr_t block, int count) +{ + panic("unimplemented!\n"); + +#if 0 + uint8_t *data = physmem->dma_addr(addr, count); + if (!data) + panic("dma out of range! write addr=%#x count=%d\n", addr, count); + + image->write(data, block, count); +#endif +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleDisk) + + SimObjectParam<System *> system; + SimObjectParam<DiskImage *> disk; + +END_DECLARE_SIM_OBJECT_PARAMS(SimpleDisk) + +BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleDisk) + + INIT_PARAM(system, "System pointer"), + INIT_PARAM(disk, "Disk Image") + +END_INIT_SIM_OBJECT_PARAMS(SimpleDisk) + +CREATE_SIM_OBJECT(SimpleDisk) +{ + return new SimpleDisk(getInstanceName(), system, disk); +} + +REGISTER_SIM_OBJECT("SimpleDisk", SimpleDisk) diff --git a/src/dev/simple_disk.hh b/src/dev/simple_disk.hh new file mode 100644 index 000000000..9f588cb95 --- /dev/null +++ b/src/dev/simple_disk.hh @@ -0,0 +1,64 @@ +/* + * 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 + */ + +/* @file + * Simple disk interface for the system console + */ + +#ifndef __DEV_SIMPLE_DISK_HH__ +#define __DEV_SIMPLE_DISK_HH__ + +#include "sim/sim_object.hh" +#include "arch/isa_traits.hh" + +class DiskImage; +class System; + +/* + * Trivial interface to a disk image used by the System Console + */ +class SimpleDisk : public SimObject +{ + public: + typedef uint64_t baddr_t; + + protected: + System *system; + DiskImage *image; + + public: + SimpleDisk(const std::string &name, System *sys, DiskImage *img); + ~SimpleDisk(); + + void read(Addr addr, baddr_t block, int count) const; + void write(Addr addr, baddr_t block, int count); +}; + +#endif // __DEV_SIMPLE_DISK_HH__ diff --git a/src/dev/sinic.cc b/src/dev/sinic.cc new file mode 100644 index 000000000..a0223733b --- /dev/null +++ b/src/dev/sinic.cc @@ -0,0 +1,1755 @@ +/* + * 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: Nathan Binkert + */ + +#include <deque> +#include <limits> +#include <string> + +#include "base/inet.hh" +#include "cpu/thread_context.hh" +#include "cpu/intr_control.hh" +#include "dev/etherlink.hh" +#include "dev/sinic.hh" +#include "dev/pciconfigall.hh" +#include "mem/packet.hh" +#include "sim/builder.hh" +#include "sim/debug.hh" +#include "sim/eventq.hh" +#include "sim/host.hh" +#include "sim/stats.hh" +#include "arch/vtophys.hh" + +using namespace Net; +using namespace TheISA; + +namespace Sinic { + +const char *RxStateStrings[] = +{ + "rxIdle", + "rxFifoBlock", + "rxBeginCopy", + "rxCopy", + "rxCopyDone" +}; + +const char *TxStateStrings[] = +{ + "txIdle", + "txFifoBlock", + "txBeginCopy", + "txCopy", + "txCopyDone" +}; + + +/////////////////////////////////////////////////////////////////////// +// +// Sinic PCI Device +// +Base::Base(Params *p) + : PciDev(p), rxEnable(false), txEnable(false), clock(p->clock), + intrDelay(p->intr_delay), intrTick(0), cpuIntrEnable(false), + cpuPendingIntr(false), intrEvent(0), interface(NULL) +{ +} + +Device::Device(Params *p) + : Base(p), rxUnique(0), txUnique(0), + virtualRegs(p->virtual_count < 1 ? 1 : p->virtual_count), + rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), + rxKickTick(0), txKickTick(0), + txEvent(this), rxDmaEvent(this), txDmaEvent(this), + dmaReadDelay(p->dma_read_delay), dmaReadFactor(p->dma_read_factor), + dmaWriteDelay(p->dma_write_delay), dmaWriteFactor(p->dma_write_factor) +{ + reset(); + +} + +Device::~Device() +{} + +void +Device::regStats() +{ + rxBytes + .name(name() + ".rxBytes") + .desc("Bytes Received") + .prereq(rxBytes) + ; + + rxBandwidth + .name(name() + ".rxBandwidth") + .desc("Receive Bandwidth (bits/s)") + .precision(0) + .prereq(rxBytes) + ; + + rxPackets + .name(name() + ".rxPackets") + .desc("Number of Packets Received") + .prereq(rxBytes) + ; + + rxPacketRate + .name(name() + ".rxPPS") + .desc("Packet Reception Rate (packets/s)") + .precision(0) + .prereq(rxBytes) + ; + + rxIpPackets + .name(name() + ".rxIpPackets") + .desc("Number of IP Packets Received") + .prereq(rxBytes) + ; + + rxTcpPackets + .name(name() + ".rxTcpPackets") + .desc("Number of Packets Received") + .prereq(rxBytes) + ; + + rxUdpPackets + .name(name() + ".rxUdpPackets") + .desc("Number of UDP Packets Received") + .prereq(rxBytes) + ; + + rxIpChecksums + .name(name() + ".rxIpChecksums") + .desc("Number of rx IP Checksums done by device") + .precision(0) + .prereq(rxBytes) + ; + + rxTcpChecksums + .name(name() + ".rxTcpChecksums") + .desc("Number of rx TCP Checksums done by device") + .precision(0) + .prereq(rxBytes) + ; + + rxUdpChecksums + .name(name() + ".rxUdpChecksums") + .desc("Number of rx UDP Checksums done by device") + .precision(0) + .prereq(rxBytes) + ; + + totBandwidth + .name(name() + ".totBandwidth") + .desc("Total Bandwidth (bits/s)") + .precision(0) + .prereq(totBytes) + ; + + totPackets + .name(name() + ".totPackets") + .desc("Total Packets") + .precision(0) + .prereq(totBytes) + ; + + totBytes + .name(name() + ".totBytes") + .desc("Total Bytes") + .precision(0) + .prereq(totBytes) + ; + + totPacketRate + .name(name() + ".totPPS") + .desc("Total Tranmission Rate (packets/s)") + .precision(0) + .prereq(totBytes) + ; + + txBytes + .name(name() + ".txBytes") + .desc("Bytes Transmitted") + .prereq(txBytes) + ; + + txBandwidth + .name(name() + ".txBandwidth") + .desc("Transmit Bandwidth (bits/s)") + .precision(0) + .prereq(txBytes) + ; + + txPackets + .name(name() + ".txPackets") + .desc("Number of Packets Transmitted") + .prereq(txBytes) + ; + + txPacketRate + .name(name() + ".txPPS") + .desc("Packet Tranmission Rate (packets/s)") + .precision(0) + .prereq(txBytes) + ; + + txIpPackets + .name(name() + ".txIpPackets") + .desc("Number of IP Packets Transmitted") + .prereq(txBytes) + ; + + txTcpPackets + .name(name() + ".txTcpPackets") + .desc("Number of TCP Packets Transmitted") + .prereq(txBytes) + ; + + txUdpPackets + .name(name() + ".txUdpPackets") + .desc("Number of Packets Transmitted") + .prereq(txBytes) + ; + + txIpChecksums + .name(name() + ".txIpChecksums") + .desc("Number of tx IP Checksums done by device") + .precision(0) + .prereq(txBytes) + ; + + txTcpChecksums + .name(name() + ".txTcpChecksums") + .desc("Number of tx TCP Checksums done by device") + .precision(0) + .prereq(txBytes) + ; + + txUdpChecksums + .name(name() + ".txUdpChecksums") + .desc("Number of tx UDP Checksums done by device") + .precision(0) + .prereq(txBytes) + ; + + txBandwidth = txBytes * Stats::constant(8) / simSeconds; + rxBandwidth = rxBytes * Stats::constant(8) / simSeconds; + totBandwidth = txBandwidth + rxBandwidth; + totBytes = txBytes + rxBytes; + totPackets = txPackets + rxPackets; + txPacketRate = txPackets / simSeconds; + rxPacketRate = rxPackets / simSeconds; +} + +void +Device::prepareIO(int cpu, int index) +{ + int size = virtualRegs.size(); + if (index > size) + panic("Trying to access a vnic that doesn't exist %d > %d\n", + index, size); +} + +void +Device::prepareRead(int cpu, int index) +{ + using namespace Regs; + prepareIO(cpu, index); + + VirtualReg &vnic = virtualRegs[index]; + + // update rx registers + uint64_t rxdone = vnic.RxDone; + rxdone = set_RxDone_Packets(rxdone, rxFifo.countPacketsAfter(rxFifoPtr)); + rxdone = set_RxDone_Empty(rxdone, rxFifo.empty()); + rxdone = set_RxDone_High(rxdone, rxFifo.size() > regs.RxFifoMark); + rxdone = set_RxDone_NotHigh(rxdone, rxLow); + regs.RxData = vnic.RxData; + regs.RxDone = rxdone; + regs.RxWait = rxdone; + + // update tx regsiters + uint64_t txdone = vnic.TxDone; + txdone = set_TxDone_Packets(txdone, txFifo.packets()); + txdone = set_TxDone_Full(txdone, txFifo.avail() < regs.TxMaxCopy); + txdone = set_TxDone_Low(txdone, txFifo.size() < regs.TxFifoMark); + regs.TxData = vnic.TxData; + regs.TxDone = txdone; + regs.TxWait = txdone; +} + +void +Device::prepareWrite(int cpu, int index) +{ + prepareIO(cpu, index); +} + +/** + * I/O read of device register + */ +Tick +Device::read(Packet *pkt) +{ + assert(config.command & PCI_CMD_MSE); + assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]); + + int cpu = pkt->req->getCpuNum(); + Addr daddr = pkt->getAddr() - BARAddrs[0]; + Addr index = daddr >> Regs::VirtualShift; + Addr raddr = daddr & Regs::VirtualMask; + + pkt->allocate(); + + if (!regValid(raddr)) + panic("invalid register: cpu=%d vnic=%d da=%#x pa=%#x size=%d", + cpu, index, daddr, pkt->getAddr(), pkt->getSize()); + + const Regs::Info &info = regInfo(raddr); + if (!info.read) + panic("read %s (write only): " + "cpu=%d vnic=%d da=%#x pa=%#x size=%d", + info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize()); + + panic("read %s (invalid size): " + "cpu=%d vnic=%d da=%#x pa=%#x size=%d", + info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize()); + + prepareRead(cpu, index); + + uint64_t value = 0; + if (pkt->getSize() == 4) { + uint32_t reg = regData32(raddr); + pkt->set(reg); + value = reg; + } + + if (pkt->getSize() == 8) { + uint64_t reg = regData64(raddr); + pkt->set(reg); + value = reg; + } + + DPRINTF(EthernetPIO, + "read %s: cpu=%d vnic=%d da=%#x pa=%#x size=%d val=%#x\n", + info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize(), value); + + // reading the interrupt status register has the side effect of + // clearing it + if (raddr == Regs::IntrStatus) + devIntrClear(); + + return pioDelay; +} + +/** + * IPR read of device register + + Fault +Device::iprRead(Addr daddr, int cpu, uint64_t &result) +{ + if (!regValid(daddr)) + panic("invalid address: da=%#x", daddr); + + const Regs::Info &info = regInfo(daddr); + if (!info.read) + panic("reading %s (write only): cpu=%d da=%#x", info.name, cpu, daddr); + + DPRINTF(EthernetPIO, "IPR read %s: cpu=%d da=%#x\n", + info.name, cpu, daddr); + + prepareRead(cpu, 0); + + if (info.size == 4) + result = regData32(daddr); + + if (info.size == 8) + result = regData64(daddr); + + DPRINTF(EthernetPIO, "IPR read %s: cpu=%s da=%#x val=%#x\n", + info.name, cpu, result); + + return NoFault; +} +*/ +/** + * I/O write of device register + */ +Tick +Device::write(Packet *pkt) +{ + assert(config.command & PCI_CMD_MSE); + assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]); + + int cpu = pkt->req->getCpuNum(); + Addr daddr = pkt->getAddr() - BARAddrs[0]; + Addr index = daddr >> Regs::VirtualShift; + Addr raddr = daddr & Regs::VirtualMask; + + if (!regValid(raddr)) + panic("invalid register: cpu=%d, da=%#x pa=%#x size=%d", + cpu, daddr, pkt->getAddr(), pkt->getSize()); + + const Regs::Info &info = regInfo(raddr); + if (!info.write) + panic("write %s (read only): " + "cpu=%d vnic=%d da=%#x pa=%#x size=%d", + info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize()); + + if (pkt->getSize() != info.size) + panic("write %s (invalid size): " + "cpu=%d vnic=%d da=%#x pa=%#x size=%d", + info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize()); + + VirtualReg &vnic = virtualRegs[index]; + + DPRINTF(EthernetPIO, + "write %s vnic %d: cpu=%d val=%#x da=%#x pa=%#x size=%d\n", + info.name, index, cpu, info.size == 4 ? pkt->get<uint32_t>() : + pkt->get<uint64_t>(), daddr, pkt->getAddr(), pkt->getSize()); + + prepareWrite(cpu, index); + + switch (raddr) { + case Regs::Config: + changeConfig(pkt->get<uint32_t>()); + break; + + case Regs::Command: + command(pkt->get<uint32_t>()); + break; + + case Regs::IntrStatus: + devIntrClear(regs.IntrStatus & pkt->get<uint32_t>()); + break; + + case Regs::IntrMask: + devIntrChangeMask(pkt->get<uint32_t>()); + break; + + case Regs::RxData: + if (Regs::get_RxDone_Busy(vnic.RxDone)) + panic("receive machine busy with another request! rxState=%s", + RxStateStrings[rxState]); + + vnic.rxUnique = rxUnique++; + vnic.RxDone = Regs::RxDone_Busy; + vnic.RxData = pkt->get<uint64_t>(); + + if (Regs::get_RxData_Vaddr(pkt->get<uint64_t>())) { + panic("vtophys not implemented in newmem"); +/* Addr vaddr = Regs::get_RxData_Addr(reg64); + Addr paddr = vtophys(req->xc, vaddr); + DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d): " + "vaddr=%#x, paddr=%#x\n", + index, vnic.rxUnique, vaddr, paddr); + + vnic.RxData = Regs::set_RxData_Addr(vnic.RxData, paddr);*/ + } else { + DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d)\n", + index, vnic.rxUnique); + } + + if (vnic.rxPacket == rxFifo.end()) { + DPRINTF(EthernetPIO, "request new packet...appending to rxList\n"); + rxList.push_back(index); + } else { + DPRINTF(EthernetPIO, "packet exists...appending to rxBusy\n"); + rxBusy.push_back(index); + } + + if (rxEnable && (rxState == rxIdle || rxState == rxFifoBlock)) { + rxState = rxFifoBlock; + rxKick(); + } + break; + + case Regs::TxData: + if (Regs::get_TxDone_Busy(vnic.TxDone)) + panic("transmit machine busy with another request! txState=%s", + TxStateStrings[txState]); + + vnic.txUnique = txUnique++; + vnic.TxDone = Regs::TxDone_Busy; + + if (Regs::get_TxData_Vaddr(pkt->get<uint64_t>())) { + panic("vtophys won't work here in newmem.\n"); + /*Addr vaddr = Regs::get_TxData_Addr(reg64); + Addr paddr = vtophys(req->xc, vaddr); + DPRINTF(EthernetPIO, "write TxData vnic %d (rxunique %d): " + "vaddr=%#x, paddr=%#x\n", + index, vnic.txUnique, vaddr, paddr); + + vnic.TxData = Regs::set_TxData_Addr(vnic.TxData, paddr);*/ + } else { + DPRINTF(EthernetPIO, "write TxData vnic %d (rxunique %d)\n", + index, vnic.txUnique); + } + + if (txList.empty() || txList.front() != index) + txList.push_back(index); + if (txEnable && txState == txIdle && txList.front() == index) { + txState = txFifoBlock; + txKick(); + } + break; + } + + return pioDelay; +} + +void +Device::devIntrPost(uint32_t interrupts) +{ + if ((interrupts & Regs::Intr_Res)) + panic("Cannot set a reserved interrupt"); + + regs.IntrStatus |= interrupts; + + DPRINTF(EthernetIntr, + "interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n", + interrupts, regs.IntrStatus, regs.IntrMask); + + interrupts = regs.IntrStatus & regs.IntrMask; + + // Intr_RxHigh is special, we only signal it if we've emptied the fifo + // and then filled it above the high watermark + if (rxEmpty) + rxEmpty = false; + else + interrupts &= ~Regs::Intr_RxHigh; + + // Intr_TxLow is special, we only signal it if we've filled up the fifo + // and then dropped below the low watermark + if (txFull) + txFull = false; + else + interrupts &= ~Regs::Intr_TxLow; + + if (interrupts) { + Tick when = curTick; + if ((interrupts & Regs::Intr_NoDelay) == 0) + when += intrDelay; + cpuIntrPost(when); + } +} + +void +Device::devIntrClear(uint32_t interrupts) +{ + if ((interrupts & Regs::Intr_Res)) + panic("Cannot clear a reserved interrupt"); + + regs.IntrStatus &= ~interrupts; + + DPRINTF(EthernetIntr, + "interrupt cleared from intStatus: intr=%x status=%x mask=%x\n", + interrupts, regs.IntrStatus, regs.IntrMask); + + if (!(regs.IntrStatus & regs.IntrMask)) + cpuIntrClear(); +} + +void +Device::devIntrChangeMask(uint32_t newmask) +{ + if (regs.IntrMask == newmask) + return; + + regs.IntrMask = newmask; + + DPRINTF(EthernetIntr, + "interrupt mask changed: intStatus=%x intMask=%x masked=%x\n", + regs.IntrStatus, regs.IntrMask, regs.IntrStatus & regs.IntrMask); + + if (regs.IntrStatus & regs.IntrMask) + cpuIntrPost(curTick); + else + cpuIntrClear(); +} + +void +Base::cpuIntrPost(Tick when) +{ + // If the interrupt you want to post is later than an interrupt + // already scheduled, just let it post in the coming one and don't + // schedule another. + // HOWEVER, must be sure that the scheduled intrTick is in the + // future (this was formerly the source of a bug) + /** + * @todo this warning should be removed and the intrTick code should + * be fixed. + */ + assert(when >= curTick); + assert(intrTick >= curTick || intrTick == 0); + if (!cpuIntrEnable) { + DPRINTF(EthernetIntr, "interrupts not enabled.\n", + intrTick); + return; + } + + if (when > intrTick && intrTick != 0) { + DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n", + intrTick); + return; + } + + intrTick = when; + if (intrTick < curTick) { + debug_break(); + intrTick = curTick; + } + + DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", + intrTick); + + if (intrEvent) + intrEvent->squash(); + intrEvent = new IntrEvent(this, true); + intrEvent->schedule(intrTick); +} + +void +Base::cpuInterrupt() +{ + assert(intrTick == curTick); + + // Whether or not there's a pending interrupt, we don't care about + // it anymore + intrEvent = 0; + intrTick = 0; + + // Don't send an interrupt if there's already one + if (cpuPendingIntr) { + DPRINTF(EthernetIntr, + "would send an interrupt now, but there's already pending\n"); + } else { + // Send interrupt + cpuPendingIntr = true; + + DPRINTF(EthernetIntr, "posting interrupt\n"); + intrPost(); + } +} + +void +Base::cpuIntrClear() +{ + if (!cpuPendingIntr) + return; + + if (intrEvent) { + intrEvent->squash(); + intrEvent = 0; + } + + intrTick = 0; + + cpuPendingIntr = false; + + DPRINTF(EthernetIntr, "clearing cchip interrupt\n"); + intrClear(); +} + +bool +Base::cpuIntrPending() const +{ return cpuPendingIntr; } + +void +Device::changeConfig(uint32_t newconf) +{ + uint32_t changed = regs.Config ^ newconf; + if (!changed) + return; + + regs.Config = newconf; + + if ((changed & Regs::Config_IntEn)) { + cpuIntrEnable = regs.Config & Regs::Config_IntEn; + if (cpuIntrEnable) { + if (regs.IntrStatus & regs.IntrMask) + cpuIntrPost(curTick); + } else { + cpuIntrClear(); + } + } + + if ((changed & Regs::Config_TxEn)) { + txEnable = regs.Config & Regs::Config_TxEn; + if (txEnable) + txKick(); + } + + if ((changed & Regs::Config_RxEn)) { + rxEnable = regs.Config & Regs::Config_RxEn; + if (rxEnable) + rxKick(); + } +} + +void +Device::command(uint32_t command) +{ + if (command & Regs::Command_Intr) + devIntrPost(Regs::Intr_Soft); + + if (command & Regs::Command_Reset) + reset(); +} + +void +Device::reset() +{ + using namespace Regs; + + memset(®s, 0, sizeof(regs)); + + regs.Config = 0; + if (params()->rx_thread) + regs.Config |= Config_RxThread; + if (params()->tx_thread) + regs.Config |= Config_TxThread; + if (params()->rss) + regs.Config |= Config_RSS; + if (params()->zero_copy) + regs.Config |= Config_ZeroCopy; + if (params()->delay_copy) + regs.Config |= Config_DelayCopy; + if (params()->virtual_addr) + regs.Config |= Config_Vaddr; + + if (params()->delay_copy && params()->zero_copy) + panic("Can't delay copy and zero copy"); + + regs.IntrMask = Intr_Soft | Intr_RxHigh | Intr_RxPacket | Intr_TxLow; + regs.RxMaxCopy = params()->rx_max_copy; + regs.TxMaxCopy = params()->tx_max_copy; + regs.RxMaxIntr = params()->rx_max_intr; + regs.VirtualCount = params()->virtual_count; + regs.RxFifoSize = params()->rx_fifo_size; + regs.TxFifoSize = params()->tx_fifo_size; + regs.RxFifoMark = params()->rx_fifo_threshold; + regs.TxFifoMark = params()->tx_fifo_threshold; + regs.HwAddr = params()->eaddr; + + rxList.clear(); + rxBusy.clear(); + rxActive = -1; + txList.clear(); + + rxState = rxIdle; + txState = txIdle; + + rxFifo.clear(); + rxFifoPtr = rxFifo.end(); + txFifo.clear(); + rxEmpty = false; + rxLow = true; + txFull = false; + + int size = virtualRegs.size(); + virtualRegs.clear(); + virtualRegs.resize(size); + for (int i = 0; i < size; ++i) + virtualRegs[i].rxPacket = rxFifo.end(); +} + +void +Device::rxDmaDone() +{ + assert(rxState == rxCopy); + rxState = rxCopyDone; + DPRINTF(EthernetDMA, "end rx dma write paddr=%#x len=%d\n", + rxDmaAddr, rxDmaLen); + DDUMP(EthernetData, rxDmaData, rxDmaLen); + + // If the transmit state machine has a pending DMA, let it go first + if (txState == txBeginCopy) + txKick(); + + rxKick(); +} + +void +Device::rxKick() +{ + VirtualReg *vnic = NULL; + + DPRINTF(EthernetSM, "rxKick: rxState=%s (rxFifo.size=%d)\n", + RxStateStrings[rxState], rxFifo.size()); + + if (rxKickTick > curTick) { + DPRINTF(EthernetSM, "rxKick: exiting, can't run till %d\n", + rxKickTick); + return; + } + + next: + if (rxState == rxIdle) + goto exit; + + if (rxActive == -1) { + if (rxState != rxFifoBlock) + panic("no active vnic while in state %s", RxStateStrings[rxState]); + + DPRINTF(EthernetSM, "processing rxState=%s\n", + RxStateStrings[rxState]); + } else { + vnic = &virtualRegs[rxActive]; + DPRINTF(EthernetSM, + "processing rxState=%s for vnic %d (rxunique %d)\n", + RxStateStrings[rxState], rxActive, vnic->rxUnique); + } + + switch (rxState) { + case rxFifoBlock: + if (DTRACE(EthernetSM)) { + PacketFifo::iterator end = rxFifo.end(); + int size = virtualRegs.size(); + for (int i = 0; i < size; ++i) { + VirtualReg *vn = &virtualRegs[i]; + if (vn->rxPacket != end && + !Regs::get_RxDone_Busy(vn->RxDone)) { + DPRINTF(EthernetSM, + "vnic %d (rxunique %d), has outstanding packet %d\n", + i, vn->rxUnique, + rxFifo.countPacketsBefore(vn->rxPacket)); + } + } + } + + if (!rxBusy.empty()) { + rxActive = rxBusy.front(); + rxBusy.pop_front(); + vnic = &virtualRegs[rxActive]; + + if (vnic->rxPacket == rxFifo.end()) + panic("continuing vnic without packet\n"); + + DPRINTF(EthernetSM, + "continue processing for vnic %d (rxunique %d)\n", + rxActive, vnic->rxUnique); + + rxState = rxBeginCopy; + + break; + } + + if (rxFifoPtr == rxFifo.end()) { + DPRINTF(EthernetSM, "receive waiting for data. Nothing to do.\n"); + goto exit; + } + + if (rxList.empty()) + panic("Not idle, but nothing to do!"); + + assert(!rxFifo.empty()); + + rxActive = rxList.front(); + rxList.pop_front(); + vnic = &virtualRegs[rxActive]; + + DPRINTF(EthernetSM, + "processing new packet for vnic %d (rxunique %d)\n", + rxActive, vnic->rxUnique); + + // Grab a new packet from the fifo. + vnic->rxPacket = rxFifoPtr++; + vnic->rxPacketOffset = 0; + vnic->rxPacketBytes = (*vnic->rxPacket)->length; + assert(vnic->rxPacketBytes); + + vnic->rxDoneData = 0; + /* scope for variables */ { + IpPtr ip(*vnic->rxPacket); + if (ip) { + DPRINTF(Ethernet, "ID is %d\n", ip->id()); + vnic->rxDoneData |= Regs::RxDone_IpPacket; + rxIpChecksums++; + if (cksum(ip) != 0) { + DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); + vnic->rxDoneData |= Regs::RxDone_IpError; + } + TcpPtr tcp(ip); + UdpPtr udp(ip); + if (tcp) { + DPRINTF(Ethernet, + "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", + tcp->sport(), tcp->dport(), tcp->seq(), + tcp->ack()); + vnic->rxDoneData |= Regs::RxDone_TcpPacket; + rxTcpChecksums++; + if (cksum(tcp) != 0) { + DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); + vnic->rxDoneData |= Regs::RxDone_TcpError; + } + } else if (udp) { + vnic->rxDoneData |= Regs::RxDone_UdpPacket; + rxUdpChecksums++; + if (cksum(udp) != 0) { + DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); + vnic->rxDoneData |= Regs::RxDone_UdpError; + } + } + } + } + rxState = rxBeginCopy; + break; + + case rxBeginCopy: + if (dmaPending()) + goto exit; + + rxDmaAddr = params()->platform->pciToDma( + Regs::get_RxData_Addr(vnic->RxData)); + rxDmaLen = std::min<int>(Regs::get_RxData_Len(vnic->RxData), + vnic->rxPacketBytes); + rxDmaData = (*vnic->rxPacket)->data + vnic->rxPacketOffset; + rxState = rxCopy; + if (rxDmaAddr == 1LL) { + rxState = rxCopyDone; + break; + } + + + dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaEvent, rxDmaData); + break; + + case rxCopy: + DPRINTF(EthernetSM, "receive machine still copying\n"); + goto exit; + + case rxCopyDone: + vnic->RxDone = vnic->rxDoneData; + vnic->RxDone |= Regs::RxDone_Complete; + + if (vnic->rxPacketBytes == rxDmaLen) { + // Packet is complete. Indicate how many bytes were copied + vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, rxDmaLen); + + DPRINTF(EthernetSM, + "rxKick: packet complete on vnic %d (rxunique %d)\n", + rxActive, vnic->rxUnique); + rxFifo.remove(vnic->rxPacket); + vnic->rxPacket = rxFifo.end(); + } else { + vnic->rxPacketBytes -= rxDmaLen; + vnic->rxPacketOffset += rxDmaLen; + vnic->RxDone |= Regs::RxDone_More; + vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, + vnic->rxPacketBytes); + DPRINTF(EthernetSM, + "rxKick: packet not complete on vnic %d (rxunique %d): " + "%d bytes left\n", + rxActive, vnic->rxUnique, vnic->rxPacketBytes); + } + + rxActive = -1; + rxState = rxBusy.empty() && rxList.empty() ? rxIdle : rxFifoBlock; + + if (rxFifo.empty()) { + devIntrPost(Regs::Intr_RxEmpty); + rxEmpty = true; + } + + if (rxFifo.size() < params()->rx_fifo_low_mark) + rxLow = true; + + if (rxFifo.size() > params()->rx_fifo_threshold) + rxLow = false; + + devIntrPost(Regs::Intr_RxDMA); + break; + + default: + panic("Invalid rxState!"); + } + + DPRINTF(EthernetSM, "entering next rxState=%s\n", + RxStateStrings[rxState]); + + goto next; + + exit: + /** + * @todo do we want to schedule a future kick? + */ + DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", + RxStateStrings[rxState]); +} + +void +Device::txDmaDone() +{ + assert(txState == txCopy); + txState = txCopyDone; + DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", + txDmaAddr, txDmaLen); + DDUMP(EthernetData, txDmaData, txDmaLen); + + // If the receive state machine has a pending DMA, let it go first + if (rxState == rxBeginCopy) + rxKick(); + + txKick(); +} + +void +Device::transmit() +{ + if (txFifo.empty()) { + DPRINTF(Ethernet, "nothing to transmit\n"); + return; + } + + uint32_t interrupts; + EthPacketPtr packet = txFifo.front(); + if (!interface->sendPacket(packet)) { + DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n", + txFifo.avail()); + goto reschedule; + } + + txFifo.pop(); +#if TRACING_ON + if (DTRACE(Ethernet)) { + IpPtr ip(packet); + if (ip) { + DPRINTF(Ethernet, "ID is %d\n", ip->id()); + TcpPtr tcp(ip); + if (tcp) { + DPRINTF(Ethernet, + "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", + tcp->sport(), tcp->dport(), tcp->seq(), + tcp->ack()); + } + } + } +#endif + + DDUMP(EthernetData, packet->data, packet->length); + txBytes += packet->length; + txPackets++; + + DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n", + txFifo.avail()); + + interrupts = Regs::Intr_TxPacket; + if (txFifo.size() < regs.TxFifoMark) + interrupts |= Regs::Intr_TxLow; + devIntrPost(interrupts); + + reschedule: + if (!txFifo.empty() && !txEvent.scheduled()) { + DPRINTF(Ethernet, "reschedule transmit\n"); + txEvent.schedule(curTick + retryTime); + } +} + +void +Device::txKick() +{ + VirtualReg *vnic; + DPRINTF(EthernetSM, "txKick: txState=%s (txFifo.size=%d)\n", + TxStateStrings[txState], txFifo.size()); + + if (txKickTick > curTick) { + DPRINTF(EthernetSM, "txKick: exiting, can't run till %d\n", + txKickTick); + return; + } + + next: + if (txState == txIdle) + goto exit; + + assert(!txList.empty()); + vnic = &virtualRegs[txList.front()]; + + switch (txState) { + case txFifoBlock: + assert(Regs::get_TxDone_Busy(vnic->TxDone)); + if (!txPacket) { + // Grab a new packet from the fifo. + txPacket = new EthPacketData(16384); + txPacketOffset = 0; + } + + if (txFifo.avail() - txPacket->length < + Regs::get_TxData_Len(vnic->TxData)) { + DPRINTF(EthernetSM, "transmit fifo full. Nothing to do.\n"); + goto exit; + } + + txState = txBeginCopy; + break; + + case txBeginCopy: + if (dmaPending()) + goto exit; + + txDmaAddr = params()->platform->pciToDma( + Regs::get_TxData_Addr(vnic->TxData)); + txDmaLen = Regs::get_TxData_Len(vnic->TxData); + txDmaData = txPacket->data + txPacketOffset; + txState = txCopy; + + dmaRead(txDmaAddr, txDmaLen, &txDmaEvent, txDmaData); + break; + + case txCopy: + DPRINTF(EthernetSM, "transmit machine still copying\n"); + goto exit; + + case txCopyDone: + vnic->TxDone = txDmaLen | Regs::TxDone_Complete; + txPacket->length += txDmaLen; + if ((vnic->TxData & Regs::TxData_More)) { + txPacketOffset += txDmaLen; + txState = txIdle; + devIntrPost(Regs::Intr_TxDMA); + break; + } + + assert(txPacket->length <= txFifo.avail()); + if ((vnic->TxData & Regs::TxData_Checksum)) { + IpPtr ip(txPacket); + if (ip) { + TcpPtr tcp(ip); + if (tcp) { + tcp->sum(0); + tcp->sum(cksum(tcp)); + txTcpChecksums++; + } + + UdpPtr udp(ip); + if (udp) { + udp->sum(0); + udp->sum(cksum(udp)); + txUdpChecksums++; + } + + ip->sum(0); + ip->sum(cksum(ip)); + txIpChecksums++; + } + } + + txFifo.push(txPacket); + if (txFifo.avail() < regs.TxMaxCopy) { + devIntrPost(Regs::Intr_TxFull); + txFull = true; + } + txPacket = 0; + transmit(); + txList.pop_front(); + txState = txList.empty() ? txIdle : txFifoBlock; + devIntrPost(Regs::Intr_TxDMA); + break; + + default: + panic("Invalid txState!"); + } + + DPRINTF(EthernetSM, "entering next txState=%s\n", + TxStateStrings[txState]); + + goto next; + + exit: + /** + * @todo do we want to schedule a future kick? + */ + DPRINTF(EthernetSM, "tx state machine exited txState=%s\n", + TxStateStrings[txState]); +} + +void +Device::transferDone() +{ + if (txFifo.empty()) { + DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n"); + return; + } + + DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); + + if (txEvent.scheduled()) + txEvent.reschedule(curTick + cycles(1)); + else + txEvent.schedule(curTick + cycles(1)); +} + +bool +Device::rxFilter(const EthPacketPtr &packet) +{ + if (!Regs::get_Config_Filter(regs.Config)) + return false; + + panic("receive filter not implemented\n"); + bool drop = true; + +#if 0 + string type; + + EthHdr *eth = packet->eth(); + if (eth->unicast()) { + // If we're accepting all unicast addresses + if (acceptUnicast) + drop = false; + + // If we make a perfect match + if (acceptPerfect && params->eaddr == eth.dst()) + drop = false; + + if (acceptArp && eth->type() == ETH_TYPE_ARP) + drop = false; + + } else if (eth->broadcast()) { + // if we're accepting broadcasts + if (acceptBroadcast) + drop = false; + + } else if (eth->multicast()) { + // if we're accepting all multicasts + if (acceptMulticast) + drop = false; + + } + + if (drop) { + DPRINTF(Ethernet, "rxFilter drop\n"); + DDUMP(EthernetData, packet->data, packet->length); + } +#endif + return drop; +} + +bool +Device::recvPacket(EthPacketPtr packet) +{ + rxBytes += packet->length; + rxPackets++; + + DPRINTF(Ethernet, "Receiving packet from wire, rxFifo Available is %d\n", + rxFifo.avail()); + + if (!rxEnable) { + DPRINTF(Ethernet, "receive disabled...packet dropped\n"); + return true; + } + + if (rxFilter(packet)) { + DPRINTF(Ethernet, "packet filtered...dropped\n"); + return true; + } + + if (rxFifo.size() >= regs.RxFifoMark) + devIntrPost(Regs::Intr_RxHigh); + + if (!rxFifo.push(packet)) { + DPRINTF(Ethernet, + "packet will not fit in receive buffer...packet dropped\n"); + return false; + } + + // If we were at the last element, back up one ot go to the new + // last element of the list. + if (rxFifoPtr == rxFifo.end()) + --rxFifoPtr; + + devIntrPost(Regs::Intr_RxPacket); + rxKick(); + return true; +} + +//===================================================================== +// +// +void +Base::serialize(std::ostream &os) +{ + // Serialize the PciDev base class + PciDev::serialize(os); + + SERIALIZE_SCALAR(rxEnable); + SERIALIZE_SCALAR(txEnable); + SERIALIZE_SCALAR(cpuIntrEnable); + + /* + * Keep track of pending interrupt status. + */ + SERIALIZE_SCALAR(intrTick); + SERIALIZE_SCALAR(cpuPendingIntr); + Tick intrEventTick = 0; + if (intrEvent) + intrEventTick = intrEvent->when(); + SERIALIZE_SCALAR(intrEventTick); +} + +void +Base::unserialize(Checkpoint *cp, const std::string §ion) +{ + // Unserialize the PciDev base class + PciDev::unserialize(cp, section); + + UNSERIALIZE_SCALAR(rxEnable); + UNSERIALIZE_SCALAR(txEnable); + UNSERIALIZE_SCALAR(cpuIntrEnable); + + /* + * Keep track of pending interrupt status. + */ + UNSERIALIZE_SCALAR(intrTick); + UNSERIALIZE_SCALAR(cpuPendingIntr); + Tick intrEventTick; + UNSERIALIZE_SCALAR(intrEventTick); + if (intrEventTick) { + intrEvent = new IntrEvent(this, true); + intrEvent->schedule(intrEventTick); + } +} + +void +Device::serialize(std::ostream &os) +{ + int count; + + // Serialize the PciDev base class + Base::serialize(os); + + if (rxState == rxCopy) + panic("can't serialize with an in flight dma request rxState=%s", + RxStateStrings[rxState]); + + if (txState == txCopy) + panic("can't serialize with an in flight dma request txState=%s", + TxStateStrings[txState]); + + /* + * Serialize the device registers + */ + SERIALIZE_SCALAR(regs.Config); + SERIALIZE_SCALAR(regs.IntrStatus); + SERIALIZE_SCALAR(regs.IntrMask); + SERIALIZE_SCALAR(regs.RxMaxCopy); + SERIALIZE_SCALAR(regs.TxMaxCopy); + SERIALIZE_SCALAR(regs.RxMaxIntr); + SERIALIZE_SCALAR(regs.VirtualCount); + SERIALIZE_SCALAR(regs.RxData); + SERIALIZE_SCALAR(regs.RxDone); + SERIALIZE_SCALAR(regs.TxData); + SERIALIZE_SCALAR(regs.TxDone); + + /* + * Serialize the virtual nic state + */ + int virtualRegsSize = virtualRegs.size(); + SERIALIZE_SCALAR(virtualRegsSize); + for (int i = 0; i < virtualRegsSize; ++i) { + VirtualReg *vnic = &virtualRegs[i]; + + std::string reg = csprintf("vnic%d", i); + paramOut(os, reg + ".RxData", vnic->RxData); + paramOut(os, reg + ".RxDone", vnic->RxDone); + paramOut(os, reg + ".TxData", vnic->TxData); + paramOut(os, reg + ".TxDone", vnic->TxDone); + + bool rxPacketExists = vnic->rxPacket != rxFifo.end(); + paramOut(os, reg + ".rxPacketExists", rxPacketExists); + if (rxPacketExists) { + int rxPacket = 0; + PacketFifo::iterator i = rxFifo.begin(); + while (i != vnic->rxPacket) { + assert(i != rxFifo.end()); + ++i; + ++rxPacket; + } + + paramOut(os, reg + ".rxPacket", rxPacket); + paramOut(os, reg + ".rxPacketOffset", vnic->rxPacketOffset); + paramOut(os, reg + ".rxPacketBytes", vnic->rxPacketBytes); + } + paramOut(os, reg + ".rxDoneData", vnic->rxDoneData); + } + + int rxFifoPtr = rxFifo.countPacketsBefore(this->rxFifoPtr); + SERIALIZE_SCALAR(rxFifoPtr); + + SERIALIZE_SCALAR(rxActive); + + VirtualList::iterator i, end; + for (count = 0, i = rxList.begin(), end = rxList.end(); i != end; ++i) + paramOut(os, csprintf("rxList%d", count++), *i); + int rxListSize = count; + SERIALIZE_SCALAR(rxListSize); + + for (count = 0, i = rxBusy.begin(), end = rxBusy.end(); i != end; ++i) + paramOut(os, csprintf("rxBusy%d", count++), *i); + int rxBusySize = count; + SERIALIZE_SCALAR(rxBusySize); + + for (count = 0, i = txList.begin(), end = txList.end(); i != end; ++i) + paramOut(os, csprintf("txList%d", count++), *i); + int txListSize = count; + SERIALIZE_SCALAR(txListSize); + + /* + * Serialize rx state machine + */ + int rxState = this->rxState; + SERIALIZE_SCALAR(rxState); + SERIALIZE_SCALAR(rxEmpty); + SERIALIZE_SCALAR(rxLow); + rxFifo.serialize("rxFifo", os); + + /* + * Serialize tx state machine + */ + int txState = this->txState; + SERIALIZE_SCALAR(txState); + SERIALIZE_SCALAR(txFull); + txFifo.serialize("txFifo", os); + bool txPacketExists = txPacket; + SERIALIZE_SCALAR(txPacketExists); + if (txPacketExists) { + txPacket->serialize("txPacket", os); + SERIALIZE_SCALAR(txPacketOffset); + SERIALIZE_SCALAR(txPacketBytes); + } + + /* + * If there's a pending transmit, store the time so we can + * reschedule it later + */ + Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0; + SERIALIZE_SCALAR(transmitTick); +} + +void +Device::unserialize(Checkpoint *cp, const std::string §ion) +{ + // Unserialize the PciDev base class + Base::unserialize(cp, section); + + /* + * Unserialize the device registers + */ + UNSERIALIZE_SCALAR(regs.Config); + UNSERIALIZE_SCALAR(regs.IntrStatus); + UNSERIALIZE_SCALAR(regs.IntrMask); + UNSERIALIZE_SCALAR(regs.RxMaxCopy); + UNSERIALIZE_SCALAR(regs.TxMaxCopy); + UNSERIALIZE_SCALAR(regs.RxMaxIntr); + UNSERIALIZE_SCALAR(regs.VirtualCount); + UNSERIALIZE_SCALAR(regs.RxData); + UNSERIALIZE_SCALAR(regs.RxDone); + UNSERIALIZE_SCALAR(regs.TxData); + UNSERIALIZE_SCALAR(regs.TxDone); + + UNSERIALIZE_SCALAR(rxActive); + + int rxListSize; + UNSERIALIZE_SCALAR(rxListSize); + rxList.clear(); + for (int i = 0; i < rxListSize; ++i) { + int value; + paramIn(cp, section, csprintf("rxList%d", i), value); + rxList.push_back(value); + } + + int rxBusySize; + UNSERIALIZE_SCALAR(rxBusySize); + rxBusy.clear(); + for (int i = 0; i < rxBusySize; ++i) { + int value; + paramIn(cp, section, csprintf("rxBusy%d", i), value); + rxBusy.push_back(value); + } + + int txListSize; + UNSERIALIZE_SCALAR(txListSize); + txList.clear(); + for (int i = 0; i < txListSize; ++i) { + int value; + paramIn(cp, section, csprintf("txList%d", i), value); + txList.push_back(value); + } + + /* + * Unserialize rx state machine + */ + int rxState; + UNSERIALIZE_SCALAR(rxState); + UNSERIALIZE_SCALAR(rxEmpty); + UNSERIALIZE_SCALAR(rxLow); + this->rxState = (RxState) rxState; + rxFifo.unserialize("rxFifo", cp, section); + + int rxFifoPtr; + UNSERIALIZE_SCALAR(rxFifoPtr); + this->rxFifoPtr = rxFifo.begin(); + for (int i = 0; i < rxFifoPtr; ++i) + ++this->rxFifoPtr; + + /* + * Unserialize tx state machine + */ + int txState; + UNSERIALIZE_SCALAR(txState); + UNSERIALIZE_SCALAR(txFull); + this->txState = (TxState) txState; + txFifo.unserialize("txFifo", cp, section); + bool txPacketExists; + UNSERIALIZE_SCALAR(txPacketExists); + txPacket = 0; + if (txPacketExists) { + txPacket = new EthPacketData(16384); + txPacket->unserialize("txPacket", cp, section); + UNSERIALIZE_SCALAR(txPacketOffset); + UNSERIALIZE_SCALAR(txPacketBytes); + } + + /* + * unserialize the virtual nic registers/state + * + * this must be done after the unserialization of the rxFifo + * because the packet iterators depend on the fifo being populated + */ + int virtualRegsSize; + UNSERIALIZE_SCALAR(virtualRegsSize); + virtualRegs.clear(); + virtualRegs.resize(virtualRegsSize); + for (int i = 0; i < virtualRegsSize; ++i) { + VirtualReg *vnic = &virtualRegs[i]; + std::string reg = csprintf("vnic%d", i); + + paramIn(cp, section, reg + ".RxData", vnic->RxData); + paramIn(cp, section, reg + ".RxDone", vnic->RxDone); + paramIn(cp, section, reg + ".TxData", vnic->TxData); + paramIn(cp, section, reg + ".TxDone", vnic->TxDone); + + vnic->rxUnique = rxUnique++; + vnic->txUnique = txUnique++; + + bool rxPacketExists; + paramIn(cp, section, reg + ".rxPacketExists", rxPacketExists); + if (rxPacketExists) { + int rxPacket; + paramIn(cp, section, reg + ".rxPacket", rxPacket); + vnic->rxPacket = rxFifo.begin(); + while (rxPacket--) + ++vnic->rxPacket; + + paramIn(cp, section, reg + ".rxPacketOffset", + vnic->rxPacketOffset); + paramIn(cp, section, reg + ".rxPacketBytes", vnic->rxPacketBytes); + } else { + vnic->rxPacket = rxFifo.end(); + } + paramIn(cp, section, reg + ".rxDoneData", vnic->rxDoneData); + } + + /* + * If there's a pending transmit, reschedule it now + */ + Tick transmitTick; + UNSERIALIZE_SCALAR(transmitTick); + if (transmitTick) + txEvent.schedule(curTick + transmitTick); + + pioPort->sendStatusChange(Port::RangeChange); + +} + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(Interface) + + SimObjectParam<EtherInt *> peer; + SimObjectParam<Device *> device; + +END_DECLARE_SIM_OBJECT_PARAMS(Interface) + +BEGIN_INIT_SIM_OBJECT_PARAMS(Interface) + + INIT_PARAM_DFLT(peer, "peer interface", NULL), + INIT_PARAM(device, "Ethernet device of this interface") + +END_INIT_SIM_OBJECT_PARAMS(Interface) + +CREATE_SIM_OBJECT(Interface) +{ + Interface *dev_int = new Interface(getInstanceName(), device); + + EtherInt *p = (EtherInt *)peer; + if (p) { + dev_int->setPeer(p); + p->setPeer(dev_int); + } + + return dev_int; +} + +REGISTER_SIM_OBJECT("SinicInt", Interface) + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(Device) + + + SimObjectParam<System *> system; + SimObjectParam<Platform *> platform; + SimObjectParam<PciConfigAll *> configspace; + SimObjectParam<PciConfigData *> configdata; + Param<uint32_t> pci_bus; + Param<uint32_t> pci_dev; + Param<uint32_t> pci_func; + Param<Tick> pio_latency; + Param<Tick> intr_delay; + + Param<Tick> clock; + Param<Tick> dma_read_delay; + Param<Tick> dma_read_factor; + Param<Tick> dma_write_delay; + Param<Tick> dma_write_factor; + + Param<Tick> rx_delay; + Param<Tick> tx_delay; + Param<uint32_t> rx_max_copy; + Param<uint32_t> tx_max_copy; + Param<uint32_t> rx_max_intr; + Param<uint32_t> rx_fifo_size; + Param<uint32_t> tx_fifo_size; + Param<uint32_t> rx_fifo_threshold; + Param<uint32_t> rx_fifo_low_mark; + Param<uint32_t> tx_fifo_high_mark; + Param<uint32_t> tx_fifo_threshold; + + Param<bool> rx_filter; + Param<std::string> hardware_address; + Param<bool> rx_thread; + Param<bool> tx_thread; + Param<bool> rss; + Param<uint32_t> virtual_count; + Param<bool> zero_copy; + Param<bool> delay_copy; + Param<bool> virtual_addr; + +END_DECLARE_SIM_OBJECT_PARAMS(Device) + +BEGIN_INIT_SIM_OBJECT_PARAMS(Device) + + + INIT_PARAM(system, "System pointer"), + INIT_PARAM(platform, "Platform pointer"), + INIT_PARAM(configspace, "PCI Configspace"), + INIT_PARAM(configdata, "PCI Config data"), + INIT_PARAM(pci_bus, "PCI bus ID"), + INIT_PARAM(pci_dev, "PCI device number"), + INIT_PARAM(pci_func, "PCI function code"), + INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), + INIT_PARAM(intr_delay, "Interrupt Delay"), + INIT_PARAM(clock, "State machine cycle time"), + + INIT_PARAM(dma_read_delay, "fixed delay for dma reads"), + INIT_PARAM(dma_read_factor, "multiplier for dma reads"), + INIT_PARAM(dma_write_delay, "fixed delay for dma writes"), + INIT_PARAM(dma_write_factor, "multiplier for dma writes"), + + INIT_PARAM(rx_delay, "Receive Delay"), + INIT_PARAM(tx_delay, "Transmit Delay"), + INIT_PARAM(rx_max_copy, "rx max copy"), + INIT_PARAM(tx_max_copy, "rx max copy"), + INIT_PARAM(rx_max_intr, "rx max intr"), + INIT_PARAM(rx_fifo_size, "max size in bytes of rxFifo"), + INIT_PARAM(tx_fifo_size, "max size in bytes of txFifo"), + INIT_PARAM(rx_fifo_threshold, "max size in bytes of rxFifo"), + INIT_PARAM(rx_fifo_low_mark, "max size in bytes of rxFifo"), + INIT_PARAM(tx_fifo_high_mark, "max size in bytes of txFifo"), + INIT_PARAM(tx_fifo_threshold, "max size in bytes of txFifo"), + + INIT_PARAM(rx_filter, "Enable Receive Filter"), + INIT_PARAM(hardware_address, "Ethernet Hardware Address"), + INIT_PARAM(rx_thread, ""), + INIT_PARAM(tx_thread, ""), + INIT_PARAM(rss, ""), + INIT_PARAM(virtual_count, ""), + INIT_PARAM(zero_copy, ""), + INIT_PARAM(delay_copy, ""), + INIT_PARAM(virtual_addr, "") + +END_INIT_SIM_OBJECT_PARAMS(Device) + + +CREATE_SIM_OBJECT(Device) +{ + Device::Params *params = new Device::Params; + params->name = getInstanceName(); + params->platform = platform; + params->system = system; + params->configSpace = configspace; + params->configData = configdata; + params->busNum = pci_bus; + params->deviceNum = pci_dev; + params->functionNum = pci_func; + params->pio_delay = pio_latency; + params->intr_delay = intr_delay; + params->clock = clock; + + params->dma_read_delay = dma_read_delay; + params->dma_read_factor = dma_read_factor; + params->dma_write_delay = dma_write_delay; + params->dma_write_factor = dma_write_factor; + + params->tx_delay = tx_delay; + params->rx_delay = rx_delay; + params->rx_max_copy = rx_max_copy; + params->tx_max_copy = tx_max_copy; + params->rx_max_intr = rx_max_intr; + params->rx_fifo_size = rx_fifo_size; + params->tx_fifo_size = tx_fifo_size; + params->rx_fifo_threshold = rx_fifo_threshold; + params->rx_fifo_low_mark = rx_fifo_low_mark; + params->tx_fifo_high_mark = tx_fifo_high_mark; + params->tx_fifo_threshold = tx_fifo_threshold; + + params->rx_filter = rx_filter; + params->eaddr = hardware_address; + params->rx_thread = rx_thread; + params->tx_thread = tx_thread; + params->rss = rss; + params->virtual_count = virtual_count; + params->zero_copy = zero_copy; + params->delay_copy = delay_copy; + params->virtual_addr = virtual_addr; + + return new Device(params); +} + +REGISTER_SIM_OBJECT("Sinic", Device) + +/* namespace Sinic */ } diff --git a/src/dev/sinic.hh b/src/dev/sinic.hh new file mode 100644 index 000000000..f6c229039 --- /dev/null +++ b/src/dev/sinic.hh @@ -0,0 +1,373 @@ +/* + * 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: Nathan Binkert + */ + +#ifndef __DEV_SINIC_HH__ +#define __DEV_SINIC_HH__ + +#include "base/inet.hh" +#include "base/statistics.hh" +#include "dev/etherint.hh" +#include "dev/etherpkt.hh" +#include "dev/io_device.hh" +#include "dev/pcidev.hh" +#include "dev/pktfifo.hh" +#include "dev/sinicreg.hh" +#include "sim/eventq.hh" + +namespace Sinic { + +class Interface; +class Base : public PciDev +{ + protected: + bool rxEnable; + bool txEnable; + Tick clock; + inline Tick cycles(int numCycles) const { return numCycles * clock; } + + protected: + Tick intrDelay; + Tick intrTick; + bool cpuIntrEnable; + bool cpuPendingIntr; + void cpuIntrPost(Tick when); + void cpuInterrupt(); + void cpuIntrClear(); + + typedef EventWrapper<Base, &Base::cpuInterrupt> IntrEvent; + friend void IntrEvent::process(); + IntrEvent *intrEvent; + Interface *interface; + + bool cpuIntrPending() const; + void cpuIntrAck() { cpuIntrClear(); } + +/** + * Serialization stuff + */ + public: + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + +/** + * Construction/Destruction/Parameters + */ + public: + struct Params : public PciDev::Params + { + Tick clock; + Tick intr_delay; + }; + + Base(Params *p); +}; + +class Device : public Base +{ + protected: + /** Receive State Machine States */ + enum RxState { + rxIdle, + rxFifoBlock, + rxBeginCopy, + rxCopy, + rxCopyDone + }; + + /** Transmit State Machine states */ + enum TxState { + txIdle, + txFifoBlock, + txBeginCopy, + txCopy, + txCopyDone + }; + + /** device register file */ + struct { + uint32_t Config; // 0x00 + uint32_t Command; // 0x04 + uint32_t IntrStatus; // 0x08 + uint32_t IntrMask; // 0x0c + uint32_t RxMaxCopy; // 0x10 + uint32_t TxMaxCopy; // 0x14 + uint32_t RxMaxIntr; // 0x18 + uint32_t VirtualCount; // 0x1c + uint32_t RxFifoSize; // 0x20 + uint32_t TxFifoSize; // 0x24 + uint32_t RxFifoMark; // 0x28 + uint32_t TxFifoMark; // 0x2c + uint64_t RxData; // 0x30 + uint64_t RxDone; // 0x38 + uint64_t RxWait; // 0x40 + uint64_t TxData; // 0x48 + uint64_t TxDone; // 0x50 + uint64_t TxWait; // 0x58 + uint64_t HwAddr; // 0x60 + } regs; + + struct VirtualReg { + uint64_t RxData; + uint64_t RxDone; + uint64_t TxData; + uint64_t TxDone; + + PacketFifo::iterator rxPacket; + int rxPacketOffset; + int rxPacketBytes; + uint64_t rxDoneData; + + Counter rxUnique; + Counter txUnique; + + VirtualReg() + : RxData(0), RxDone(0), TxData(0), TxDone(0), + rxPacketOffset(0), rxPacketBytes(0), rxDoneData(0) + { } + }; + typedef std::vector<VirtualReg> VirtualRegs; + typedef std::list<int> VirtualList; + Counter rxUnique; + Counter txUnique; + VirtualRegs virtualRegs; + VirtualList rxList; + VirtualList rxBusy; + int rxActive; + VirtualList txList; + + uint8_t ®Data8(Addr daddr) { return *((uint8_t *)®s + daddr); } + uint32_t ®Data32(Addr daddr) { return *(uint32_t *)®Data8(daddr); } + uint64_t ®Data64(Addr daddr) { return *(uint64_t *)®Data8(daddr); } + + protected: + RxState rxState; + PacketFifo rxFifo; + PacketFifo::iterator rxFifoPtr; + bool rxEmpty; + bool rxLow; + Addr rxDmaAddr; + uint8_t *rxDmaData; + int rxDmaLen; + + TxState txState; + PacketFifo txFifo; + bool txFull; + EthPacketPtr txPacket; + int txPacketOffset; + int txPacketBytes; + Addr txDmaAddr; + uint8_t *txDmaData; + int txDmaLen; + + protected: + void reset(); + + void rxKick(); + Tick rxKickTick; + typedef EventWrapper<Device, &Device::rxKick> RxKickEvent; + friend void RxKickEvent::process(); + + void txKick(); + Tick txKickTick; + typedef EventWrapper<Device, &Device::txKick> TxKickEvent; + friend void TxKickEvent::process(); + + /** + * Retransmit event + */ + void transmit(); + void txEventTransmit() + { + transmit(); + if (txState == txFifoBlock) + txKick(); + } + typedef EventWrapper<Device, &Device::txEventTransmit> TxEvent; + friend void TxEvent::process(); + TxEvent txEvent; + + void txDump() const; + void rxDump() const; + + /** + * receive address filter + */ + bool rxFilter(const EthPacketPtr &packet); + +/** + * device configuration + */ + void changeConfig(uint32_t newconfig); + void command(uint32_t command); + +/** + * device ethernet interface + */ + public: + bool recvPacket(EthPacketPtr packet); + void transferDone(); + void setInterface(Interface *i) { assert(!interface); interface = i; } + +/** + * DMA parameters + */ + protected: + void rxDmaDone(); + friend class EventWrapper<Device, &Device::rxDmaDone>; + EventWrapper<Device, &Device::rxDmaDone> rxDmaEvent; + + void txDmaDone(); + friend class EventWrapper<Device, &Device::txDmaDone>; + EventWrapper<Device, &Device::txDmaDone> txDmaEvent; + + Tick dmaReadDelay; + Tick dmaReadFactor; + Tick dmaWriteDelay; + Tick dmaWriteFactor; + +/** + * Interrupt management + */ + protected: + void devIntrPost(uint32_t interrupts); + void devIntrClear(uint32_t interrupts = Regs::Intr_All); + void devIntrChangeMask(uint32_t newmask); + +/** + * Memory Interface + */ + public: + virtual Tick read(Packet *pkt); + virtual Tick write(Packet *pkt); + + void prepareIO(int cpu, int index); + void prepareRead(int cpu, int index); + void prepareWrite(int cpu, int index); + // Fault iprRead(Addr daddr, int cpu, uint64_t &result); + +/** + * Statistics + */ + private: + Stats::Scalar<> rxBytes; + Stats::Formula rxBandwidth; + Stats::Scalar<> rxPackets; + Stats::Formula rxPacketRate; + Stats::Scalar<> rxIpPackets; + Stats::Scalar<> rxTcpPackets; + Stats::Scalar<> rxUdpPackets; + Stats::Scalar<> rxIpChecksums; + Stats::Scalar<> rxTcpChecksums; + Stats::Scalar<> rxUdpChecksums; + + Stats::Scalar<> txBytes; + Stats::Formula txBandwidth; + Stats::Formula totBandwidth; + Stats::Formula totPackets; + Stats::Formula totBytes; + Stats::Formula totPacketRate; + Stats::Scalar<> txPackets; + Stats::Formula txPacketRate; + Stats::Scalar<> txIpPackets; + Stats::Scalar<> txTcpPackets; + Stats::Scalar<> txUdpPackets; + Stats::Scalar<> txIpChecksums; + Stats::Scalar<> txTcpChecksums; + Stats::Scalar<> txUdpChecksums; + + public: + virtual void regStats(); + +/** + * Serialization stuff + */ + public: + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + +/** + * Construction/Destruction/Parameters + */ + public: + struct Params : public Base::Params + { + Tick tx_delay; + Tick rx_delay; + bool rx_filter; + Net::EthAddr eaddr; + uint32_t rx_max_copy; + uint32_t tx_max_copy; + uint32_t rx_max_intr; + uint32_t rx_fifo_size; + uint32_t tx_fifo_size; + uint32_t rx_fifo_threshold; + uint32_t rx_fifo_low_mark; + uint32_t tx_fifo_high_mark; + uint32_t tx_fifo_threshold; + Tick dma_read_delay; + Tick dma_read_factor; + Tick dma_write_delay; + Tick dma_write_factor; + bool rx_thread; + bool tx_thread; + bool rss; + uint32_t virtual_count; + bool zero_copy; + bool delay_copy; + bool virtual_addr; + }; + + protected: + const Params *params() const { return (const Params *)_params; } + + public: + Device(Params *params); + ~Device(); +}; + +/* + * Ethernet Interface for an Ethernet Device + */ +class Interface : public EtherInt +{ + private: + Device *dev; + + public: + Interface(const std::string &name, Device *d) + : EtherInt(name), dev(d) { dev->setInterface(this); } + + virtual bool recvPacket(EthPacketPtr pkt) { return dev->recvPacket(pkt); } + virtual void sendDone() { dev->transferDone(); } +}; + +/* namespace Sinic */ } + +#endif // __DEV_SINIC_HH__ diff --git a/src/dev/sinicreg.hh b/src/dev/sinicreg.hh new file mode 100644 index 000000000..de4188145 --- /dev/null +++ b/src/dev/sinicreg.hh @@ -0,0 +1,222 @@ +/* + * 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: Nathan Binkert + */ + +#ifndef __DEV_SINICREG_HH__ +#define __DEV_SINICREG_HH__ + +#define __SINIC_REG32(NAME, VAL) static const uint32_t NAME = (VAL) +#define __SINIC_REG64(NAME, VAL) static const uint64_t NAME = (VAL) + +#define __SINIC_VAL32(NAME, OFFSET, WIDTH) \ + static const uint32_t NAME##_width = WIDTH; \ + static const uint32_t NAME##_offset = OFFSET; \ + static const uint32_t NAME##_mask = (1 << WIDTH) - 1; \ + static const uint32_t NAME = ((1 << WIDTH) - 1) << OFFSET; \ + static inline uint32_t get_##NAME(uint32_t reg) \ + { return (reg & NAME) >> OFFSET; } \ + static inline uint32_t set_##NAME(uint32_t reg, uint32_t val) \ + { return (reg & ~NAME) | ((val << OFFSET) & NAME); } + +#define __SINIC_VAL64(NAME, OFFSET, WIDTH) \ + static const uint64_t NAME##_width = WIDTH; \ + static const uint64_t NAME##_offset = OFFSET; \ + static const uint64_t NAME##_mask = (ULL(1) << WIDTH) - 1; \ + static const uint64_t NAME = ((ULL(1) << WIDTH) - 1) << OFFSET; \ + static inline uint64_t get_##NAME(uint64_t reg) \ + { return (reg & NAME) >> OFFSET; } \ + static inline uint64_t set_##NAME(uint64_t reg, uint64_t val) \ + { return (reg & ~NAME) | ((val << OFFSET) & NAME); } + +namespace Sinic { +namespace Regs { + +static const int VirtualShift = 8; +static const int VirtualMask = 0xff; + +// Registers +__SINIC_REG32(Config, 0x00); // 32: configuration register +__SINIC_REG32(Command, 0x04); // 32: command register +__SINIC_REG32(IntrStatus, 0x08); // 32: interrupt status +__SINIC_REG32(IntrMask, 0x0c); // 32: interrupt mask +__SINIC_REG32(RxMaxCopy, 0x10); // 32: max bytes per rx copy +__SINIC_REG32(TxMaxCopy, 0x14); // 32: max bytes per tx copy +__SINIC_REG32(RxMaxIntr, 0x18); // 32: max receives per interrupt +__SINIC_REG32(VirtualCount, 0x1c); // 32: number of virutal NICs +__SINIC_REG32(RxFifoSize, 0x20); // 32: rx fifo capacity in bytes +__SINIC_REG32(TxFifoSize, 0x24); // 32: tx fifo capacity in bytes +__SINIC_REG32(RxFifoMark, 0x28); // 32: rx fifo high watermark +__SINIC_REG32(TxFifoMark, 0x2c); // 32: tx fifo low watermark +__SINIC_REG32(RxData, 0x30); // 64: receive data +__SINIC_REG32(RxDone, 0x38); // 64: receive done +__SINIC_REG32(RxWait, 0x40); // 64: receive done (busy wait) +__SINIC_REG32(TxData, 0x48); // 64: transmit data +__SINIC_REG32(TxDone, 0x50); // 64: transmit done +__SINIC_REG32(TxWait, 0x58); // 64: transmit done (busy wait) +__SINIC_REG32(HwAddr, 0x60); // 64: mac address +__SINIC_REG32(Size, 0x68); // register addres space size + +// Config register bits +__SINIC_VAL32(Config_ZeroCopy, 12, 1); // enable zero copy +__SINIC_VAL32(Config_DelayCopy,11, 1); // enable delayed copy +__SINIC_VAL32(Config_RSS, 10, 1); // enable receive side scaling +__SINIC_VAL32(Config_RxThread, 9, 1); // enable receive threads +__SINIC_VAL32(Config_TxThread, 8, 1); // enable transmit thread +__SINIC_VAL32(Config_Filter, 7, 1); // enable receive filter +__SINIC_VAL32(Config_Vlan, 6, 1); // enable vlan tagging +__SINIC_VAL32(Config_Vaddr, 5, 1); // enable virtual addressing +__SINIC_VAL32(Config_Desc, 4, 1); // enable tx/rx descriptors +__SINIC_VAL32(Config_Poll, 3, 1); // enable polling +__SINIC_VAL32(Config_IntEn, 2, 1); // enable interrupts +__SINIC_VAL32(Config_TxEn, 1, 1); // enable transmit +__SINIC_VAL32(Config_RxEn, 0, 1); // enable receive + +// Command register bits +__SINIC_VAL32(Command_Intr, 1, 1); // software interrupt +__SINIC_VAL32(Command_Reset, 0, 1); // reset chip + +// Interrupt register bits +__SINIC_VAL32(Intr_Soft, 8, 1); // software interrupt +__SINIC_VAL32(Intr_TxLow, 7, 1); // tx fifo dropped below watermark +__SINIC_VAL32(Intr_TxFull, 6, 1); // tx fifo full +__SINIC_VAL32(Intr_TxDMA, 5, 1); // tx dma completed w/ interrupt +__SINIC_VAL32(Intr_TxPacket, 4, 1); // packet transmitted +__SINIC_VAL32(Intr_RxHigh, 3, 1); // rx fifo above high watermark +__SINIC_VAL32(Intr_RxEmpty, 2, 1); // rx fifo empty +__SINIC_VAL32(Intr_RxDMA, 1, 1); // rx dma completed w/ interrupt +__SINIC_VAL32(Intr_RxPacket, 0, 1); // packet received +__SINIC_REG32(Intr_All, 0x01ff); // all valid interrupts +__SINIC_REG32(Intr_NoDelay, 0x01cc); // interrupts that aren't coalesced +__SINIC_REG32(Intr_Res, ~0x01ff); // reserved interrupt bits + +// RX Data Description +__SINIC_VAL64(RxData_Vaddr, 60, 1); // Addr is virtual +__SINIC_VAL64(RxData_Len, 40, 20); // 0 - 256k +__SINIC_VAL64(RxData_Addr, 0, 40); // Address 1TB + +// TX Data Description +__SINIC_VAL64(TxData_More, 63, 1); // Packet not complete (will dma more) +__SINIC_VAL64(TxData_Checksum, 62, 1); // do checksum +__SINIC_VAL64(TxData_Vaddr, 60, 1); // Addr is virtual +__SINIC_VAL64(TxData_Len, 40, 20); // 0 - 256k +__SINIC_VAL64(TxData_Addr, 0, 40); // Address 1TB + +// RX Done/Busy Information +__SINIC_VAL64(RxDone_Packets, 32, 16); // number of packets in rx fifo +__SINIC_VAL64(RxDone_Busy, 31, 1); // receive dma busy copying +__SINIC_VAL64(RxDone_Complete, 30, 1); // valid data (packet complete) +__SINIC_VAL64(RxDone_More, 29, 1); // Packet has more data (dma again) +__SINIC_VAL64(RxDone_Empty, 28, 1); // rx fifo is empty +__SINIC_VAL64(RxDone_High, 27, 1); // rx fifo is above the watermark +__SINIC_VAL64(RxDone_NotHigh, 26, 1); // rxfifo never hit the high watermark +__SINIC_VAL64(RxDone_TcpError, 25, 1); // TCP packet error (bad checksum) +__SINIC_VAL64(RxDone_UdpError, 24, 1); // UDP packet error (bad checksum) +__SINIC_VAL64(RxDone_IpError, 23, 1); // IP packet error (bad checksum) +__SINIC_VAL64(RxDone_TcpPacket, 22, 1); // this is a TCP packet +__SINIC_VAL64(RxDone_UdpPacket, 21, 1); // this is a UDP packet +__SINIC_VAL64(RxDone_IpPacket, 20, 1); // this is an IP packet +__SINIC_VAL64(RxDone_CopyLen, 0, 20); // up to 256k + +// TX Done/Busy Information +__SINIC_VAL64(TxDone_Packets, 32, 16); // number of packets in tx fifo +__SINIC_VAL64(TxDone_Busy, 31, 1); // transmit dma busy copying +__SINIC_VAL64(TxDone_Complete, 30, 1); // valid data (packet complete) +__SINIC_VAL64(TxDone_Full, 29, 1); // tx fifo is full +__SINIC_VAL64(TxDone_Low, 28, 1); // tx fifo is below the watermark +__SINIC_VAL64(TxDone_Res0, 27, 1); // reserved +__SINIC_VAL64(TxDone_Res1, 26, 1); // reserved +__SINIC_VAL64(TxDone_Res2, 25, 1); // reserved +__SINIC_VAL64(TxDone_Res3, 24, 1); // reserved +__SINIC_VAL64(TxDone_Res4, 23, 1); // reserved +__SINIC_VAL64(TxDone_Res5, 22, 1); // reserved +__SINIC_VAL64(TxDone_Res6, 21, 1); // reserved +__SINIC_VAL64(TxDone_Res7, 20, 1); // reserved +__SINIC_VAL64(TxDone_CopyLen, 0, 20); // up to 256k + +struct Info +{ + uint8_t size; + bool read; + bool write; + const char *name; +}; + +/* namespace Regs */ } + +inline const Regs::Info& +regInfo(Addr daddr) +{ + static Regs::Info invalid = { 0, false, false, "invalid" }; + static Regs::Info info [] = { + { 4, true, true, "Config" }, + { 4, false, true, "Command" }, + { 4, true, true, "IntrStatus" }, + { 4, true, true, "IntrMask" }, + { 4, true, false, "RxMaxCopy" }, + { 4, true, false, "TxMaxCopy" }, + { 4, true, false, "RxMaxIntr" }, + { 4, true, false, "VirtualCount" }, + { 4, true, false, "RxFifoSize" }, + { 4, true, false, "TxFifoSize" }, + { 4, true, false, "RxFifoMark" }, + { 4, true, false, "TxFifoMark" }, + { 8, true, true, "RxData" }, + invalid, + { 8, true, false, "RxDone" }, + invalid, + { 8, true, false, "RxWait" }, + invalid, + { 8, true, true, "TxData" }, + invalid, + { 8, true, false, "TxDone" }, + invalid, + { 8, true, false, "TxWait" }, + invalid, + { 8, true, false, "HwAddr" }, + invalid, + }; + + return info[daddr / 4]; +} + +inline bool +regValid(Addr daddr) +{ + if (daddr > Regs::Size) + return false; + + if (regInfo(daddr).size == 0) + return false; + + return true; +} + +/* namespace Sinic */ } + +#endif // __DEV_SINICREG_HH__ diff --git a/src/dev/tsunami.cc b/src/dev/tsunami.cc new file mode 100644 index 000000000..c9e15581d --- /dev/null +++ b/src/dev/tsunami.cc @@ -0,0 +1,129 @@ +/* + * 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: Ali Saidi + */ + +/** @file + * Implementation of Tsunami platform. + */ + +#include <deque> +#include <string> +#include <vector> + +#include "cpu/intr_control.hh" +#include "dev/simconsole.hh" +#include "dev/tsunami_cchip.hh" +#include "dev/tsunami_pchip.hh" +#include "dev/tsunami_io.hh" +#include "dev/tsunami.hh" +#include "sim/builder.hh" +#include "sim/system.hh" + +using namespace std; +//Should this be AlphaISA? +using namespace TheISA; + +Tsunami::Tsunami(const string &name, System *s, IntrControl *ic) + : Platform(name, ic), system(s) +{ + // set the back pointer from the system to myself + system->platform = this; + + for (int i = 0; i < Tsunami::Max_CPUs; i++) + intr_sum_type[i] = 0; +} + +Tick +Tsunami::intrFrequency() +{ + return io->frequency(); +} + +void +Tsunami::postConsoleInt() +{ + io->postPIC(0x10); +} + +void +Tsunami::clearConsoleInt() +{ + io->clearPIC(0x10); +} + +void +Tsunami::postPciInt(int line) +{ + cchip->postDRIR(line); +} + +void +Tsunami::clearPciInt(int line) +{ + cchip->clearDRIR(line); +} + +Addr +Tsunami::pciToDma(Addr pciAddr) const +{ + return pchip->translatePciToDma(pciAddr); +} + +void +Tsunami::serialize(std::ostream &os) +{ + SERIALIZE_ARRAY(intr_sum_type, Tsunami::Max_CPUs); +} + +void +Tsunami::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_ARRAY(intr_sum_type, Tsunami::Max_CPUs); +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(Tsunami) + + SimObjectParam<System *> system; + SimObjectParam<IntrControl *> intrctrl; + +END_DECLARE_SIM_OBJECT_PARAMS(Tsunami) + +BEGIN_INIT_SIM_OBJECT_PARAMS(Tsunami) + + INIT_PARAM(system, "system"), + INIT_PARAM(intrctrl, "interrupt controller") + +END_INIT_SIM_OBJECT_PARAMS(Tsunami) + +CREATE_SIM_OBJECT(Tsunami) +{ + return new Tsunami(getInstanceName(), system, intrctrl); +} + +REGISTER_SIM_OBJECT("Tsunami", Tsunami) diff --git a/src/dev/tsunami.hh b/src/dev/tsunami.hh new file mode 100644 index 000000000..13fc4417c --- /dev/null +++ b/src/dev/tsunami.hh @@ -0,0 +1,132 @@ +/* + * 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: Ali Saidi + */ + +/** + * @file + * Declaration of top level class for the Tsunami chipset. This class just + * retains pointers to all its children so the children can communicate. + */ + +#ifndef __DEV_TSUNAMI_HH__ +#define __DEV_TSUNAMI_HH__ + +#include "dev/platform.hh" + +class IdeController; +class TsunamiCChip; +class TsunamiPChip; +class TsunamiIO; +class System; + +/** + * Top level class for Tsunami Chipset emulation. + * This structure just contains pointers to all the + * children so the children can commnicate to do the + * read work + */ + +class Tsunami : public Platform +{ + public: + /** Max number of CPUs in a Tsunami */ + static const int Max_CPUs = 64; + + /** Pointer to the system */ + System *system; + + /** Pointer to the TsunamiIO device which has the RTC */ + TsunamiIO *io; + + /** Pointer to the Tsunami CChip. + * The chip contains some configuration information and + * all the interrupt mask and status registers + */ + TsunamiCChip *cchip; + + /** Pointer to the Tsunami PChip. + * The pchip is the interface to the PCI bus, in our case + * it does not have to do much. + */ + TsunamiPChip *pchip; + + int intr_sum_type[Tsunami::Max_CPUs]; + int ipi_pending[Tsunami::Max_CPUs]; + + public: + /** + * Constructor for the Tsunami Class. + * @param name name of the object + * @param intrctrl pointer to the interrupt controller + */ + Tsunami(const std::string &name, System *s, IntrControl *intctrl); + + /** + * Return the interrupting frequency to AlphaAccess + * @return frequency of RTC interrupts + */ + virtual Tick intrFrequency(); + + /** + * Cause the cpu to post a serial interrupt to the CPU. + */ + virtual void postConsoleInt(); + + /** + * Clear a posted CPU interrupt (id=55) + */ + virtual void clearConsoleInt(); + + /** + * Cause the chipset to post a cpi interrupt to the CPU. + */ + virtual void postPciInt(int line); + + /** + * Clear a posted PCI->CPU interrupt + */ + virtual void clearPciInt(int line); + + virtual Addr pciToDma(Addr pciAddr) const; + + /** + * Serialize this object to the given output stream. + * @param os The stream to serialize to. + */ + virtual void serialize(std::ostream &os); + + /** + * Reconstruct the state of this object from a checkpoint. + * @param cp The checkpoint use. + * @param section The section name of this object + */ + virtual void unserialize(Checkpoint *cp, const std::string §ion); +}; + +#endif // __DEV_TSUNAMI_HH__ diff --git a/src/dev/tsunami_cchip.cc b/src/dev/tsunami_cchip.cc new file mode 100644 index 000000000..3feb7439f --- /dev/null +++ b/src/dev/tsunami_cchip.cc @@ -0,0 +1,553 @@ +/* + * 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: Ali Saidi + * Ron Dreslinski + */ + +/** @file + * Emulation of the Tsunami CChip CSRs + */ + +#include <deque> +#include <string> +#include <vector> + +#include "arch/alpha/ev5.hh" +#include "base/trace.hh" +#include "dev/tsunami_cchip.hh" +#include "dev/tsunamireg.h" +#include "dev/tsunami.hh" +#include "mem/port.hh" +#include "cpu/thread_context.hh" +#include "cpu/intr_control.hh" +#include "sim/builder.hh" +#include "sim/system.hh" + +using namespace std; +//Should this be AlphaISA? +using namespace TheISA; + +TsunamiCChip::TsunamiCChip(Params *p) + : BasicPioDevice(p), tsunami(p->tsunami) +{ + pioSize = 0xfffffff; + + drir = 0; + ipint = 0; + itint = 0; + + for (int x = 0; x < Tsunami::Max_CPUs; x++) + { + dim[x] = 0; + dir[x] = 0; + } + + //Put back pointer in tsunami + tsunami->cchip = this; +} + +Tick +TsunamiCChip::read(Packet *pkt) +{ + DPRINTF(Tsunami, "read va=%#x size=%d\n", pkt->getAddr(), pkt->getSize()); + + assert(pkt->result == Packet::Unknown); + assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); + + Addr regnum = (pkt->getAddr() - pioAddr) >> 6; + Addr daddr = (pkt->getAddr() - pioAddr); + + pkt->allocate(); + switch (pkt->getSize()) { + + case sizeof(uint64_t): + if (daddr & TSDEV_CC_BDIMS) + { + pkt->set(dim[(daddr >> 4) & 0x3F]); + break; + } + + if (daddr & TSDEV_CC_BDIRS) + { + pkt->set(dir[(daddr >> 4) & 0x3F]); + break; + } + + switch(regnum) { + case TSDEV_CC_CSR: + pkt->set(0x0); + break; + case TSDEV_CC_MTR: + panic("TSDEV_CC_MTR not implemeted\n"); + break; + case TSDEV_CC_MISC: + pkt->set((ipint << 8) & 0xF | (itint << 4) & 0xF | + (pkt->req->getCpuNum() & 0x3)); + break; + case TSDEV_CC_AAR0: + case TSDEV_CC_AAR1: + case TSDEV_CC_AAR2: + case TSDEV_CC_AAR3: + pkt->set(0); + break; + case TSDEV_CC_DIM0: + pkt->set(dim[0]); + break; + case TSDEV_CC_DIM1: + pkt->set(dim[1]); + break; + case TSDEV_CC_DIM2: + pkt->set(dim[2]); + break; + case TSDEV_CC_DIM3: + pkt->set(dim[3]); + break; + case TSDEV_CC_DIR0: + pkt->set(dir[0]); + break; + case TSDEV_CC_DIR1: + pkt->set(dir[1]); + break; + case TSDEV_CC_DIR2: + pkt->set(dir[2]); + break; + case TSDEV_CC_DIR3: + pkt->set(dir[3]); + break; + case TSDEV_CC_DRIR: + pkt->set(drir); + break; + case TSDEV_CC_PRBEN: + panic("TSDEV_CC_PRBEN not implemented\n"); + break; + case TSDEV_CC_IIC0: + case TSDEV_CC_IIC1: + case TSDEV_CC_IIC2: + case TSDEV_CC_IIC3: + panic("TSDEV_CC_IICx not implemented\n"); + break; + case TSDEV_CC_MPR0: + case TSDEV_CC_MPR1: + case TSDEV_CC_MPR2: + case TSDEV_CC_MPR3: + panic("TSDEV_CC_MPRx not implemented\n"); + break; + case TSDEV_CC_IPIR: + pkt->set(ipint); + break; + case TSDEV_CC_ITIR: + pkt->set(itint); + break; + default: + panic("default in cchip read reached, accessing 0x%x\n"); + } // uint64_t + + break; + case sizeof(uint32_t): + case sizeof(uint16_t): + case sizeof(uint8_t): + default: + panic("invalid access size(?) for tsunami register!\n"); + } + DPRINTF(Tsunami, "Tsunami CChip: read regnum=%#x size=%d data=%lld\n", + regnum, pkt->getSize(), pkt->get<uint64_t>()); + + pkt->result = Packet::Success; + return pioDelay; +} + +Tick +TsunamiCChip::write(Packet *pkt) +{ + assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); + Addr daddr = pkt->getAddr() - pioAddr; + Addr regnum = (pkt->getAddr() - pioAddr) >> 6 ; + + + assert(pkt->getSize() == sizeof(uint64_t)); + + DPRINTF(Tsunami, "write - addr=%#x value=%#x\n", pkt->getAddr(), pkt->get<uint64_t>()); + + bool supportedWrite = false; + + + if (daddr & TSDEV_CC_BDIMS) + { + int number = (daddr >> 4) & 0x3F; + + uint64_t bitvector; + uint64_t olddim; + uint64_t olddir; + + olddim = dim[number]; + olddir = dir[number]; + dim[number] = pkt->get<uint64_t>(); + dir[number] = dim[number] & drir; + for(int x = 0; x < Tsunami::Max_CPUs; x++) + { + bitvector = ULL(1) << x; + // Figure out which bits have changed + if ((dim[number] & bitvector) != (olddim & bitvector)) + { + // The bit is now set and it wasn't before (set) + if((dim[number] & bitvector) && (dir[number] & bitvector)) + { + tsunami->intrctrl->post(number, TheISA::INTLEVEL_IRQ1, x); + DPRINTF(Tsunami, "dim write resulting in posting dir" + " interrupt to cpu %d\n", number); + } + else if ((olddir & bitvector) && + !(dir[number] & bitvector)) + { + // The bit was set and now its now clear and + // we were interrupting on that bit before + tsunami->intrctrl->clear(number, TheISA::INTLEVEL_IRQ1, x); + DPRINTF(Tsunami, "dim write resulting in clear" + " dir interrupt to cpu %d\n", number); + + } + + + } + } + } else { + switch(regnum) { + case TSDEV_CC_CSR: + panic("TSDEV_CC_CSR write\n"); + case TSDEV_CC_MTR: + panic("TSDEV_CC_MTR write not implemented\n"); + case TSDEV_CC_MISC: + uint64_t ipreq; + ipreq = (pkt->get<uint64_t>() >> 12) & 0xF; + //If it is bit 12-15, this is an IPI post + if (ipreq) { + reqIPI(ipreq); + supportedWrite = true; + } + + //If it is bit 8-11, this is an IPI clear + uint64_t ipintr; + ipintr = (pkt->get<uint64_t>() >> 8) & 0xF; + if (ipintr) { + clearIPI(ipintr); + supportedWrite = true; + } + + //If it is the 4-7th bit, clear the RTC interrupt + uint64_t itintr; + itintr = (pkt->get<uint64_t>() >> 4) & 0xF; + if (itintr) { + clearITI(itintr); + supportedWrite = true; + } + + // ignore NXMs + if (pkt->get<uint64_t>() & 0x10000000) + supportedWrite = true; + + if(!supportedWrite) + panic("TSDEV_CC_MISC write not implemented\n"); + + break; + case TSDEV_CC_AAR0: + case TSDEV_CC_AAR1: + case TSDEV_CC_AAR2: + case TSDEV_CC_AAR3: + panic("TSDEV_CC_AARx write not implemeted\n"); + case TSDEV_CC_DIM0: + case TSDEV_CC_DIM1: + case TSDEV_CC_DIM2: + case TSDEV_CC_DIM3: + int number; + if(regnum == TSDEV_CC_DIM0) + number = 0; + else if(regnum == TSDEV_CC_DIM1) + number = 1; + else if(regnum == TSDEV_CC_DIM2) + number = 2; + else + number = 3; + + uint64_t bitvector; + uint64_t olddim; + uint64_t olddir; + + olddim = dim[number]; + olddir = dir[number]; + dim[number] = pkt->get<uint64_t>(); + dir[number] = dim[number] & drir; + for(int x = 0; x < 64; x++) + { + bitvector = ULL(1) << x; + // Figure out which bits have changed + if ((dim[number] & bitvector) != (olddim & bitvector)) + { + // The bit is now set and it wasn't before (set) + if((dim[number] & bitvector) && (dir[number] & bitvector)) + { + tsunami->intrctrl->post(number, TheISA::INTLEVEL_IRQ1, x); + DPRINTF(Tsunami, "posting dir interrupt to cpu 0\n"); + } + else if ((olddir & bitvector) && + !(dir[number] & bitvector)) + { + // The bit was set and now its now clear and + // we were interrupting on that bit before + tsunami->intrctrl->clear(number, TheISA::INTLEVEL_IRQ1, x); + DPRINTF(Tsunami, "dim write resulting in clear" + " dir interrupt to cpu %d\n", + x); + + } + + + } + } + break; + case TSDEV_CC_DIR0: + case TSDEV_CC_DIR1: + case TSDEV_CC_DIR2: + case TSDEV_CC_DIR3: + panic("TSDEV_CC_DIR write not implemented\n"); + case TSDEV_CC_DRIR: + panic("TSDEV_CC_DRIR write not implemented\n"); + case TSDEV_CC_PRBEN: + panic("TSDEV_CC_PRBEN write not implemented\n"); + case TSDEV_CC_IIC0: + case TSDEV_CC_IIC1: + case TSDEV_CC_IIC2: + case TSDEV_CC_IIC3: + panic("TSDEV_CC_IICx write not implemented\n"); + case TSDEV_CC_MPR0: + case TSDEV_CC_MPR1: + case TSDEV_CC_MPR2: + case TSDEV_CC_MPR3: + panic("TSDEV_CC_MPRx write not implemented\n"); + case TSDEV_CC_IPIR: + clearIPI(pkt->get<uint64_t>()); + break; + case TSDEV_CC_ITIR: + clearITI(pkt->get<uint64_t>()); + break; + case TSDEV_CC_IPIQ: + reqIPI(pkt->get<uint64_t>()); + break; + default: + panic("default in cchip read reached, accessing 0x%x\n"); + } // swtich(regnum) + } // not BIG_TSUNAMI write + pkt->result = Packet::Success; + return pioDelay; +} + +void +TsunamiCChip::clearIPI(uint64_t ipintr) +{ + int numcpus = tsunami->intrctrl->cpu->system->threadContexts.size(); + assert(numcpus <= Tsunami::Max_CPUs); + + if (ipintr) { + for (int cpunum=0; cpunum < numcpus; cpunum++) { + // Check each cpu bit + uint64_t cpumask = ULL(1) << cpunum; + if (ipintr & cpumask) { + // Check if there is a pending ipi + if (ipint & cpumask) { + ipint &= ~cpumask; + tsunami->intrctrl->clear(cpunum, TheISA::INTLEVEL_IRQ3, 0); + DPRINTF(IPI, "clear IPI IPI cpu=%d\n", cpunum); + } + else + warn("clear IPI for CPU=%d, but NO IPI\n", cpunum); + } + } + } + else + panic("Big IPI Clear, but not processors indicated\n"); +} + +void +TsunamiCChip::clearITI(uint64_t itintr) +{ + int numcpus = tsunami->intrctrl->cpu->system->threadContexts.size(); + assert(numcpus <= Tsunami::Max_CPUs); + + if (itintr) { + for (int i=0; i < numcpus; i++) { + uint64_t cpumask = ULL(1) << i; + if (itintr & cpumask & itint) { + tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ2, 0); + itint &= ~cpumask; + DPRINTF(Tsunami, "clearing rtc interrupt to cpu=%d\n", i); + } + } + } + else + panic("Big ITI Clear, but not processors indicated\n"); +} + +void +TsunamiCChip::reqIPI(uint64_t ipreq) +{ + int numcpus = tsunami->intrctrl->cpu->system->threadContexts.size(); + assert(numcpus <= Tsunami::Max_CPUs); + + if (ipreq) { + for (int cpunum=0; cpunum < numcpus; cpunum++) { + // Check each cpu bit + uint64_t cpumask = ULL(1) << cpunum; + if (ipreq & cpumask) { + // Check if there is already an ipi (bits 8:11) + if (!(ipint & cpumask)) { + ipint |= cpumask; + tsunami->intrctrl->post(cpunum, TheISA::INTLEVEL_IRQ3, 0); + DPRINTF(IPI, "send IPI cpu=%d\n", cpunum); + } + else + warn("post IPI for CPU=%d, but IPI already\n", cpunum); + } + } + } + else + panic("Big IPI Request, but not processors indicated\n"); +} + + +void +TsunamiCChip::postRTC() +{ + int size = tsunami->intrctrl->cpu->system->threadContexts.size(); + assert(size <= Tsunami::Max_CPUs); + + for (int i = 0; i < size; i++) { + uint64_t cpumask = ULL(1) << i; + if (!(cpumask & itint)) { + itint |= cpumask; + tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ2, 0); + DPRINTF(Tsunami, "Posting RTC interrupt to cpu=%d", i); + } + } + +} + +void +TsunamiCChip::postDRIR(uint32_t interrupt) +{ + uint64_t bitvector = ULL(1) << interrupt; + uint64_t size = tsunami->intrctrl->cpu->system->threadContexts.size(); + assert(size <= Tsunami::Max_CPUs); + drir |= bitvector; + + for(int i=0; i < size; i++) { + dir[i] = dim[i] & drir; + if (dim[i] & bitvector) { + tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ1, interrupt); + DPRINTF(Tsunami, "posting dir interrupt to cpu %d," + "interrupt %d\n",i, interrupt); + } + } +} + +void +TsunamiCChip::clearDRIR(uint32_t interrupt) +{ + uint64_t bitvector = ULL(1) << interrupt; + uint64_t size = tsunami->intrctrl->cpu->system->threadContexts.size(); + assert(size <= Tsunami::Max_CPUs); + + if (drir & bitvector) + { + drir &= ~bitvector; + for(int i=0; i < size; i++) { + if (dir[i] & bitvector) { + tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ1, interrupt); + DPRINTF(Tsunami, "clearing dir interrupt to cpu %d," + "interrupt %d\n",i, interrupt); + + } + dir[i] = dim[i] & drir; + } + } + else + DPRINTF(Tsunami, "Spurrious clear? interrupt %d\n", interrupt); +} + + +void +TsunamiCChip::serialize(std::ostream &os) +{ + SERIALIZE_ARRAY(dim, Tsunami::Max_CPUs); + SERIALIZE_ARRAY(dir, Tsunami::Max_CPUs); + SERIALIZE_SCALAR(ipint); + SERIALIZE_SCALAR(itint); + SERIALIZE_SCALAR(drir); +} + +void +TsunamiCChip::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_ARRAY(dim, Tsunami::Max_CPUs); + UNSERIALIZE_ARRAY(dir, Tsunami::Max_CPUs); + UNSERIALIZE_SCALAR(ipint); + UNSERIALIZE_SCALAR(itint); + UNSERIALIZE_SCALAR(drir); +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip) + + Param<Addr> pio_addr; + Param<Tick> pio_latency; + SimObjectParam<Platform *> platform; + SimObjectParam<System *> system; + SimObjectParam<Tsunami *> tsunami; + +END_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip) + +BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiCChip) + + INIT_PARAM(pio_addr, "Device Address"), + INIT_PARAM(pio_latency, "Programmed IO latency"), + INIT_PARAM(platform, "platform"), + INIT_PARAM(system, "system object"), + INIT_PARAM(tsunami, "Tsunami") + +END_INIT_SIM_OBJECT_PARAMS(TsunamiCChip) + +CREATE_SIM_OBJECT(TsunamiCChip) +{ + TsunamiCChip::Params *p = new TsunamiCChip::Params; + p->name = getInstanceName(); + p->pio_addr = pio_addr; + p->pio_delay = pio_latency; + p->platform = platform; + p->system = system; + p->tsunami = tsunami; + return new TsunamiCChip(p); +} + +REGISTER_SIM_OBJECT("TsunamiCChip", TsunamiCChip) diff --git a/src/dev/tsunami_cchip.hh b/src/dev/tsunami_cchip.hh new file mode 100644 index 000000000..ef43f621f --- /dev/null +++ b/src/dev/tsunami_cchip.hh @@ -0,0 +1,152 @@ +/* + * 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: Ali Saidi + */ + +/** @file + * Emulation of the Tsunami CChip CSRs + */ + +#ifndef __TSUNAMI_CCHIP_HH__ +#define __TSUNAMI_CCHIP_HH__ + +#include "dev/tsunami.hh" +#include "base/range.hh" +#include "dev/io_device.hh" + + +/** + * Tsunami CChip CSR Emulation. This device includes all the interrupt + * handling code for the chipset. + */ +class TsunamiCChip : public BasicPioDevice +{ + protected: + /** + * pointer to the tsunami object. + * This is our access to all the other tsunami + * devices. + */ + Tsunami *tsunami; + + /** + * The dims are device interrupt mask registers. + * One exists for each CPU, the DRIR X DIM = DIR + */ + uint64_t dim[Tsunami::Max_CPUs]; + + /** + * The dirs are device interrupt registers. + * One exists for each CPU, the DRIR X DIM = DIR + */ + uint64_t dir[Tsunami::Max_CPUs]; + + /** + * This register contains bits for each PCI interrupt + * that can occur. + */ + uint64_t drir; + + /** Indicator of which CPUs have an IPI interrupt */ + uint64_t ipint; + + /** Indicator of which CPUs have an RTC interrupt */ + uint64_t itint; + + public: + struct Params : public BasicPioDevice::Params + { + Tsunami *tsunami; + }; + protected: + const Params *params() const {return (const Params *)_params; } + + public: + /** + * Initialize the Tsunami CChip by setting all of the + * device register to 0. + * @param p params struct + */ + TsunamiCChip(Params *p); + + virtual Tick read(Packet *pkt); + + virtual Tick write(Packet *pkt); + + /** + * post an RTC interrupt to the CPU + */ + void postRTC(); + + /** + * post an interrupt to the CPU. + * @param interrupt the interrupt number to post (0-64) + */ + void postDRIR(uint32_t interrupt); + + /** + * clear an interrupt previously posted to the CPU. + * @param interrupt the interrupt number to post (0-64) + */ + void clearDRIR(uint32_t interrupt); + + /** + * post an ipi interrupt to the CPU. + * @param ipintr the cpu number to clear(bitvector) + */ + void clearIPI(uint64_t ipintr); + + /** + * clear a timer interrupt previously posted to the CPU. + * @param itintr the cpu number to clear(bitvector) + */ + void clearITI(uint64_t itintr); + + /** + * request an interrupt be posted to the CPU. + * @param ipreq the cpu number to interrupt(bitvector) + */ + void reqIPI(uint64_t ipreq); + + + /** + * Serialize this object to the given output stream. + * @param os The stream to serialize to. + */ + virtual void serialize(std::ostream &os); + + /** + * Reconstruct the state of this object from a checkpoint. + * @param cp The checkpoint use. + * @param section The section name of this object + */ + virtual void unserialize(Checkpoint *cp, const std::string §ion); + +}; + +#endif // __TSUNAMI_CCHIP_HH__ diff --git a/src/dev/tsunami_io.cc b/src/dev/tsunami_io.cc new file mode 100644 index 000000000..e3da10eb5 --- /dev/null +++ b/src/dev/tsunami_io.cc @@ -0,0 +1,686 @@ +/* + * 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: Ali Saidi + * Andrew Schultz + * Miguel Serrano + */ + +/** @file + * Tsunami I/O including PIC, PIT, RTC, DMA + */ + +#include <sys/time.h> + +#include <deque> +#include <string> +#include <vector> + +#include "base/trace.hh" +#include "dev/pitreg.h" +#include "dev/rtcreg.h" +#include "dev/tsunami_cchip.hh" +#include "dev/tsunami.hh" +#include "dev/tsunami_io.hh" +#include "dev/tsunamireg.h" +#include "mem/port.hh" +#include "sim/builder.hh" +#include "sim/system.hh" + +using namespace std; +//Should this be AlphaISA? +using namespace TheISA; + +TsunamiIO::RTC::RTC(const string &name, Tsunami* t, Tick i) + : _name(name), event(t, i), addr(0) +{ + memset(clock_data, 0, sizeof(clock_data)); + stat_regA = RTCA_32768HZ | RTCA_1024HZ; + stat_regB = RTCB_PRDC_IE |RTCB_BIN | RTCB_24HR; +} + +void +TsunamiIO::RTC::set_time(time_t t) +{ + struct tm tm; + gmtime_r(&t, &tm); + + sec = tm.tm_sec; + min = tm.tm_min; + hour = tm.tm_hour; + wday = tm.tm_wday + 1; + mday = tm.tm_mday; + mon = tm.tm_mon + 1; + year = tm.tm_year; + + DPRINTFN("Real-time clock set to %s", asctime(&tm)); +} + +void +TsunamiIO::RTC::writeAddr(const uint8_t data) +{ + if (data <= RTC_STAT_REGD) + addr = data; + else + panic("RTC addresses over 0xD are not implemented.\n"); +} + +void +TsunamiIO::RTC::writeData(const uint8_t data) +{ + if (addr < RTC_STAT_REGA) + clock_data[addr] = data; + else { + switch (addr) { + case RTC_STAT_REGA: + if (data != (RTCA_32768HZ | RTCA_1024HZ)) + panic("Unimplemented RTC register A value write!\n"); + stat_regA = data; + break; + case RTC_STAT_REGB: + if ((data & ~(RTCB_PRDC_IE | RTCB_SQWE)) != (RTCB_BIN | RTCB_24HR)) + panic("Write to RTC reg B bits that are not implemented!\n"); + + if (data & RTCB_PRDC_IE) { + if (!event.scheduled()) + event.scheduleIntr(); + } else { + if (event.scheduled()) + event.deschedule(); + } + stat_regB = data; + break; + case RTC_STAT_REGC: + case RTC_STAT_REGD: + panic("RTC status registers C and D are not implemented.\n"); + break; + } + } +} + +uint8_t +TsunamiIO::RTC::readData() +{ + if (addr < RTC_STAT_REGA) + return clock_data[addr]; + else { + switch (addr) { + case RTC_STAT_REGA: + // toggle UIP bit for linux + stat_regA ^= RTCA_UIP; + return stat_regA; + break; + case RTC_STAT_REGB: + return stat_regB; + break; + case RTC_STAT_REGC: + case RTC_STAT_REGD: + return 0x00; + break; + default: + panic("Shouldn't be here"); + } + } +} + +void +TsunamiIO::RTC::serialize(const string &base, ostream &os) +{ + paramOut(os, base + ".addr", addr); + arrayParamOut(os, base + ".clock_data", clock_data, sizeof(clock_data)); + paramOut(os, base + ".stat_regA", stat_regA); + paramOut(os, base + ".stat_regB", stat_regB); +} + +void +TsunamiIO::RTC::unserialize(const string &base, Checkpoint *cp, + const string §ion) +{ + paramIn(cp, section, base + ".addr", addr); + arrayParamIn(cp, section, base + ".clock_data", clock_data, + sizeof(clock_data)); + paramIn(cp, section, base + ".stat_regA", stat_regA); + paramIn(cp, section, base + ".stat_regB", stat_regB); + + // We're not unserializing the event here, but we need to + // rescehedule the event since curTick was moved forward by the + // checkpoint + event.reschedule(curTick + event.interval); +} + +TsunamiIO::RTC::RTCEvent::RTCEvent(Tsunami*t, Tick i) + : Event(&mainEventQueue), tsunami(t), interval(i) +{ + DPRINTF(MC146818, "RTC Event Initilizing\n"); + schedule(curTick + interval); +} + +void +TsunamiIO::RTC::RTCEvent::scheduleIntr() +{ + schedule(curTick + interval); +} + +void +TsunamiIO::RTC::RTCEvent::process() +{ + DPRINTF(MC146818, "RTC Timer Interrupt\n"); + schedule(curTick + interval); + //Actually interrupt the processor here + tsunami->cchip->postRTC(); +} + +const char * +TsunamiIO::RTC::RTCEvent::description() +{ + return "tsunami RTC interrupt"; +} + +TsunamiIO::PITimer::PITimer(const string &name) + : _name(name), counter0(name + ".counter0"), counter1(name + ".counter1"), + counter2(name + ".counter2") +{ + counter[0] = &counter0; + counter[1] = &counter0; + counter[2] = &counter0; +} + +void +TsunamiIO::PITimer::writeControl(const uint8_t data) +{ + int rw; + int sel; + + sel = GET_CTRL_SEL(data); + + if (sel == PIT_READ_BACK) + panic("PITimer Read-Back Command is not implemented.\n"); + + rw = GET_CTRL_RW(data); + + if (rw == PIT_RW_LATCH_COMMAND) + counter[sel]->latchCount(); + else { + counter[sel]->setRW(rw); + counter[sel]->setMode(GET_CTRL_MODE(data)); + counter[sel]->setBCD(GET_CTRL_BCD(data)); + } +} + +void +TsunamiIO::PITimer::serialize(const string &base, ostream &os) +{ + // serialize the counters + counter0.serialize(base + ".counter0", os); + counter1.serialize(base + ".counter1", os); + counter2.serialize(base + ".counter2", os); +} + +void +TsunamiIO::PITimer::unserialize(const string &base, Checkpoint *cp, + const string §ion) +{ + // unserialze the counters + counter0.unserialize(base + ".counter0", cp, section); + counter1.unserialize(base + ".counter1", cp, section); + counter2.unserialize(base + ".counter2", cp, section); +} + +TsunamiIO::PITimer::Counter::Counter(const string &name) + : _name(name), event(this), count(0), latched_count(0), period(0), + mode(0), output_high(false), latch_on(false), read_byte(LSB), + write_byte(LSB) +{ + +} + +void +TsunamiIO::PITimer::Counter::latchCount() +{ + // behave like a real latch + if(!latch_on) { + latch_on = true; + read_byte = LSB; + latched_count = count; + } +} + +uint8_t +TsunamiIO::PITimer::Counter::read() +{ + if (latch_on) { + switch (read_byte) { + case LSB: + read_byte = MSB; + return (uint8_t)latched_count; + break; + case MSB: + read_byte = LSB; + latch_on = false; + return latched_count >> 8; + break; + default: + panic("Shouldn't be here"); + } + } else { + switch (read_byte) { + case LSB: + read_byte = MSB; + return (uint8_t)count; + break; + case MSB: + read_byte = LSB; + return count >> 8; + break; + default: + panic("Shouldn't be here"); + } + } +} + +void +TsunamiIO::PITimer::Counter::write(const uint8_t data) +{ + switch (write_byte) { + case LSB: + count = (count & 0xFF00) | data; + + if (event.scheduled()) + event.deschedule(); + output_high = false; + write_byte = MSB; + break; + + case MSB: + count = (count & 0x00FF) | (data << 8); + period = count; + + if (period > 0) { + DPRINTF(Tsunami, "Timer set to curTick + %d\n", + count * event.interval); + event.schedule(curTick + count * event.interval); + } + write_byte = LSB; + break; + } +} + +void +TsunamiIO::PITimer::Counter::setRW(int rw_val) +{ + if (rw_val != PIT_RW_16BIT) + panic("Only LSB/MSB read/write is implemented.\n"); +} + +void +TsunamiIO::PITimer::Counter::setMode(int mode_val) +{ + if(mode_val != PIT_MODE_INTTC && mode_val != PIT_MODE_RATEGEN && + mode_val != PIT_MODE_SQWAVE) + panic("PIT mode %#x is not implemented: \n", mode_val); + + mode = mode_val; +} + +void +TsunamiIO::PITimer::Counter::setBCD(int bcd_val) +{ + if (bcd_val != PIT_BCD_FALSE) + panic("PITimer does not implement BCD counts.\n"); +} + +bool +TsunamiIO::PITimer::Counter::outputHigh() +{ + return output_high; +} + +void +TsunamiIO::PITimer::Counter::serialize(const string &base, ostream &os) +{ + paramOut(os, base + ".count", count); + paramOut(os, base + ".latched_count", latched_count); + paramOut(os, base + ".period", period); + paramOut(os, base + ".mode", mode); + paramOut(os, base + ".output_high", output_high); + paramOut(os, base + ".latch_on", latch_on); + paramOut(os, base + ".read_byte", read_byte); + paramOut(os, base + ".write_byte", write_byte); + + Tick event_tick = 0; + if (event.scheduled()) + event_tick = event.when(); + paramOut(os, base + ".event_tick", event_tick); +} + +void +TsunamiIO::PITimer::Counter::unserialize(const string &base, Checkpoint *cp, + const string §ion) +{ + paramIn(cp, section, base + ".count", count); + paramIn(cp, section, base + ".latched_count", latched_count); + paramIn(cp, section, base + ".period", period); + paramIn(cp, section, base + ".mode", mode); + paramIn(cp, section, base + ".output_high", output_high); + paramIn(cp, section, base + ".latch_on", latch_on); + paramIn(cp, section, base + ".read_byte", read_byte); + paramIn(cp, section, base + ".write_byte", write_byte); + + Tick event_tick; + paramIn(cp, section, base + ".event_tick", event_tick); + if (event_tick) + event.schedule(event_tick); +} + +TsunamiIO::PITimer::Counter::CounterEvent::CounterEvent(Counter* c_ptr) + : Event(&mainEventQueue) +{ + interval = (Tick)(Clock::Float::s / 1193180.0); + counter = c_ptr; +} + +void +TsunamiIO::PITimer::Counter::CounterEvent::process() +{ + DPRINTF(Tsunami, "Timer Interrupt\n"); + switch (counter->mode) { + case PIT_MODE_INTTC: + counter->output_high = true; + case PIT_MODE_RATEGEN: + case PIT_MODE_SQWAVE: + break; + default: + panic("Unimplemented PITimer mode.\n"); + } +} + +const char * +TsunamiIO::PITimer::Counter::CounterEvent::description() +{ + return "tsunami 8254 Interval timer"; +} + +TsunamiIO::TsunamiIO(Params *p) + : BasicPioDevice(p), tsunami(p->tsunami), pitimer(p->name + "pitimer"), + rtc(p->name + ".rtc", p->tsunami, p->frequency) +{ + pioSize = 0xff; + + // set the back pointer from tsunami to myself + tsunami->io = this; + + timerData = 0; + rtc.set_time(p->init_time == 0 ? time(NULL) : p->init_time); + picr = 0; + picInterrupting = false; +} + +Tick +TsunamiIO::frequency() const +{ + return Clock::Frequency / params()->frequency; +} + +Tick +TsunamiIO::read(Packet *pkt) +{ + assert(pkt->result == Packet::Unknown); + assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); + + Addr daddr = pkt->getAddr() - pioAddr; + + DPRINTF(Tsunami, "io read va=%#x size=%d IOPorrt=%#x\n", pkt->getAddr(), + pkt->getSize(), daddr); + + pkt->allocate(); + + if (pkt->getSize() == sizeof(uint8_t)) { + switch(daddr) { + // PIC1 mask read + case TSDEV_PIC1_MASK: + pkt->set(~mask1); + break; + case TSDEV_PIC2_MASK: + pkt->set(~mask2); + break; + case TSDEV_PIC1_ISR: + // !!! If this is modified 64bit case needs to be too + // Pal code has to do a 64 bit physical read because there is + // no load physical byte instruction + pkt->set(picr); + break; + case TSDEV_PIC2_ISR: + // PIC2 not implemnted... just return 0 + pkt->set(0x00); + break; + case TSDEV_TMR0_DATA: + pkt->set(pitimer.counter0.read()); + break; + case TSDEV_TMR1_DATA: + pkt->set(pitimer.counter1.read()); + break; + case TSDEV_TMR2_DATA: + pkt->set(pitimer.counter2.read()); + break; + case TSDEV_RTC_DATA: + pkt->set(rtc.readData()); + break; + case TSDEV_CTRL_PORTB: + if (pitimer.counter2.outputHigh()) + pkt->set(PORTB_SPKR_HIGH); + else + pkt->set(0x00); + break; + default: + panic("I/O Read - va%#x size %d\n", pkt->getAddr(), pkt->getSize()); + } + } else if (pkt->getSize() == sizeof(uint64_t)) { + if (daddr == TSDEV_PIC1_ISR) + pkt->set<uint64_t>(picr); + else + panic("I/O Read - invalid addr - va %#x size %d\n", + pkt->getAddr(), pkt->getSize()); + } else { + panic("I/O Read - invalid size - va %#x size %d\n", pkt->getAddr(), pkt->getSize()); + } + pkt->result = Packet::Success; + return pioDelay; +} + +Tick +TsunamiIO::write(Packet *pkt) +{ + assert(pkt->result == Packet::Unknown); + assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); + Addr daddr = pkt->getAddr() - pioAddr; + + DPRINTF(Tsunami, "io write - va=%#x size=%d IOPort=%#x Data=%#x\n", + pkt->getAddr(), pkt->getSize(), pkt->getAddr() & 0xfff, (uint32_t)pkt->get<uint8_t>()); + + assert(pkt->getSize() == sizeof(uint8_t)); + + switch(daddr) { + case TSDEV_PIC1_MASK: + mask1 = ~(pkt->get<uint8_t>()); + if ((picr & mask1) && !picInterrupting) { + picInterrupting = true; + tsunami->cchip->postDRIR(55); + DPRINTF(Tsunami, "posting pic interrupt to cchip\n"); + } + if ((!(picr & mask1)) && picInterrupting) { + picInterrupting = false; + tsunami->cchip->clearDRIR(55); + DPRINTF(Tsunami, "clearing pic interrupt\n"); + } + break; + case TSDEV_PIC2_MASK: + mask2 = pkt->get<uint8_t>(); + //PIC2 Not implemented to interrupt + break; + case TSDEV_PIC1_ACK: + // clear the interrupt on the PIC + picr &= ~(1 << (pkt->get<uint8_t>() & 0xF)); + if (!(picr & mask1)) + tsunami->cchip->clearDRIR(55); + break; + case TSDEV_DMA1_MODE: + mode1 = pkt->get<uint8_t>(); + break; + case TSDEV_DMA2_MODE: + mode2 = pkt->get<uint8_t>(); + break; + case TSDEV_TMR0_DATA: + pitimer.counter0.write(pkt->get<uint8_t>()); + break; + case TSDEV_TMR1_DATA: + pitimer.counter1.write(pkt->get<uint8_t>()); + break; + case TSDEV_TMR2_DATA: + pitimer.counter2.write(pkt->get<uint8_t>()); + break; + case TSDEV_TMR_CTRL: + pitimer.writeControl(pkt->get<uint8_t>()); + break; + case TSDEV_RTC_ADDR: + rtc.writeAddr(pkt->get<uint8_t>()); + break; + case TSDEV_RTC_DATA: + rtc.writeData(pkt->get<uint8_t>()); + break; + case TSDEV_KBD: + case TSDEV_DMA1_CMND: + case TSDEV_DMA2_CMND: + case TSDEV_DMA1_MMASK: + case TSDEV_DMA2_MMASK: + case TSDEV_PIC2_ACK: + case TSDEV_DMA1_RESET: + case TSDEV_DMA2_RESET: + case TSDEV_DMA1_MASK: + case TSDEV_DMA2_MASK: + case TSDEV_CTRL_PORTB: + break; + default: + panic("I/O Write - va%#x size %d data %#x\n", pkt->getAddr(), pkt->getSize(), pkt->get<uint8_t>()); + } + + pkt->result = Packet::Success; + return pioDelay; +} + +void +TsunamiIO::postPIC(uint8_t bitvector) +{ + //PIC2 Is not implemented, because nothing of interest there + picr |= bitvector; + if (picr & mask1) { + tsunami->cchip->postDRIR(55); + DPRINTF(Tsunami, "posting pic interrupt to cchip\n"); + } +} + +void +TsunamiIO::clearPIC(uint8_t bitvector) +{ + //PIC2 Is not implemented, because nothing of interest there + picr &= ~bitvector; + if (!(picr & mask1)) { + tsunami->cchip->clearDRIR(55); + DPRINTF(Tsunami, "clearing pic interrupt to cchip\n"); + } +} + +void +TsunamiIO::serialize(ostream &os) +{ + SERIALIZE_SCALAR(timerData); + SERIALIZE_SCALAR(mask1); + SERIALIZE_SCALAR(mask2); + SERIALIZE_SCALAR(mode1); + SERIALIZE_SCALAR(mode2); + SERIALIZE_SCALAR(picr); + SERIALIZE_SCALAR(picInterrupting); + + // Serialize the timers + pitimer.serialize("pitimer", os); + rtc.serialize("rtc", os); +} + +void +TsunamiIO::unserialize(Checkpoint *cp, const string §ion) +{ + UNSERIALIZE_SCALAR(timerData); + UNSERIALIZE_SCALAR(mask1); + UNSERIALIZE_SCALAR(mask2); + UNSERIALIZE_SCALAR(mode1); + UNSERIALIZE_SCALAR(mode2); + UNSERIALIZE_SCALAR(picr); + UNSERIALIZE_SCALAR(picInterrupting); + + // Unserialize the timers + pitimer.unserialize("pitimer", cp, section); + rtc.unserialize("rtc", cp, section); +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO) + + Param<Addr> pio_addr; + Param<Tick> pio_latency; + Param<Tick> frequency; + SimObjectParam<Platform *> platform; + SimObjectParam<System *> system; + Param<time_t> time; + SimObjectParam<Tsunami *> tsunami; + +END_DECLARE_SIM_OBJECT_PARAMS(TsunamiIO) + +BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiIO) + + INIT_PARAM(pio_addr, "Device Address"), + INIT_PARAM(pio_latency, "Programmed IO latency"), + INIT_PARAM(frequency, "clock interrupt frequency"), + INIT_PARAM(platform, "platform"), + INIT_PARAM(system, "system object"), + INIT_PARAM(time, "System time to use (0 for actual time"), + INIT_PARAM(tsunami, "Tsunami") + +END_INIT_SIM_OBJECT_PARAMS(TsunamiIO) + +CREATE_SIM_OBJECT(TsunamiIO) +{ + TsunamiIO::Params *p = new TsunamiIO::Params; + p->frequency = frequency; + p->name = getInstanceName(); + p->pio_addr = pio_addr; + p->pio_delay = pio_latency; + p->platform = platform; + p->system = system; + p->init_time = time; + p->tsunami = tsunami; + return new TsunamiIO(p); +} + +REGISTER_SIM_OBJECT("TsunamiIO", TsunamiIO) diff --git a/src/dev/tsunami_io.hh b/src/dev/tsunami_io.hh new file mode 100644 index 000000000..ee25bbdfd --- /dev/null +++ b/src/dev/tsunami_io.hh @@ -0,0 +1,355 @@ +/* + * 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: Ali Saidi + * Andrew Schultz + * Miguel Serrano + */ + +/** @file + * Tsunami I/O Space mapping including RTC/timer interrupts + */ + +#ifndef __DEV_TSUNAMI_IO_HH__ +#define __DEV_TSUNAMI_IO_HH__ + +#include "dev/io_device.hh" +#include "base/range.hh" +#include "dev/tsunami.hh" +#include "sim/eventq.hh" + +/** + * Tsunami I/O device is a catch all for all the south bridge stuff we care + * to implement. + */ +class TsunamiIO : public BasicPioDevice +{ + private: + struct tm tm; + + protected: + /** Real-Time Clock (MC146818) */ + class RTC + { + private: + /** Event for RTC periodic interrupt */ + struct RTCEvent : public Event + { + /** A pointer back to tsunami to create interrupt the processor. */ + Tsunami* tsunami; + Tick interval; + + RTCEvent(Tsunami* t, Tick i); + + /** Schedule the RTC periodic interrupt */ + void scheduleIntr(); + + /** Event process to occur at interrupt*/ + virtual void process(); + + /** Event description */ + virtual const char *description(); + }; + + private: + std::string _name; + const std::string &name() const { return _name; } + + /** RTC periodic interrupt event */ + RTCEvent event; + + /** Current RTC register address/index */ + int addr; + + /** Data for real-time clock function */ + union { + uint8_t clock_data[10]; + + struct { + uint8_t sec; + uint8_t sec_alrm; + uint8_t min; + uint8_t min_alrm; + uint8_t hour; + uint8_t hour_alrm; + uint8_t wday; + uint8_t mday; + uint8_t mon; + uint8_t year; + }; + }; + + /** RTC status register A */ + uint8_t stat_regA; + + /** RTC status register B */ + uint8_t stat_regB; + + public: + RTC(const std::string &name, Tsunami* t, Tick i); + + /** Set the initial RTC time/date */ + void set_time(time_t t); + + /** RTC address port: write address of RTC RAM data to access */ + void writeAddr(const uint8_t data); + + /** RTC write data */ + void writeData(const uint8_t data); + + /** RTC read data */ + uint8_t readData(); + + /** + * Serialize this object to the given output stream. + * @param os The stream to serialize to. + */ + void serialize(const std::string &base, 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 + */ + void unserialize(const std::string &base, Checkpoint *cp, + const std::string §ion); + }; + + /** Programmable Interval Timer (Intel 8254) */ + class PITimer + { + /** Counter element for PIT */ + class Counter + { + /** Event for counter interrupt */ + class CounterEvent : public Event + { + private: + /** Pointer back to Counter */ + Counter* counter; + Tick interval; + + public: + CounterEvent(Counter*); + + /** Event process */ + virtual void process(); + + /** Event description */ + virtual const char *description(); + + friend class Counter; + }; + + private: + std::string _name; + const std::string &name() const { return _name; } + + CounterEvent event; + + /** Current count value */ + uint16_t count; + + /** Latched count */ + uint16_t latched_count; + + /** Interrupt period */ + uint16_t period; + + /** Current mode of operation */ + uint8_t mode; + + /** Output goes high when the counter reaches zero */ + bool output_high; + + /** State of the count latch */ + bool latch_on; + + /** Set of values for read_byte and write_byte */ + enum {LSB, MSB}; + + /** Determine which byte of a 16-bit count value to read/write */ + uint8_t read_byte, write_byte; + + public: + Counter(const std::string &name); + + /** Latch the current count (if one is not already latched) */ + void latchCount(); + + /** Set the read/write mode */ + void setRW(int rw_val); + + /** Set operational mode */ + void setMode(int mode_val); + + /** Set count encoding */ + void setBCD(int bcd_val); + + /** Read a count byte */ + uint8_t read(); + + /** Write a count byte */ + void write(const uint8_t data); + + /** Is the output high? */ + bool outputHigh(); + + /** + * Serialize this object to the given output stream. + * @param os The stream to serialize to. + */ + void serialize(const std::string &base, 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 + */ + void unserialize(const std::string &base, Checkpoint *cp, + const std::string §ion); + }; + + private: + std::string _name; + const std::string &name() const { return _name; } + + /** PIT has three seperate counters */ + Counter *counter[3]; + + public: + /** Public way to access individual counters (avoid array accesses) */ + Counter counter0; + Counter counter1; + Counter counter2; + + PITimer(const std::string &name); + + /** Write control word */ + void writeControl(const uint8_t data); + + /** + * Serialize this object to the given output stream. + * @param os The stream to serialize to. + */ + void serialize(const std::string &base, 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 + */ + void unserialize(const std::string &base, Checkpoint *cp, + const std::string §ion); + }; + + /** Mask of the PIC1 */ + uint8_t mask1; + + /** Mask of the PIC2 */ + uint8_t mask2; + + /** Mode of PIC1. Not used for anything */ + uint8_t mode1; + + /** Mode of PIC2. Not used for anything */ + uint8_t mode2; + + /** Raw PIC interrupt register before masking */ + uint8_t picr; //Raw PIC interrput register + + /** Is the pic interrupting right now or not. */ + bool picInterrupting; + + /** A pointer to the Tsunami device which be belong to */ + Tsunami *tsunami; + + /** Intel 8253 Periodic Interval Timer */ + PITimer pitimer; + + RTC rtc; + + /** The interval is set via two writes to the PIT. + * This variable contains a flag as to how many writes have happened, and + * the time so far. + */ + uint16_t timerData; + + public: + /** + * Return the freqency of the RTC + * @return interrupt rate of the RTC + */ + Tick frequency() const; + + struct Params : public BasicPioDevice::Params + { + Tick frequency; + Tsunami *tsunami; + time_t init_time; + }; + protected: + const Params *params() const { return (const Params*)_params; } + + public: + /** + * Initialize all the data for devices supported by Tsunami I/O. + * @param p pointer to Params struct + */ + TsunamiIO(Params *p); + + virtual Tick read(Packet *pkt); + virtual Tick write(Packet *pkt); + + /** + * Post an PIC interrupt to the CPU via the CChip + * @param bitvector interrupt to post. + */ + void postPIC(uint8_t bitvector); + + /** + * Clear a posted interrupt + * @param bitvector interrupt to clear + */ + void clearPIC(uint8_t bitvector); + + /** + * Serialize this object to the given output stream. + * @param os The stream to serialize to. + */ + virtual void serialize(std::ostream &os); + + /** + * Reconstruct the state of this object from a checkpoint. + * @param cp The checkpoint use. + * @param section The section name of this object + */ + virtual void unserialize(Checkpoint *cp, const std::string §ion); + +}; + +#endif // __DEV_TSUNAMI_IO_HH__ diff --git a/src/dev/tsunami_pchip.cc b/src/dev/tsunami_pchip.cc new file mode 100644 index 000000000..a376b908d --- /dev/null +++ b/src/dev/tsunami_pchip.cc @@ -0,0 +1,357 @@ +/* + * 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: Ali Saidi + * Andrew Schultz + */ + +/** @file + * Tsunami PChip (pci) + */ + +#include <deque> +#include <string> +#include <vector> + +#include "base/trace.hh" +#include "dev/tsunami_pchip.hh" +#include "dev/tsunamireg.h" +#include "dev/tsunami.hh" +#include "mem/packet.hh" +#include "sim/builder.hh" +#include "sim/system.hh" + +using namespace std; +//Should this be AlphaISA? +using namespace TheISA; + +TsunamiPChip::TsunamiPChip(Params *p) +: BasicPioDevice(p) +{ + pioSize = 0xfff; + + for (int i = 0; i < 4; i++) { + wsba[i] = 0; + wsm[i] = 0; + tba[i] = 0; + } + + // initialize pchip control register + pctl = (ULL(0x1) << 20) | (ULL(0x1) << 32) | (ULL(0x2) << 36); + + //Set back pointer in tsunami + p->tsunami->pchip = this; +} + +Tick +TsunamiPChip::read(Packet *pkt) +{ + assert(pkt->result == Packet::Unknown); + assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); + + pkt->allocate(); + Addr daddr = (pkt->getAddr() - pioAddr) >> 6;; + assert(pkt->getSize() == sizeof(uint64_t)); + + + DPRINTF(Tsunami, "read va=%#x size=%d\n", pkt->getAddr(), pkt->getSize()); + + switch(daddr) { + case TSDEV_PC_WSBA0: + pkt->set(wsba[0]); + break; + case TSDEV_PC_WSBA1: + pkt->set(wsba[1]); + break; + case TSDEV_PC_WSBA2: + pkt->set(wsba[2]); + break; + case TSDEV_PC_WSBA3: + pkt->set(wsba[3]); + break; + case TSDEV_PC_WSM0: + pkt->set(wsm[0]); + break; + case TSDEV_PC_WSM1: + pkt->set(wsm[1]); + break; + case TSDEV_PC_WSM2: + pkt->set(wsm[2]); + break; + case TSDEV_PC_WSM3: + pkt->set(wsm[3]); + break; + case TSDEV_PC_TBA0: + pkt->set(tba[0]); + break; + case TSDEV_PC_TBA1: + pkt->set(tba[1]); + break; + case TSDEV_PC_TBA2: + pkt->set(tba[2]); + break; + case TSDEV_PC_TBA3: + pkt->set(tba[3]); + break; + case TSDEV_PC_PCTL: + pkt->set(pctl); + break; + case TSDEV_PC_PLAT: + panic("PC_PLAT not implemented\n"); + case TSDEV_PC_RES: + panic("PC_RES not implemented\n"); + case TSDEV_PC_PERROR: + pkt->set((uint64_t)0x00); + break; + case TSDEV_PC_PERRMASK: + pkt->set((uint64_t)0x00); + break; + case TSDEV_PC_PERRSET: + panic("PC_PERRSET not implemented\n"); + case TSDEV_PC_TLBIV: + panic("PC_TLBIV not implemented\n"); + case TSDEV_PC_TLBIA: + pkt->set((uint64_t)0x00); // shouldn't be readable, but linux + break; + case TSDEV_PC_PMONCTL: + panic("PC_PMONCTL not implemented\n"); + case TSDEV_PC_PMONCNT: + panic("PC_PMONCTN not implemented\n"); + default: + panic("Default in PChip Read reached reading 0x%x\n", daddr); + } + pkt->result = Packet::Success; + return pioDelay; + +} + +Tick +TsunamiPChip::write(Packet *pkt) +{ + assert(pkt->result == Packet::Unknown); + assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); + Addr daddr = (pkt->getAddr() - pioAddr) >> 6; + + assert(pkt->getSize() == sizeof(uint64_t)); + + DPRINTF(Tsunami, "write - va=%#x size=%d \n", pkt->getAddr(), pkt->getSize()); + + switch(daddr) { + case TSDEV_PC_WSBA0: + wsba[0] = pkt->get<uint64_t>(); + break; + case TSDEV_PC_WSBA1: + wsba[1] = pkt->get<uint64_t>(); + break; + case TSDEV_PC_WSBA2: + wsba[2] = pkt->get<uint64_t>(); + break; + case TSDEV_PC_WSBA3: + wsba[3] = pkt->get<uint64_t>(); + break; + case TSDEV_PC_WSM0: + wsm[0] = pkt->get<uint64_t>(); + break; + case TSDEV_PC_WSM1: + wsm[1] = pkt->get<uint64_t>(); + break; + case TSDEV_PC_WSM2: + wsm[2] = pkt->get<uint64_t>(); + break; + case TSDEV_PC_WSM3: + wsm[3] = pkt->get<uint64_t>(); + break; + case TSDEV_PC_TBA0: + tba[0] = pkt->get<uint64_t>(); + break; + case TSDEV_PC_TBA1: + tba[1] = pkt->get<uint64_t>(); + break; + case TSDEV_PC_TBA2: + tba[2] = pkt->get<uint64_t>(); + break; + case TSDEV_PC_TBA3: + tba[3] = pkt->get<uint64_t>(); + break; + case TSDEV_PC_PCTL: + pctl = pkt->get<uint64_t>(); + break; + case TSDEV_PC_PLAT: + panic("PC_PLAT not implemented\n"); + case TSDEV_PC_RES: + panic("PC_RES not implemented\n"); + case TSDEV_PC_PERROR: + break; + case TSDEV_PC_PERRMASK: + panic("PC_PERRMASK not implemented\n"); + case TSDEV_PC_PERRSET: + panic("PC_PERRSET not implemented\n"); + case TSDEV_PC_TLBIV: + panic("PC_TLBIV not implemented\n"); + case TSDEV_PC_TLBIA: + break; // value ignored, supposted to invalidate SG TLB + case TSDEV_PC_PMONCTL: + panic("PC_PMONCTL not implemented\n"); + case TSDEV_PC_PMONCNT: + panic("PC_PMONCTN not implemented\n"); + default: + panic("Default in PChip write reached reading 0x%x\n", daddr); + + } // uint64_t + + pkt->result = Packet::Success; + return pioDelay; +} + +#define DMA_ADDR_MASK ULL(0x3ffffffff) + +Addr +TsunamiPChip::translatePciToDma(Addr busAddr) +{ + // compare the address to the window base registers + uint64_t tbaMask = 0; + uint64_t baMask = 0; + + uint64_t windowMask = 0; + uint64_t windowBase = 0; + + uint64_t pteEntry = 0; + + Addr pteAddr; + Addr dmaAddr; + +#if 0 + DPRINTF(IdeDisk, "Translation for bus address: %#x\n", busAddr); + for (int i = 0; i < 4; i++) { + DPRINTF(IdeDisk, "(%d) base:%#x mask:%#x\n", + i, wsba[i], wsm[i]); + + windowBase = wsba[i]; + windowMask = ~wsm[i] & (ULL(0xfff) << 20); + + if ((busAddr & windowMask) == (windowBase & windowMask)) { + DPRINTF(IdeDisk, "Would have matched %d (wb:%#x wm:%#x --> ba&wm:%#x wb&wm:%#x)\n", + i, windowBase, windowMask, (busAddr & windowMask), + (windowBase & windowMask)); + } + } +#endif + + for (int i = 0; i < 4; i++) { + + windowBase = wsba[i]; + windowMask = ~wsm[i] & (ULL(0xfff) << 20); + + if ((busAddr & windowMask) == (windowBase & windowMask)) { + + if (wsba[i] & 0x1) { // see if enabled + if (wsba[i] & 0x2) { // see if SG bit is set + /** @todo + This currently is faked by just doing a direct + read from memory, however, to be realistic, this + needs to actually do a bus transaction. The process + is explained in the tsunami documentation on page + 10-12 and basically munges the address to look up a + PTE from a table in memory and then uses that mapping + to create an address for the SG page + */ + + tbaMask = ~(((wsm[i] & (ULL(0xfff) << 20)) >> 10) | ULL(0x3ff)); + baMask = (wsm[i] & (ULL(0xfff) << 20)) | (ULL(0x7f) << 13); + pteAddr = (tba[i] & tbaMask) | ((busAddr & baMask) >> 10); + + pioPort->readBlob(pteAddr, (uint8_t*)&pteEntry, sizeof(uint64_t)); + + dmaAddr = ((pteEntry & ~ULL(0x1)) << 12) | (busAddr & ULL(0x1fff)); + + } else { + baMask = (wsm[i] & (ULL(0xfff) << 20)) | ULL(0xfffff); + tbaMask = ~baMask; + dmaAddr = (tba[i] & tbaMask) | (busAddr & baMask); + } + + return (dmaAddr & DMA_ADDR_MASK); + } + } + } + + // if no match was found, then return the original address + return busAddr; +} + +void +TsunamiPChip::serialize(std::ostream &os) +{ + SERIALIZE_SCALAR(pctl); + SERIALIZE_ARRAY(wsba, 4); + SERIALIZE_ARRAY(wsm, 4); + SERIALIZE_ARRAY(tba, 4); +} + +void +TsunamiPChip::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_SCALAR(pctl); + UNSERIALIZE_ARRAY(wsba, 4); + UNSERIALIZE_ARRAY(wsm, 4); + UNSERIALIZE_ARRAY(tba, 4); +} + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiPChip) + + Param<Addr> pio_addr; + Param<Tick> pio_latency; + SimObjectParam<Platform *> platform; + SimObjectParam<System *> system; + SimObjectParam<Tsunami *> tsunami; + +END_DECLARE_SIM_OBJECT_PARAMS(TsunamiPChip) + +BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiPChip) + + INIT_PARAM(pio_addr, "Device Address"), + INIT_PARAM(pio_latency, "Programmed IO latency"), + INIT_PARAM(platform, "platform"), + INIT_PARAM(system, "system object"), + INIT_PARAM(tsunami, "Tsunami") + +END_INIT_SIM_OBJECT_PARAMS(TsunamiPChip) + +CREATE_SIM_OBJECT(TsunamiPChip) +{ + TsunamiPChip::Params *p = new TsunamiPChip::Params; + p->name = getInstanceName(); + p->pio_addr = pio_addr; + p->pio_delay = pio_latency; + p->platform = platform; + p->system = system; + p->tsunami = tsunami; + return new TsunamiPChip(p); +} + +REGISTER_SIM_OBJECT("TsunamiPChip", TsunamiPChip) diff --git a/src/dev/tsunami_pchip.hh b/src/dev/tsunami_pchip.hh new file mode 100644 index 000000000..9f80f7d68 --- /dev/null +++ b/src/dev/tsunami_pchip.hh @@ -0,0 +1,100 @@ +/* + * 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: Ali Saidi + */ + +/** @file + * Tsunami PCI interface CSRs + */ + +#ifndef __TSUNAMI_PCHIP_HH__ +#define __TSUNAMI_PCHIP_HH__ + +#include "dev/tsunami.hh" +#include "base/range.hh" +#include "dev/io_device.hh" + +/** + * A very simple implementation of the Tsunami PCI interface chips. + */ +class TsunamiPChip : public BasicPioDevice +{ + protected: + /** Pchip control register */ + uint64_t pctl; + + /** Window Base addresses */ + uint64_t wsba[4]; + + /** Window masks */ + uint64_t wsm[4]; + + /** Translated Base Addresses */ + uint64_t tba[4]; + + public: + struct Params : public BasicPioDevice::Params + { + Tsunami *tsunami; + }; + protected: + const Params *params() const { return (const Params*)_params; } + + public: + /** + * Register the PChip with the mmu and init all wsba, wsm, and tba to 0 + * @param p pointer to the parameters struct + */ + TsunamiPChip(Params *p); + + /** + * Translate a PCI bus address to a memory address for DMA. + * @todo Andrew says this needs to be fixed. What's wrong with it? + * @param busAddr PCI address to translate. + * @return memory system address + */ + Addr translatePciToDma(Addr busAddr); + + virtual Tick read(Packet *pkt); + virtual Tick write(Packet *pkt); + + /** + * Serialize this object to the given output stream. + * @param os The stream to serialize to. + */ + virtual void serialize(std::ostream &os); + + /** + * Reconstruct the state of this object from a checkpoint. + * @param cp The checkpoint use. + * @param section The section name of this object + */ + virtual void unserialize(Checkpoint *cp, const std::string §ion); +}; + +#endif // __TSUNAMI_PCHIP_HH__ diff --git a/src/dev/tsunamireg.h b/src/dev/tsunamireg.h new file mode 100644 index 000000000..d603972be --- /dev/null +++ b/src/dev/tsunamireg.h @@ -0,0 +1,173 @@ +/* + * 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: Ali Saidi + */ + +/** @file + * List of Tsunami CSRs + */ + +#ifndef __TSUNAMIREG_H__ +#define __TSUNAMIREG_H__ + +#define ALPHA_K0SEG_BASE ULL(0xfffffc0000000000) + +// CChip Registers +#define TSDEV_CC_CSR 0x00 +#define TSDEV_CC_MTR 0x01 +#define TSDEV_CC_MISC 0x02 + +#define TSDEV_CC_AAR0 0x04 +#define TSDEV_CC_AAR1 0x05 +#define TSDEV_CC_AAR2 0x06 +#define TSDEV_CC_AAR3 0x07 +#define TSDEV_CC_DIM0 0x08 +#define TSDEV_CC_DIM1 0x09 +#define TSDEV_CC_DIR0 0x0A +#define TSDEV_CC_DIR1 0x0B +#define TSDEV_CC_DRIR 0x0C +#define TSDEV_CC_PRBEN 0x0D +#define TSDEV_CC_IIC0 0x0E +#define TSDEV_CC_IIC1 0x0F +#define TSDEV_CC_MPR0 0x10 +#define TSDEV_CC_MPR1 0x11 +#define TSDEV_CC_MPR2 0x12 +#define TSDEV_CC_MPR3 0x13 + +#define TSDEV_CC_DIM2 0x18 +#define TSDEV_CC_DIM3 0x19 +#define TSDEV_CC_DIR2 0x1A +#define TSDEV_CC_DIR3 0x1B +#define TSDEV_CC_IIC2 0x1C +#define TSDEV_CC_IIC3 0x1D + +// BigTsunami Registers +#define TSDEV_CC_BDIMS 0x1000000 +#define TSDEV_CC_BDIRS 0x2000000 +#define TSDEV_CC_IPIQ 0x20 //0xf01a000800 +#define TSDEV_CC_IPIR 0x21 //0xf01a000840 +#define TSDEV_CC_ITIR 0x22 //0xf01a000880 + + +// PChip Registers +#define TSDEV_PC_WSBA0 0x00 +#define TSDEV_PC_WSBA1 0x01 +#define TSDEV_PC_WSBA2 0x02 +#define TSDEV_PC_WSBA3 0x03 +#define TSDEV_PC_WSM0 0x04 +#define TSDEV_PC_WSM1 0x05 +#define TSDEV_PC_WSM2 0x06 +#define TSDEV_PC_WSM3 0x07 +#define TSDEV_PC_TBA0 0x08 +#define TSDEV_PC_TBA1 0x09 +#define TSDEV_PC_TBA2 0x0A +#define TSDEV_PC_TBA3 0x0B +#define TSDEV_PC_PCTL 0x0C +#define TSDEV_PC_PLAT 0x0D +#define TSDEV_PC_RES 0x0E +#define TSDEV_PC_PERROR 0x0F +#define TSDEV_PC_PERRMASK 0x10 +#define TSDEV_PC_PERRSET 0x11 +#define TSDEV_PC_TLBIV 0x12 +#define TSDEV_PC_TLBIA 0x13 +#define TSDEV_PC_PMONCTL 0x14 +#define TSDEV_PC_PMONCNT 0x15 + +#define TSDEV_PC_SPST 0x20 + + +// DChip Registers +#define TSDEV_DC_DSC 0x20 +#define TSDEV_DC_STR 0x21 +#define TSDEV_DC_DREV 0x22 +#define TSDEV_DC_DSC2 0x23 + +// I/O Ports +#define TSDEV_PIC1_MASK 0x21 +#define TSDEV_PIC2_MASK 0xA1 +#define TSDEV_PIC1_ISR 0x20 +#define TSDEV_PIC2_ISR 0xA0 +#define TSDEV_PIC1_ACK 0x20 +#define TSDEV_PIC2_ACK 0xA0 +#define TSDEV_DMA1_RESET 0x0D +#define TSDEV_DMA2_RESET 0xDA +#define TSDEV_DMA1_MODE 0x0B +#define TSDEV_DMA2_MODE 0xD6 +#define TSDEV_DMA1_MASK 0x0A +#define TSDEV_DMA2_MASK 0xD4 +#define TSDEV_CTRL_PORTB 0x61 +#define TSDEV_TMR0_DATA 0x40 +#define TSDEV_TMR1_DATA 0x41 +#define TSDEV_TMR2_DATA 0x42 +#define TSDEV_TMR_CTRL 0x43 +#define TSDEV_KBD 0x64 +#define TSDEV_DMA1_CMND 0x08 +#define TSDEV_DMA1_STAT TSDEV_DMA1_CMND +#define TSDEV_DMA2_CMND 0xD0 +#define TSDEV_DMA2_STAT TSDEV_DMA2_CMND +#define TSDEV_DMA1_MMASK 0x0F +#define TSDEV_DMA2_MMASK 0xDE + +/* Added for keyboard accesses */ +#define TSDEV_KBD 0x64 + +/* Added for ATA PCI DMA */ +#define ATA_PCI_DMA 0x00 +#define ATA_PCI_DMA2 0x02 +#define ATA_PCI_DMA3 0x16 +#define ATA_PCI_DMA4 0x17 +#define ATA_PCI_DMA5 0x1a +#define ATA_PCI_DMA6 0x11 +#define ATA_PCI_DMA7 0x14 + +#define TSDEV_RTC_ADDR 0x70 +#define TSDEV_RTC_DATA 0x71 + +#define PCHIP_PCI0_MEMORY ULL(0x00000000000) +#define PCHIP_PCI0_IO ULL(0x001FC000000) +#define TSUNAMI_UNCACHABLE_BIT ULL(0x80000000000) +#define TSUNAMI_PCI0_MEMORY TSUNAMI_UNCACHABLE_BIT + PCHIP_PCI0_MEMORY +#define TSUNAMI_PCI0_IO TSUNAMI_UNCACHABLE_BIT + PCHIP_PCI0_IO + + +// UART Defines +#define UART_IER_RDI 0x01 +#define UART_IER_THRI 0x02 +#define UART_IER_RLSI 0x04 + + +#define UART_LSR_TEMT 0x40 +#define UART_LSR_THRE 0x20 +#define UART_LSR_DR 0x01 + +#define UART_MCR_LOOP 0x10 + +// System Control PortB Status Bits +#define PORTB_SPKR_HIGH 0x20 + +#endif // __TSUNAMIREG_H__ diff --git a/src/dev/uart.cc b/src/dev/uart.cc new file mode 100644 index 000000000..f769b720b --- /dev/null +++ b/src/dev/uart.cc @@ -0,0 +1,54 @@ +/* + * 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: Ali Saidi + */ + +/** @file + * Implements a base class for UARTs + */ + +#include "dev/simconsole.hh" +#include "dev/uart.hh" +#include "dev/platform.hh" +#include "sim/builder.hh" + +using namespace std; + +Uart::Uart(Params *p) + : BasicPioDevice(p), platform(p->platform), cons(p->cons) +{ + + status = 0; + + // set back pointers + cons->uart = this; + platform->uart = this; +} + +DEFINE_SIM_OBJECT_CLASS_NAME("Uart", Uart) + diff --git a/src/dev/uart.hh b/src/dev/uart.hh new file mode 100644 index 000000000..f0ae0854c --- /dev/null +++ b/src/dev/uart.hh @@ -0,0 +1,81 @@ +/* + * 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: Ali Saidi + */ + +/** @file + * Base class for UART + */ + +#ifndef __UART_HH__ +#define __UART_HH__ + +#include "base/range.hh" +#include "dev/io_device.hh" + +class SimConsole; +class Platform; + +const int RX_INT = 0x1; +const int TX_INT = 0x2; + + +class Uart : public BasicPioDevice +{ + + protected: + int status; + Platform *platform; + SimConsole *cons; + + public: + struct Params : public BasicPioDevice::Params + { + SimConsole *cons; + }; + + Uart(Params *p); + + /** + * Inform the uart that there is data available. + */ + virtual void dataAvailable() = 0; + + + /** + * Return if we have an interrupt pending + * @return interrupt status + */ + bool intStatus() { return status ? true : false; } + + protected: + const Params *params() const {return (const Params *)_params; } + +}; + +#endif // __UART_HH__ diff --git a/src/dev/uart8250.cc b/src/dev/uart8250.cc new file mode 100644 index 000000000..b92527b5a --- /dev/null +++ b/src/dev/uart8250.cc @@ -0,0 +1,366 @@ +/* + * Copyright (c) 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: Ali Saidi + */ + +/** @file + * Implements a 8250 UART + */ + +#include <string> +#include <vector> + +#include "arch/alpha/ev5.hh" +#include "base/inifile.hh" +#include "base/str.hh" // for to_number +#include "base/trace.hh" +#include "dev/simconsole.hh" +#include "dev/uart8250.hh" +#include "dev/platform.hh" +#include "sim/builder.hh" + +using namespace std; +using namespace TheISA; + +Uart8250::IntrEvent::IntrEvent(Uart8250 *u, int bit) + : Event(&mainEventQueue), uart(u) +{ + DPRINTF(Uart, "UART Interrupt Event Initilizing\n"); + intrBit = bit; +} + +const char * +Uart8250::IntrEvent::description() +{ + return "uart interrupt delay event"; +} + +void +Uart8250::IntrEvent::process() +{ + if (intrBit & uart->IER) { + DPRINTF(Uart, "UART InterEvent, interrupting\n"); + uart->platform->postConsoleInt(); + uart->status |= intrBit; + } + else + DPRINTF(Uart, "UART InterEvent, not interrupting\n"); + +} + +/* The linux serial driver (8250.c about line 1182) loops reading from + * the device until the device reports it has no more data to + * read. After a maximum of 255 iterations the code prints "serial8250 + * too much work for irq X," and breaks out of the loop. Since the + * simulated system is so much slower than the actual system, if a + * user is typing on the keyboard it is very easy for them to provide + * input at a fast enough rate to not allow the loop to exit and thus + * the error to be printed. This magic number provides a delay between + * the time the UART receives a character to send to the simulated + * system and the time it actually notifies the system it has a + * character to send to alleviate this problem. --Ali + */ +void +Uart8250::IntrEvent::scheduleIntr() +{ + static const Tick interval = (Tick)((Clock::Float::s / 2e9) * 450); + DPRINTF(Uart, "Scheduling IER interrupt for %#x, at cycle %lld\n", intrBit, + curTick + interval); + if (!scheduled()) + schedule(curTick + interval); + else + reschedule(curTick + interval); +} + + +Uart8250::Uart8250(Params *p) + : Uart(p), txIntrEvent(this, TX_INT), rxIntrEvent(this, RX_INT) +{ + pioSize = 8; + + IER = 0; + DLAB = 0; + LCR = 0; + MCR = 0; +} + +Tick +Uart8250::read(Packet *pkt) +{ + assert(pkt->result == Packet::Unknown); + assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); + assert(pkt->getSize() == 1); + + Addr daddr = pkt->getAddr() - pioAddr; + pkt->allocate(); + + DPRINTF(Uart, " read register %#x\n", daddr); + + switch (daddr) { + case 0x0: + if (!(LCR & 0x80)) { // read byte + if (cons->dataAvailable()) + pkt->set(cons->in()); + else { + pkt->set((uint8_t)0); + // A limited amount of these are ok. + DPRINTF(Uart, "empty read of RX register\n"); + } + status &= ~RX_INT; + platform->clearConsoleInt(); + + if (cons->dataAvailable() && (IER & UART_IER_RDI)) + rxIntrEvent.scheduleIntr(); + } else { // dll divisor latch + ; + } + break; + case 0x1: + if (!(LCR & 0x80)) { // Intr Enable Register(IER) + pkt->set(IER); + } else { // DLM divisor latch MSB + ; + } + break; + case 0x2: // Intr Identification Register (IIR) + DPRINTF(Uart, "IIR Read, status = %#x\n", (uint32_t)status); + + if (status & RX_INT) /* Rx data interrupt has a higher priority */ + pkt->set(IIR_RXID); + else if (status & TX_INT) + pkt->set(IIR_TXID); + else + pkt->set(IIR_NOPEND); + + //Tx interrupts are cleared on IIR reads + status &= ~TX_INT; + break; + case 0x3: // Line Control Register (LCR) + pkt->set(LCR); + break; + case 0x4: // Modem Control Register (MCR) + break; + case 0x5: // Line Status Register (LSR) + uint8_t lsr; + lsr = 0; + // check if there are any bytes to be read + if (cons->dataAvailable()) + lsr = UART_LSR_DR; + lsr |= UART_LSR_TEMT | UART_LSR_THRE; + pkt->set(lsr); + break; + case 0x6: // Modem Status Register (MSR) + pkt->set((uint8_t)0); + break; + case 0x7: // Scratch Register (SCR) + pkt->set((uint8_t)0); // doesn't exist with at 8250. + break; + default: + panic("Tried to access a UART port that doesn't exist\n"); + break; + } +/* uint32_t d32 = *data; + DPRINTF(Uart, "Register read to register %#x returned %#x\n", daddr, d32); +*/ + pkt->result = Packet::Success; + return pioDelay; +} + +Tick +Uart8250::write(Packet *pkt) +{ + + assert(pkt->result == Packet::Unknown); + assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); + assert(pkt->getSize() == 1); + + Addr daddr = pkt->getAddr() - pioAddr; + + DPRINTF(Uart, " write register %#x value %#x\n", daddr, pkt->get<uint8_t>()); + + switch (daddr) { + case 0x0: + if (!(LCR & 0x80)) { // write byte + cons->out(pkt->get<uint8_t>()); + platform->clearConsoleInt(); + status &= ~TX_INT; + if (UART_IER_THRI & IER) + txIntrEvent.scheduleIntr(); + } else { // dll divisor latch + ; + } + break; + case 0x1: + if (!(LCR & 0x80)) { // Intr Enable Register(IER) + IER = pkt->get<uint8_t>(); + if (UART_IER_THRI & IER) + { + DPRINTF(Uart, "IER: IER_THRI set, scheduling TX intrrupt\n"); + txIntrEvent.scheduleIntr(); + } + else + { + DPRINTF(Uart, "IER: IER_THRI cleared, descheduling TX intrrupt\n"); + if (txIntrEvent.scheduled()) + txIntrEvent.deschedule(); + if (status & TX_INT) + platform->clearConsoleInt(); + status &= ~TX_INT; + } + + if ((UART_IER_RDI & IER) && cons->dataAvailable()) { + DPRINTF(Uart, "IER: IER_RDI set, scheduling RX intrrupt\n"); + rxIntrEvent.scheduleIntr(); + } else { + DPRINTF(Uart, "IER: IER_RDI cleared, descheduling RX intrrupt\n"); + if (rxIntrEvent.scheduled()) + rxIntrEvent.deschedule(); + if (status & RX_INT) + platform->clearConsoleInt(); + status &= ~RX_INT; + } + } else { // DLM divisor latch MSB + ; + } + break; + case 0x2: // FIFO Control Register (FCR) + break; + case 0x3: // Line Control Register (LCR) + LCR = pkt->get<uint8_t>(); + break; + case 0x4: // Modem Control Register (MCR) + if (pkt->get<uint8_t>() == (UART_MCR_LOOP | 0x0A)) + MCR = 0x9A; + break; + case 0x7: // Scratch Register (SCR) + // We are emulating a 8250 so we don't have a scratch reg + break; + default: + panic("Tried to access a UART port that doesn't exist\n"); + break; + } + pkt->result = Packet::Success; + return pioDelay; +} + +void +Uart8250::dataAvailable() +{ + // if the kernel wants an interrupt when we have data + if (IER & UART_IER_RDI) + { + platform->postConsoleInt(); + status |= RX_INT; + } + +} + +void +Uart8250::addressRanges(AddrRangeList &range_list) +{ + assert(pioSize != 0); + range_list.clear(); + range_list.push_back(RangeSize(pioAddr, pioSize)); +} + + + +void +Uart8250::serialize(ostream &os) +{ + SERIALIZE_SCALAR(status); + SERIALIZE_SCALAR(IER); + SERIALIZE_SCALAR(DLAB); + SERIALIZE_SCALAR(LCR); + SERIALIZE_SCALAR(MCR); + Tick rxintrwhen; + if (rxIntrEvent.scheduled()) + rxintrwhen = rxIntrEvent.when(); + else + rxintrwhen = 0; + Tick txintrwhen; + if (txIntrEvent.scheduled()) + txintrwhen = txIntrEvent.when(); + else + txintrwhen = 0; + SERIALIZE_SCALAR(rxintrwhen); + SERIALIZE_SCALAR(txintrwhen); +} + +void +Uart8250::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_SCALAR(status); + UNSERIALIZE_SCALAR(IER); + UNSERIALIZE_SCALAR(DLAB); + UNSERIALIZE_SCALAR(LCR); + UNSERIALIZE_SCALAR(MCR); + Tick rxintrwhen; + Tick txintrwhen; + UNSERIALIZE_SCALAR(rxintrwhen); + UNSERIALIZE_SCALAR(txintrwhen); + if (rxintrwhen != 0) + rxIntrEvent.schedule(rxintrwhen); + if (txintrwhen != 0) + txIntrEvent.schedule(txintrwhen); +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(Uart8250) + + Param<Addr> pio_addr; + Param<Tick> pio_latency; + SimObjectParam<Platform *> platform; + SimObjectParam<SimConsole *> sim_console; + SimObjectParam<System *> system; + +END_DECLARE_SIM_OBJECT_PARAMS(Uart8250) + +BEGIN_INIT_SIM_OBJECT_PARAMS(Uart8250) + + INIT_PARAM(pio_addr, "Device Address"), + INIT_PARAM_DFLT(pio_latency, "Programmed IO latency", 1000), + INIT_PARAM(platform, "platform"), + INIT_PARAM(sim_console, "The Simulator Console"), + INIT_PARAM(system, "system object") + +END_INIT_SIM_OBJECT_PARAMS(Uart8250) + +CREATE_SIM_OBJECT(Uart8250) +{ + Uart8250::Params *p = new Uart8250::Params; + p->name = getInstanceName(); + p->pio_addr = pio_addr; + p->pio_delay = pio_latency; + p->platform = platform; + p->cons = sim_console; + p->system = system; + return new Uart8250(p); +} + +REGISTER_SIM_OBJECT("Uart8250", Uart8250) + diff --git a/src/dev/uart8250.hh b/src/dev/uart8250.hh new file mode 100644 index 000000000..44e90132f --- /dev/null +++ b/src/dev/uart8250.hh @@ -0,0 +1,107 @@ +/* + * Copyright (c) 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: Ali Saidi + */ + +/** @file + * Defines a 8250 UART + */ + +#ifndef __DEV_UART8250_HH__ +#define __DEV_UART8250_HH__ + +#include "dev/tsunamireg.h" +#include "base/range.hh" +#include "dev/io_device.hh" +#include "dev/uart.hh" + + +/* UART8250 Interrupt ID Register + * bit 0 Interrupt Pending 0 = true, 1 = false + * bit 2:1 ID of highest priority interrupt + * bit 7:3 zeroes + */ +const uint8_t IIR_NOPEND = 0x1; + +// Interrupt IDs +const uint8_t IIR_MODEM = 0x00; /* Modem Status (lowest priority) */ +const uint8_t IIR_TXID = 0x02; /* Tx Data */ +const uint8_t IIR_RXID = 0x04; /* Rx Data */ +const uint8_t IIR_LINE = 0x06; /* Rx Line Status (highest priority)*/ + +class SimConsole; +class Platform; + +class Uart8250 : public Uart +{ + + + protected: + uint8_t IER, DLAB, LCR, MCR; + + class IntrEvent : public Event + { + protected: + Uart8250 *uart; + int intrBit; + public: + IntrEvent(Uart8250 *u, int bit); + virtual void process(); + virtual const char *description(); + void scheduleIntr(); + }; + + IntrEvent txIntrEvent; + IntrEvent rxIntrEvent; + + public: + Uart8250(Params *p); + + virtual Tick read(Packet *pkt); + virtual Tick write(Packet *pkt); + virtual void addressRanges(AddrRangeList &range_list); + + + /** + * Inform the uart that there is data available. + */ + virtual void dataAvailable(); + + + /** + * Return if we have an interrupt pending + * @return interrupt status + */ + virtual bool intStatus() { return status ? true : false; } + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + +}; + +#endif // __TSUNAMI_UART_HH__ diff --git a/src/kern/kernel_stats.cc b/src/kern/kernel_stats.cc new file mode 100644 index 000000000..f7868b50f --- /dev/null +++ b/src/kern/kernel_stats.cc @@ -0,0 +1,290 @@ +/* + * 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: Lisa Hsu + * Nathan Binkert + */ + +#include <map> +#include <stack> +#include <string> + +#include "arch/alpha/osfpal.hh" +#include "base/trace.hh" +#include "cpu/thread_context.hh" +#include "kern/kernel_stats.hh" +#include "kern/tru64/tru64_syscalls.hh" +#include "sim/system.hh" + +using namespace std; +using namespace Stats; + +namespace Kernel { + +const char *modestr[] = { "kernel", "user", "idle" }; + +Statistics::Statistics(System *system) + : idleProcess((Addr)-1), themode(kernel), lastModeTick(0), + iplLast(0), iplLastTick(0) +{ +} + +void +Statistics::regStats(const string &_name) +{ + myname = _name; + + _arm + .name(name() + ".inst.arm") + .desc("number of arm instructions executed") + ; + + _quiesce + .name(name() + ".inst.quiesce") + .desc("number of quiesce instructions executed") + ; + + _ivlb + .name(name() + ".inst.ivlb") + .desc("number of ivlb instructions executed") + ; + + _ivle + .name(name() + ".inst.ivle") + .desc("number of ivle instructions executed") + ; + + _hwrei + .name(name() + ".inst.hwrei") + .desc("number of hwrei instructions executed") + ; + + _iplCount + .init(32) + .name(name() + ".ipl_count") + .desc("number of times we switched to this ipl") + .flags(total | pdf | nozero | nonan) + ; + + _iplGood + .init(32) + .name(name() + ".ipl_good") + .desc("number of times we switched to this ipl from a different ipl") + .flags(total | pdf | nozero | nonan) + ; + + _iplTicks + .init(32) + .name(name() + ".ipl_ticks") + .desc("number of cycles we spent at this ipl") + .flags(total | pdf | nozero | nonan) + ; + + _iplUsed + .name(name() + ".ipl_used") + .desc("fraction of swpipl calls that actually changed the ipl") + .flags(total | nozero | nonan) + ; + + _iplUsed = _iplGood / _iplCount; + + _callpal + .init(256) + .name(name() + ".callpal") + .desc("number of callpals executed") + .flags(total | pdf | nozero | nonan) + ; + + for (int i = 0; i < PAL::NumCodes; ++i) { + const char *str = PAL::name(i); + if (str) + _callpal.subname(i, str); + } + + _syscall + .init(SystemCalls<Tru64>::Number) + .name(name() + ".syscall") + .desc("number of syscalls executed") + .flags(total | pdf | nozero | nonan) + ; + + for (int i = 0; i < SystemCalls<Tru64>::Number; ++i) { + const char *str = SystemCalls<Tru64>::name(i); + if (str) { + _syscall.subname(i, str); + } + } + + _mode + .init(cpu_mode_num) + .name(name() + ".mode_switch") + .desc("number of protection mode switches") + ; + + for (int i = 0; i < cpu_mode_num; ++i) + _mode.subname(i, modestr[i]); + + _modeGood + .init(cpu_mode_num) + .name(name() + ".mode_good") + ; + + for (int i = 0; i < cpu_mode_num; ++i) + _modeGood.subname(i, modestr[i]); + + _modeFraction + .name(name() + ".mode_switch_good") + .desc("fraction of useful protection mode switches") + .flags(total) + ; + + for (int i = 0; i < cpu_mode_num; ++i) + _modeFraction.subname(i, modestr[i]); + + _modeFraction = _modeGood / _mode; + + _modeTicks + .init(cpu_mode_num) + .name(name() + ".mode_ticks") + .desc("number of ticks spent at the given mode") + .flags(pdf) + ; + for (int i = 0; i < cpu_mode_num; ++i) + _modeTicks.subname(i, modestr[i]); + + _swap_context + .name(name() + ".swap_context") + .desc("number of times the context was actually changed") + ; +} + +void +Statistics::setIdleProcess(Addr idlepcbb, ThreadContext *tc) +{ + assert(themode == kernel); + idleProcess = idlepcbb; + themode = idle; + changeMode(themode, tc); +} + +void +Statistics::changeMode(cpu_mode newmode, ThreadContext *tc) +{ + _mode[newmode]++; + + if (newmode == themode) + return; + + DPRINTF(Context, "old mode=%-8s new mode=%-8s\n", + modestr[themode], modestr[newmode]); + + _modeGood[newmode]++; + _modeTicks[themode] += curTick - lastModeTick; + + lastModeTick = curTick; + themode = newmode; +} + +void +Statistics::swpipl(int ipl) +{ + assert(ipl >= 0 && ipl <= 0x1f && "invalid IPL\n"); + + _iplCount[ipl]++; + + if (ipl == iplLast) + return; + + _iplGood[ipl]++; + _iplTicks[iplLast] += curTick - iplLastTick; + iplLastTick = curTick; + iplLast = ipl; +} + +void +Statistics::mode(cpu_mode newmode, ThreadContext *tc) +{ + Addr pcbb = tc->readMiscReg(AlphaISA::IPR_PALtemp23); + + if (newmode == kernel && pcbb == idleProcess) + newmode = idle; + + changeMode(newmode, tc); +} + +void +Statistics::context(Addr oldpcbb, Addr newpcbb, ThreadContext *tc) +{ + assert(themode != user); + + _swap_context++; + changeMode(newpcbb == idleProcess ? idle : kernel, tc); +} + +void +Statistics::callpal(int code, ThreadContext *tc) +{ + if (!PAL::name(code)) + return; + + _callpal[code]++; + + switch (code) { + case PAL::callsys: { + int number = tc->readIntReg(0); + if (SystemCalls<Tru64>::validSyscallNumber(number)) { + int cvtnum = SystemCalls<Tru64>::convert(number); + _syscall[cvtnum]++; + } + } break; + } +} + +void +Statistics::serialize(ostream &os) +{ + int exemode = themode; + SERIALIZE_SCALAR(exemode); + SERIALIZE_SCALAR(idleProcess); + SERIALIZE_SCALAR(iplLast); + SERIALIZE_SCALAR(iplLastTick); + SERIALIZE_SCALAR(lastModeTick); +} + +void +Statistics::unserialize(Checkpoint *cp, const string §ion) +{ + int exemode; + UNSERIALIZE_SCALAR(exemode); + UNSERIALIZE_SCALAR(idleProcess); + UNSERIALIZE_SCALAR(iplLast); + UNSERIALIZE_SCALAR(iplLastTick); + UNSERIALIZE_SCALAR(lastModeTick); + themode = (cpu_mode)exemode; +} + +/* end namespace Kernel */ } diff --git a/src/kern/kernel_stats.hh b/src/kern/kernel_stats.hh new file mode 100644 index 000000000..c691ad8cf --- /dev/null +++ b/src/kern/kernel_stats.hh @@ -0,0 +1,117 @@ +/* + * 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: Lisa Hsu + * Nathan Binkert + */ + +#ifndef __KERNEL_STATS_HH__ +#define __KERNEL_STATS_HH__ + +#include <map> +#include <stack> +#include <string> +#include <vector> + +#include "cpu/static_inst.hh" + +class BaseCPU; +class ThreadContext; +class FnEvent; +// What does kernel stats expect is included? +class System; + +namespace Kernel { + +enum cpu_mode { kernel, user, idle, cpu_mode_num }; +extern const char *modestr[]; + +class Statistics : public Serializable +{ + private: + std::string myname; + + Addr idleProcess; + cpu_mode themode; + Tick lastModeTick; + + void changeMode(cpu_mode newmode, ThreadContext *tc); + + private: + Stats::Scalar<> _arm; + Stats::Scalar<> _quiesce; + Stats::Scalar<> _ivlb; + Stats::Scalar<> _ivle; + Stats::Scalar<> _hwrei; + + Stats::Vector<> _iplCount; + Stats::Vector<> _iplGood; + Stats::Vector<> _iplTicks; + Stats::Formula _iplUsed; + + Stats::Vector<> _callpal; + Stats::Vector<> _syscall; +// Stats::Vector<> _faults; + + Stats::Vector<> _mode; + Stats::Vector<> _modeGood; + Stats::Formula _modeFraction; + Stats::Vector<> _modeTicks; + + Stats::Scalar<> _swap_context; + + private: + int iplLast; + Tick iplLastTick; + + public: + Statistics(System *system); + + const std::string name() const { return myname; } + void regStats(const std::string &name); + + public: + void arm() { _arm++; } + void quiesce() { _quiesce++; } + void ivlb() { _ivlb++; } + void ivle() { _ivle++; } + void hwrei() { _hwrei++; } + void swpipl(int ipl); + void mode(cpu_mode newmode, ThreadContext *tc); + void context(Addr oldpcbb, Addr newpcbb, ThreadContext *tc); + void callpal(int code, ThreadContext *tc); + + void setIdleProcess(Addr idle, ThreadContext *tc); + + public: + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); +}; + +/* end namespace Kernel */ } + +#endif // __KERNEL_STATS_HH__ diff --git a/src/kern/linux/events.cc b/src/kern/linux/events.cc new file mode 100644 index 000000000..5ff7e26db --- /dev/null +++ b/src/kern/linux/events.cc @@ -0,0 +1,57 @@ +/* + * 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: Ali Saidi + */ + +#include "arch/arguments.hh" +#include "base/trace.hh" +#include "cpu/thread_context.hh" +#include "kern/linux/events.hh" +#include "kern/linux/printk.hh" +#include "kern/system_events.hh" +#include "sim/system.hh" + + +namespace Linux { + +void +DebugPrintkEvent::process(ThreadContext *tc) +{ + if (DTRACE(DebugPrintf)) { + if (!raw) { + StringWrap name(tc->getSystemPtr()->name() + ".dprintk"); + DPRINTFN(""); + } + + AlphaISA::AlphaArguments args(tc); + Printk(args); + SkipFuncEvent::process(tc); + } +} + +} // namespace linux diff --git a/src/kern/linux/events.hh b/src/kern/linux/events.hh new file mode 100644 index 000000000..65f794a9c --- /dev/null +++ b/src/kern/linux/events.hh @@ -0,0 +1,52 @@ +/* + * 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: Ali Saidi + */ + +#ifndef __KERN_LINUX_EVENTS_HH__ +#define __KERN_LINUX_EVENTS_HH__ + +#include "kern/system_events.hh" + +namespace Linux { + +class DebugPrintkEvent : public SkipFuncEvent +{ + private: + bool raw; + + public: + DebugPrintkEvent(PCEventQueue *q, const std::string &desc, Addr addr, + bool r = false) + : SkipFuncEvent(q, desc, addr), raw(r) {} + virtual void process(ThreadContext *xc); +}; + +} + +#endif diff --git a/src/kern/linux/linux.hh b/src/kern/linux/linux.hh new file mode 100644 index 000000000..af5e23b95 --- /dev/null +++ b/src/kern/linux/linux.hh @@ -0,0 +1,285 @@ +/* + * 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: Ali Saidi + */ + +#ifndef __LINUX_HH__ +#define __LINUX_HH__ +#include "config/full_system.hh" + +#if FULL_SYSTEM + +class Linux {}; + +#else //!FULL_SYSTEM + +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> // for host open() flags +#include <string.h> // for memset() +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "arch/isa_traits.hh" +#include "sim/syscall_emul.hh" + +class TranslatingPort; + +/// +/// This class encapsulates the types, structures, constants, +/// functions, and syscall-number mappings specific to the Alpha Linux +/// syscall interface. +/// +class Linux { + + public: + + //@{ + /// Basic Linux types. + typedef uint64_t size_t; + typedef uint64_t off_t; + typedef int64_t time_t; + typedef uint32_t uid_t; + typedef uint32_t gid_t; + //@} + +#if BSD_HOST + typedef struct stat hst_stat; + typedef struct stat hst_stat64; +#else + typedef struct stat hst_stat ; + typedef struct stat64 hst_stat64; +#endif + + /// Stat buffer. Note that we can't call it 'stat' since that + /// gets #defined to something else on some systems. + struct tgt_stat { + uint32_t st_dev; //!< device + uint32_t st_ino; //!< inode + uint32_t st_mode; //!< mode + uint32_t st_nlink; //!< link count + uint32_t st_uid; //!< owner's user ID + uint32_t st_gid; //!< owner's group ID + uint32_t st_rdev; //!< device number + int32_t _pad1; //!< for alignment + int64_t st_size; //!< file size in bytes + uint64_t st_atimeX; //!< time of last access + uint64_t st_mtimeX; //!< time of last modification + uint64_t st_ctimeX; //!< time of last status change + uint32_t st_blksize; //!< optimal I/O block size + int32_t st_blocks; //!< number of blocks allocated + uint32_t st_flags; //!< flags + uint32_t st_gen; //!< unknown + }; + + // same for stat64 + struct tgt_stat64 { + uint64_t st_dev; + uint64_t st_ino; + uint64_t st_rdev; + int64_t st_size; + uint64_t st_blocks; + + uint32_t st_mode; + uint32_t st_uid; + uint32_t st_gid; + uint32_t st_blksize; + uint32_t st_nlink; + uint32_t __pad0; + + uint64_t tgt_st_atime; + uint64_t st_atime_nsec; + uint64_t tgt_st_mtime; + uint64_t st_mtime_nsec; + uint64_t tgt_st_ctime; + uint64_t st_ctime_nsec; + int64_t ___unused[3]; + }; + + /// Length of strings in struct utsname (plus 1 for null char). + static const int _SYS_NMLN = 65; + + /// Interface struct for uname(). + struct utsname { + char sysname[_SYS_NMLN]; //!< System name. + char nodename[_SYS_NMLN]; //!< Node name. + char release[_SYS_NMLN]; //!< OS release. + char version[_SYS_NMLN]; //!< OS version. + char machine[_SYS_NMLN]; //!< Machine type. + }; + + /// Limit struct for getrlimit/setrlimit. + struct rlimit { + uint64_t rlim_cur; //!< soft limit + uint64_t rlim_max; //!< hard limit + }; + + /// For gettimeofday(). + struct timeval { + int64_t tv_sec; //!< seconds + int64_t tv_usec; //!< microseconds + }; + + // For writev/readv + struct tgt_iovec { + uint64_t iov_base; // void * + uint64_t iov_len; + }; + + + /// For getrusage(). + struct rusage { + struct timeval ru_utime; //!< user time used + struct timeval ru_stime; //!< system time used + int64_t ru_maxrss; //!< max rss + int64_t ru_ixrss; //!< integral shared memory size + int64_t ru_idrss; //!< integral unshared data " + int64_t ru_isrss; //!< integral unshared stack " + int64_t ru_minflt; //!< page reclaims - total vmfaults + int64_t ru_majflt; //!< page faults + int64_t ru_nswap; //!< swaps + int64_t ru_inblock; //!< block input operations + int64_t ru_oublock; //!< block output operations + int64_t ru_msgsnd; //!< messages sent + int64_t ru_msgrcv; //!< messages received + int64_t ru_nsignals; //!< signals received + int64_t ru_nvcsw; //!< voluntary context switches + int64_t ru_nivcsw; //!< involuntary " + }; + + /// Helper function to convert a host stat buffer to a target stat + /// buffer. Also copies the target buffer out to the simulated + /// memory space. Used by stat(), fstat(), and lstat(). +#if !BSD_HOST + static void + copyOutStatBuf(TranslatingPort *mem, Addr addr, hst_stat *host) + { + using namespace TheISA; + + TypedBufferArg<Linux::tgt_stat> tgt(addr); + + tgt->st_dev = htog(host->st_dev); + tgt->st_ino = htog(host->st_ino); + tgt->st_mode = htog(host->st_mode); + tgt->st_nlink = htog(host->st_nlink); + tgt->st_uid = htog(host->st_uid); + tgt->st_gid = htog(host->st_gid); + tgt->st_rdev = htog(host->st_rdev); + tgt->st_size = htog(host->st_size); + tgt->st_atimeX = htog(host->st_atime); + tgt->st_mtimeX = htog(host->st_mtime); + tgt->st_ctimeX = htog(host->st_ctime); + tgt->st_blksize = htog(host->st_blksize); + tgt->st_blocks = htog(host->st_blocks); + + tgt.copyOut(mem); + } +#else + // Third version for bsd systems which no longer have any support for + // the old stat() call and stat() is actually a stat64() + static void + copyOutStatBuf(TranslatingPort *mem, Addr addr, hst_stat64 *host) + { + using namespace TheISA; + + TypedBufferArg<Linux::tgt_stat> tgt(addr); + + tgt->st_dev = htog(host->st_dev); + tgt->st_ino = htog(host->st_ino); + tgt->st_mode = htog(host->st_mode); + tgt->st_nlink = htog(host->st_nlink); + tgt->st_uid = htog(host->st_uid); + tgt->st_gid = htog(host->st_gid); + tgt->st_rdev = htog(host->st_rdev); + tgt->st_size = htog(host->st_size); + tgt->st_atimeX = htog(host->st_atime); + tgt->st_mtimeX = htog(host->st_mtime); + tgt->st_ctimeX = htog(host->st_ctime); + tgt->st_blksize = htog(host->st_blksize); + tgt->st_blocks = htog(host->st_blocks); + + tgt.copyOut(mem); + } +#endif + + + // Same for stat64 + static void + copyOutStat64Buf(TranslatingPort *mem, int fd, Addr addr, hst_stat64 *host) + { + using namespace TheISA; + + TypedBufferArg<Linux::tgt_stat64> tgt(addr); + + // fd == 1 checks are because libc does some checks + // that the stdout is interactive vs. a file + // this makes it work on non-linux systems + if (fd == 1) + tgt->st_dev = htog((uint64_t)0xA); + else + tgt->st_dev = htog((uint64_t)host->st_dev); + // XXX What about STAT64_HAS_BROKEN_ST_INO ??? + tgt->st_ino = htog((uint64_t)host->st_ino); + if (fd == 1) + tgt->st_rdev = htog((uint64_t)0x880d); + else + tgt->st_rdev = htog((uint64_t)host->st_rdev); + tgt->st_size = htog((int64_t)host->st_size); + tgt->st_blocks = htog((uint64_t)host->st_blocks); + + if (fd == 1) + tgt->st_mode = htog((uint32_t)0x2190); + else + tgt->st_mode = htog((uint32_t)host->st_mode); + tgt->st_uid = htog((uint32_t)host->st_uid); + tgt->st_gid = htog((uint32_t)host->st_gid); + tgt->st_blksize = htog((uint32_t)host->st_blksize); + tgt->st_nlink = htog((uint32_t)host->st_nlink); + tgt->tgt_st_atime = htog((uint64_t)host->st_atime); + tgt->tgt_st_mtime = htog((uint64_t)host->st_mtime); + tgt->tgt_st_ctime = htog((uint64_t)host->st_ctime); +#if defined(STAT_HAVE_NSEC) + tgt->st_atime_nsec = htog(host->st_atime_nsec); + tgt->st_mtime_nsec = htog(host->st_mtime_nsec); + tgt->st_ctime_nsec = htog(host->st_ctime_nsec); +#else + tgt->st_atime_nsec = 0; + tgt->st_mtime_nsec = 0; + tgt->st_ctime_nsec = 0; +#endif + + tgt.copyOut(mem); + } + +}; // class Linux + + +#endif // FULL_SYSTEM + +#endif // __LINUX_HH__ diff --git a/src/kern/linux/linux_syscalls.cc b/src/kern/linux/linux_syscalls.cc new file mode 100644 index 000000000..7c2821dec --- /dev/null +++ b/src/kern/linux/linux_syscalls.cc @@ -0,0 +1,376 @@ +/* + * 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: Ali Saidi + */ + +#include "kern/linux/linux_syscalls.hh" + +namespace { + const char * + standard_strings[SystemCalls<Linux>::Number] = { + + + "llseek", //0 + "newselect", //1 + "sysctl", //2 + "access", //3 + "acct", //4 + "adjtimex", //5 + "afs_syscall", //6 + "alarm", //7 + "bdflush", //8 + "break", //9 + + + "brk", //10 + "capget", //11 + "capset", //12 + "chdir", //13 + "chmod", //14 + "chown", //15 + "chown32", //16 + "chroot", //17 + "clock_getres", //18 + "clock_gettime", //19 + + + "clock_nanosleep", //20 + "clock_settime", //21 + "clone", //22 + "close", //23 + "creat", //24 + "create_module", //25 + "delete_module", //26 + "dup", //27 + "dup2", //28 + "epoll_create", //29 + + + "epoll_ctl", //30 + "epoll_wait", //31 + "execve", //32 + "exit", //33 + "exit_group", //34 + "fadvise64", //35 + "fadvise64_64", //36 + "fchdir", //37 + "fchmod", //38 + "fchown", //39 + + + "fchown32", //40 + "fcntl", //41 + "fcntl64", //42 + "fdatasync", //43 + "fgetxattr", //44 + "flistxattr", //45 + "flock", //46 + "fork", //47 + "fremovexattr", //48 + "fsetxattr", //49 + + + "fstat", //50 + "fstat64", //51 + "fstatfs", //52 + "fstatfs64", //53 + "fsync", //54 + "ftime", //55 + "ftruncate", //56 + "ftruncate64", //57 + "futex", //58 + "get_kernel_syms", //59 + + + "get_thread_area", //60 + "getcwd", //61 + "getdents", //62 + "getdents64", //63 + "getegid", //64 + "getegid32", //65 + "geteuid", //66 + "geteuid32", //67 + "getgid", //68 + "getgid32", //69 + + + "getgroups", //70 + "getgroups32", //71 + "getitimer", //72 + "getpgid", //73 + "getpgrp", //74 + "getpid", //75 + "getpmsg", //76 + "getppid", //77 + "getpriority", //78 + "getresgid", //79 + + + "getresgid32", //80 + "getresuid", //81 + "getresuid32", //82 + "getrlimit", //83 + "getrusage", //84 + "getsid", //85 + "gettid", //86 + "gettimeofday", //87 + "getuid", //88 + "getuid32", //89 + + + "getxattr", //90 + "gtty", //91 + "idle", //92 + "init_module", //93 + "io_cancel", //94 + "io_destroy", //95 + "io_getevents", //96 + "io_setup", //97 + "io_submit", //98 + "ioctl", //99 + + + "ioperm", //100 + "iopl", //101 + "ipc", //102 + "kill", //103 + "lchown", //104 + "lchown32", //105 + "lgetxattr", //106 + "link", //107 + "listxattr", //108 + "llistxattr", //109 + + + "lock", //110 + "lookup_dcookie", //111 + "lremovexattr", //112 + "lseek", //113 + "lsetxattr", //114 + "lstat", //115 + "lstat64", //116 + "madvise", //117 + "madvise1", //118 + "mincore", //119 + + + "mkdir", //120 + "mknod", //121 + "mlock", //122 + "mlockall", //123 + "mmap", //124 + "mmap2", //125 + "modify_ldt", //126 + "mount", //127 + "mprotect", //128 + "mpx", //129 + + + "mremap", //130 + "msync", //131 + "munlock", //132 + "munlockall", //133 + "munmap", //134 + "nanosleep", //135 + "nfsservctl", //136 + "nice", //137 + "oldfstat", //138 + "oldlstat", //139 + + + "oldolduname", //140 + "oldstat", //141 + "olduname", //142 + "open", //143 + "pause", //144 + "personality", //145 + "pipe", //146 + "pivot_root", //147 + "poll", //148 + "prctl", //149 + + + "pread64", //150 + "prof", //151 + "profil", //152 + "ptrace", //153 + "putpmsg", //154 + "pwrite64", //155 + "query_module", //156 + "quotactl", //157 + "read", //158 + "readahead", //159 + + + "readdir", //160 + "readlink", //161 + "readv", //162 + "reboot", //163 + "remap_file_pages", //164 + "removexattr", //165 + "rename", //166 + "restart_syscall", //167 + "rmdir", //168 + "rt_sigaction", //169 + + + "rt_sigpending", //170 + "rt_sigprocmask", //171 + "rt_sigqueueinfo", //172 + "rt_sigreturn", //173 + "rt_sigsuspend", //174 + "rt_sigtimedwait", //175 + "sched_get_priority_max", //176 + "sched_get_priority_min", //177 + "sched_getaffinity", //178 + "sched_getparam", //179 + + + "sched_getscheduler", //180 + "sched_rr_get_interval", //181 + "sched_setaffinity", //182 + "sched_setparam", //183 + "sched_setscheduler", //184 + "sched_yield", //185 + "select", //186 + "sendfile", //187 + "sendfile64", //188 + "set_thread_area", //189 + + + "set_tid_address", //190 + "setdomainname", //191 + "setfsgid", //192 + "setfsgid32", //193 + "setfsuid", //194 + "setfsuid32", //195 + "setgid", //196 + "setgid32", //197 + "setgroups", //198 + "setgroups32", //199 + + + "sethostname", //200 + "setitimer", //201 + "setpgid", //202 + "setpriority", //203 + "setregid", //204 + "setregid32", //205 + "setresgid", //206 + "setresgid32", //207 + "setresuid", //208 + "setresuid32", //209 + + + "setreuid", //210 + "setreuid32", //211 + "setrlimit", //212 + "setsid", //213 + "settimeofday", //214 + "setuid", //215 + "setuid32", //216 + "setxattr", //217 + "sgetmask", //218 + "sigaction", //219 + + + "sigaltstack", //220 + "signal", //221 + "sigpending", //222 + "sigprocmask", //223 + "sigreturn", //224 + "sigsuspend", //225 + "socketcall", //226 + "ssetmask", //227 + "stat", //228 + "stat64", //229 + + + "statfs", //230 + "statfs64", //231 + "stime", //232 + "stty", //233 + "swapoff", //234 + "swapon", //235 + "symlink", //236 + "sync", //237 + "sysfs", //238 + "sysinfo", //239 + + + "syslog", //240 + "tgkill", //241 + "time", //242 + "timer_create", //243 + "timer_delete", //244 + "timer_getoverrun", //245 + "timer_gettime", //246 + "timer_settime", //247 + "times", //248 + "tkill", //249 + + + "truncate", //250 + "truncate64", //251 + "ugetrlimit", //252 + "ulimit", //253 + "umask", //254 + "umount", //255 + "umount2", //256 + "uname", //257 + "unlink", //258 + "uselib", //259 + + + "ustat", //260 + "utime", //261 + "utimes", //262 + "vfork", //263 + "vhangup", //264 + "vm86", //265 + "vm86old", //266 + "vserver", //267 + "wait4", //268 + "waitpid", //269 + + + "write", //270 + "writev", //271 + }; + + +} + +const char * +SystemCalls<Linux>::name(int num) +{ + if ((num >= 0) && (num < Number)) + return standard_strings[num]; + else + return 0; +} diff --git a/src/kern/linux/linux_syscalls.hh b/src/kern/linux/linux_syscalls.hh new file mode 100644 index 000000000..65616e862 --- /dev/null +++ b/src/kern/linux/linux_syscalls.hh @@ -0,0 +1,328 @@ +/* + * 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: Ali Saidi + */ + +#ifndef __KERN_LINUX_LINUX_SYSCALLS_HH__ +#define __KERN_LINUX_LINUX_SYSCALLS_HH__ + +#include "kern/linux/linux.hh" + +template <class OS> +class SystemCalls; + +template <> +class SystemCalls<Linux> +{ + public: + enum { + syscall = 0, + llseek = 1, + newselect = 2, + sysctl = 3, + access = 4, + acct = 5, + adjtimex = 6, + afs_syscall = 7, + alarm = 8, + bdflush = 9, + _break = 10, /*renamed from break*/ + brk = 11, + capget = 12, + capset = 13, + chdir = 14, + chmod = 15, + chown = 16, + chown32 = 17, + chroot = 18, + clock_getres = 19, + clock_gettime = 20, + clock_nanosleep = 21, + clock_settime = 22, + clone = 23, + close = 24, + creat = 25, + create_module = 26, + delete_module = 27, + dup = 28, + dup2 = 29, + epoll_create = 30, + epoll_ctl = 31, + epoll_wait = 32, + execve = 33, + exit = 34, + exit_group = 35, + fadvise64 = 36, + fadvise64_64 = 37, + fchdir = 38, + fchmod = 39, + fchown = 40, + fchown32 = 41, + fcntl = 42, + fcntl64 = 43, + fdatasync = 44, + fgetxattr = 45, + flistxattr = 46, + flock = 47, + fork = 48, + fremovexattr = 49, + fsetxattr = 50, + fstat = 51, + fstat64 = 52, + fstatfs = 53, + fstatfs64 = 54, + fsync = 55, + ftime = 56, + ftruncate = 57, + ftruncate64 = 58, + futex = 59, + get_kernel_syms = 60, + get_thread_area = 61, + getcwd = 62, + getdents = 63, + getdents64 = 64, + getegid = 65, + getegid32 = 66, + geteuid = 67, + geteuid32 = 68, + getgid = 69, + getgid32 = 70, + getgroups = 71, + getgroups32 = 72, + getitimer = 73, + getpgid = 74, + getpgrp = 75, + getpid = 76, + getpmsg = 77, + getppid = 78, + getpriority = 79, + getresgid = 80, + getresgid32 = 81, + getresuid = 82, + getresuid32 = 83, + getrlimit = 84, + getrusage = 85, + getsid = 86, + gettid = 87, + gettimeofday = 88, + getuid = 89, + getuid32 = 90, + getxattr = 91, + gtty = 92, + idle = 93, + init_module = 94, + io_cancel = 95, + io_destroy = 96, + io_getevents = 97, + io_setup = 98, + io_submit = 99, + ioctl = 100, + ioperm = 101, + iopl = 102, + ipc = 103, + kill = 104, + lchown = 105, + lchown32 = 106, + lgetxattr = 107, + link = 108, + listxattr = 109, + llistxattr = 110, + lock = 111, + lookup_dcookie = 112, + lremovexattr = 113, + lseek = 114, + lsetxattr = 115, + lstat = 116, + lstat64 = 117, + madvise = 118, + madvise1 = 119, + mincore = 120, + mkdir = 121, + mknod = 122, + mlock = 123, + mlockall = 124, + mmap = 125, + mmap2 = 126, + modify_ldt = 127, + mount = 128, + mprotect = 129, + mpx = 130, + mremap = 131, + msync = 132, + munlock = 133, + munlockall = 134, + munmap = 135, + nanosleep = 136, + nfsservctl = 137, + nice = 138, + oldfstat = 139, + oldlstat = 140, + oldolduname = 141, + oldstat = 142, + olduname = 143, + open = 144, + pause = 145, + personality = 146, + pipe = 147, + pivot_root = 148, + poll = 149, + prctl = 150, + pread64 = 151, + prof = 152, + profil = 153, + ptrace = 154, + putpmsg = 155, + pwrite64 = 156, + query_module = 157, + quotactl = 158, + read = 159, + readahead = 160, + readdir = 161, + readlink = 162, + readv = 163, + reboot = 164, + remap_file_pages = 165, + removexattr = 166, + rename = 167, + restart_syscall = 168, + rmdir = 169, + rt_sigaction = 170, + rt_sigpending = 171, + rt_sigprocmask = 172, + rt_sigqueueinfo = 173, + rt_sigreturn = 174, + rt_sigsuspend = 175, + rt_sigtimedwait = 176, + sched_get_priority_max = 177, + sched_get_priority_min = 178, + sched_getaffinity = 179, + sched_getparam = 180, + sched_getscheduler = 181, + sched_rr_get_interval = 182, + sched_setaffinity = 183, + sched_setparam = 184, + sched_setscheduler = 185, + sched_yield = 186, + select = 187, + sendfile = 188, + sendfile64 = 189, + set_thread_area = 190, + set_tid_address = 191, + setdomainname = 192, + setfsgid = 193, + setfsgid32 = 194, + setfsuid = 195, + setfsuid32 = 196, + setgid = 197, + setgid32 = 198, + setgroups = 199, + setgroups32 = 200, + sethostname = 201, + setitimer = 202, + setpgid = 203, + setpriority = 204, + setregid = 205, + setregid32 = 206, + setresgid = 207, + setresgid32 = 208, + setresuid = 209, + setresuid32 = 210, + setreuid = 211, + setreuid32 = 212, + setrlimit = 213, + setsid = 214, + settimeofday = 215, + setuid = 216, + setuid32 = 217, + setxattr = 218, + sgetmask = 219, + sigaction = 220, + sigaltstack = 221, + signal = 222, + sigpending = 223, + sigprocmask = 224, + sigreturn = 225, + sigsuspend = 226, + socketcall = 227, + ssetmask = 228, + stat = 229, + stat64 = 230, + statfs = 231, + statfs64 = 232, + stime = 233, + stty = 234, + swapoff = 235, + swapon = 236, + symlink = 237, + sync = 238, + sysfs = 239, + sysinfo = 240, + syslog = 241, + tgkill = 242, + time = 243, + timer_create = 244, + timer_delete = 245, + timer_getoverrun = 246, + timer_gettime = 247, + timer_settime = 248, + times = 249, + tkill = 250, + truncate = 251, + truncate64 = 252, + ugetrlimit = 253, + ulimit = 254, + umask = 255, + umount = 256, + umount2 = 257, + uname = 258, + unlink = 259, + uselib = 260, + ustat = 261, + utime = 262, + utimes = 263, + vfork = 264, + vhangup = 265, + vm86 = 266, + vm86old = 267, + vserver = 268, + wait4 = 269, + waitpid = 270, + write = 271, + writev = 272, + Number + }; + + static const char *name(int num); + + static bool validSyscallNumber(int num) { + return num < Number; + } + +}; + +#endif // __KERN_LINUX_LINUX_SYSCALLS_HH__ diff --git a/src/kern/linux/printk.cc b/src/kern/linux/printk.cc new file mode 100644 index 000000000..e39a15982 --- /dev/null +++ b/src/kern/linux/printk.cc @@ -0,0 +1,263 @@ +/* + * 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: Ali Saidi + */ + +#include <sys/types.h> +#include <algorithm> + +#include "base/trace.hh" +#include "arch/arguments.hh" + +using namespace std; + + +void +Printk(AlphaISA::AlphaArguments args) +{ + char *p = (char *)args++; + + ios::fmtflags saved_flags = DebugOut().flags(); + char old_fill = DebugOut().fill(); + int old_precision = DebugOut().precision(); + + while (*p) { + switch (*p) { + case '%': { + bool more = true; + bool islong = false; + bool leftjustify = false; + bool format = false; + bool zero = false; + int width = 0; + while (more && *++p) { + switch (*p) { + case 'l': + case 'L': + islong = true; + break; + case '-': + leftjustify = true; + break; + case '#': + format = true; + break; + case '0': + if (width) + width *= 10; + else + zero = true; + break; + default: + if (*p >= '1' && *p <= '9') + width = 10 * width + *p - '0'; + else + more = false; + break; + } + } + + bool hexnum = false; + bool octal = false; + bool sign = false; + switch (*p) { + case 'X': + case 'x': + hexnum = true; + break; + case 'O': + case 'o': + octal = true; + break; + case 'D': + case 'd': + sign = true; + break; + case 'P': + format = true; + case 'p': + hexnum = true; + break; + } + + switch (*p) { + case 'D': + case 'd': + case 'U': + case 'u': + case 'X': + case 'x': + case 'O': + case 'o': + case 'P': + case 'p': { + if (hexnum) + DebugOut() << hex; + + if (octal) + DebugOut() << oct; + + if (format) { + if (!zero) + DebugOut().setf(ios::showbase); + else { + if (hexnum) { + DebugOut() << "0x"; + width -= 2; + } else if (octal) { + DebugOut() << "0"; + width -= 1; + } + } + } + + if (zero) + DebugOut().fill('0'); + + if (width > 0) + DebugOut().width(width); + + if (leftjustify && !zero) + DebugOut().setf(ios::left); + + if (sign) { + if (islong) + DebugOut() << (int64_t)args; + else + DebugOut() << (int32_t)args; + } else { + if (islong) + DebugOut() << (uint64_t)args; + else + DebugOut() << (uint32_t)args; + } + + if (zero) + DebugOut().fill(' '); + + if (width > 0) + DebugOut().width(0); + + DebugOut() << dec; + + ++args; + } + break; + + case 's': { + char *s = (char *)args; + if (!s) + s = "<NULL>"; + + if (width > 0) + DebugOut().width(width); + if (leftjustify) + DebugOut().setf(ios::left); + + DebugOut() << s; + ++args; + } + break; + case 'C': + case 'c': { + uint64_t mask = (*p == 'C') ? 0xffL : 0x7fL; + uint64_t num; + int width; + + if (islong) { + num = (uint64_t)args; + width = sizeof(uint64_t); + } else { + num = (uint32_t)args; + width = sizeof(uint32_t); + } + + while (width-- > 0) { + char c = (char)(num & mask); + if (c) + DebugOut() << c; + num >>= 8; + } + + ++args; + } + break; + case 'b': { + uint64_t n = (uint64_t)args++; + char *s = (char *)args++; + DebugOut() << s << ": " << n; + } + break; + case 'n': + case 'N': { + args += 2; +#if 0 + uint64_t n = (uint64_t)args++; + struct reg_values *rv = (struct reg_values *)args++; +#endif + } + break; + case 'r': + case 'R': { + args += 2; +#if 0 + uint64_t n = (uint64_t)args++; + struct reg_desc *rd = (struct reg_desc *)args++; +#endif + } + break; + case '%': + DebugOut() << '%'; + break; + } + ++p; + } + break; + case '\n': + DebugOut() << endl; + ++p; + break; + case '\r': + ++p; + if (*p != '\n') + DebugOut() << endl; + break; + + default: { + size_t len = strcspn(p, "%\n\r\0"); + DebugOut().write(p, len); + p += len; + } + } + } + + DebugOut().flags(saved_flags); + DebugOut().fill(old_fill); + DebugOut().precision(old_precision); +} + diff --git a/src/kern/linux/printk.hh b/src/kern/linux/printk.hh new file mode 100644 index 000000000..f9203717a --- /dev/null +++ b/src/kern/linux/printk.hh @@ -0,0 +1,38 @@ +/* + * 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: Ali Saidi + */ + +#ifndef __PRINTK_HH__ +#define __PRINTK_HH__ + +class AlphaISA::AlphaArguments; + +void Printk(AlphaISA::AlphaArguments args); + +#endif // __PRINTK_HH__ diff --git a/src/kern/linux/sched.hh b/src/kern/linux/sched.hh new file mode 100644 index 000000000..f849cee30 --- /dev/null +++ b/src/kern/linux/sched.hh @@ -0,0 +1,48 @@ +/* + * Copyright (c) 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: Ali Saidi + * Nathan Binkert + */ + +#ifndef __KERN_LINUX_SCHED_HH__ +#define __KERN_LINUX_SCHED_HH__ + +namespace Linux { + struct task_struct { + uint8_t junk1[0xf4]; + int32_t pid; + uint8_t junk2[0x190]; + uint64_ta start; + uint8_t junk3[0x5c]; + char name[16]; + }; + + +} + +#endif // __KERN_LINUX_SCHED_HH__ diff --git a/src/kern/solaris/solaris.hh b/src/kern/solaris/solaris.hh new file mode 100644 index 000000000..0fec0bcce --- /dev/null +++ b/src/kern/solaris/solaris.hh @@ -0,0 +1,306 @@ +/* + * 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: Ali Saidi + */ + +#ifndef __SOLARIS_HH__ +#define __SOLARIS_HH__ +#include "config/full_system.hh" + +#if FULL_SYSTEM + +class Solaris {}; + +#else //!FULL_SYSTEM + +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> // for host open() flags +#include <string.h> // for memset() +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "arch/isa_traits.hh" +#include "sim/syscall_emul.hh" + +class TranslatingPort; + +/// +/// This class encapsulates the types, structures, constants, +/// functions, and syscall-number mappings specific to the Solaris +/// syscall interface. +/// +class Solaris { + + public: + + //@{ + /// Basic Solaris types. + typedef uint64_t size_t; + typedef uint64_t off_t; + typedef int64_t time_t; + typedef int32_t uid_t; + typedef int32_t gid_t; + typedef uint64_t rlim_t; + typedef uint64_t ino_t; + typedef uint64_t dev_t; + typedef uint32_t mode_t; + typedef uint32_t nlink_t; + //@} + +#if BSD_HOST + typedef struct stat hst_stat; + typedef struct stat hst_stat64; +#else + typedef struct stat hst_stat ; + typedef struct stat64 hst_stat64; +#endif + struct tgt_timespec { + int64_t tv_sec; + int64_t tv_nsec; + }; + + /// Stat buffer. Note that we can't call it 'stat' since that + /// gets #defined to something else on some systems. + struct tgt_stat { + uint64_t st_dev; //!< device + uint64_t st_ino; //!< inode + uint32_t st_mode; //!< mode + uint32_t st_nlink; //!< link count + int32_t st_uid; //!< owner's user ID + int32_t st_gid; //!< owner's group ID + uint64_t st_rdev; //!< device number + int64_t st_size; //!< file size in bytes + struct tgt_timespec st_atimeX; //!< time of last access + struct tgt_timespec st_mtimeX; //!< time of last modification + struct tgt_timespec st_ctimeX; //!< time of last status change + int32_t st_blksize; //!< optimal I/O block size + int64_t st_blocks; //!< number of blocks allocated + char st_fstype[16]; + }; + + // same for stat64 + struct tgt_stat64 { + uint64_t st_dev; //!< device + uint64_t st_ino; //!< inode + uint32_t st_mode; //!< mode + uint32_t st_nlink; //!< link count + int32_t st_uid; //!< owner's user ID + int32_t st_gid; //!< owner's group ID + uint64_t st_rdev; //!< device number + int64_t st_size; //!< file size in bytes + struct tgt_timespec st_atimeX; //!< time of last access + struct tgt_timespec st_mtimeX; //!< time of last modification + struct tgt_timespec st_ctimeX; //!< time of last status change + int32_t st_blksize; //!< optimal I/O block size + int64_t st_blocks; //!< number of blocks allocated + char st_fstype[16]; + }; + + /// Length of strings in struct utsname (plus 1 for null char). + static const int _SYS_NMLN = 257; + + /// Interface struct for uname(). + struct utsname { + char sysname[_SYS_NMLN]; //!< System name. + char nodename[_SYS_NMLN]; //!< Node name. + char release[_SYS_NMLN]; //!< OS release. + char version[_SYS_NMLN]; //!< OS version. + char machine[_SYS_NMLN]; //!< Machine type. + }; + + /// Limit struct for getrlimit/setrlimit. + struct rlimit { + uint64_t rlim_cur; //!< soft limit + uint64_t rlim_max; //!< hard limit + }; + + /// For gettimeofday(). + struct timeval { + int64_t tv_sec; //!< seconds + int64_t tv_usec; //!< microseconds + }; + + // For writev/readv + struct tgt_iovec { + uint64_t iov_base; // void * + uint64_t iov_len; + }; + + + /// For getrusage(). + struct rusage { + struct timeval ru_utime; //!< user time used + struct timeval ru_stime; //!< system time used + int64_t ru_maxrss; //!< max rss + int64_t ru_ixrss; //!< integral shared memory size + int64_t ru_idrss; //!< integral unshared data " + int64_t ru_isrss; //!< integral unshared stack " + int64_t ru_minflt; //!< page reclaims - total vmfaults + int64_t ru_majflt; //!< page faults + int64_t ru_nswap; //!< swaps + int64_t ru_inblock; //!< block input operations + int64_t ru_oublock; //!< block output operations + int64_t ru_msgsnd; //!< messages sent + int64_t ru_msgrcv; //!< messages received + int64_t ru_nsignals; //!< signals received + int64_t ru_nvcsw; //!< voluntary context switches + int64_t ru_nivcsw; //!< involuntary " + }; + + /// Helper function to convert a host stat buffer to a target stat + /// buffer. Also copies the target buffer out to the simulated + /// memory space. Used by stat(), fstat(), and lstat(). +#if !BSD_HOST + static void + copyOutStatBuf(TranslatingPort *mem, Addr addr, hst_stat *host) + { + using namespace TheISA; + + TypedBufferArg<Solaris::tgt_stat> tgt(addr); + + tgt->st_dev = htog(host->st_dev); + tgt->st_ino = htog(host->st_ino); + tgt->st_mode = htog(host->st_mode); + tgt->st_nlink = htog(host->st_nlink); + tgt->st_uid = htog(host->st_uid); + tgt->st_gid = htog(host->st_gid); + tgt->st_rdev = htog(host->st_rdev); + tgt->st_size = htog(host->st_size); + tgt->st_atimeX.tv_sec = htog((uint64_t)host->st_atime); + tgt->st_mtimeX.tv_sec = htog((uint64_t)host->st_mtime); + tgt->st_ctimeX.tv_sec = htog((uint64_t)host->st_ctime); +#if defined(STAT_HAVE_NSEC) + tgt->st_atimeX.tv_nsec = htog(host->st_atime_nsec); + tgt->st_mtimeX.tv_nsec = htog(host->st_mtime_nsec); + tgt->st_ctimeX.tv_nsec = htog(host->st_ctime_nsec); +#else + tgt->st_atimeX.tv_nsec = 0; + tgt->st_mtimeX.tv_nsec = 0; + tgt->st_ctimeX.tv_nsec = 0; +#endif + tgt->st_blksize = htog(host->st_blksize); + tgt->st_blocks = htog(host->st_blocks); + strncpy(tgt->st_fstype, "????", 16); + + tgt.copyOut(mem); + } +#else + // Third version for bsd systems which no longer have any support for + // the old stat() call and stat() is actually a stat64() + static void + copyOutStatBuf(TranslatingPort *mem, Addr addr, hst_stat64 *host) + { + using namespace TheISA; + + TypedBufferArg<Solaris::tgt_stat> tgt(addr); + + tgt->st_dev = htog(host->st_dev); + tgt->st_ino = htog(host->st_ino); + tgt->st_mode = htog(host->st_mode); + tgt->st_nlink = htog(host->st_nlink); + tgt->st_uid = htog(host->st_uid); + tgt->st_gid = htog(host->st_gid); + tgt->st_rdev = htog(host->st_rdev); + tgt->st_size = htog(host->st_size); + tgt->st_atimeX.tv_sec = htog((uint64_t)host->st_atime); + tgt->st_mtimeX.tv_sec = htog((uint64_t)host->st_mtime); + tgt->st_ctimeX.tv_sec = htog((uint64_t)host->st_ctime); +#if defined(STAT_HAVE_NSEC) + tgt->st_atimeX.tv_nsec = htog(host->st_atime_nsec); + tgt->st_mtimeX.tv_nsec = htog(host->st_mtime_nsec); + tgt->st_ctimeX.tv_nsec = htog(host->st_ctime_nsec); +#else + tgt->st_atimeX.tv_nsec = 0; + tgt->st_mtimeX.tv_nsec = 0; + tgt->st_ctimeX.tv_nsec = 0; +#endif + tgt->st_blksize = htog(host->st_blksize); + tgt->st_blocks = htog(host->st_blocks); + strncpy(tgt->st_fstype, "????", 16); + + tgt.copyOut(mem); + } +#endif + + + // Same for stat64 + static void + copyOutStat64Buf(TranslatingPort *mem, int fd, Addr addr, hst_stat64 *host) + { + using namespace TheISA; + + TypedBufferArg<Solaris::tgt_stat64> tgt(addr); + + // fd == 1 checks are because libc does some checks + // that the stdout is interactive vs. a file + // this makes it work on non-solaris systems + if (fd == 1) + tgt->st_dev = htog((uint64_t)0xA); + else + tgt->st_dev = htog((uint64_t)host->st_dev); + // XXX What about STAT64_HAS_BROKEN_ST_INO ??? + tgt->st_ino = htog((uint64_t)host->st_ino); + if (fd == 1) + tgt->st_rdev = htog((uint64_t)0x880d); + else + tgt->st_rdev = htog((uint64_t)host->st_rdev); + tgt->st_size = htog((int64_t)host->st_size); + tgt->st_blocks = htog((uint64_t)host->st_blocks); + + if (fd == 1) + tgt->st_mode = htog((uint32_t)0x2190); + else + tgt->st_mode = htog((uint32_t)host->st_mode); + tgt->st_uid = htog((uint32_t)host->st_uid); + tgt->st_gid = htog((uint32_t)host->st_gid); + tgt->st_blksize = htog((uint32_t)host->st_blksize); + tgt->st_nlink = htog((uint32_t)host->st_nlink); + tgt->st_atimeX.tv_sec = htog((uint64_t)host->st_atime); + tgt->st_mtimeX.tv_sec = htog((uint64_t)host->st_mtime); + tgt->st_ctimeX.tv_sec = htog((uint64_t)host->st_ctime); +#if defined(STAT_HAVE_NSEC) + tgt->st_atimeX.tv_nsec = htog(host->st_atime_nsec); + tgt->st_mtimeX.tv_nsec = htog(host->st_mtime_nsec); + tgt->st_ctimeX.tv_nsec = htog(host->st_ctime_nsec); +#else + tgt->st_atimeX.tv_nsec = 0; + tgt->st_mtimeX.tv_nsec = 0; + tgt->st_ctimeX.tv_nsec = 0; +#endif + + tgt.copyOut(mem); + } + +}; // class Solaris + + +#endif // FULL_SYSTEM + +#endif // __SOLARIS_HH__ diff --git a/src/kern/system_events.cc b/src/kern/system_events.cc new file mode 100644 index 000000000..177ce96d1 --- /dev/null +++ b/src/kern/system_events.cc @@ -0,0 +1,65 @@ +/* + * 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: Lisa Hsu + * Nathan Binkert + */ + +#include "cpu/base.hh" +#include "cpu/thread_context.hh" +#include "kern/kernel_stats.hh" +#include "kern/system_events.hh" +#include "sim/system.hh" + +using namespace TheISA; + +void +SkipFuncEvent::process(ThreadContext *tc) +{ + Addr newpc = tc->readIntReg(ReturnAddressReg); + + DPRINTF(PCEvent, "skipping %s: pc=%x, newpc=%x\n", description, + tc->readPC(), newpc); + + tc->setPC(newpc); + tc->setNextPC(tc->readPC() + sizeof(TheISA::MachInst)); +/* + BranchPred *bp = tc->getCpuPtr()->getBranchPred(); + if (bp != NULL) { + bp->popRAS(tc->getThreadNum()); + } +*/ +} + +void +IdleStartEvent::process(ThreadContext *tc) +{ + if (tc->getKernelStats()) + tc->getKernelStats()->setIdleProcess( + tc->readMiscReg(AlphaISA::IPR_PALtemp23), tc); + remove(); +} diff --git a/src/kern/system_events.hh b/src/kern/system_events.hh new file mode 100644 index 000000000..ccd6bd9a4 --- /dev/null +++ b/src/kern/system_events.hh @@ -0,0 +1,57 @@ +/* + * 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: Lisa Hsu + * Ali Saidi + */ + +#ifndef __SYSTEM_EVENTS_HH__ +#define __SYSTEM_EVENTS_HH__ + +#include "cpu/pc_event.hh" + +class System; + +class SkipFuncEvent : public PCEvent +{ + public: + SkipFuncEvent(PCEventQueue *q, const std::string &desc, Addr addr) + : PCEvent(q, desc, addr) + {} + virtual void process(ThreadContext *tc); +}; + +class IdleStartEvent : public PCEvent +{ + public: + IdleStartEvent(PCEventQueue *q, const std::string &desc, Addr addr) + : PCEvent(q, desc, addr) + {} + virtual void process(ThreadContext *tc); +}; + +#endif // __SYSTEM_EVENTS_HH__ diff --git a/src/kern/tru64/dump_mbuf.cc b/src/kern/tru64/dump_mbuf.cc new file mode 100644 index 000000000..8f88f8904 --- /dev/null +++ b/src/kern/tru64/dump_mbuf.cc @@ -0,0 +1,80 @@ +/* + * Copyright (c) 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: Nathan Binkert + */ + +#include <sys/types.h> +#include <algorithm> + +#include "base/cprintf.hh" +#include "base/trace.hh" +#include "base/loader/symtab.hh" +#include "cpu/thread_context.hh" +#include "kern/tru64/mbuf.hh" +#include "sim/host.hh" +#include "sim/system.hh" +#include "arch/arguments.hh" +#include "arch/isa_traits.hh" +#include "arch/vtophys.hh" + +using namespace TheISA; + +namespace tru64 { + +void +DumpMbuf(AlphaArguments args) +{ + ThreadContext *tc = args.getThreadContext(); + Addr addr = (Addr)args; + struct mbuf m; + + CopyOut(tc, &m, addr, sizeof(m)); + + int count = m.m_pkthdr.len; + + ccprintf(DebugOut(), "m=%#lx, m->m_pkthdr.len=%#d\n", addr, + m.m_pkthdr.len); + + while (count > 0) { + ccprintf(DebugOut(), "m=%#lx, m->m_data=%#lx, m->m_len=%d\n", + addr, m.m_data, m.m_len); + char *buffer = new char[m.m_len]; + CopyOut(tc, buffer, m.m_data, m.m_len); + Trace::dataDump(curTick, tc->getSystemPtr()->name(), (uint8_t *)buffer, + m.m_len); + delete [] buffer; + + count -= m.m_len; + if (!m.m_next) + break; + + CopyOut(tc, &m, m.m_next, sizeof(m)); + } +} + +} // namespace Tru64 diff --git a/src/kern/tru64/dump_mbuf.hh b/src/kern/tru64/dump_mbuf.hh new file mode 100644 index 000000000..25c6fd31d --- /dev/null +++ b/src/kern/tru64/dump_mbuf.hh @@ -0,0 +1,40 @@ +/* + * Copyright (c) 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: Nathan Binkert + */ + +#ifndef __DUMP_MBUF_HH__ +#define __DUMP_MBUF_HH__ + +#include "arch/arguments.hh" + +namespace tru64 { + void DumpMbuf(AlphaISA::AlphaArguments args); +} + +#endif // __DUMP_MBUF_HH__ diff --git a/src/kern/tru64/mbuf.hh b/src/kern/tru64/mbuf.hh new file mode 100644 index 000000000..cb5a84a7e --- /dev/null +++ b/src/kern/tru64/mbuf.hh @@ -0,0 +1,100 @@ +/* + * Copyright (c) 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: Nathan Binkert + */ + +#ifndef __MBUF_HH__ +#define __MBUF_HH__ + +#include "sim/host.hh" +#include "arch/isa_traits.hh" + +namespace tru64 { + +struct m_hdr { + Addr mh_next; // 0x00 + Addr mh_nextpkt; // 0x08 + Addr mh_data; // 0x10 + int32_t mh_len; // 0x18 + int32_t mh_type; // 0x1C + int32_t mh_flags; // 0x20 + int32_t mh_pad0; // 0x24 + Addr mh_foo[4]; // 0x28, 0x30, 0x38, 0x40 +}; + +struct pkthdr { + int32_t len; + int32_t protocolSum; + Addr rcvif; +}; + +struct m_ext { + Addr ext_buf; // 0x00 + Addr ext_free; // 0x08 + uint32_t ext_size; // 0x10 + uint32_t ext_pad0; // 0x14 + Addr ext_arg; // 0x18 + struct ext_refq { + Addr forw, back; // 0x20, 0x28 + } ext_ref; + Addr uiomove_f; // 0x30 + int32_t protocolSum; // 0x38 + int32_t bytesSummed; // 0x3C + Addr checksum; // 0x40 +}; + +struct mbuf { + struct m_hdr m_hdr; + union { + struct { + struct pkthdr MH_pkthdr; + union { + struct m_ext MH_ext; + char MH_databuf[1]; + } MH_dat; + } MH; + char M_databuf[1]; + } M_dat; +}; + +#define m_attr m_hdr.mh_attr +#define m_next m_hdr.mh_next +#define m_len m_hdr.mh_len +#define m_data m_hdr.mh_data +#define m_type m_hdr.mh_type +#define m_flags m_hdr.mh_flags +#define m_nextpkt m_hdr.mh_nextpkt +#define m_act m_nextpkt +#define m_pkthdr M_dat.MH.MH_pkthdr +#define m_ext M_dat.MH.MH_dat.MH_ext +#define m_pktdat M_dat.MH.MH_dat.MH_databuf +#define m_dat M_dat.M_databuf + +} + +#endif // __MBUF_HH__ diff --git a/src/kern/tru64/printf.cc b/src/kern/tru64/printf.cc new file mode 100644 index 000000000..29dd443d2 --- /dev/null +++ b/src/kern/tru64/printf.cc @@ -0,0 +1,268 @@ +/* + * Copyright (c) 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: Nathan Binkert + */ + +#include <sys/types.h> +#include <algorithm> + +#include "base/cprintf.hh" +#include "base/trace.hh" +#include "sim/host.hh" +#include "arch/arguments.hh" +#include "arch/vtophys.hh" + +using namespace std; + +namespace tru64 { + +void +Printf(AlphaISA::AlphaArguments args) +{ + char *p = (char *)args++; + + ios::fmtflags saved_flags = DebugOut().flags(); + char old_fill = DebugOut().fill(); + int old_precision = DebugOut().precision(); + + while (*p) { + switch (*p) { + case '%': { + bool more = true; + bool islong = false; + bool leftjustify = false; + bool format = false; + bool zero = false; + int width = 0; + while (more && *++p) { + switch (*p) { + case 'l': + case 'L': + islong = true; + break; + case '-': + leftjustify = true; + break; + case '#': + format = true; + break; + case '0': + if (width) + width *= 10; + else + zero = true; + break; + default: + if (*p >= '1' && *p <= '9') + width = 10 * width + *p - '0'; + else + more = false; + break; + } + } + + bool hexnum = false; + bool octal = false; + bool sign = false; + switch (*p) { + case 'X': + case 'x': + hexnum = true; + break; + case 'O': + case 'o': + octal = true; + break; + case 'D': + case 'd': + sign = true; + break; + case 'P': + format = true; + case 'p': + hexnum = true; + break; + } + + switch (*p) { + case 'D': + case 'd': + case 'U': + case 'u': + case 'X': + case 'x': + case 'O': + case 'o': + case 'P': + case 'p': { + if (hexnum) + DebugOut() << hex; + + if (octal) + DebugOut() << oct; + + if (format) { + if (!zero) + DebugOut().setf(ios::showbase); + else { + if (hexnum) { + DebugOut() << "0x"; + width -= 2; + } else if (octal) { + DebugOut() << "0"; + width -= 1; + } + } + } + + if (zero) + DebugOut().fill('0'); + + if (width > 0) + DebugOut().width(width); + + if (leftjustify && !zero) + DebugOut().setf(ios::left); + + if (sign) { + if (islong) + DebugOut() << (int64_t)args; + else + DebugOut() << (int32_t)args; + } else { + if (islong) + DebugOut() << (uint64_t)args; + else + DebugOut() << (uint32_t)args; + } + + if (zero) + DebugOut().fill(' '); + + if (width > 0) + DebugOut().width(0); + + DebugOut() << dec; + + ++args; + } + break; + + case 's': { + char *s = (char *)args; + if (!s) + s = "<NULL>"; + + if (width > 0) + DebugOut().width(width); + if (leftjustify) + DebugOut().setf(ios::left); + + DebugOut() << s; + ++args; + } + break; + case 'C': + case 'c': { + uint64_t mask = (*p == 'C') ? 0xffL : 0x7fL; + uint64_t num; + int width; + + if (islong) { + num = (uint64_t)args; + width = sizeof(uint64_t); + } else { + num = (uint32_t)args; + width = sizeof(uint32_t); + } + + while (width-- > 0) { + char c = (char)(num & mask); + if (c) + DebugOut() << c; + num >>= 8; + } + + ++args; + } + break; + case 'b': { + uint64_t n = (uint64_t)args++; + char *s = (char *)args++; + DebugOut() << s << ": " << n; + } + break; + case 'n': + case 'N': { + args += 2; +#if 0 + uint64_t n = (uint64_t)args++; + struct reg_values *rv = (struct reg_values *)args++; +#endif + } + break; + case 'r': + case 'R': { + args += 2; +#if 0 + uint64_t n = (uint64_t)args++; + struct reg_desc *rd = (struct reg_desc *)args++; +#endif + } + break; + case '%': + DebugOut() << '%'; + break; + } + ++p; + } + break; + case '\n': + DebugOut() << endl; + ++p; + break; + case '\r': + ++p; + if (*p != '\n') + DebugOut() << endl; + break; + + default: { + size_t len = strcspn(p, "%\n\r\0"); + DebugOut().write(p, len); + p += len; + } + } + } + + DebugOut().flags(saved_flags); + DebugOut().fill(old_fill); + DebugOut().precision(old_precision); +} + +} // namespace Tru64 diff --git a/src/kern/tru64/printf.hh b/src/kern/tru64/printf.hh new file mode 100644 index 000000000..f6a4544ad --- /dev/null +++ b/src/kern/tru64/printf.hh @@ -0,0 +1,40 @@ +/* + * Copyright (c) 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: Nathan Binkert + */ + +#ifndef __PRINTF_HH__ +#define __PRINTF_HH__ + +#include "arch/arguments.hh" + +namespace tru64 { + void Printf(AlphaISA::AlphaArguments args); +} + +#endif // __PRINTF_HH__ diff --git a/src/kern/tru64/tru64.hh b/src/kern/tru64/tru64.hh new file mode 100644 index 000000000..d2b7c862f --- /dev/null +++ b/src/kern/tru64/tru64.hh @@ -0,0 +1,1243 @@ +/* + * 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 + * Ali Saidi + */ + +#ifndef __TRU64_HH__ +#define __TRU64_HH__ +#include "config/full_system.hh" + +#if FULL_SYSTEM + +class Tru64 {}; + +#else //!FULL_SYSTEM + +#include <sys/types.h> +#include <sys/stat.h> +#if defined(__OpenBSD__) || defined(__APPLE__) || defined(__FreeBSD__) +#include <sys/param.h> +#include <sys/mount.h> +#else +#include <sys/statfs.h> +#endif + +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <string.h> // for memset() +#include <unistd.h> + +#include "cpu/base.hh" +#include "sim/root.hh" +#include "sim/syscall_emul.hh" + +typedef struct stat global_stat; +typedef struct statfs global_statfs; +typedef struct dirent global_dirent; + +class TranslatingPort; + +/// +/// This class encapsulates the types, structures, constants, +/// functions, and syscall-number mappings specific to the Alpha Tru64 +/// syscall interface. +/// +class Tru64 { + + public: + + //@{ + /// Basic Tru64 types. + typedef uint64_t size_t; + typedef uint64_t off_t; + typedef uint16_t nlink_t; + typedef int32_t dev_t; + typedef uint32_t uid_t; + typedef uint32_t gid_t; + typedef uint32_t time_t; + typedef uint32_t mode_t; + typedef uint32_t ino_t; + typedef struct { int val[2]; } quad; + typedef quad fsid_t; + //@} + + /// Stat buffer. Note that Tru64 v5.0+ use a new "F64" stat + /// structure, and a new set of syscall numbers for stat calls. + /// On some hosts (notably Linux) define st_atime, st_mtime, and + /// st_ctime as macros, so we append an X to get around this. + struct F64_stat { + dev_t st_dev; //!< st_dev + int32_t st_retired1; //!< st_retired1 + mode_t st_mode; //!< st_mode + nlink_t st_nlink; //!< st_nlink + uint16_t st_nlink_reserved; //!< st_nlink_reserved + uid_t st_uid; //!< st_uid + gid_t st_gid; //!< st_gid + dev_t st_rdev; //!< st_rdev + dev_t st_ldev; //!< st_ldev + off_t st_size; //!< st_size + time_t st_retired2; //!< st_retired2 + int32_t st_uatime; //!< st_uatime + time_t st_retired3; //!< st_retired3 + int32_t st_umtime; //!< st_umtime + time_t st_retired4; //!< st_retired4 + int32_t st_uctime; //!< st_uctime + int32_t st_retired5; //!< st_retired5 + int32_t st_retired6; //!< st_retired6 + uint32_t st_flags; //!< st_flags + uint32_t st_gen; //!< st_gen + uint64_t st_spare[4]; //!< st_spare[4] + ino_t st_ino; //!< st_ino + int32_t st_ino_reserved; //!< st_ino_reserved + time_t st_atimeX; //!< st_atime + int32_t st_atime_reserved; //!< st_atime_reserved + time_t st_mtimeX; //!< st_mtime + int32_t st_mtime_reserved; //!< st_mtime_reserved + time_t st_ctimeX; //!< st_ctime + int32_t st_ctime_reserved; //!< st_ctime_reserved + uint64_t st_blksize; //!< st_blksize + uint64_t st_blocks; //!< st_blocks + }; + + + /// Old Tru64 v4.x stat struct. + /// Tru64 maintains backwards compatibility with v4.x by + /// implementing another set of stat functions using the old + /// structure definition and binding them to the old syscall + /// numbers. + + struct pre_F64_stat { + dev_t st_dev; + ino_t st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid __attribute__ ((aligned(sizeof(uid_t)))); + gid_t st_gid; + dev_t st_rdev; + off_t st_size __attribute__ ((aligned(sizeof(off_t)))); + time_t st_atimeX; + int32_t st_uatime; + time_t st_mtimeX; + int32_t st_umtime; + time_t st_ctimeX; + int32_t st_uctime; + uint32_t st_blksize; + int32_t st_blocks; + uint32_t st_flags; + uint32_t st_gen; + }; + + /// For statfs(). + struct F64_statfs { + int16_t f_type; + int16_t f_flags; + int32_t f_retired1; + int32_t f_retired2; + int32_t f_retired3; + int32_t f_retired4; + int32_t f_retired5; + int32_t f_retired6; + int32_t f_retired7; + fsid_t f_fsid; + int32_t f_spare[9]; + char f_retired8[90]; + char f_retired9[90]; + uint64_t dummy[10]; // was union mount_info mount_info; + uint64_t f_flags2; + int64_t f_spare2[14]; + int64_t f_fsize; + int64_t f_bsize; + int64_t f_blocks; + int64_t f_bfree; + int64_t f_bavail; + int64_t f_files; + int64_t f_ffree; + char f_mntonname[1024]; + char f_mntfromname[1024]; + }; + + /// For old Tru64 v4.x statfs() + struct pre_F64_statfs { + int16_t f_type; + int16_t f_flags; + int32_t f_fsize; + int32_t f_bsize; + int32_t f_blocks; + int32_t f_bfree; + int32_t f_bavail; + int32_t f_files; + int32_t f_ffree; + fsid_t f_fsid; + int32_t f_spare[9]; + char f_mntonname[90]; + char f_mntfromname[90]; + uint64_t dummy[10]; // was union mount_info mount_info; + }; + + /// For getdirentries(). + struct dirent + { + ino_t d_ino; //!< file number of entry + uint16_t d_reclen; //!< length of this record + uint16_t d_namlen; //!< length of string in d_name + char d_name[256]; //!< dummy name length + }; + + + /// Length of strings in struct utsname (plus 1 for null char). + static const int _SYS_NMLN = 32; + + /// Interface struct for uname(). + struct utsname { + char sysname[_SYS_NMLN]; //!< System name. + char nodename[_SYS_NMLN]; //!< Node name. + char release[_SYS_NMLN]; //!< OS release. + char version[_SYS_NMLN]; //!< OS version. + char machine[_SYS_NMLN]; //!< Machine type. + }; + + /// Limit struct for getrlimit/setrlimit. + struct rlimit { + uint64_t rlim_cur; //!< soft limit + uint64_t rlim_max; //!< hard limit + }; + + + /// For getsysinfo() GSI_CPU_INFO option. + struct cpu_info { + uint32_t current_cpu; //!< current_cpu + uint32_t cpus_in_box; //!< cpus_in_box + uint32_t cpu_type; //!< cpu_type + uint32_t ncpus; //!< ncpus + uint64_t cpus_present; //!< cpus_present + uint64_t cpus_running; //!< cpus_running + uint64_t cpu_binding; //!< cpu_binding + uint64_t cpu_ex_binding; //!< cpu_ex_binding + uint32_t mhz; //!< mhz + uint32_t unused[3]; //!< future expansion + }; + + /// For gettimeofday. + struct timeval { + uint32_t tv_sec; //!< seconds + uint32_t tv_usec; //!< microseconds + }; + + /// For getrusage(). + struct rusage { + struct timeval ru_utime; //!< user time used + struct timeval ru_stime; //!< system time used + uint64_t ru_maxrss; //!< ru_maxrss + uint64_t ru_ixrss; //!< integral shared memory size + uint64_t ru_idrss; //!< integral unshared data " + uint64_t ru_isrss; //!< integral unshared stack " + uint64_t ru_minflt; //!< page reclaims - total vmfaults + uint64_t ru_majflt; //!< page faults + uint64_t ru_nswap; //!< swaps + uint64_t ru_inblock; //!< block input operations + uint64_t ru_oublock; //!< block output operations + uint64_t ru_msgsnd; //!< messages sent + uint64_t ru_msgrcv; //!< messages received + uint64_t ru_nsignals; //!< signals received + uint64_t ru_nvcsw; //!< voluntary context switches + uint64_t ru_nivcsw; //!< involuntary " + }; + + /// For sigreturn(). + struct sigcontext { + int64_t sc_onstack; //!< sigstack state to restore + int64_t sc_mask; //!< signal mask to restore + int64_t sc_pc; //!< pc at time of signal + int64_t sc_ps; //!< psl to retore + int64_t sc_regs[32]; //!< processor regs 0 to 31 + int64_t sc_ownedfp; //!< fp has been used + int64_t sc_fpregs[32]; //!< fp regs 0 to 31 + uint64_t sc_fpcr; //!< floating point control reg + uint64_t sc_fp_control; //!< software fpcr + int64_t sc_reserved1; //!< reserved for kernel + uint32_t sc_kreserved1; //!< reserved for kernel + uint32_t sc_kreserved2; //!< reserved for kernel + size_t sc_ssize; //!< stack size + caddr_t sc_sbase; //!< stack start + uint64_t sc_traparg_a0; //!< a0 argument to trap on exc + uint64_t sc_traparg_a1; //!< a1 argument to trap on exc + uint64_t sc_traparg_a2; //!< a2 argument to trap on exc + uint64_t sc_fp_trap_pc; //!< imprecise pc + uint64_t sc_fp_trigger_sum; //!< Exception summary at trigg + uint64_t sc_fp_trigger_inst; //!< Instruction at trigger pc + }; + + + + /// For table(). + struct tbl_sysinfo { + uint64_t si_user; //!< User time + uint64_t si_nice; //!< Nice time + uint64_t si_sys; //!< System time + uint64_t si_idle; //!< Idle time + uint64_t si_hz; //!< hz + uint64_t si_phz; //!< phz + uint64_t si_boottime; //!< Boot time in seconds + uint64_t wait; //!< Wait time + uint32_t si_max_procs; //!< rpb->rpb_numprocs + uint32_t pad; //!< padding + }; + + + /// For stack_create. + struct vm_stack { + // was void * + Addr address; //!< address hint + size_t rsize; //!< red zone size + size_t ysize; //!< yellow zone size + size_t gsize; //!< green zone size + size_t swap; //!< amount of swap to reserve + size_t incr; //!< growth increment + uint64_t align; //!< address alignment + uint64_t flags; //!< MAP_FIXED etc. + // was struct memalloc_attr * + Addr attr; //!< allocation policy + uint64_t reserved; //!< reserved + }; + + /// Return values for nxm calls. + enum { + KERN_NOT_RECEIVER = 7, + KERN_NOT_IN_SET = 12 + }; + + /// For nxm_task_init. + static const int NXM_TASK_INIT_VP = 2; //!< initial thread is VP + + /// Task attribute structure. + struct nxm_task_attr { + int64_t nxm_callback; //!< nxm_callback + unsigned int nxm_version; //!< nxm_version + unsigned short nxm_uniq_offset; //!< nxm_uniq_offset + unsigned short flags; //!< flags + int nxm_quantum; //!< nxm_quantum + int pad1; //!< pad1 + int64_t pad2; //!< pad2 + }; + + /// Signal set. + typedef uint64_t sigset_t; + + /// Thread state shared between user & kernel. + struct ushared_state { + sigset_t sigmask; //!< thread signal mask + sigset_t sig; //!< thread pending mask + // struct nxm_pth_state * + Addr pth_id; //!< out-of-line state + int flags; //!< shared flags +#define US_SIGSTACK 0x1 // thread called sigaltstack +#define US_ONSTACK 0x2 // thread is running on altstack +#define US_PROFILE 0x4 // thread called profil +#define US_SYSCALL 0x8 // thread in syscall +#define US_TRAP 0x10 // thread has trapped +#define US_YELLOW 0x20 // thread has mellowed yellow +#define US_YZONE 0x40 // thread has zoned out +#define US_FP_OWNED 0x80 // thread used floating point + + int cancel_state; //!< thread's cancelation state +#define US_CANCEL 0x1 // cancel pending +#define US_NOCANCEL 0X2 // synch cancel disabled +#define US_SYS_NOCANCEL 0x4 // syscall cancel disabled +#define US_ASYNC_NOCANCEL 0x8 // asynch cancel disabled +#define US_CANCEL_BITS (US_NOCANCEL|US_SYS_NOCANCEL|US_ASYNC_NOCANCEL) +#define US_CANCEL_MASK (US_CANCEL|US_NOCANCEL|US_SYS_NOCANCEL| \ + US_ASYNC_NOCANCEL) + + // These are semi-shared. They are always visible to + // the kernel but are never context-switched by the library. + + int nxm_ssig; //!< scheduler's synchronous signals + int reserved1; //!< reserved1 + int64_t nxm_active; //!< scheduler active + int64_t reserved2; //!< reserved2 + }; + + struct nxm_sched_state { + struct ushared_state nxm_u; //!< state own by user thread + unsigned int nxm_bits; //!< scheduler state / slot + int nxm_quantum; //!< quantum count-down value + int nxm_set_quantum; //!< quantum reset value + int nxm_sysevent; //!< syscall state + // struct nxm_upcall * + Addr nxm_uc_ret; //!< stack ptr of null thread + // void * + Addr nxm_tid; //!< scheduler's thread id + int64_t nxm_va; //!< page fault address + // struct nxm_pth_state * + Addr nxm_pthid; //!< id of null thread + uint64_t nxm_bound_pcs_count; //!< bound PCS thread count + int64_t pad[2]; //!< pad + }; + + /// nxm_shared. + struct nxm_shared { + int64_t nxm_callback; //!< address of upcall routine + unsigned int nxm_version; //!< version number + unsigned short nxm_uniq_offset; //!< correction factor for TEB + unsigned short pad1; //!< pad1 + int64_t space[2]; //!< future growth + struct nxm_sched_state nxm_ss[1]; //!< array of shared areas + }; + + /// nxm_slot_state_t. + enum nxm_slot_state_t { + NXM_SLOT_AVAIL, + NXM_SLOT_BOUND, + NXM_SLOT_UNBOUND, + NXM_SLOT_EMPTY + }; + + /// nxm_config_info + struct nxm_config_info { + int nxm_nslots_per_rad; //!< max number of VP slots per RAD + int nxm_nrads; //!< max number of RADs + // nxm_slot_state_t * + Addr nxm_slot_state; //!< per-VP slot state + // struct nxm_shared * + Addr nxm_rad[1]; //!< per-RAD shared areas + }; + + /// For nxm_thread_create. + enum nxm_thread_type { + NXM_TYPE_SCS = 0, + NXM_TYPE_VP = 1, + NXM_TYPE_MANAGER = 2 + }; + + /// Thread attributes. + struct nxm_thread_attr { + int version; //!< version + int type; //!< type + int cancel_flags; //!< cancel_flags + int priority; //!< priority + int policy; //!< policy + int signal_type; //!< signal_type + // void * + Addr pthid; //!< pthid + sigset_t sigmask; //!< sigmask + /// Initial register values. + struct { + uint64_t pc; //!< pc + uint64_t sp; //!< sp + uint64_t a0; //!< a0 + } registers; + uint64_t pad2[2]; //!< pad2 + }; + + /// Helper function to convert a host stat buffer to a target stat + /// buffer. Also copies the target buffer out to the simulated + /// memory space. Used by stat(), fstat(), and lstat(). + template <class T> + static void + copyOutStatBuf(TranslatingPort *mem, Addr addr, global_stat *host) + { + using namespace TheISA; + + TypedBufferArg<T> tgt(addr); + + tgt->st_dev = htog(host->st_dev); + tgt->st_ino = htog(host->st_ino); + tgt->st_mode = htog(host->st_mode); + tgt->st_nlink = htog(host->st_nlink); + tgt->st_uid = htog(host->st_uid); + tgt->st_gid = htog(host->st_gid); + tgt->st_rdev = htog(host->st_rdev); + tgt->st_size = htog(host->st_size); + tgt->st_atimeX = htog(host->st_atime); + tgt->st_mtimeX = htog(host->st_mtime); + tgt->st_ctimeX = htog(host->st_ctime); + tgt->st_blksize = htog(host->st_blksize); + tgt->st_blocks = htog(host->st_blocks); + + tgt.copyOut(mem); + } + + /// Helper function to convert a host statfs buffer to a target statfs + /// buffer. Also copies the target buffer out to the simulated + /// memory space. Used by statfs() and fstatfs(). + template <class T> + static void + copyOutStatfsBuf(TranslatingPort *mem, Addr addr, global_statfs *host) + { + using namespace TheISA; + + TypedBufferArg<T> tgt(addr); + +#if defined(__OpenBSD__) || defined(__APPLE__) || defined(__FreeBSD__) + tgt->f_type = 0; +#else + tgt->f_type = htog(host->f_type); +#endif + tgt->f_bsize = htog(host->f_bsize); + tgt->f_blocks = htog(host->f_blocks); + tgt->f_bfree = htog(host->f_bfree); + tgt->f_bavail = htog(host->f_bavail); + tgt->f_files = htog(host->f_files); + tgt->f_ffree = htog(host->f_ffree); + + // Is this as string normally? + memcpy(&tgt->f_fsid, &host->f_fsid, sizeof(host->f_fsid)); + + tgt.copyOut(mem); + } + + class F64 { + public: + static void copyOutStatBuf(TranslatingPort *mem, Addr addr, + global_stat *host) + { + Tru64::copyOutStatBuf<Tru64::F64_stat>(mem, addr, host); + } + + static void copyOutStatfsBuf(TranslatingPort *mem, Addr addr, + global_statfs *host) + { + Tru64::copyOutStatfsBuf<Tru64::F64_statfs>(mem, addr, host); + } + }; + + class PreF64 { + public: + static void copyOutStatBuf(TranslatingPort *mem, Addr addr, + global_stat *host) + { + Tru64::copyOutStatBuf<Tru64::pre_F64_stat>(mem, addr, host); + } + + static void copyOutStatfsBuf(TranslatingPort *mem, Addr addr, + global_statfs *host) + { + Tru64::copyOutStatfsBuf<Tru64::pre_F64_statfs>(mem, addr, host); + } + }; + + /// Helper function to convert a host stat buffer to an old pre-F64 + /// (4.x) target stat buffer. Also copies the target buffer out to + /// the simulated memory space. Used by pre_F64_stat(), + /// pre_F64_fstat(), and pre_F64_lstat(). + static void + copyOutPreF64StatBuf(TranslatingPort *mem, Addr addr, struct stat *host) + { + using namespace TheISA; + + TypedBufferArg<Tru64::pre_F64_stat> tgt(addr); + + tgt->st_dev = htog(host->st_dev); + tgt->st_ino = htog(host->st_ino); + tgt->st_mode = htog(host->st_mode); + tgt->st_nlink = htog(host->st_nlink); + tgt->st_uid = htog(host->st_uid); + tgt->st_gid = htog(host->st_gid); + tgt->st_rdev = htog(host->st_rdev); + tgt->st_size = htog(host->st_size); + tgt->st_atimeX = htog(host->st_atime); + tgt->st_mtimeX = htog(host->st_mtime); + tgt->st_ctimeX = htog(host->st_ctime); + tgt->st_blksize = htog(host->st_blksize); + tgt->st_blocks = htog(host->st_blocks); + + tgt.copyOut(mem); + } + + + /// The target system's hostname. + static const char *hostname; + + + /// Target getdirentries() handler. + static SyscallReturn + getdirentriesFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) + { + using namespace TheISA; + +#ifdef __CYGWIN__ + panic("getdirent not implemented on cygwin!"); +#else + int fd = process->sim_fd(tc->getSyscallArg(0)); + Addr tgt_buf = tc->getSyscallArg(1); + int tgt_nbytes = tc->getSyscallArg(2); + Addr tgt_basep = tc->getSyscallArg(3); + + char * const host_buf = new char[tgt_nbytes]; + + // just pass basep through uninterpreted. + TypedBufferArg<int64_t> basep(tgt_basep); + basep.copyIn(tc->getMemPort()); + long host_basep = (off_t)htog((int64_t)*basep); + int host_result = getdirentries(fd, host_buf, tgt_nbytes, &host_basep); + + // check for error + if (host_result < 0) { + delete [] host_buf; + return -errno; + } + + // no error: copy results back to target space + Addr tgt_buf_ptr = tgt_buf; + char *host_buf_ptr = host_buf; + char *host_buf_end = host_buf + host_result; + while (host_buf_ptr < host_buf_end) { + global_dirent *host_dp = (global_dirent *)host_buf_ptr; + int namelen = strlen(host_dp->d_name); + + // Actual size includes padded string rounded up for alignment. + // Subtract 256 for dummy char array in Tru64::dirent definition. + // Add 1 to namelen for terminating null char. + int tgt_bufsize = sizeof(Tru64::dirent) - 256 + roundUp(namelen+1, 8); + TypedBufferArg<Tru64::dirent> tgt_dp(tgt_buf_ptr, tgt_bufsize); + tgt_dp->d_ino = host_dp->d_ino; + tgt_dp->d_reclen = tgt_bufsize; + tgt_dp->d_namlen = namelen; + strcpy(tgt_dp->d_name, host_dp->d_name); + tgt_dp.copyOut(tc->getMemPort()); + + tgt_buf_ptr += tgt_bufsize; + host_buf_ptr += host_dp->d_reclen; + } + + delete [] host_buf; + + *basep = htog((int64_t)host_basep); + basep.copyOut(tc->getMemPort()); + + return tgt_buf_ptr - tgt_buf; +#endif + } + + /// Target sigreturn() handler. + static SyscallReturn + sigreturnFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) + { + using namespace TheISA; + + using TheISA::RegFile; + TypedBufferArg<Tru64::sigcontext> sc(tc->getSyscallArg(0)); + + sc.copyIn(tc->getMemPort()); + + // Restore state from sigcontext structure. + // Note that we'll advance PC <- NPC before the end of the cycle, + // so we need to restore the desired PC into NPC. + // The current regs->pc will get clobbered. + tc->setNextPC(htog(sc->sc_pc)); + + for (int i = 0; i < 31; ++i) { + tc->setIntReg(i, htog(sc->sc_regs[i])); + tc->setFloatRegBits(i, htog(sc->sc_fpregs[i])); + } + + tc->setMiscReg(TheISA::Fpcr_DepTag, htog(sc->sc_fpcr)); + + return 0; + } + + + // + // Mach syscalls -- identified by negated syscall numbers + // + + /// Create a stack region for a thread. + static SyscallReturn + stack_createFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) + { + using namespace TheISA; + + TypedBufferArg<Tru64::vm_stack> argp(tc->getSyscallArg(0)); + + argp.copyIn(tc->getMemPort()); + + // if the user chose an address, just let them have it. Otherwise + // pick one for them. + if (htog(argp->address) == 0) { + argp->address = htog(process->next_thread_stack_base); + int stack_size = (htog(argp->rsize) + htog(argp->ysize) + + htog(argp->gsize)); + process->next_thread_stack_base -= stack_size; + argp.copyOut(tc->getMemPort()); + } + + return 0; + } + + /// NXM library version stamp. + static + const int NXM_LIB_VERSION = 301003; + + /// This call sets up the interface between the user and kernel + /// schedulers by creating a shared-memory region. The shared memory + /// region has several structs, some global, some per-RAD, some per-VP. + static SyscallReturn + nxm_task_initFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) + { + using namespace std; + using namespace TheISA; + + TypedBufferArg<Tru64::nxm_task_attr> attrp(tc->getSyscallArg(0)); + TypedBufferArg<Addr> configptr_ptr(tc->getSyscallArg(1)); + + attrp.copyIn(tc->getMemPort()); + + if (gtoh(attrp->nxm_version) != NXM_LIB_VERSION) { + cerr << "nxm_task_init: thread library version mismatch! " + << "got " << attrp->nxm_version + << ", expected " << NXM_LIB_VERSION << endl; + abort(); + } + + if (gtoh(attrp->flags) != Tru64::NXM_TASK_INIT_VP) { + cerr << "nxm_task_init: bad flag value " << attrp->flags + << " (expected " << Tru64::NXM_TASK_INIT_VP << ")" << endl; + abort(); + } + + const Addr base_addr = 0x12000; // was 0x3f0000000LL; + Addr cur_addr = base_addr; // next addresses to use + // first comes the config_info struct + Addr config_addr = cur_addr; + cur_addr += sizeof(Tru64::nxm_config_info); + // next comes the per-cpu state vector + Addr slot_state_addr = cur_addr; + int slot_state_size = + process->numCpus() * sizeof(Tru64::nxm_slot_state_t); + cur_addr += slot_state_size; + // now the per-RAD state struct (we only support one RAD) + cur_addr = 0x14000; // bump up addr for alignment + Addr rad_state_addr = cur_addr; + int rad_state_size = + (sizeof(Tru64::nxm_shared) + + (process->numCpus()-1) * sizeof(Tru64::nxm_sched_state)); + cur_addr += rad_state_size; + + // now initialize a config_info struct and copy it out to user space + TypedBufferArg<Tru64::nxm_config_info> config(config_addr); + + config->nxm_nslots_per_rad = htog(process->numCpus()); + config->nxm_nrads = htog(1); // only one RAD in our system! + config->nxm_slot_state = htog(slot_state_addr); + config->nxm_rad[0] = htog(rad_state_addr); + + config.copyOut(tc->getMemPort()); + + // initialize the slot_state array and copy it out + TypedBufferArg<Tru64::nxm_slot_state_t> slot_state(slot_state_addr, + slot_state_size); + for (int i = 0; i < process->numCpus(); ++i) { + // CPU 0 is bound to the calling process; all others are available + // XXX this code should have an endian conversion, but I don't think + // it works anyway + slot_state[i] = + (i == 0) ? Tru64::NXM_SLOT_BOUND : Tru64::NXM_SLOT_AVAIL; + } + + slot_state.copyOut(tc->getMemPort()); + + // same for the per-RAD "shared" struct. Note that we need to + // allocate extra bytes for the per-VP array which is embedded at + // the end. + TypedBufferArg<Tru64::nxm_shared> rad_state(rad_state_addr, + rad_state_size); + + rad_state->nxm_callback = attrp->nxm_callback; + rad_state->nxm_version = attrp->nxm_version; + rad_state->nxm_uniq_offset = attrp->nxm_uniq_offset; + for (int i = 0; i < process->numCpus(); ++i) { + Tru64::nxm_sched_state *ssp = &rad_state->nxm_ss[i]; + ssp->nxm_u.sigmask = htog(0); + ssp->nxm_u.sig = htog(0); + ssp->nxm_u.flags = htog(0); + ssp->nxm_u.cancel_state = htog(0); + ssp->nxm_u.nxm_ssig = 0; + ssp->nxm_bits = htog(0); + ssp->nxm_quantum = attrp->nxm_quantum; + ssp->nxm_set_quantum = attrp->nxm_quantum; + ssp->nxm_sysevent = htog(0); + + if (i == 0) { + uint64_t uniq = tc->readMiscReg(TheISA::Uniq_DepTag); + ssp->nxm_u.pth_id = htog(uniq + gtoh(attrp->nxm_uniq_offset)); + ssp->nxm_u.nxm_active = htog(uniq | 1); + } + else { + ssp->nxm_u.pth_id = htog(0); + ssp->nxm_u.nxm_active = htog(0); + } + } + + rad_state.copyOut(tc->getMemPort()); + + // + // copy pointer to shared config area out to user + // + *configptr_ptr = htog(config_addr); + configptr_ptr.copyOut(tc->getMemPort()); + + // Register this as a valid address range with the process + process->nxm_start = base_addr; + process->nxm_end = cur_addr; + + return 0; + } + + /// Initialize thread context. + static void + init_thread_context(ThreadContext *tc, + Tru64::nxm_thread_attr *attrp, uint64_t uniq_val) + { + using namespace TheISA; + + tc->clearArchRegs(); + + tc->setIntReg(TheISA::ArgumentReg0, gtoh(attrp->registers.a0)); + tc->setIntReg(27/*t12*/, gtoh(attrp->registers.pc)); + tc->setIntReg(TheISA::StackPointerReg, gtoh(attrp->registers.sp)); + tc->setMiscReg(TheISA::Uniq_DepTag, uniq_val); + + tc->setPC(gtoh(attrp->registers.pc)); + tc->setNextPC(gtoh(attrp->registers.pc) + sizeof(TheISA::MachInst)); + + tc->activate(); + } + + /// Create thread. + static SyscallReturn + nxm_thread_createFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) + { + using namespace std; + using namespace TheISA; + + TypedBufferArg<Tru64::nxm_thread_attr> attrp(tc->getSyscallArg(0)); + TypedBufferArg<uint64_t> kidp(tc->getSyscallArg(1)); + int thread_index = tc->getSyscallArg(2); + + // get attribute args + attrp.copyIn(tc->getMemPort()); + + if (gtoh(attrp->version) != NXM_LIB_VERSION) { + cerr << "nxm_thread_create: thread library version mismatch! " + << "got " << attrp->version + << ", expected " << NXM_LIB_VERSION << endl; + abort(); + } + + if (thread_index < 0 | thread_index > process->numCpus()) { + cerr << "nxm_thread_create: bad thread index " << thread_index + << endl; + abort(); + } + + // On a real machine, the per-RAD shared structure is in + // shared memory, so both the user and kernel can get at it. + // We don't have that luxury, so we just copy it in and then + // back out again. + int rad_state_size = + (sizeof(Tru64::nxm_shared) + + (process->numCpus()-1) * sizeof(Tru64::nxm_sched_state)); + + TypedBufferArg<Tru64::nxm_shared> rad_state(0x14000, + rad_state_size); + rad_state.copyIn(tc->getMemPort()); + + uint64_t uniq_val = gtoh(attrp->pthid) - gtoh(rad_state->nxm_uniq_offset); + + if (gtoh(attrp->type) == Tru64::NXM_TYPE_MANAGER) { + // DEC pthreads seems to always create one of these (in + // addition to N application threads), but we don't use it, + // so don't bother creating it. + + // This is supposed to be a port number. Make something up. + *kidp = htog(99); + kidp.copyOut(tc->getMemPort()); + + return 0; + } else if (gtoh(attrp->type) == Tru64::NXM_TYPE_VP) { + // A real "virtual processor" kernel thread. Need to fork + // this thread on another CPU. + Tru64::nxm_sched_state *ssp = &rad_state->nxm_ss[thread_index]; + + if (gtoh(ssp->nxm_u.nxm_active) != 0) + return (int) Tru64::KERN_NOT_RECEIVER; + + ssp->nxm_u.pth_id = attrp->pthid; + ssp->nxm_u.nxm_active = htog(uniq_val | 1); + + rad_state.copyOut(tc->getMemPort()); + + Addr slot_state_addr = 0x12000 + sizeof(Tru64::nxm_config_info); + int slot_state_size = + process->numCpus() * sizeof(Tru64::nxm_slot_state_t); + + TypedBufferArg<Tru64::nxm_slot_state_t> + slot_state(slot_state_addr, + slot_state_size); + + slot_state.copyIn(tc->getMemPort()); + + if (slot_state[thread_index] != Tru64::NXM_SLOT_AVAIL) { + cerr << "nxm_thread_createFunc: requested VP slot " + << thread_index << " not available!" << endl; + fatal(""); + } + + // XXX This should have an endian conversion but I think this code + // doesn't work anyway + slot_state[thread_index] = Tru64::NXM_SLOT_BOUND; + + slot_state.copyOut(tc->getMemPort()); + + // Find a free simulator thread context. + for (int i = 0; i < process->numCpus(); ++i) { + ThreadContext *tc = process->threadContexts[i]; + + if (tc->status() == ThreadContext::Suspended) { + // inactive context... grab it + init_thread_context(tc, attrp, uniq_val); + + // This is supposed to be a port number, but we'll try + // and get away with just sticking the thread index + // here. + *kidp = htog(thread_index); + kidp.copyOut(tc->getMemPort()); + + return 0; + } + } + + // fell out of loop... no available inactive context + cerr << "nxm_thread_create: no idle contexts available." << endl; + abort(); + } else { + cerr << "nxm_thread_create: can't handle thread type " + << attrp->type << endl; + abort(); + } + + return 0; + } + + /// Thread idle call (like yield()). + static SyscallReturn + nxm_idleFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) + { + return 0; + } + + /// Block thread. + static SyscallReturn + nxm_thread_blockFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) + { + using namespace std; + + uint64_t tid = tc->getSyscallArg(0); + uint64_t secs = tc->getSyscallArg(1); + uint64_t flags = tc->getSyscallArg(2); + uint64_t action = tc->getSyscallArg(3); + uint64_t usecs = tc->getSyscallArg(4); + + cout << tc->getCpuPtr()->name() << ": nxm_thread_block " << tid << " " + << secs << " " << flags << " " << action << " " << usecs << endl; + + return 0; + } + + /// block. + static SyscallReturn + nxm_blockFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) + { + using namespace std; + + Addr uaddr = tc->getSyscallArg(0); + uint64_t val = tc->getSyscallArg(1); + uint64_t secs = tc->getSyscallArg(2); + uint64_t usecs = tc->getSyscallArg(3); + uint64_t flags = tc->getSyscallArg(4); + + BaseCPU *cpu = tc->getCpuPtr(); + + cout << cpu->name() << ": nxm_block " + << hex << uaddr << dec << " " << val + << " " << secs << " " << usecs + << " " << flags << endl; + + return 0; + } + + /// Unblock thread. + static SyscallReturn + nxm_unblockFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) + { + using namespace std; + + Addr uaddr = tc->getSyscallArg(0); + + cout << tc->getCpuPtr()->name() << ": nxm_unblock " + << hex << uaddr << dec << endl; + + return 0; + } + + /// Switch thread priority. + static SyscallReturn + swtch_priFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) + { + // Attempts to switch to another runnable thread (if there is + // one). Returns false if there are no other threads to run + // (i.e., the thread can reasonably spin-wait) or true if there + // are other threads. + // + // Since we assume at most one "kernel" thread per CPU, it's + // always safe to return false here. + return 0; //false; + } + + + /// Activate thread context waiting on a channel. Just activate one + /// by default. + static int + activate_waiting_context(Addr uaddr, Process *process, + bool activate_all = false) + { + using namespace std; + + int num_activated = 0; + + list<Process::WaitRec>::iterator i = process->waitList.begin(); + list<Process::WaitRec>::iterator end = process->waitList.end(); + + while (i != end && (num_activated == 0 || activate_all)) { + if (i->waitChan == uaddr) { + // found waiting process: make it active + ThreadContext *newCtx = i->waitingContext; + assert(newCtx->status() == ThreadContext::Suspended); + newCtx->activate(); + + // get rid of this record + i = process->waitList.erase(i); + + ++num_activated; + } else { + ++i; + } + } + + return num_activated; + } + + /// M5 hacked-up lock acquire. + static void + m5_lock_mutex(Addr uaddr, Process *process, ThreadContext *tc) + { + using namespace TheISA; + + TypedBufferArg<uint64_t> lockp(uaddr); + + lockp.copyIn(tc->getMemPort()); + + if (gtoh(*lockp) == 0) { + // lock is free: grab it + *lockp = htog(1); + lockp.copyOut(tc->getMemPort()); + } else { + // lock is busy: disable until free + process->waitList.push_back(Process::WaitRec(uaddr, tc)); + tc->suspend(); + } + } + + /// M5 unlock call. + static void + m5_unlock_mutex(Addr uaddr, Process *process, ThreadContext *tc) + { + TypedBufferArg<uint64_t> lockp(uaddr); + + lockp.copyIn(tc->getMemPort()); + assert(*lockp != 0); + + // Check for a process waiting on the lock. + int num_waiting = activate_waiting_context(uaddr, process); + + // clear lock field if no waiting context is taking over the lock + if (num_waiting == 0) { + *lockp = 0; + lockp.copyOut(tc->getMemPort()); + } + } + + /// Lock acquire syscall handler. + static SyscallReturn + m5_mutex_lockFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) + { + Addr uaddr = tc->getSyscallArg(0); + + m5_lock_mutex(uaddr, process, tc); + + // Return 0 since we will always return to the user with the lock + // acquired. We will just keep the context inactive until that is + // true. + return 0; + } + + /// Try lock (non-blocking). + static SyscallReturn + m5_mutex_trylockFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) + { + using namespace TheISA; + + Addr uaddr = tc->getSyscallArg(0); + TypedBufferArg<uint64_t> lockp(uaddr); + + lockp.copyIn(tc->getMemPort()); + + if (gtoh(*lockp) == 0) { + // lock is free: grab it + *lockp = htog(1); + lockp.copyOut(tc->getMemPort()); + return 0; + } else { + return 1; + } + } + + /// Unlock syscall handler. + static SyscallReturn + m5_mutex_unlockFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) + { + Addr uaddr = tc->getSyscallArg(0); + + m5_unlock_mutex(uaddr, process, tc); + + return 0; + } + + /// Signal ocndition. + static SyscallReturn + m5_cond_signalFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) + { + Addr cond_addr = tc->getSyscallArg(0); + + // Wake up one process waiting on the condition variable. + activate_waiting_context(cond_addr, process); + + return 0; + } + + /// Wake up all processes waiting on the condition variable. + static SyscallReturn + m5_cond_broadcastFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) + { + Addr cond_addr = tc->getSyscallArg(0); + + activate_waiting_context(cond_addr, process, true); + + return 0; + } + + /// Wait on a condition. + static SyscallReturn + m5_cond_waitFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) + { + using namespace TheISA; + + Addr cond_addr = tc->getSyscallArg(0); + Addr lock_addr = tc->getSyscallArg(1); + TypedBufferArg<uint64_t> condp(cond_addr); + TypedBufferArg<uint64_t> lockp(lock_addr); + + // user is supposed to acquire lock before entering + lockp.copyIn(tc->getMemPort()); + assert(gtoh(*lockp) != 0); + + m5_unlock_mutex(lock_addr, process, tc); + + process->waitList.push_back(Process::WaitRec(cond_addr, tc)); + tc->suspend(); + + return 0; + } + + /// Thread exit. + static SyscallReturn + m5_thread_exitFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) + { + assert(tc->status() == ThreadContext::Active); + tc->deallocate(); + + return 0; + } + + /// Indirect syscall invocation (call #0). + static SyscallReturn + indirectSyscallFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) + { + int new_callnum = tc->getSyscallArg(0); + LiveProcess *lp = dynamic_cast<LiveProcess*>(process); + assert(lp); + + for (int i = 0; i < 5; ++i) + tc->setSyscallArg(i, tc->getSyscallArg(i+1)); + + + SyscallDesc *new_desc = lp->getDesc(new_callnum); + if (desc == NULL) + fatal("Syscall %d out of range", callnum); + + new_desc->doSyscall(new_callnum, process, tc); + + return 0; + } + +}; // class Tru64 + + +#endif // FULL_SYSTEM + +#endif // __TRU64_HH__ diff --git a/src/kern/tru64/tru64_events.cc b/src/kern/tru64/tru64_events.cc new file mode 100644 index 000000000..69638bde1 --- /dev/null +++ b/src/kern/tru64/tru64_events.cc @@ -0,0 +1,108 @@ +/* + * Copyright (c) 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: Nathan Binkert + * Lisa Hsu + */ + +#include "cpu/thread_context.hh" +#include "cpu/base.hh" +#include "kern/system_events.hh" +#include "kern/tru64/tru64_events.hh" +#include "kern/tru64/dump_mbuf.hh" +#include "kern/tru64/printf.hh" +#include "arch/alpha/ev5.hh" +#include "arch/arguments.hh" +#include "arch/isa_traits.hh" +#include "sim/system.hh" + +using namespace TheISA; + +//void SkipFuncEvent::process(ExecContext *tc); + +void +BadAddrEvent::process(ThreadContext *tc) +{ + // The following gross hack is the equivalent function to the + // annotation for vmunix::badaddr in: + // simos/simulation/apps/tcl/osf/tlaser.tcl + + uint64_t a0 = tc->readIntReg(ArgumentReg0); + + AddrRangeList resp; + AddrRangeList snoop; + AddrRangeIter iter; + bool found = false; + + tc->getPhysPort()->getPeerAddressRanges(resp, snoop); + for(iter = resp.begin(); iter != resp.end(); iter++) + { + if (*iter == (TheISA::K0Seg2Phys(a0) & EV5::PAddrImplMask)) + found = true; + } + + if (!TheISA::IsK0Seg(a0) || found ) { + + DPRINTF(BADADDR, "badaddr arg=%#x bad\n", a0); + tc->setIntReg(ReturnValueReg, 0x1); + SkipFuncEvent::process(tc); + } + else + DPRINTF(BADADDR, "badaddr arg=%#x good\n", a0); +} + +void +PrintfEvent::process(ThreadContext *tc) +{ + if (DTRACE(Printf)) { + DebugOut() << curTick << ": " << tc->getCpuPtr()->name() << ": "; + + AlphaArguments args(tc); + tru64::Printf(args); + } +} + +void +DebugPrintfEvent::process(ThreadContext *tc) +{ + if (DTRACE(DebugPrintf)) { + if (!raw) + DebugOut() << curTick << ": " << tc->getCpuPtr()->name() << ": "; + + AlphaArguments args(tc); + tru64::Printf(args); + } +} + +void +DumpMbufEvent::process(ThreadContext *tc) +{ + if (DTRACE(DebugPrintf)) { + AlphaArguments args(tc); + tru64::DumpMbuf(args); + } +} diff --git a/src/kern/tru64/tru64_events.hh b/src/kern/tru64/tru64_events.hh new file mode 100644 index 000000000..6a1ab2e51 --- /dev/null +++ b/src/kern/tru64/tru64_events.hh @@ -0,0 +1,86 @@ +/* + * Copyright (c) 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: Nathan Binkert + * Lisa Hsu + */ + +#ifndef __TRU64_EVENTS_HH__ +#define __TRU64_EVENTS_HH__ + +#include <string> + +#include "cpu/pc_event.hh" +#include "kern/system_events.hh" + +class ThreadContext; + +class BadAddrEvent : public SkipFuncEvent +{ + public: + BadAddrEvent(PCEventQueue *q, const std::string &desc, Addr addr) + : SkipFuncEvent(q, desc, addr) {} + virtual void process(ThreadContext *tc); +}; + +class PrintfEvent : public PCEvent +{ + public: + PrintfEvent(PCEventQueue *q, const std::string &desc, Addr addr) + : PCEvent(q, desc, addr) {} + virtual void process(ThreadContext *tc); +}; + +class DebugPrintfEvent : public PCEvent +{ + private: + bool raw; + + public: + DebugPrintfEvent(PCEventQueue *q, const std::string &desc, Addr addr, + bool r = false) + : PCEvent(q, desc, addr), raw(r) {} + virtual void process(ThreadContext *tc); +}; + +class DebugPrintfrEvent : public DebugPrintfEvent +{ + public: + DebugPrintfrEvent(PCEventQueue *q, const std::string &desc, Addr addr) + : DebugPrintfEvent(q, desc, addr, true) + {} +}; + +class DumpMbufEvent : public PCEvent +{ + public: + DumpMbufEvent(PCEventQueue *q, const std::string &desc, Addr addr) + : PCEvent(q, desc, addr) {} + virtual void process(ThreadContext *tc); +}; + +#endif // __TRU64_EVENTS_HH__ diff --git a/src/kern/tru64/tru64_syscalls.cc b/src/kern/tru64/tru64_syscalls.cc new file mode 100644 index 000000000..8051b9efb --- /dev/null +++ b/src/kern/tru64/tru64_syscalls.cc @@ -0,0 +1,440 @@ +/* + * Copyright (c) 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: Nathan Binkert + */ + +#include "kern/tru64/tru64_syscalls.hh" + +namespace { + const char * + standard_strings[SystemCalls<Tru64>::StandardNumber] = { + "syscall", // 0 + "exit", // 1 + "fork", // 2 + "read", // 3 + "write", // 4 + "old_open", // 5 + "close", // 6 + "wait4", // 7 + "old_creat", // 8 + "link", // 9 + + "unlink", // 10 + "execv", // 11 + "chdir", // 12 + "fchdir", // 13 + "mknod", // 14 + "chmod", // 15 + "chown", // 16 + "obreak", // 17 + "pre_F64_getfsstat", // 18 + "lseek", // 19 + + "getpid", // 20 + "mount", // 21 + "unmount", // 22 + "setuid", // 23 + "getuid", // 24 + "exec_with_loader", // 25 + "ptrace", // 26 + "recvmsg", // 27 + "sendmsg", // 28 + "recvfrom", // 29 + + "accept", // 30 + "getpeername", // 31 + "getsockname", // 32 + "access", // 33 + "chflags", // 34 + "fchflags", // 35 + "sync", // 36 + "kill", // 37 + "old_stat", // 38 + "setpgid", // 39 + + "old_lstat", // 40 + "dup", // 41 + "pipe", // 42 + "set_program_attributes", // 43 + "profil", // 44 + "open", // 45 + "obsolete_osigaction", // 46 + "getgid", // 47 + "sigprocmask", // 48 + "getlogin", // 49 + + "setlogin", // 50 + "acct", // 51 + "sigpending", // 52 + "classcntl", // 53 + "ioctl", // 54 + "reboot", // 55 + "revoke", // 56 + "symlink", // 57 + "readlink", // 58 + "execve", // 59 + + "umask", // 60 + "chroot", // 61 + "old_fstat", // 62 + "getpgrp", // 63 + "getpagesize", // 64 + "mremap", // 65 + "vfork", // 66 + "pre_F64_stat", // 67 + "pre_F64_lstat", // 68 + "sbrk", // 69 + + "sstk", // 70 + "mmap", // 71 + "ovadvise", // 72 + "munmap", // 73 + "mprotect", // 74 + "madvise", // 75 + "old_vhangup", // 76 + "kmodcall", // 77 + "mincore", // 78 + "getgroups", // 79 + + "setgroups", // 80 + "old_getpgrp", // 81 + "setpgrp", // 82 + "setitimer", // 83 + "old_wait", // 84 + "table", // 85 + "getitimer", // 86 + "gethostname", // 87 + "sethostname", // 88 + "getdtablesize", // 89 + + "dup2", // 90 + "pre_F64_fstat", // 91 + "fcntl", // 92 + "select", // 93 + "poll", // 94 + "fsync", // 95 + "setpriority", // 96 + "socket", // 97 + "connect", // 98 + "old_accept", // 99 + + "getpriority", // 100 + "old_send", // 101 + "old_recv", // 102 + "sigreturn", // 103 + "bind", // 104 + "setsockopt", // 105 + "listen", // 106 + "plock", // 107 + "old_sigvec", // 108 + "old_sigblock", // 109 + + "old_sigsetmask", // 110 + "sigsuspend", // 111 + "sigstack", // 112 + "old_recvmsg", // 113 + "old_sendmsg", // 114 + "obsolete_vtrcae", // 115 + "gettimeofday", // 116 + "getrusage", // 117 + "getsockopt", // 118 + "numa_syscalls", // 119 + + "readv", // 120 + "writev", // 121 + "settimeofday", // 122 + "fchown", // 123 + "fchmod", // 124 + "old_recvfrom", // 125 + "setreuid", // 126 + "setregid", // 127 + "rename", // 128 + "truncate", // 129 + + "ftruncate", // 130 + "flock", // 131 + "setgid", // 132 + "sendto", // 133 + "shutdown", // 134 + "socketpair", // 135 + "mkdir", // 136 + "rmdir", // 137 + "utimes", // 138 + "obsolete_42_sigreturn", // 139 + + "adjtime", // 140 + "old_getpeername", // 141 + "gethostid", // 142 + "sethostid", // 143 + "getrlimit", // 144 + "setrlimit", // 145 + "old_killpg", // 146 + "setsid", // 147 + "quotactl", // 148 + "oldquota", // 149 + + "old_getsockname", // 150 + "pread", // 151 + "pwrite", // 152 + "pid_block", // 153 + "pid_unblock", // 154 + "signal_urti", // 155 + "sigaction", // 156 + "sigwaitprim", // 157 + "nfssvc", // 158 + "getdirentries", // 159 + + "pre_F64_statfs", // 160 + "pre_F64_fstatfs", // 161 + 0, // 162 + "async_daemon", // 163 + "getfh", // 164 + "getdomainname", // 165 + "setdomainname", // 166 + 0, // 167 + 0, // 168 + "exportfs", // 169 + + 0, // 170 + 0, // 171 + 0, // 172 + 0, // 173 + 0, // 174 + 0, // 175 + 0, // 176 + 0, // 177 + 0, // 178 + 0, // 179 + + 0, // 180 + "alt_plock", // 181 + 0, // 182 + 0, // 183 + "getmnt", // 184 + 0, // 185 + 0, // 186 + "alt_sigpending", // 187 + "alt_setsid", // 188 + 0, // 189 + + 0, // 190 + 0, // 191 + 0, // 192 + 0, // 193 + 0, // 194 + 0, // 195 + 0, // 196 + 0, // 197 + 0, // 198 + "swapon", // 199 + + "msgctl", // 200 + "msgget", // 201 + "msgrcv", // 202 + "msgsnd", // 203 + "semctl", // 204 + "semget", // 205 + "semop", // 206 + "uname", // 207 + "lchown", // 208 + "shmat", // 209 + + "shmctl", // 210 + "shmdt", // 211 + "shmget", // 212 + "mvalid", // 213 + "getaddressconf", // 214 + "msleep", // 215 + "mwakeup", // 216 + "msync", // 217 + "signal", // 218 + "utc_gettime", // 219 + + "utc_adjtime", // 220 + 0, // 221 + "security", // 222 + "kloadcall", // 223 + "stat", // 224 + "lstat", // 225 + "fstat", // 226 + "statfs", // 227 + "fstatfs", // 228 + "getfsstat", // 229 + + "gettimeofday64", // 230 + "settimeofday64", // 231 + 0, // 232 + "getpgid", // 233 + "getsid", // 234 + "sigaltstack", // 235 + "waitid", // 236 + "priocntlset", // 237 + "sigsendset", // 238 + "set_speculative", // 239 + + "msfs_syscall", // 240 + "sysinfo", // 241 + "uadmin", // 242 + "fuser", // 243 + "proplist_syscall", // 244 + "ntp_adjtime", // 245 + "ntp_gettime", // 246 + "pathconf", // 247 + "fpathconf", // 248 + "sync2", // 249 + + "uswitch", // 250 + "usleep_thread", // 251 + "audcntl", // 252 + "audgen", // 253 + "sysfs", // 254 + "subsys_info", // 255 + "getsysinfo", // 256 + "setsysinfo", // 257 + "afs_syscall", // 258 + "swapctl", // 259 + + "memcntl", // 260 + "fdatasync", // 261 + "oflock", // 262 + "_F64_readv", // 263 + "_F64_writev", // 264 + "cdslxlate", // 265 + "sendfile", // 266 + }; + + const char * + mach_strings[SystemCalls<Tru64>::MachNumber] = { + 0, // 0 + 0, // 1 + 0, // 2 + 0, // 3 + 0, // 4 + 0, // 5 + 0, // 6 + 0, // 7 + 0, // 8 + 0, // 9 + + "task_self", // 10 + "thread_reply", // 11 + "task_notify", // 12 + "thread_self", // 13 + 0, // 14 + 0, // 15 + 0, // 16 + 0, // 17 + 0, // 18 + 0, // 19 + + "msg_send_trap", // 20 + "msg_receive_trap", // 21 + "msg_rpc_trap", // 22 + 0, // 23 + "nxm_block", // 24 + "nxm_unblock", // 25 + 0, // 26 + 0, // 27 + 0, // 28 + "nxm_thread_destroy", // 29 + + "lw_wire", // 30 + "lw_unwire", // 31 + "nxm_thread_create", // 32 + "nxm_task_init", // 33 + 0, // 34 + "nxm_idle", // 35 + "nxm_wakeup_idle", // 36 + "nxm_set_pthid", // 37 + "nxm_thread_kill", // 38 + "nxm_thread_block", // 39 + + "nxm_thread_wakeup", // 40 + "init_process", // 41 + "nxm_get_binding", // 42 + "map_fd", // 43 + "nxm_resched", // 44 + "nxm_set_cancel", // 45 + "nxm_set_binding", // 46 + "stack_create", // 47 + "nxm_get_state", // 48 + "nxm_thread_suspend", // 49 + + "nxm_thread_resume", // 50 + "nxm_signal_check", // 51 + "htg_unix_syscall", // 52 + 0, // 53 + 0, // 54 + "host_self", // 55 + "host_priv_self", // 56 + 0, // 57 + 0, // 58 + "swtch_pri", // 59 + + "swtch", // 60 + "thread_switch", // 61 + "semop_fast", // 62 + "nxm_pshared_init", // 63 + "nxm_pshared_block", // 64 + "nxm_pshared_unblock", // 65 + "nxm_pshared_destroy", // 66 + "nxm_swtch_pri", // 67 + "lw_syscall", // 68 + 0, // 69 + + "mach_sctimes_0", // 70 + "mach_sctimes_1", // 71 + "mach_sctimes_2", // 72 + "mach_sctimes_3", // 73 + "mach_sctimes_4", // 74 + "mach_sctimes_5", // 75 + "mach_sctimes_6", // 76 + "mach_sctimes_7", // 77 + "mach_sctimes_8", // 78 + "mach_sctimes_9", // 79 + + "mach_sctimes_10", // 80 + "mach_sctimes_11", // 81 + "mach_sctimes_port_alloc_dealloc", // 82 + }; +} + +const char * +SystemCalls<Tru64>::name(int num) +{ + if (num >= Number) + return 0; + else if (num >= StandardNumber) + return mach_strings[num - StandardNumber]; + else if (num >= 0) + return standard_strings[num]; + else if (num > -MachNumber) + return mach_strings[-num]; + else + return 0; +} diff --git a/src/kern/tru64/tru64_syscalls.hh b/src/kern/tru64/tru64_syscalls.hh new file mode 100644 index 000000000..66f5c2d39 --- /dev/null +++ b/src/kern/tru64/tru64_syscalls.hh @@ -0,0 +1,361 @@ +/* + * Copyright (c) 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: Nathan Binkert + */ + +#ifndef __KERN_TRU64_TRU64_SYSCALLS_HH__ +#define __KERN_TRU64_TRU64_SYSCALLS_HH__ + +#include "kern/tru64/tru64.hh" + +template <class OS> +class SystemCalls; + +template <> +class SystemCalls<Tru64> +{ + public: + enum { + syscall = 0, + exit = 1, + fork = 2, + read = 3, + write = 4, + old_open = 5, + close = 6, + wait4 = 7, + old_creat = 8, + link = 9, + unlink = 10, + execv = 11, + chdir = 12, + fchdir = 13, + mknod = 14, + chmod = 15, + chown = 16, + obreak = 17, + pre_F64_getfsstat = 18, + lseek = 19, + getpid = 20, + mount = 21, + unmount = 22, + setuid = 23, + getuid = 24, + exec_with_loader = 25, + ptrace = 26, + recvmsg = 27, + sendmsg = 28, + recvfrom = 29, + accept = 30, + getpeername = 31, + getsockname = 32, + access = 33, + chflags = 34, + fchflags = 35, + sync = 36, + kill = 37, + old_stat = 38, + setpgid = 39, + old_lstat = 40, + dup = 41, + pipe = 42, + set_program_attributes = 43, + profil = 44, + open = 45, + obsolete_osigaction = 46, + getgid = 47, + sigprocmask = 48, + getlogin = 49, + setlogin = 50, + acct = 51, + sigpending = 52, + classcntl = 53, + ioctl = 54, + reboot = 55, + revoke = 56, + symlink = 57, + readlink = 58, + execve = 59, + umask = 60, + chroot = 61, + old_fstat = 62, + getpgrp = 63, + getpagesize = 64, + mremap = 65, + vfork = 66, + pre_F64_stat = 67, + pre_F64_lstat = 68, + sbrk = 69, + sstk = 70, + mmap = 71, + ovadvise = 72, + munmap = 73, + mprotect = 74, + madvise = 75, + old_vhangup = 76, + kmodcall = 77, + mincore = 78, + getgroups = 79, + setgroups = 80, + old_getpgrp = 81, + setpgrp = 82, + setitimer = 83, + old_wait = 84, + table = 85, + getitimer = 86, + gethostname = 87, + sethostname = 88, + getdtablesize = 89, + dup2 = 90, + pre_F64_fstat = 91, + fcntl = 92, + select = 93, + poll = 94, + fsync = 95, + setpriority = 96, + socket = 97, + connect = 98, + old_accept = 99, + getpriority = 100, + old_send = 101, + old_recv = 102, + sigreturn = 103, + bind = 104, + setsockopt = 105, + listen = 106, + plock = 107, + old_sigvec = 108, + old_sigblock = 109, + old_sigsetmask = 110, + sigsuspend = 111, + sigstack = 112, + old_recvmsg = 113, + old_sendmsg = 114, + obsolete_vtrcae = 115, + gettimeofday = 116, + getrusage = 117, + getsockopt = 118, + numa_syscalls = 119, + readv = 120, + writev = 121, + settimeofday = 122, + fchown = 123, + fchmod = 124, + old_recvfrom = 125, + setreuid = 126, + setregid = 127, + rename = 128, + truncate = 129, + ftruncate = 130, + flock = 131, + setgid = 132, + sendto = 133, + shutdown = 134, + socketpair = 135, + mkdir = 136, + rmdir = 137, + utimes = 138, + obsolete_42_sigreturn = 139, + adjtime = 140, + old_getpeername = 141, + gethostid = 142, + sethostid = 143, + getrlimit = 144, + setrlimit = 145, + old_killpg = 146, + setsid = 147, + quotactl = 148, + oldquota = 149, + old_getsockname = 150, + pread = 151, + pwrite = 152, + pid_block = 153, + pid_unblock = 154, + signal_urti = 155, + sigaction = 156, + sigwaitprim = 157, + nfssvc = 158, + getdirentries = 159, + pre_F64_statfs = 160, + pre_F64_fstatfs = 161, + async_daemon = 163, + getfh = 164, + getdomainname = 165, + setdomainname = 166, + exportfs = 169, + alt_plock = 181, + getmnt = 184, + alt_sigpending = 187, + alt_setsid = 188, + swapon = 199, + msgctl = 200, + msgget = 201, + msgrcv = 202, + msgsnd = 203, + semctl = 204, + semget = 205, + semop = 206, + uname = 207, + lchown = 208, + shmat = 209, + shmctl = 210, + shmdt = 211, + shmget = 212, + mvalid = 213, + getaddressconf = 214, + msleep = 215, + mwakeup = 216, + msync = 217, + signal = 218, + utc_gettime = 219, + utc_adjtime = 220, + security = 222, + kloadcall = 223, + stat = 224, + lstat = 225, + fstat = 226, + statfs = 227, + fstatfs = 228, + getfsstat = 229, + gettimeofday64 = 230, + settimeofday64 = 231, + getpgid = 233, + getsid = 234, + sigaltstack = 235, + waitid = 236, + priocntlset = 237, + sigsendset = 238, + set_speculative = 239, + msfs_syscall = 240, + sysinfo = 241, + uadmin = 242, + fuser = 243, + proplist_syscall = 244, + ntp_adjtime = 245, + ntp_gettime = 246, + pathconf = 247, + fpathconf = 248, + sync2 = 249, + uswitch = 250, + usleep_thread = 251, + audcntl = 252, + audgen = 253, + sysfs = 254, + subsys_info = 255, + getsysinfo = 256, + setsysinfo = 257, + afs_syscall = 258, + swapctl = 259, + memcntl = 260, + fdatasync = 261, + oflock = 262, + _F64_readv = 263, + _F64_writev = 264, + cdslxlate = 265, + sendfile = 266, + StandardNumber + }; + + enum { + task_self = 10, + thread_reply = 11, + task_notify = 12, + thread_self = 13, + msg_send_trap = 20, + msg_receive_trap = 21, + msg_rpc_trap = 22, + nxm_block = 24, + nxm_unblock = 25, + nxm_thread_destroy = 29, + lw_wire = 30, + lw_unwire = 31, + nxm_thread_create = 32, + nxm_task_init = 33, + nxm_idle = 35, + nxm_wakeup_idle = 36, + nxm_set_pthid = 37, + nxm_thread_kill = 38, + nxm_thread_block = 39, + nxm_thread_wakeup = 40, + init_process = 41, + nxm_get_binding = 42, + map_fd = 43, + nxm_resched = 44, + nxm_set_cancel = 45, + nxm_set_binding = 46, + stack_create = 47, + nxm_get_state = 48, + nxm_thread_suspend = 49, + nxm_thread_resume = 50, + nxm_signal_check = 51, + htg_unix_syscall = 52, + host_self = 55, + host_priv_self = 56, + swtch_pri = 59, + swtch = 60, + thread_switch = 61, + semop_fast = 62, + nxm_pshared_init = 63, + nxm_pshared_block = 64, + nxm_pshared_unblock = 65, + nxm_pshared_destroy = 66, + nxm_swtch_pri = 67, + lw_syscall = 68, + mach_sctimes_0 = 70, + mach_sctimes_1 = 71, + mach_sctimes_2 = 72, + mach_sctimes_3 = 73, + mach_sctimes_4 = 74, + mach_sctimes_5 = 75, + mach_sctimes_6 = 76, + mach_sctimes_7 = 77, + mach_sctimes_8 = 78, + mach_sctimes_9 = 79, + mach_sctimes_10 = 80, + mach_sctimes_11 = 81, + mach_sctimes_port_alloc_dealloc = 82, + MachNumber + }; + + static const int Number = StandardNumber + MachNumber; + + static const char *name(int num); + + static bool validSyscallNumber(int num) { + return -MachNumber < num && num < StandardNumber; + } + + static int convert(int syscall_num) { + if (!validSyscallNumber(syscall_num)) + return -1; + + return syscall_num < 0 ? StandardNumber - syscall_num : syscall_num; + } +}; + +#endif // __KERN_TRU64_TRU64_SYSCALLS_HH__ diff --git a/src/mem/bridge.cc b/src/mem/bridge.cc new file mode 100644 index 000000000..3718cbaaf --- /dev/null +++ b/src/mem/bridge.cc @@ -0,0 +1,261 @@ + +/* + * 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 + * Steve Reinhardt + */ + +/** + * @file Definition of a simple bus bridge without buffering. + */ + +#include <algorithm> + +#include "base/trace.hh" +#include "mem/bridge.hh" +#include "sim/builder.hh" + +Bridge::BridgePort::BridgePort(const std::string &_name, + Bridge *_bridge, BridgePort *_otherPort, + int _delay, int _queueLimit) + : Port(_name), bridge(_bridge), otherPort(_otherPort), + delay(_delay), outstandingResponses(0), + queueLimit(_queueLimit), sendEvent(this) +{ +} + +Bridge::Bridge(const std::string &n, int qsa, int qsb, + Tick _delay, int write_ack) + : MemObject(n), + portA(n + "-portA", this, &portB, _delay, qsa), + portB(n + "-portB", this, &portA, _delay, qsa), + ackWrites(write_ack) +{ +} + +Port * +Bridge::getPort(const std::string &if_name) +{ + BridgePort *port; + + if (if_name == "side_a") + port = &portA; + else if (if_name == "side_b") + port = &portB; + else + return NULL; + + if (port->getPeer() != NULL) + panic("bridge side %s already connected to.", if_name); + return port; +} + + +void +Bridge::init() +{ + // Make sure that both sides are connected to. + if (portA.getPeer() == NULL || portB.getPeer() == NULL) + panic("Both ports of bus bridge are not connected to a bus.\n"); +} + + +/** Function called by the port when the bus is receiving a Timing + * transaction.*/ +bool +Bridge::BridgePort::recvTiming(Packet *pkt) +{ + DPRINTF(BusBridge, "recvTiming: src %d dest %d addr 0x%x\n", + pkt->getSrc(), pkt->getDest(), pkt->getAddr()); + + return otherPort->queueForSendTiming(pkt); +} + + +bool +Bridge::BridgePort::queueForSendTiming(Packet *pkt) +{ + if (queueFull()) + return false; + + if (pkt->isResponse()) { + // This is a response for a request we forwarded earlier. The + // corresponding PacketBuffer should be stored in the packet's + // senderState field. + PacketBuffer *buf = dynamic_cast<PacketBuffer*>(pkt->senderState); + assert(buf != NULL); + // set up new packet dest & senderState based on values saved + // from original request + buf->fixResponse(pkt); + DPRINTF(BusBridge, "restoring sender state: %#X, from packet buffer: %#X\n", + pkt->senderState, buf); + DPRINTF(BusBridge, " is response, new dest %d\n", pkt->getDest()); + delete buf; + } + + Tick readyTime = curTick + delay; + PacketBuffer *buf = new PacketBuffer(pkt, readyTime); + DPRINTF(BusBridge, "old sender state: %#X, new sender state: %#X\n", + buf->origSenderState, buf); + + // If we're about to put this packet at the head of the queue, we + // need to schedule an event to do the transmit. Otherwise there + // should already be an event scheduled for sending the head + // packet. + if (sendQueue.empty()) { + sendEvent.schedule(readyTime); + } + + sendQueue.push_back(buf); + + return true; +} + +void +Bridge::BridgePort::trySend() +{ + assert(!sendQueue.empty()); + + bool was_full = queueFull(); + + PacketBuffer *buf = sendQueue.front(); + + assert(buf->ready <= curTick); + + Packet *pkt = buf->pkt; + + DPRINTF(BusBridge, "trySend: origSrc %d dest %d addr 0x%x\n", + buf->origSrc, pkt->getDest(), pkt->getAddr()); + + if (sendTiming(pkt)) { + // send successful + sendQueue.pop_front(); + buf->pkt = NULL; // we no longer own packet, so it's not safe to look at it + + if (buf->expectResponse) { + // Must wait for response. We just need to count outstanding + // responses (in case we want to cap them); PacketBuffer + // pointer will be recovered on response. + ++outstandingResponses; + DPRINTF(BusBridge, " successful: awaiting response (%d)\n", + outstandingResponses); + } else { + // no response expected... deallocate packet buffer now. + DPRINTF(BusBridge, " successful: no response expected\n"); + delete buf; + } + + // If there are more packets to send, schedule event to try again. + if (!sendQueue.empty()) { + buf = sendQueue.front(); + sendEvent.schedule(std::max(buf->ready, curTick + 1)); + } + // Let things start sending again + if (was_full) { + DPRINTF(BusBridge, "Queue was full, sending retry\n"); + otherPort->sendRetry(); + } + + } else { + DPRINTF(BusBridge, " unsuccessful\n"); + } +} + + +void +Bridge::BridgePort::recvRetry() +{ + trySend(); +} + +/** Function called by the port when the bus is receiving a Atomic + * transaction.*/ +Tick +Bridge::BridgePort::recvAtomic(Packet *pkt) +{ + return otherPort->sendAtomic(pkt) + delay; +} + +/** Function called by the port when the bus is receiving a Functional + * transaction.*/ +void +Bridge::BridgePort::recvFunctional(Packet *pkt) +{ + std::list<PacketBuffer*>::iterator i; + bool pktContinue = true; + + for (i = sendQueue.begin(); i != sendQueue.end(); ++i) { + if (pkt->intersect((*i)->pkt)) { + pktContinue &= fixPacket(pkt, (*i)->pkt); + } + } + + if (pktContinue) { + otherPort->sendFunctional(pkt); + } +} + +/** Function called by the port when the bus is receiving a status change.*/ +void +Bridge::BridgePort::recvStatusChange(Port::Status status) +{ + otherPort->sendStatusChange(status); +} + +void +Bridge::BridgePort::getDeviceAddressRanges(AddrRangeList &resp, + AddrRangeList &snoop) +{ + otherPort->getPeerAddressRanges(resp, snoop); +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bridge) + + Param<int> queue_size_a; + Param<int> queue_size_b; + Param<Tick> delay; + Param<bool> write_ack; + +END_DECLARE_SIM_OBJECT_PARAMS(Bridge) + +BEGIN_INIT_SIM_OBJECT_PARAMS(Bridge) + + INIT_PARAM(queue_size_a, "The size of the queue for data coming into side a"), + INIT_PARAM(queue_size_b, "The size of the queue for data coming into side b"), + INIT_PARAM(delay, "The miminum delay to cross this bridge"), + INIT_PARAM(write_ack, "Acknowledge any writes that are received.") + +END_INIT_SIM_OBJECT_PARAMS(Bridge) + +CREATE_SIM_OBJECT(Bridge) +{ + return new Bridge(getInstanceName(), queue_size_a, queue_size_b, delay, + write_ack); +} + +REGISTER_SIM_OBJECT("Bridge", Bridge) diff --git a/src/mem/bridge.hh b/src/mem/bridge.hh new file mode 100644 index 000000000..37fb92662 --- /dev/null +++ b/src/mem/bridge.hh @@ -0,0 +1,187 @@ +/* + * 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 + * Steve Reinhardt + */ + +/** + * @file Decleration of a simple bus bridge object with no buffering + */ + +#ifndef __MEM_BRIDGE_HH__ +#define __MEM_BRIDGE_HH__ + +#include <string> +#include <list> +#include <inttypes.h> +#include <queue> + +#include "mem/mem_object.hh" +#include "mem/packet.hh" +#include "mem/port.hh" +#include "sim/eventq.hh" + +class Bridge : public MemObject +{ + protected: + /** Decleration of the buses port type, one will be instantiated for each + of the interfaces connecting to the bus. */ + class BridgePort : public Port + { + /** A pointer to the bridge to which this port belongs. */ + Bridge *bridge; + + /** + * Pointer to the port on the other side of the bridge + * (connected to the other bus). + */ + BridgePort *otherPort; + + /** Minimum delay though this bridge. */ + Tick delay; + + class PacketBuffer : public Packet::SenderState { + + public: + Tick ready; + Packet *pkt; + Packet::SenderState *origSenderState; + short origSrc; + bool expectResponse; + + PacketBuffer(Packet *_pkt, Tick t) + : ready(t), pkt(_pkt), + origSenderState(_pkt->senderState), origSrc(_pkt->getSrc()), + expectResponse(_pkt->needsResponse()) + { + if (!pkt->isResponse()) + pkt->senderState = this; + } + + void fixResponse(Packet *pkt) + { + assert(pkt->senderState == this); + pkt->setDest(origSrc); + pkt->senderState = origSenderState; + } + }; + + /** + * Outbound packet queue. Packets are held in this queue for a + * specified delay to model the processing delay of the + * bridge. + */ + std::list<PacketBuffer*> sendQueue; + + int outstandingResponses; + + /** Max queue size for outbound packets */ + int queueLimit; + + /** + * Is this side blocked from accepting outbound packets? + */ + bool queueFull() { return (sendQueue.size() == queueLimit); } + + bool queueForSendTiming(Packet *pkt); + + void finishSend(PacketBuffer *buf); + + /** + * Handle send event, scheduled when the packet at the head of + * the outbound queue is ready to transmit (for timing + * accesses only). + */ + void trySend(); + + class SendEvent : public Event + { + BridgePort *port; + + public: + SendEvent(BridgePort *p) + : Event(&mainEventQueue), port(p) {} + + virtual void process() { port->trySend(); } + + virtual const char *description() { return "bridge send event"; } + }; + + SendEvent sendEvent; + + public: + + /** Constructor for the BusPort.*/ + BridgePort(const std::string &_name, + Bridge *_bridge, BridgePort *_otherPort, + int _delay, int _queueLimit); + + protected: + + /** When receiving a timing request from the peer port, + pass it to the bridge. */ + virtual bool recvTiming(Packet *pkt); + + /** When receiving a retry request from the peer port, + pass it to the bridge. */ + virtual void recvRetry(); + + /** When receiving a Atomic requestfrom the peer port, + pass it to the bridge. */ + virtual Tick recvAtomic(Packet *pkt); + + /** When receiving a Functional request from the peer port, + pass it to the bridge. */ + virtual void recvFunctional(Packet *pkt); + + /** When receiving a status changefrom the peer port, + pass it to the bridge. */ + virtual void recvStatusChange(Status status); + + /** When receiving a address range request the peer port, + pass it to the bridge. */ + virtual void getDeviceAddressRanges(AddrRangeList &resp, + AddrRangeList &snoop); + }; + + BridgePort portA, portB; + + /** If this bridge should acknowledge writes. */ + bool ackWrites; + + public: + + /** A function used to return the port associated with this bus object. */ + virtual Port *getPort(const std::string &if_name); + + virtual void init(); + + Bridge(const std::string &n, int qsa, int qsb, Tick _delay, int write_ack); +}; + +#endif //__MEM_BUS_HH__ diff --git a/src/mem/bus.cc b/src/mem/bus.cc new file mode 100644 index 000000000..919acd23c --- /dev/null +++ b/src/mem/bus.cc @@ -0,0 +1,234 @@ +/* + * 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 + */ + +/** + * @file Definition of a bus object. + */ + + +#include "base/trace.hh" +#include "mem/bus.hh" +#include "sim/builder.hh" + +Port * +Bus::getPort(const std::string &if_name) +{ + // if_name ignored? forced to be empty? + int id = interfaces.size(); + BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id); + interfaces.push_back(bp); + return bp; +} + +/** Get the ranges of anyone that we are connected to. */ +void +Bus::init() +{ + std::vector<Port*>::iterator intIter; + for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++) + (*intIter)->sendStatusChange(Port::RangeChange); +} + + +/** Function called by the port when the bus is receiving a Timing + * transaction.*/ +bool +Bus::recvTiming(Packet *pkt) +{ + Port *port; + DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s\n", + pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); + + short dest = pkt->getDest(); + if (dest == Packet::Broadcast) { + port = findPort(pkt->getAddr(), pkt->getSrc()); + } else { + assert(dest >= 0 && dest < interfaces.size()); + assert(dest != pkt->getSrc()); // catch infinite loops + port = interfaces[dest]; + } + if (port->sendTiming(pkt)) { + // packet was successfully sent, just return true. + return true; + } + + // packet not successfully sent + retryList.push_back(interfaces[pkt->getSrc()]); + return false; +} + +void +Bus::recvRetry(int id) +{ + // Go through all the elements on the list calling sendRetry on each + // This is not very efficient at all but it works. Ultimately we should end + // up with something that is more intelligent. + int initialSize = retryList.size(); + int i; + Port *p; + + for (i = 0; i < initialSize; i++) { + assert(retryList.size() > 0); + p = retryList.front(); + retryList.pop_front(); + p->sendRetry(); + } +} + + +Port * +Bus::findPort(Addr addr, int id) +{ + /* An interval tree would be a better way to do this. --ali. */ + int dest_id = -1; + int i = 0; + bool found = false; + + while (i < portList.size() && !found) + { + if (portList[i].range == addr) { + dest_id = portList[i].portId; + found = true; + DPRINTF(Bus, " found addr 0x%llx on device %d\n", addr, dest_id); + } + i++; + } + if (dest_id == -1) + panic("Unable to find destination for addr: %llx", addr); + + // we shouldn't be sending this back to where it came from + assert(dest_id != id); + + return interfaces[dest_id]; +} + +/** Function called by the port when the bus is receiving a Atomic + * transaction.*/ +Tick +Bus::recvAtomic(Packet *pkt) +{ + DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n", + pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); + assert(pkt->getDest() == Packet::Broadcast); + return findPort(pkt->getAddr(), pkt->getSrc())->sendAtomic(pkt); +} + +/** Function called by the port when the bus is receiving a Functional + * transaction.*/ +void +Bus::recvFunctional(Packet *pkt) +{ + DPRINTF(Bus, "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n", + pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); + assert(pkt->getDest() == Packet::Broadcast); + findPort(pkt->getAddr(), pkt->getSrc())->sendFunctional(pkt); +} + +/** Function called by the port when the bus is receiving a status change.*/ +void +Bus::recvStatusChange(Port::Status status, int id) +{ + assert(status == Port::RangeChange && + "The other statuses need to be implemented."); + + DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id); + + assert(id < interfaces.size() && id >= 0); + int x; + Port *port = interfaces[id]; + AddrRangeList ranges; + AddrRangeList snoops; + AddrRangeIter iter; + std::vector<DevMap>::iterator portIter; + + // Clean out any previously existent ids + for (portIter = portList.begin(); portIter != portList.end(); ) { + if (portIter->portId == id) + portIter = portList.erase(portIter); + else + portIter++; + } + + port->getPeerAddressRanges(ranges, snoops); + + // not dealing with snooping yet either + assert(snoops.size() == 0); + for(iter = ranges.begin(); iter != ranges.end(); iter++) { + DevMap dm; + dm.portId = id; + dm.range = *iter; + + DPRINTF(BusAddrRanges, "Adding range %llx - %llx for id %d\n", + dm.range.start, dm.range.end, id); + portList.push_back(dm); + } + DPRINTF(MMU, "port list has %d entries\n", portList.size()); + + // tell all our peers that our address range has changed. + // Don't tell the device that caused this change, it already knows + for (x = 0; x < interfaces.size(); x++) + if (x != id) + interfaces[x]->sendStatusChange(Port::RangeChange); +} + +void +Bus::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id) +{ + std::vector<DevMap>::iterator portIter; + + resp.clear(); + snoop.clear(); + + DPRINTF(BusAddrRanges, "received address range request, returning:\n"); + for (portIter = portList.begin(); portIter != portList.end(); portIter++) { + if (portIter->portId != id) { + resp.push_back(portIter->range); + DPRINTF(BusAddrRanges, " -- %#llX : %#llX\n", + portIter->range.start, portIter->range.end); + } + } +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bus) + + Param<int> bus_id; + +END_DECLARE_SIM_OBJECT_PARAMS(Bus) + +BEGIN_INIT_SIM_OBJECT_PARAMS(Bus) + INIT_PARAM(bus_id, "a globally unique bus id") +END_INIT_SIM_OBJECT_PARAMS(Bus) + +CREATE_SIM_OBJECT(Bus) +{ + return new Bus(getInstanceName(), bus_id); +} + +REGISTER_SIM_OBJECT("Bus", Bus) diff --git a/src/mem/bus.hh b/src/mem/bus.hh new file mode 100644 index 000000000..50bfba6e4 --- /dev/null +++ b/src/mem/bus.hh @@ -0,0 +1,173 @@ +/* + * 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: Ron Dreslinski + */ + +/** + * @file Decleration of a bus object. + */ + +#ifndef __MEM_BUS_HH__ +#define __MEM_BUS_HH__ + +#include <string> +#include <list> +#include <inttypes.h> + +#include "base/range.hh" +#include "mem/mem_object.hh" +#include "mem/packet.hh" +#include "mem/port.hh" +#include "mem/request.hh" + +class Bus : public MemObject +{ + /** a globally unique id for this bus. */ + int busId; + + struct DevMap { + int portId; + Range<Addr> range; + }; + std::vector<DevMap> portList; + + + /** Function called by the port when the bus is recieving a Timing + transaction.*/ + bool recvTiming(Packet *pkt); + + /** Function called by the port when the bus is recieving a Atomic + transaction.*/ + Tick recvAtomic(Packet *pkt); + + /** Function called by the port when the bus is recieving a Functional + transaction.*/ + void recvFunctional(Packet *pkt); + + /** Timing function called by port when it is once again able to process + * requests. */ + void recvRetry(int id); + + /** Function called by the port when the bus is recieving a status change.*/ + void recvStatusChange(Port::Status status, int id); + + /** Find which port connected to this bus (if any) should be given a packet + * with this address. + * @param addr Address to find port for. + * @param id Id of the port this packet was received from (to prevent + * loops) + * @return pointer to port that the packet should be sent out of. + */ + Port *findPort(Addr addr, int id); + + /** Process address range request. + * @param resp addresses that we can respond to + * @param snoop addresses that we would like to snoop + * @param id ide of the busport that made the request. + */ + void addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id); + + + /** Decleration of the buses port type, one will be instantiated for each + of the interfaces connecting to the bus. */ + class BusPort : public Port + { + /** A pointer to the bus to which this port belongs. */ + Bus *bus; + + /** A id to keep track of the intercafe ID this port is connected to. */ + int id; + + public: + + /** Constructor for the BusPort.*/ + BusPort(const std::string &_name, Bus *_bus, int _id) + : Port(_name), bus(_bus), id(_id) + { } + + protected: + + /** When reciving a timing request from the peer port (at id), + pass it to the bus. */ + virtual bool recvTiming(Packet *pkt) + { pkt->setSrc(id); return bus->recvTiming(pkt); } + + /** When reciving a Atomic requestfrom the peer port (at id), + pass it to the bus. */ + virtual Tick recvAtomic(Packet *pkt) + { pkt->setSrc(id); return bus->recvAtomic(pkt); } + + /** When reciving a Functional requestfrom the peer port (at id), + pass it to the bus. */ + virtual void recvFunctional(Packet *pkt) + { pkt->setSrc(id); bus->recvFunctional(pkt); } + + /** When reciving a status changefrom the peer port (at id), + pass it to the bus. */ + virtual void recvStatusChange(Status status) + { bus->recvStatusChange(status, id); } + + /** When reciving a retry from the peer port (at id), + pass it to the bus. */ + virtual void recvRetry() + { bus->recvRetry(id); } + + // This should return all the 'owned' addresses that are + // downstream from this bus, yes? That is, the union of all + // the 'owned' address ranges of all the other interfaces on + // this bus... + virtual void getDeviceAddressRanges(AddrRangeList &resp, + AddrRangeList &snoop) + { bus->addressRanges(resp, snoop, id); } + + // Hack to make translating port work without changes + virtual int deviceBlockSize() { return 32; } + + }; + + /** An array of pointers to the peer port interfaces + connected to this bus.*/ + std::vector<Port*> interfaces; + + /** An array of pointers to ports that retry should be called on because the + * original send failed for whatever reason.*/ + std::list<Port*> retryList; + + public: + + /** A function used to return the port associated with this bus object. */ + virtual Port *getPort(const std::string &if_name); + + virtual void init(); + + Bus(const std::string &n, int bus_id) + : MemObject(n), busId(bus_id) {} + +}; + +#endif //__MEM_BUS_HH__ diff --git a/src/mem/cache/prefetch/tagged_prefetcher_impl.hh b/src/mem/cache/prefetch/tagged_prefetcher_impl.hh new file mode 100644 index 000000000..7bdabbe14 --- /dev/null +++ b/src/mem/cache/prefetch/tagged_prefetcher_impl.hh @@ -0,0 +1,75 @@ +/* + * Copyright (c) 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: Ron Dreslinski + */ + +/** + * @file + * Describes a tagged prefetcher based on template policies. + */ + +#include "mem/cache/prefetch/tagged_prefetcher.hh" + +template <class TagStore, class Buffering> +TaggedPrefetcher<TagStore, Buffering>:: +TaggedPrefetcher(int size, bool pageStop, bool serialSquash, + bool cacheCheckPush, bool onlyData, + Tick latency, int degree) + :Prefetcher<TagStore, Buffering>(size, pageStop, serialSquash, + cacheCheckPush, onlyData), + latency(latency), degree(degree) +{ +} + +template <class TagStore, class Buffering> +void +TaggedPrefetcher<TagStore, Buffering>:: +calculatePrefetch(MemReqPtr &req, std::list<Addr> &addresses, + std::list<Tick> &delays) +{ + Addr blkAddr = req->paddr & ~(Addr)(this->blkSize-1); + + for (int d=1; d <= degree; d++) { + Addr newAddr = blkAddr + d*(this->blkSize); + if (this->pageStop && + (blkAddr & ~(TheISA::VMPageSize - 1)) != + (newAddr & ~(TheISA::VMPageSize - 1))) + { + //Spanned the page, so now stop + this->pfSpanPage += degree - d + 1; + return; + } + else + { + addresses.push_back(newAddr); + delays.push_back(latency); + } + } +} + + diff --git a/src/mem/config/prefetch.hh b/src/mem/config/prefetch.hh new file mode 100644 index 000000000..d24db79da --- /dev/null +++ b/src/mem/config/prefetch.hh @@ -0,0 +1,41 @@ +/* + * 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: Ron Dreslinski + */ + +/** + * @file + * Central location to configure which prefetch types we want to build + * into the simulator. In the future, this should probably be + * autogenerated by some sort of configuration script. + */ +#define USE_TAGGED 1 //Be sure not to turn this off, it is also used for no + //prefetching case unless you always want to use a + //different prefetcher +//#define USE_STRIDED 1 +//#define USE_GHB 1 diff --git a/src/mem/mem_object.cc b/src/mem/mem_object.cc new file mode 100644 index 000000000..d4d3fd283 --- /dev/null +++ b/src/mem/mem_object.cc @@ -0,0 +1,39 @@ +/* + * 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: Steve Reinhardt + */ + +#include "mem/mem_object.hh" +#include "sim/param.hh" + +MemObject::MemObject(const std::string &name) + : SimObject(name) +{ +} + +DEFINE_SIM_OBJECT_CLASS_NAME("MemObject", MemObject) diff --git a/src/mem/mem_object.hh b/src/mem/mem_object.hh new file mode 100644 index 000000000..ac547619d --- /dev/null +++ b/src/mem/mem_object.hh @@ -0,0 +1,56 @@ +/* + * 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: Ron Dreslinski + */ + +/** + * @file + * Base Memory Object decleration. + */ + +#ifndef __MEM_MEM_OBJECT_HH__ +#define __MEM_MEM_OBJECT_HH__ + +#include "sim/sim_object.hh" +#include "mem/port.hh" + +/** + * The base MemoryObject class, allows for an accesor function to a + * simobj that returns the Port. + */ +class MemObject : public SimObject +{ + public: + MemObject(const std::string &name); + + public: + /** Additional function to return the Port of a memory object. */ + virtual Port *getPort(const std::string &if_name) = 0; +}; + +#endif //__MEM_MEM_OBJECT_HH__ diff --git a/src/mem/packet.cc b/src/mem/packet.cc new file mode 100644 index 000000000..56dd2bdfa --- /dev/null +++ b/src/mem/packet.cc @@ -0,0 +1,107 @@ +/* + * 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 + * Steve Reinhardt + */ + +/** + * @file + * Definition of the Packet Class, a packet is a transaction occuring + * between a single level of the memory heirarchy (ie L1->L2). + */ +#include "base/misc.hh" +#include "mem/packet.hh" + +static const std::string ReadReqString("ReadReq"); +static const std::string WriteReqString("WriteReq"); +static const std::string WriteReqNoAckString("WriteReqNoAck"); +static const std::string ReadRespString("ReadResp"); +static const std::string WriteRespString("WriteResp"); +static const std::string OtherCmdString("<other>"); + +const std::string & +Packet::cmdString() const +{ + switch (cmd) { + case ReadReq: return ReadReqString; + case WriteReq: return WriteReqString; + case WriteReqNoAck: return WriteReqNoAckString; + case ReadResp: return ReadRespString; + case WriteResp: return WriteRespString; + default: return OtherCmdString; + } +} + +/** delete the data pointed to in the data pointer. Ok to call to matter how + * data was allocted. */ +void +Packet::deleteData() +{ + assert(staticData || dynamicData); + if (staticData) + return; + + if (arrayData) + delete [] data; + else + delete data; +} + +/** If there isn't data in the packet, allocate some. */ +void +Packet::allocate() +{ + if (data) + return; + assert(!staticData); + dynamicData = true; + arrayData = true; + data = new uint8_t[getSize()]; +} + +/** Do the packet modify the same addresses. */ +bool +Packet::intersect(Packet *p) +{ + Addr s1 = getAddr(); + Addr e1 = getAddr() + getSize(); + Addr s2 = p->getAddr(); + Addr e2 = p->getAddr() + p->getSize(); + + if (s1 >= s2 && s1 < e2) + return true; + if (e1 >= s2 && e1 < e2) + return true; + return false; +} + +bool +fixPacket(Packet *func, Packet *timing) +{ + panic("Need to implement!"); +} diff --git a/src/mem/packet.hh b/src/mem/packet.hh new file mode 100644 index 000000000..403039d96 --- /dev/null +++ b/src/mem/packet.hh @@ -0,0 +1,300 @@ +/* + * 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: Ron Dreslinski + * Steve Reinhardt + * Ali Saidi + */ + +/** + * @file + * Declaration of the Packet class. + */ + +#ifndef __MEM_PACKET_HH__ +#define __MEM_PACKET_HH__ + +#include "mem/request.hh" +#include "arch/isa_traits.hh" +#include "sim/root.hh" + +struct Packet; +typedef Packet* PacketPtr; +typedef uint8_t* PacketDataPtr; + +/** + * A Packet is used to encapsulate a transfer between two objects in + * the memory system (e.g., the L1 and L2 cache). (In contrast, a + * single Request travels all the way from the requester to the + * ultimate destination and back, possibly being conveyed by several + * different Packets along the way.) + */ +class Packet +{ + private: + /** A pointer to the data being transfered. It can be differnt + * sizes at each level of the heirarchy so it belongs in the + * packet, not request. This may or may not be populated when a + * responder recieves the packet. If not populated it memory + * should be allocated. + */ + PacketDataPtr data; + + /** Is the data pointer set to a value that shouldn't be freed + * when the packet is destroyed? */ + bool staticData; + /** The data pointer points to a value that should be freed when + * the packet is destroyed. */ + bool dynamicData; + /** the data pointer points to an array (thus delete [] ) needs to + * be called on it rather than simply delete.*/ + bool arrayData; + + + /** The address of the request. This address could be virtual or + * physical, depending on the system configuration. */ + Addr addr; + + /** The size of the request or transfer. */ + int size; + + /** Device address (e.g., bus ID) of the source of the + * transaction. The source is not responsible for setting this + * field; it is set implicitly by the interconnect when the + * packet * is first sent. */ + short src; + + /** Device address (e.g., bus ID) of the destination of the + * transaction. The special value Broadcast indicates that the + * packet should be routed based on its address. This field is + * initialized in the constructor and is thus always valid + * (unlike * addr, size, and src). */ + short dest; + + /** Are the 'addr' and 'size' fields valid? */ + bool addrSizeValid; + /** Is the 'src' field valid? */ + bool srcValid; + + public: + + /** The special destination address indicating that the packet + * should be routed based on its address. */ + static const short Broadcast = -1; + + /** A pointer to the original request. */ + RequestPtr req; + + /** A virtual base opaque structure used to hold coherence-related + * state. A specific subclass would be derived from this to + * carry state specific to a particular coherence protocol. */ + class CoherenceState { + public: + virtual ~CoherenceState() {} + }; + + /** This packet's coherence state. Caches should use + * dynamic_cast<> to cast to the state appropriate for the + * system's coherence protocol. */ + CoherenceState *coherence; + + /** A virtual base opaque structure used to hold state associated + * with the packet but specific to the sending device (e.g., an + * MSHR). A pointer to this state is returned in the packet's + * response so that the sender can quickly look up the state + * needed to process it. A specific subclass would be derived + * from this to carry state specific to a particular sending + * device. */ + class SenderState { + public: + virtual ~SenderState() {} + }; + + /** This packet's sender state. Devices should use dynamic_cast<> + * to cast to the state appropriate to the sender. */ + SenderState *senderState; + + private: + /** List of command attributes. */ + enum CommandAttribute + { + IsRead = 1 << 0, + IsWrite = 1 << 1, + IsPrefetch = 1 << 2, + IsInvalidate = 1 << 3, + IsRequest = 1 << 4, + IsResponse = 1 << 5, + NeedsResponse = 1 << 6, + }; + + public: + /** List of all commands associated with a packet. */ + enum Command + { + ReadReq = IsRead | IsRequest | NeedsResponse, + WriteReq = IsWrite | IsRequest | NeedsResponse, + WriteReqNoAck = IsWrite | IsRequest, + ReadResp = IsRead | IsResponse, + WriteResp = IsWrite | IsResponse + }; + + /** Return the string name of the cmd field (for debugging and + * tracing). */ + const std::string &cmdString() const; + + /** The command field of the packet. */ + Command cmd; + + bool isRead() { return (cmd & IsRead) != 0; } + bool isRequest() { return (cmd & IsRequest) != 0; } + bool isResponse() { return (cmd & IsResponse) != 0; } + bool needsResponse() { return (cmd & NeedsResponse) != 0; } + + /** Possible results of a packet's request. */ + enum Result + { + Success, + BadAddress, + Nacked, + Unknown + }; + + /** The result of this packet's request. */ + Result result; + + /** Accessor function that returns the source index of the packet. */ + short getSrc() const { assert(srcValid); return src; } + void setSrc(short _src) { src = _src; srcValid = true; } + + /** Accessor function that returns the destination index of + the packet. */ + short getDest() const { return dest; } + void setDest(short _dest) { dest = _dest; } + + Addr getAddr() const { assert(addrSizeValid); return addr; } + int getSize() const { assert(addrSizeValid); return size; } + + /** Constructor. Note that a Request object must be constructed + * first, but the Requests's physical address and size fields + * need not be valid. The command and destination addresses + * must be supplied. */ + Packet(Request *_req, Command _cmd, short _dest) + : data(NULL), staticData(false), dynamicData(false), arrayData(false), + addr(_req->paddr), size(_req->size), dest(_dest), + addrSizeValid(_req->validPaddr), + srcValid(false), + req(_req), coherence(NULL), senderState(NULL), cmd(_cmd), + result(Unknown) + { + } + + /** Destructor. */ + ~Packet() + { deleteData(); } + + /** Reinitialize packet address and size from the associated + * Request object, and reset other fields that may have been + * modified by a previous transaction. Typically called when a + * statically allocated Request/Packet pair is reused for + * multiple transactions. */ + void reinitFromRequest() { + assert(req->validPaddr); + addr = req->paddr; + size = req->size; + addrSizeValid = true; + result = Unknown; + if (dynamicData) { + deleteData(); + dynamicData = false; + arrayData = false; + } + } + + /** Take a request packet and modify it in place to be suitable + * for returning as a response to that request. Used for timing + * accesses only. For atomic and functional accesses, the + * request packet is always implicitly passed back *without* + * modifying the command or destination fields, so this function + * should not be called. */ + void makeTimingResponse() { + assert(needsResponse()); + int icmd = (int)cmd; + icmd &= ~(IsRequest | NeedsResponse); + icmd |= IsResponse; + cmd = (Command)icmd; + dest = src; + srcValid = false; + } + + /** Take a request packet that has been returned as NACKED and modify it so + * that it can be sent out again. Only packets that need a response can be + * NACKED, so verify that that is true. */ + void reinitNacked() { + assert(needsResponse() && result == Nacked); + dest = Broadcast; + result = Unknown; + } + + + /** Set the data pointer to the following value that should not be freed. */ + template <typename T> + void dataStatic(T *p); + + /** Set the data pointer to a value that should have delete [] called on it. + */ + template <typename T> + void dataDynamicArray(T *p); + + /** set the data pointer to a value that should have delete called on it. */ + template <typename T> + void dataDynamic(T *p); + + /** return the value of what is pointed to in the packet. */ + template <typename T> + T get(); + + /** get a pointer to the data ptr. */ + template <typename T> + T* getPtr(); + + /** set the value in the data pointer to v. */ + template <typename T> + void set(T v); + + /** delete the data pointed to in the data pointer. Ok to call to matter how + * data was allocted. */ + void deleteData(); + + /** If there isn't data in the packet, allocate some. */ + void allocate(); + + /** Do the packet modify the same addresses. */ + bool intersect(Packet *p); +}; + +bool fixPacket(Packet *func, Packet *timing); +#endif //__MEM_PACKET_HH diff --git a/src/mem/page_table.cc b/src/mem/page_table.cc new file mode 100644 index 000000000..b5cecc7da --- /dev/null +++ b/src/mem/page_table.cc @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2003 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 + * Ron Dreslinski + */ + +/** + * @file + * Definitions of page table. + */ +#include <string> +#include <map> +#include <fstream> + +#include "arch/faults.hh" +#include "base/bitfield.hh" +#include "base/intmath.hh" +#include "base/trace.hh" +#include "mem/page_table.hh" +#include "sim/builder.hh" +#include "sim/sim_object.hh" +#include "sim/system.hh" + +using namespace std; +using namespace TheISA; + +PageTable::PageTable(System *_system, Addr _pageSize) + : pageSize(_pageSize), offsetMask(mask(floorLog2(_pageSize))), + system(_system) +{ + assert(isPowerOf2(pageSize)); +} + +PageTable::~PageTable() +{ +} + +Fault +PageTable::page_check(Addr addr, int size) const +{ + if (size < sizeof(uint64_t)) { + if (!isPowerOf2(size)) { + panic("Invalid request size!\n"); + return genMachineCheckFault(); + } + + if ((size - 1) & addr) + return genAlignmentFault(); + } + else { + if ((addr & (VMPageSize - 1)) + size > VMPageSize) { + panic("Invalid request size!\n"); + return genMachineCheckFault(); + } + + if ((sizeof(uint64_t) - 1) & addr) + return genAlignmentFault(); + } + + return NoFault; +} + + + + +void +PageTable::allocate(Addr vaddr, int size) +{ + // starting address must be page aligned + assert(pageOffset(vaddr) == 0); + + for (; size > 0; size -= pageSize, vaddr += pageSize) { + std::map<Addr,Addr>::iterator iter = pTable.find(vaddr); + + if (iter != pTable.end()) { + // already mapped + fatal("PageTable::allocate: address 0x%x already mapped", vaddr); + } + + pTable[vaddr] = system->new_page(); + } +} + + + +bool +PageTable::translate(Addr vaddr, Addr &paddr) +{ + Addr page_addr = pageAlign(vaddr); + std::map<Addr,Addr>::iterator iter = pTable.find(page_addr); + + if (iter == pTable.end()) { + return false; + } + + paddr = iter->second + pageOffset(vaddr); + return true; +} + + +Fault +PageTable::translate(RequestPtr &req) +{ + Addr paddr; + assert(pageAlign(req->getVaddr() + req->getSize() - 1) + == pageAlign(req->getVaddr())); + if (!translate(req->getVaddr(), paddr)) { + return genMachineCheckFault(); + } + req->setPaddr(paddr); + return page_check(req->getPaddr(), req->getSize()); +} diff --git a/src/mem/page_table.hh b/src/mem/page_table.hh new file mode 100644 index 000000000..f7212d423 --- /dev/null +++ b/src/mem/page_table.hh @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2003 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 + */ + +/** + * @file + * Declaration of a non-full system Page Table. + */ + +#ifndef __PAGE_TABLE__ +#define __PAGE_TABLE__ + +#include <string> +#include <map> + +#include "arch/isa_traits.hh" +#include "base/trace.hh" +#include "mem/request.hh" +#include "mem/packet.hh" +#include "sim/sim_object.hh" + +class System; + +/** + * Page Table Decleration. + */ +class PageTable +{ + protected: + std::map<Addr,Addr> pTable; + + const Addr pageSize; + const Addr offsetMask; + + System *system; + + public: + + PageTable(System *_system, Addr _pageSize = TheISA::VMPageSize); + + ~PageTable(); + + Addr pageAlign(Addr a) { return (a & ~offsetMask); } + Addr pageOffset(Addr a) { return (a & offsetMask); } + + Fault page_check(Addr addr, int size) const; + + void allocate(Addr vaddr, int size); + + /** + * Translate function + * @param vaddr The virtual address. + * @return Physical address from translation. + */ + bool translate(Addr vaddr, Addr &paddr); + + /** + * Perform a translation on the memory request, fills in paddr + * field of mem_req. + * @param req The memory request. + */ + Fault translate(RequestPtr &req); + +}; + +#endif diff --git a/src/mem/physical.cc b/src/mem/physical.cc new file mode 100644 index 000000000..fb31fb4a3 --- /dev/null +++ b/src/mem/physical.cc @@ -0,0 +1,378 @@ +/* + * 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: Ron Dreslinski + */ + +#include <sys/types.h> +#include <sys/mman.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <zlib.h> + +#include <iostream> +#include <string> + + +#include "base/misc.hh" +#include "config/full_system.hh" +#include "mem/packet_impl.hh" +#include "mem/physical.hh" +#include "sim/host.hh" +#include "sim/builder.hh" +#include "sim/eventq.hh" +#include "arch/isa_traits.hh" + + +using namespace std; +using namespace TheISA; + +PhysicalMemory::MemResponseEvent::MemResponseEvent(Packet *pkt, MemoryPort* _m) + : Event(&mainEventQueue, CPU_Tick_Pri), pkt(pkt), memoryPort(_m) +{ + + this->setFlags(AutoDelete); +} + +void +PhysicalMemory::MemResponseEvent::process() +{ + memoryPort->sendTiming(pkt); +} + +const char * +PhysicalMemory::MemResponseEvent::description() +{ + return "Physical Memory Timing Access respnse event"; +} + +PhysicalMemory::PhysicalMemory(const string &n, Tick latency) + : MemObject(n),base_addr(0), pmem_addr(NULL), port(NULL), lat(latency) +{ + // Hardcoded to 128 MB for now. + pmem_size = 1 << 27; + + if (pmem_size % TheISA::PageBytes != 0) + panic("Memory Size not divisible by page size\n"); + + int map_flags = MAP_ANON | MAP_PRIVATE; + pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE, + map_flags, -1, 0); + + if (pmem_addr == (void *)MAP_FAILED) { + perror("mmap"); + fatal("Could not mmap!\n"); + } + + page_ptr = 0; +} + +void +PhysicalMemory::init() +{ + if (!port) + panic("PhysicalMemory not connected to anything!"); + port->sendStatusChange(Port::RangeChange); +} + +PhysicalMemory::~PhysicalMemory() +{ + if (pmem_addr) + munmap(pmem_addr, pmem_size); + //Remove memPorts? +} + +Addr +PhysicalMemory::new_page() +{ + Addr return_addr = page_ptr << LogVMPageSize; + return_addr += base_addr; + + ++page_ptr; + return return_addr; +} + +int +PhysicalMemory::deviceBlockSize() +{ + //Can accept anysize request + return 0; +} + +bool +PhysicalMemory::doTimingAccess (Packet *pkt, MemoryPort* memoryPort) +{ + doFunctionalAccess(pkt); + + // turn packet around to go back to requester + pkt->makeTimingResponse(); + MemResponseEvent* response = new MemResponseEvent(pkt, memoryPort); + response->schedule(curTick + lat); + + return true; +} + +Tick +PhysicalMemory::doAtomicAccess(Packet *pkt) +{ + doFunctionalAccess(pkt); + return lat; +} + +void +PhysicalMemory::doFunctionalAccess(Packet *pkt) +{ + assert(pkt->getAddr() + pkt->getSize() < pmem_size); + + switch (pkt->cmd) { + case Packet::ReadReq: + memcpy(pkt->getPtr<uint8_t>(), + pmem_addr + pkt->getAddr() - base_addr, + pkt->getSize()); + break; + case Packet::WriteReq: + memcpy(pmem_addr + pkt->getAddr() - base_addr, + pkt->getPtr<uint8_t>(), + pkt->getSize()); + // temporary hack: will need to add real LL/SC implementation + // for cacheless systems later. + if (pkt->req->getFlags() & LOCKED) { + pkt->req->setScResult(1); + } + break; + default: + panic("unimplemented"); + } + + pkt->result = Packet::Success; +} + +Port * +PhysicalMemory::getPort(const std::string &if_name) +{ + if (if_name == "") { + if (port != NULL) + panic("PhysicalMemory::getPort: additional port requested to memory!"); + port = new MemoryPort(name() + "-port", this); + return port; + } else if (if_name == "functional") { + /* special port for functional writes at startup. */ + return new MemoryPort(name() + "-funcport", this); + } else { + panic("PhysicalMemory::getPort: unknown port %s requested", if_name); + } +} + +void +PhysicalMemory::recvStatusChange(Port::Status status) +{ +} + +PhysicalMemory::MemoryPort::MemoryPort(const std::string &_name, + PhysicalMemory *_memory) + : Port(_name), memory(_memory) +{ } + +void +PhysicalMemory::MemoryPort::recvStatusChange(Port::Status status) +{ + memory->recvStatusChange(status); +} + +void +PhysicalMemory::MemoryPort::getDeviceAddressRanges(AddrRangeList &resp, + AddrRangeList &snoop) +{ + memory->getAddressRanges(resp, snoop); +} + +void +PhysicalMemory::getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop) +{ + snoop.clear(); + resp.clear(); + resp.push_back(RangeSize(base_addr, pmem_size)); +} + +int +PhysicalMemory::MemoryPort::deviceBlockSize() +{ + return memory->deviceBlockSize(); +} + +bool +PhysicalMemory::MemoryPort::recvTiming(Packet *pkt) +{ + return memory->doTimingAccess(pkt, this); +} + +Tick +PhysicalMemory::MemoryPort::recvAtomic(Packet *pkt) +{ + return memory->doAtomicAccess(pkt); +} + +void +PhysicalMemory::MemoryPort::recvFunctional(Packet *pkt) +{ + memory->doFunctionalAccess(pkt); +} + + + +void +PhysicalMemory::serialize(ostream &os) +{ + gzFile compressedMem; + string filename = name() + ".physmem"; + + SERIALIZE_SCALAR(pmem_size); + SERIALIZE_SCALAR(filename); + + // write memory file + string thefile = Checkpoint::dir() + "/" + filename.c_str(); + int fd = creat(thefile.c_str(), 0664); + if (fd < 0) { + perror("creat"); + fatal("Can't open physical memory checkpoint file '%s'\n", filename); + } + + compressedMem = gzdopen(fd, "wb"); + if (compressedMem == NULL) + fatal("Insufficient memory to allocate compression state for %s\n", + filename); + + if (gzwrite(compressedMem, pmem_addr, pmem_size) != pmem_size) { + fatal("Write failed on physical memory checkpoint file '%s'\n", + filename); + } + + if (gzclose(compressedMem)) + fatal("Close failed on physical memory checkpoint file '%s'\n", + filename); +} + +void +PhysicalMemory::unserialize(Checkpoint *cp, const string §ion) +{ + gzFile compressedMem; + long *tempPage; + long *pmem_current; + uint64_t curSize; + uint32_t bytesRead; + const int chunkSize = 16384; + + + // unmap file that was mmaped in the constructor + munmap(pmem_addr, pmem_size); + + string filename; + + UNSERIALIZE_SCALAR(pmem_size); + UNSERIALIZE_SCALAR(filename); + + filename = cp->cptDir + "/" + filename; + + // mmap memoryfile + int fd = open(filename.c_str(), O_RDONLY); + if (fd < 0) { + perror("open"); + fatal("Can't open physical memory checkpoint file '%s'", filename); + } + + compressedMem = gzdopen(fd, "rb"); + if (compressedMem == NULL) + fatal("Insufficient memory to allocate compression state for %s\n", + filename); + + + pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE, -1, 0); + + if (pmem_addr == (void *)MAP_FAILED) { + perror("mmap"); + fatal("Could not mmap physical memory!\n"); + } + + curSize = 0; + tempPage = (long*)malloc(chunkSize); + if (tempPage == NULL) + fatal("Unable to malloc memory to read file %s\n", filename); + + /* Only copy bytes that are non-zero, so we don't give the VM system hell */ + while (curSize < pmem_size) { + bytesRead = gzread(compressedMem, tempPage, chunkSize); + if (bytesRead != chunkSize && bytesRead != pmem_size - curSize) + fatal("Read failed on physical memory checkpoint file '%s'" + " got %d bytes, expected %d or %d bytes\n", + filename, bytesRead, chunkSize, pmem_size-curSize); + + assert(bytesRead % sizeof(long) == 0); + + for (int x = 0; x < bytesRead/sizeof(long); x++) + { + if (*(tempPage+x) != 0) { + pmem_current = (long*)(pmem_addr + curSize + x * sizeof(long)); + *pmem_current = *(tempPage+x); + } + } + curSize += bytesRead; + } + + free(tempPage); + + if (gzclose(compressedMem)) + fatal("Close failed on physical memory checkpoint file '%s'\n", + filename); + +} + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory) + + Param<string> file; + Param<Range<Addr> > range; + Param<Tick> latency; + +END_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory) + +BEGIN_INIT_SIM_OBJECT_PARAMS(PhysicalMemory) + + INIT_PARAM_DFLT(file, "memory mapped file", ""), + INIT_PARAM(range, "Device Address Range"), + INIT_PARAM(latency, "Memory access latency") + +END_INIT_SIM_OBJECT_PARAMS(PhysicalMemory) + +CREATE_SIM_OBJECT(PhysicalMemory) +{ + + return new PhysicalMemory(getInstanceName(), latency); +} + +REGISTER_SIM_OBJECT("PhysicalMemory", PhysicalMemory) diff --git a/src/mem/physical.hh b/src/mem/physical.hh new file mode 100644 index 000000000..88ea543da --- /dev/null +++ b/src/mem/physical.hh @@ -0,0 +1,129 @@ +/* + * 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: Ron Dreslinski + */ + +/* @file + */ + +#ifndef __PHYSICAL_MEMORY_HH__ +#define __PHYSICAL_MEMORY_HH__ + +#include "base/range.hh" +#include "mem/mem_object.hh" +#include "mem/packet.hh" +#include "mem/port.hh" +#include "sim/eventq.hh" +#include <map> +#include <string> + +// +// Functional model for a contiguous block of physical memory. (i.e. RAM) +// +class PhysicalMemory : public MemObject +{ + class MemoryPort : public Port + { + PhysicalMemory *memory; + + public: + + MemoryPort(const std::string &_name, PhysicalMemory *_memory); + + protected: + + virtual bool recvTiming(Packet *pkt); + + virtual Tick recvAtomic(Packet *pkt); + + virtual void recvFunctional(Packet *pkt); + + virtual void recvStatusChange(Status status); + + virtual void getDeviceAddressRanges(AddrRangeList &resp, + AddrRangeList &snoop); + + virtual int deviceBlockSize(); + }; + + int numPorts; + + + struct MemResponseEvent : public Event + { + Packet *pkt; + MemoryPort *memoryPort; + + MemResponseEvent(Packet *pkt, MemoryPort *memoryPort); + void process(); + const char *description(); + }; + + private: + // prevent copying of a MainMemory object + PhysicalMemory(const PhysicalMemory &specmem); + const PhysicalMemory &operator=(const PhysicalMemory &specmem); + + protected: + Addr base_addr; + Addr pmem_size; + uint8_t *pmem_addr; + MemoryPort *port; + int page_ptr; + Tick lat; + + public: + Addr new_page(); + uint64_t size() { return pmem_size; } + + public: + PhysicalMemory(const std::string &n, Tick latency); + virtual ~PhysicalMemory(); + + public: + int deviceBlockSize(); + void getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop); + virtual Port *getPort(const std::string &if_name); + void virtual init(); + + // fast back-door memory access for vtophys(), remote gdb, etc. + // uint64_t phys_read_qword(Addr addr) const; + private: + bool doTimingAccess(Packet *pkt, MemoryPort *memoryPort); + Tick doAtomicAccess(Packet *pkt); + void doFunctionalAccess(Packet *pkt); + + void recvStatusChange(Port::Status status); + + public: + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + +}; + +#endif //__PHYSICAL_MEMORY_HH__ diff --git a/src/mem/port.cc b/src/mem/port.cc new file mode 100644 index 000000000..bec9d2274 --- /dev/null +++ b/src/mem/port.cc @@ -0,0 +1,85 @@ +/* + * 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: Steve Reinhardt + */ + +/** + * @file Port object definitions. + */ + +#include "base/chunk_generator.hh" +#include "base/trace.hh" +#include "mem/packet_impl.hh" +#include "mem/port.hh" + +void +Port::setPeer(Port *port) +{ + DPRINTF(Config, "setting peer to %s\n", port->name()); + peer = port; +} + +void +Port::blobHelper(Addr addr, uint8_t *p, int size, Packet::Command cmd) +{ + Request req; + Packet pkt(&req, cmd, Packet::Broadcast); + + for (ChunkGenerator gen(addr, size, peerBlockSize()); + !gen.done(); gen.next()) { + req.setPhys(gen.addr(), gen.size(), 0); + pkt.reinitFromRequest(); + pkt.dataStatic(p); + sendFunctional(&pkt); + p += gen.size(); + } +} + +void +Port::writeBlob(Addr addr, uint8_t *p, int size) +{ + blobHelper(addr, p, size, Packet::WriteReq); +} + +void +Port::readBlob(Addr addr, uint8_t *p, int size) +{ + blobHelper(addr, p, size, Packet::ReadReq); +} + +void +Port::memsetBlob(Addr addr, uint8_t val, int size) +{ + // quick and dirty... + uint8_t *buf = new uint8_t[size]; + + memset(buf, val, size); + blobHelper(addr, buf, size, Packet::WriteReq); + + delete [] buf; +} diff --git a/src/mem/port.hh b/src/mem/port.hh new file mode 100644 index 000000000..2edad095e --- /dev/null +++ b/src/mem/port.hh @@ -0,0 +1,275 @@ +/* + * 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: Ron Dreslinski + */ + +/** + * @file + * Port Object Decleration. Ports are used to interface memory objects to + * each other. They will always come in pairs, and we refer to the other + * port object as the peer. These are used to make the design more + * modular so that a specific interface between every type of objcet doesn't + * have to be created. + */ + +#ifndef __MEM_PORT_HH__ +#define __MEM_PORT_HH__ + +#include <list> +#include <inttypes.h> + +#include "base/misc.hh" +#include "base/range.hh" +#include "mem/packet.hh" +#include "mem/request.hh" + +/** This typedef is used to clean up the parameter list of + * getDeviceAddressRanges() and getPeerAddressRanges(). It's declared + * outside the Port object since it's also used by some mem objects. + * Eventually we should move this typedef to wherever Addr is + * defined. + */ + +typedef std::list<Range<Addr> > AddrRangeList; +typedef std::list<Range<Addr> >::iterator AddrRangeIter; + +/** + * Ports are used to interface memory objects to + * each other. They will always come in pairs, and we refer to the other + * port object as the peer. These are used to make the design more + * modular so that a specific interface between every type of objcet doesn't + * have to be created. + * + * Recv accesor functions are being called from the peer interface. + * Send accessor functions are being called from the device the port is + * associated with, and it will call the peer recv. accessor function. + */ +class Port +{ + private: + + /** Descriptive name (for DPRINTF output) */ + const std::string portName; + + /** A pointer to the peer port. Ports always come in pairs, that way they + can use a standardized interface to communicate between different + memory objects. */ + Port *peer; + + public: + + /** + * Constructor. + * + * @param _name Port name for DPRINTF output. Should include name + * of memory system object to which the port belongs. + */ + Port(const std::string &_name) + : portName(_name), peer(NULL) + { } + + /** Return port name (for DPRINTF). */ + const std::string &name() const { return portName; } + + virtual ~Port() {}; + + // mey be better to use subclasses & RTTI? + /** Holds the ports status. Currently just that a range recomputation needs + * to be done. */ + enum Status { + RangeChange + }; + + /** Function to set the pointer for the peer port. + @todo should be called by the configuration stuff (python). + */ + void setPeer(Port *port); + + /** Function to set the pointer for the peer port. + @todo should be called by the configuration stuff (python). + */ + Port *getPeer() { return peer; } + + protected: + + /** These functions are protected because they should only be + * called by a peer port, never directly by any outside object. */ + + /** Called to recive a timing call from the peer port. */ + virtual bool recvTiming(Packet *pkt) = 0; + + /** Called to recive a atomic call from the peer port. */ + virtual Tick recvAtomic(Packet *pkt) = 0; + + /** Called to recive a functional call from the peer port. */ + virtual void recvFunctional(Packet *pkt) = 0; + + /** Called to recieve a status change from the peer port. */ + virtual void recvStatusChange(Status status) = 0; + + /** Called by a peer port if the send was unsuccesful, and had to + wait. This shouldn't be valid for response paths (IO Devices). + so it is set to panic if it isn't already defined. + */ + virtual void recvRetry() { panic("??"); } + + /** Called by a peer port in order to determine the block size of the + device connected to this port. It sometimes doesn't make sense for + this function to be called, a DMA interface doesn't really have a + block size, so it is defaulted to a panic. + */ + virtual int deviceBlockSize() { panic("??"); } + + /** The peer port is requesting us to reply with a list of the ranges we + are responsible for. + @param resp is a list of ranges responded to + @param snoop is a list of ranges snooped + */ + virtual void getDeviceAddressRanges(AddrRangeList &resp, + AddrRangeList &snoop) + { panic("??"); } + + public: + + /** Function called by associated memory device (cache, memory, iodevice) + in order to send a timing request to the port. Simply calls the peer + port receive function. + @return This function returns if the send was succesful in it's + recieve. If it was a failure, then the port will wait for a recvRetry + at which point it can possibly issue a successful sendTiming. This is used in + case a cache has a higher priority request come in while waiting for + the bus to arbitrate. + */ + bool sendTiming(Packet *pkt) { return peer->recvTiming(pkt); } + + /** Function called by the associated device to send an atomic + * access, an access in which the data is moved and the state is + * updated in one cycle, without interleaving with other memory + * accesses. Returns estimated latency of access. + */ + Tick sendAtomic(Packet *pkt) + { return peer->recvAtomic(pkt); } + + /** Function called by the associated device to send a functional access, + an access in which the data is instantly updated everywhere in the + memory system, without affecting the current state of any block or + moving the block. + */ + void sendFunctional(Packet *pkt) + { return peer->recvFunctional(pkt); } + + /** Called by the associated device to send a status change to the device + connected to the peer interface. + */ + void sendStatusChange(Status status) {peer->recvStatusChange(status); } + + /** When a timing access doesn't return a success, some time later the + Retry will be sent. + */ + void sendRetry() { return peer->recvRetry(); } + + /** Called by the associated device if it wishes to find out the blocksize + of the device on attached to the peer port. + */ + int peerBlockSize() { return peer->deviceBlockSize(); } + + /** Called by the associated device if it wishes to find out the address + ranges connected to the peer ports devices. + */ + void getPeerAddressRanges(AddrRangeList &resp, AddrRangeList &snoop) + { peer->getDeviceAddressRanges(resp, snoop); } + + /** This function is a wrapper around sendFunctional() + that breaks a larger, arbitrarily aligned access into + appropriate chunks. The default implementation can use + getBlockSize() to determine the block size and go from there. + */ + virtual void readBlob(Addr addr, uint8_t *p, int size); + + /** This function is a wrapper around sendFunctional() + that breaks a larger, arbitrarily aligned access into + appropriate chunks. The default implementation can use + getBlockSize() to determine the block size and go from there. + */ + virtual void writeBlob(Addr addr, uint8_t *p, int size); + + /** Fill size bytes starting at addr with byte value val. This + should not need to be virtual, since it can be implemented in + terms of writeBlob(). However, it shouldn't be + performance-critical either, so it could be if we wanted to. + */ + virtual void memsetBlob(Addr addr, uint8_t val, int size); + + private: + + /** Internal helper function for read/writeBlob(). + */ + void blobHelper(Addr addr, uint8_t *p, int size, Packet::Command cmd); +}; + +/** A simple functional port that is only meant for one way communication to + * physical memory. It is only meant to be used to load data into memory before + * the simulation begins. + */ + +class FunctionalPort : public Port +{ + public: + FunctionalPort(const std::string &_name) + : Port(_name) + {} + + virtual bool recvTiming(Packet *pkt) { panic("FuncPort is UniDir"); } + virtual Tick recvAtomic(Packet *pkt) { panic("FuncPort is UniDir"); } + virtual void recvFunctional(Packet *pkt) { panic("FuncPort is UniDir"); } + virtual void recvStatusChange(Status status) {} + + /** a write function that also does an endian conversion. */ + template <typename T> + inline void writeHtoG(Addr addr, T d); + + /** a read function that also does an endian conversion. */ + template <typename T> + inline T readGtoH(Addr addr); + + template <typename T> + inline void write(Addr addr, T d) + { + writeBlob(addr, (uint8_t*)&d, sizeof(T)); + } + + template <typename T> + inline T read(Addr addr) + { + T d; + readBlob(addr, (uint8_t*)&d, sizeof(T)); + return d; + } +}; + +#endif //__MEM_PORT_HH__ diff --git a/src/mem/port_impl.hh b/src/mem/port_impl.hh new file mode 100644 index 000000000..e9a159293 --- /dev/null +++ b/src/mem/port_impl.hh @@ -0,0 +1,53 @@ +/* + * 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 "arch/isa_specific.hh" +#include "arch/isa_traits.hh" +#include "mem/port.hh" +#include "sim/byteswap.hh" + +template <typename T> +void +FunctionalPort::writeHtoG(Addr addr, T d) +{ + d = TheISA::htog(d); + writeBlob(addr, (uint8_t*)&d, sizeof(T)); +} + + +template <typename T> +T +FunctionalPort::readGtoH(Addr addr) +{ + T d; + readBlob(addr, (uint8_t*)&d, sizeof(T)); + return TheISA::gtoh(d); +} + diff --git a/src/mem/request.hh b/src/mem/request.hh new file mode 100644 index 000000000..af1d6d8a8 --- /dev/null +++ b/src/mem/request.hh @@ -0,0 +1,230 @@ +/* + * 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: Ron Dreslinski + * Steve Reinhardt + * Ali Saidi + */ + +/** + * @file Decleration of a request, the overall memory request consisting of + the parts of the request that are persistent throughout the transaction. + */ + +#ifndef __MEM_REQUEST_HH__ +#define __MEM_REQUEST_HH__ + +#include "arch/isa_traits.hh" + +class Request; + +typedef Request* RequestPtr; + +/** The request is a Load locked/store conditional. */ +const unsigned LOCKED = 0x001; +/** The virtual address is also the physical address. */ +const unsigned PHYSICAL = 0x002; +/** The request is an ALPHA VPTE pal access (hw_ld). */ +const unsigned VPTE = 0x004; +/** Use the alternate mode bits in ALPHA. */ +const unsigned ALTMODE = 0x008; +/** The request is to an uncacheable address. */ +const unsigned UNCACHEABLE = 0x010; +/** The request should not cause a page fault. */ +const unsigned NO_FAULT = 0x020; +/** The request should be prefetched into the exclusive state. */ +const unsigned PF_EXCLUSIVE = 0x100; +/** The request should be marked as LRU. */ +const unsigned EVICT_NEXT = 0x200; +/** The request should ignore unaligned access faults */ +const unsigned NO_ALIGN_FAULT = 0x400; + +class Request +{ + private: + /** + * The physical address of the request. Valid only if validPaddr + * is set. */ + Addr paddr; + + /** + * The size of the request. This field must be set when vaddr or + * paddr is written via setVirt() or setPhys(), so it is always + * valid as long as one of the address fields is valid. */ + int size; + + /** Flag structure for the request. */ + uint32_t flags; + + /** + * The time this request was started. Used to calculate + * latencies. This field is set to curTick any time paddr or vaddr + * is written. */ + Tick time; + + /** The address space ID. */ + int asid; + /** The virtual address of the request. */ + Addr vaddr; + + /** The return value of store conditional. */ + uint64_t scResult; + + /** The cpu number (for statistics, typically). */ + int cpuNum; + /** The requesting thread id (for statistics, typically). */ + int threadNum; + + /** program counter of initiating access; for tracing/debugging */ + Addr pc; + + /** Whether or not paddr is valid (has been written yet). */ + bool validPaddr; + /** Whether or not the asid & vaddr are valid. */ + bool validAsidVaddr; + /** Whether or not the sc result is valid. */ + bool validScResult; + /** Whether or not the cpu number & thread ID are valid. */ + bool validCpuAndThreadNums; + /** Whether or not the pc is valid. */ + bool validPC; + + public: + /** Minimal constructor. No fields are initialized. */ + Request() + : validPaddr(false), validAsidVaddr(false), + validScResult(false), validCpuAndThreadNums(false), validPC(false) + {} + + /** + * Constructor for physical (e.g. device) requests. Initializes + * just physical address, size, flags, and timestamp (to curTick). + * These fields are adequate to perform a request. */ + Request(Addr _paddr, int _size, int _flags) + : validCpuAndThreadNums(false) + { setPhys(_paddr, _size, _flags); } + + Request(int _asid, Addr _vaddr, int _size, int _flags, Addr _pc, + int _cpuNum, int _threadNum) + { + setThreadContext(_cpuNum, _threadNum); + setVirt(_asid, _vaddr, _size, _flags, _pc); + } + + /** + * Set up CPU and thread numbers. */ + void setThreadContext(int _cpuNum, int _threadNum) + { + cpuNum = _cpuNum; + threadNum = _threadNum; + validCpuAndThreadNums = true; + } + + /** + * Set up a physical (e.g. device) request in a previously + * allocated Request object. */ + void setPhys(Addr _paddr, int _size, int _flags) + { + paddr = _paddr; + size = _size; + flags = _flags; + time = curTick; + validPaddr = true; + validAsidVaddr = false; + validPC = false; + validScResult = false; + } + + /** + * Set up a virtual (e.g., CPU) request in a previously + * allocated Request object. */ + void setVirt(int _asid, Addr _vaddr, int _size, int _flags, Addr _pc) + { + asid = _asid; + vaddr = _vaddr; + size = _size; + flags = _flags; + pc = _pc; + time = curTick; + validPaddr = false; + validAsidVaddr = true; + validPC = true; + validScResult = false; + } + + /** Set just the physical address. This should only be used to + * record the result of a translation, and thus the vaddr must be + * valid before this method is called. Otherwise, use setPhys() + * to guarantee that the size and flags are also set. + */ + void setPaddr(Addr _paddr) + { + assert(validAsidVaddr); + paddr = _paddr; + validPaddr = true; + } + + /** Accessor for paddr. */ + Addr getPaddr() { assert(validPaddr); return paddr; } + + /** Accessor for size. */ + int getSize() { assert(validPaddr || validAsidVaddr); return size; } + /** Accessor for time. */ + Tick getTime() { assert(validPaddr || validAsidVaddr); return time; } + + /** Accessor for flags. */ + uint32_t getFlags() { assert(validPaddr || validAsidVaddr); return flags; } + /** Accessor for paddr. */ + void setFlags(uint32_t _flags) + { assert(validPaddr || validAsidVaddr); flags = _flags; } + + /** Accessor function for vaddr.*/ + Addr getVaddr() { assert(validAsidVaddr); return vaddr; } + + /** Accessor function for asid.*/ + int getAsid() { assert(validAsidVaddr); return asid; } + + /** Accessor function to check if sc result is valid. */ + bool scResultValid() { return validScResult; } + /** Accessor function for store conditional return value.*/ + uint64_t getScResult() { assert(validScResult); return scResult; } + /** Accessor function for store conditional return value.*/ + void setScResult(uint64_t _scResult) + { scResult = _scResult; validScResult = true; } + + /** Accessor function for cpu number.*/ + int getCpuNum() { assert(validCpuAndThreadNums); return cpuNum; } + /** Accessor function for thread number.*/ + int getThreadNum() { assert(validCpuAndThreadNums); return threadNum; } + + /** Accessor function for pc.*/ + Addr getPC() { assert(validPC); return pc; } + + friend class Packet; +}; + +#endif // __MEM_REQUEST_HH__ diff --git a/src/mem/translating_port.cc b/src/mem/translating_port.cc new file mode 100644 index 000000000..d2c854086 --- /dev/null +++ b/src/mem/translating_port.cc @@ -0,0 +1,190 @@ +/* + * 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: Ron Dreslinski + * Steve Reinhardt + */ + +#include <string> +#include "base/chunk_generator.hh" +#include "mem/port.hh" +#include "mem/translating_port.hh" +#include "mem/page_table.hh" + +using namespace TheISA; + +TranslatingPort::TranslatingPort(const std::string &_name, + PageTable *p_table, bool alloc) + : FunctionalPort(_name), pTable(p_table), allocating(alloc) +{ } + +TranslatingPort::~TranslatingPort() +{ } + +bool +TranslatingPort::tryReadBlob(Addr addr, uint8_t *p, int size) +{ + Addr paddr; + int prevSize = 0; + + for (ChunkGenerator gen(addr, size, VMPageSize); !gen.done(); gen.next()) { + + if (!pTable->translate(gen.addr(),paddr)) + return false; + + Port::readBlob(paddr, p + prevSize, gen.size()); + prevSize += gen.size(); + } + + return true; +} + +void +TranslatingPort::readBlob(Addr addr, uint8_t *p, int size) +{ + if (!tryReadBlob(addr, p, size)) + fatal("readBlob(0x%x, ...) failed", addr); +} + + +bool +TranslatingPort::tryWriteBlob(Addr addr, uint8_t *p, int size) +{ + + Addr paddr; + int prevSize = 0; + + for (ChunkGenerator gen(addr, size, VMPageSize); !gen.done(); gen.next()) { + + if (!pTable->translate(gen.addr(), paddr)) { + if (allocating) { + pTable->allocate(roundDown(gen.addr(), VMPageSize), + VMPageSize); + pTable->translate(gen.addr(), paddr); + } else { + return false; + } + } + + Port::writeBlob(paddr, p + prevSize, gen.size()); + prevSize += gen.size(); + } + + return true; +} + + +void +TranslatingPort::writeBlob(Addr addr, uint8_t *p, int size) +{ + if (!tryWriteBlob(addr, p, size)) + fatal("writeBlob(0x%x, ...) failed", addr); +} + +bool +TranslatingPort::tryMemsetBlob(Addr addr, uint8_t val, int size) +{ + Addr paddr; + + for (ChunkGenerator gen(addr, size, VMPageSize); !gen.done(); gen.next()) { + + if (!pTable->translate(gen.addr(), paddr)) { + if (allocating) { + pTable->allocate(roundDown(gen.addr(), VMPageSize), + VMPageSize); + pTable->translate(gen.addr(), paddr); + } else { + return false; + } + } + + Port::memsetBlob(paddr, val, gen.size()); + } + + return true; +} + +void +TranslatingPort::memsetBlob(Addr addr, uint8_t val, int size) +{ + if (!tryMemsetBlob(addr, val, size)) + fatal("memsetBlob(0x%x, ...) failed", addr); +} + + +bool +TranslatingPort::tryWriteString(Addr addr, const char *str) +{ + Addr paddr,vaddr; + uint8_t c; + + vaddr = addr; + + do { + c = *str++; + if (!pTable->translate(vaddr++,paddr)) + return false; + + Port::writeBlob(paddr, &c, 1); + } while (c); + + return true; +} + +void +TranslatingPort::writeString(Addr addr, const char *str) +{ + if (!tryWriteString(addr, str)) + fatal("writeString(0x%x, ...) failed", addr); +} + +bool +TranslatingPort::tryReadString(std::string &str, Addr addr) +{ + Addr paddr,vaddr; + uint8_t c; + + vaddr = addr; + + do { + if (!pTable->translate(vaddr++,paddr)) + return false; + + Port::readBlob(paddr, &c, 1); + str += c; + } while (c); + + return true; +} + +void +TranslatingPort::readString(std::string &str, Addr addr) +{ + if (!tryReadString(str, addr)) + fatal("readString(0x%x, ...) failed", addr); +} + diff --git a/src/mem/translating_port.hh b/src/mem/translating_port.hh new file mode 100644 index 000000000..7354278ba --- /dev/null +++ b/src/mem/translating_port.hh @@ -0,0 +1,64 @@ +/* + * 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: Ron Dreslinski + * Ali Saidi + */ + +#ifndef __MEM_TRANSLATING_PROT_HH__ +#define __MEM_TRANSLATING_PROT_HH__ + +#include "mem/port.hh" + +class PageTable; + +class TranslatingPort : public FunctionalPort +{ + private: + PageTable *pTable; + bool allocating; + + public: + TranslatingPort(const std::string &_name, + PageTable *p_table, bool alloc = false); + virtual ~TranslatingPort(); + + bool tryReadBlob(Addr addr, uint8_t *p, int size); + bool tryWriteBlob(Addr addr, uint8_t *p, int size); + bool tryMemsetBlob(Addr addr, uint8_t val, int size); + bool tryWriteString(Addr addr, const char *str); + bool tryReadString(std::string &str, Addr addr); + + virtual void readBlob(Addr addr, uint8_t *p, int size); + virtual void writeBlob(Addr addr, uint8_t *p, int size); + virtual void memsetBlob(Addr addr, uint8_t val, int size); + + void writeString(Addr addr, const char *str); + void readString(std::string &str, Addr addr); +}; + +#endif diff --git a/src/mem/vport.cc b/src/mem/vport.cc new file mode 100644 index 000000000..cd297bb8e --- /dev/null +++ b/src/mem/vport.cc @@ -0,0 +1,71 @@ +/* + * 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 + */ + +/** + * @file Port object definitions. + */ + +#include "base/chunk_generator.hh" +#include "mem/vport.hh" + +void +VirtualPort::readBlob(Addr addr, uint8_t *p, int size) +{ + Addr paddr; + for (ChunkGenerator gen(addr, size, TheISA::PageBytes); !gen.done(); + gen.next()) + { + if (tc) + paddr = TheISA::vtophys(tc,gen.addr()); + else + paddr = TheISA::vtophys(gen.addr()); + + FunctionalPort::readBlob(paddr, p, gen.size()); + p += gen.size(); + } +} + +void +VirtualPort::writeBlob(Addr addr, uint8_t *p, int size) +{ + Addr paddr; + for (ChunkGenerator gen(addr, size, TheISA::PageBytes); !gen.done(); + gen.next()) + { + if (tc) + paddr = TheISA::vtophys(tc,gen.addr()); + else + paddr = TheISA::vtophys(gen.addr()); + + FunctionalPort::writeBlob(paddr, p, gen.size()); + p += gen.size(); + } +} + diff --git a/src/mem/vport.hh b/src/mem/vport.hh new file mode 100644 index 000000000..697c8e5f3 --- /dev/null +++ b/src/mem/vport.hh @@ -0,0 +1,79 @@ +/* + * 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 + */ + +/** + * @file + * Virtual Port Object Decleration. These ports incorporate some translation + * into their access methods. Thus you can use one to read and write data + * to/from virtual addresses. + */ + +#ifndef __MEM_VPORT_HH__ +#define __MEM_VPORT_HH__ + +#include "mem/port_impl.hh" +#include "config/full_system.hh" +#include "arch/vtophys.hh" + + +/** A class that translates a virtual address to a physical address and then + * calls the above read/write functions. If a thread context is provided the + * address can alway be translated, If not it can only be translated if it is a + * simple address masking operation (such as alpha super page accesses). + */ + +class VirtualPort : public FunctionalPort +{ + private: + ThreadContext *tc; + + public: + VirtualPort(const std::string &_name, ThreadContext *_tc = NULL) + : FunctionalPort(_name), tc(_tc) + {} + + /** Return true if we have an thread context. This is used to + * prevent someone from accidently deleting the cpus statically + * allocated vport. + * @return true if a thread context isn't valid + */ + bool nullThreadContext() { return tc != NULL; } + + /** Version of readblob that translates virt->phys and deals + * with page boundries. */ + virtual void readBlob(Addr addr, uint8_t *p, int size); + + /** Version of writeBlob that translates virt->phys and deals + * with page boundries. */ + virtual void writeBlob(Addr addr, uint8_t *p, int size); +}; + +#endif //__MEM_VPORT_HH__ + diff --git a/src/python/SConscript b/src/python/SConscript new file mode 100644 index 000000000..7b0f591eb --- /dev/null +++ b/src/python/SConscript @@ -0,0 +1,106 @@ +# -*- mode:python -*- + +# 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: Steve Reinhardt +# Nathan Binkert + +import os, os.path, re, sys +from zipfile import PyZipFile + +# handy function for path joins +def join(*args): + return os.path.normpath(os.path.join(*args)) + +Import('env') + +# This SConscript is in charge of collecting .py files and generating +# a zip archive that is appended to the m5 binary. + +# List of files & directories to include in the zip file. To include +# a package, list only the root directory of the package, not any +# internal .py files (else they will get the path stripped off when +# they are imported into the zip file). +pyzip_files = [] + +# List of additional files on which the zip archive depends, but which +# are not included in pyzip_files... i.e. individual .py files within +# a package. +pyzip_dep_files = [] + +# Add the specified package to the zip archive. Adds the directory to +# pyzip_files and all included .py files to pyzip_dep_files. +def addPkg(pkgdir): + pyzip_files.append(pkgdir) + origdir = os.getcwd() + srcdir = join(Dir('.').srcnode().abspath, pkgdir) + os.chdir(srcdir) + for path, dirs, files in os.walk('.'): + for i,dir in enumerate(dirs): + if dir == 'SCCS': + del dirs[i] + break + + for f in files: + if f.endswith('.py'): + pyzip_dep_files.append(join(pkgdir, path, f)) + + os.chdir(origdir) + +# Generate Python file that contains a dict specifying the current +# build_env flags. +def MakeDefinesPyFile(target, source, env): + f = file(str(target[0]), 'w') + print >>f, "m5_build_env = ", + print >>f, source[0] + f.close() + +optionDict = dict([(opt, env[opt]) for opt in env.ExportOptions]) +env.Command('m5/defines.py', Value(optionDict), MakeDefinesPyFile) + +# Now specify the packages & files for the zip archive. +addPkg('m5') +pyzip_files.append('m5/defines.py') +pyzip_files.append(join(env['ROOT'], 'util/pbs/jobfile.py')) + +env.Command(['swig/main_wrap.cc', 'm5/main.py'], + 'swig/main.i', + '$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} ' + '-o ${TARGETS[0]} $SOURCES') + +pyzip_dep_files.append('m5/main.py') + +# Action function to build the zip archive. Uses the PyZipFile module +# included in the standard Python library. +def buildPyZip(target, source, env): + pzf = PyZipFile(str(target[0]), 'w') + for s in source: + pzf.writepy(str(s)) + +# Add the zip file target to the environment. +env.Command('m5py.zip', pyzip_files, buildPyZip) +env.Depends('m5py.zip', pyzip_dep_files) diff --git a/src/python/m5/__init__.py b/src/python/m5/__init__.py new file mode 100644 index 000000000..60a61d66e --- /dev/null +++ b/src/python/m5/__init__.py @@ -0,0 +1,114 @@ +# Copyright (c) 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 +# Steve Reinhardt + +import sys, os, time, atexit, optparse + +# import the SWIG-wrapped main C++ functions +import main +# import a few SWIG-wrapped items (those that are likely to be used +# directly by user scripts) completely into this module for +# convenience +from main import simulate, SimLoopExitEvent + +# import the m5 compile options +import defines + +# define this here so we can use it right away if necessary +def panic(string): + print >>sys.stderr, 'panic:', string + sys.exit(1) + +# Prepend given directory to system module search path. We may not +# need this anymore if we can structure our config library more like a +# Python package. +def AddToPath(path): + # if it's a relative path and we know what directory the current + # python script is in, make the path relative to that directory. + if not os.path.isabs(path) and sys.path[0]: + path = os.path.join(sys.path[0], path) + path = os.path.realpath(path) + # sys.path[0] should always refer to the current script's directory, + # so place the new dir right after that. + sys.path.insert(1, path) + + +# Callback to set trace flags. Not necessarily the best way to do +# things in the long run (particularly if we change how these global +# options are handled). +def setTraceFlags(option, opt_str, value, parser): + objects.Trace.flags = value + +# Standard optparse options. Need to be explicitly included by the +# user script when it calls optparse.OptionParser(). +standardOptions = [ + optparse.make_option("--traceflags", type="string", action="callback", + callback=setTraceFlags) + ] + +# make a SmartDict out of the build options for our local use +import smartdict +build_env = smartdict.SmartDict() +build_env.update(defines.m5_build_env) + +# make a SmartDict out of the OS environment too +env = smartdict.SmartDict() +env.update(os.environ) + +# The final hook to generate .ini files. Called from the user script +# once the config is built. +def instantiate(root): + config.ticks_per_sec = float(root.clock.frequency) + # ugly temporary hack to get output to config.ini + sys.stdout = file('config.ini', 'w') + root.print_ini() + sys.stdout.close() # close config.ini + sys.stdout = sys.__stdout__ # restore to original + main.initialize() # load config.ini into C++ and process it + noDot = True # temporary until we fix dot + if not noDot: + dot = pydot.Dot() + instance.outputDot(dot) + dot.orientation = "portrait" + dot.size = "8.5,11" + dot.ranksep="equally" + dot.rank="samerank" + dot.write("config.dot") + dot.write_ps("config.ps") + +# Export curTick to user script. +def curTick(): + return main.cvar.curTick + +# register our C++ exit callback function with Python +atexit.register(main.doExitCleanup) + +# This import allows user scripts to reference 'm5.objects.Foo' after +# just doing an 'import m5' (without an 'import m5.objects'). May not +# matter since most scripts will probably 'from m5.objects import *'. +import objects diff --git a/src/python/m5/config.py b/src/python/m5/config.py new file mode 100644 index 000000000..3eb99972f --- /dev/null +++ b/src/python/m5/config.py @@ -0,0 +1,1425 @@ +# 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: Steve Reinhardt +# Nathan Binkert + +import os, re, sys, types, inspect + +import m5 +from m5 import panic +from convert import * +from multidict import multidict + +noDot = False +try: + import pydot +except: + noDot = True + +class Singleton(type): + def __call__(cls, *args, **kwargs): + if hasattr(cls, '_instance'): + return cls._instance + + cls._instance = super(Singleton, cls).__call__(*args, **kwargs) + return cls._instance + +##################################################################### +# +# M5 Python Configuration Utility +# +# The basic idea is to write simple Python programs that build Python +# objects corresponding to M5 SimObjects for the desired simulation +# configuration. For now, the Python emits a .ini file that can be +# parsed by M5. In the future, some tighter integration between M5 +# and the Python interpreter may allow bypassing the .ini file. +# +# Each SimObject class in M5 is represented by a Python class with the +# same name. The Python inheritance tree mirrors the M5 C++ tree +# (e.g., SimpleCPU derives from BaseCPU in both cases, and all +# SimObjects inherit from a single SimObject base class). To specify +# an instance of an M5 SimObject in a configuration, the user simply +# instantiates the corresponding Python object. The parameters for +# that SimObject are given by assigning to attributes of the Python +# object, either using keyword assignment in the constructor or in +# separate assignment statements. For example: +# +# cache = BaseCache(size='64KB') +# cache.hit_latency = 3 +# cache.assoc = 8 +# +# The magic lies in the mapping of the Python attributes for SimObject +# classes to the actual SimObject parameter specifications. This +# allows parameter validity checking in the Python code. Continuing +# the example above, the statements "cache.blurfl=3" or +# "cache.assoc='hello'" would both result in runtime errors in Python, +# since the BaseCache object has no 'blurfl' parameter and the 'assoc' +# parameter requires an integer, respectively. This magic is done +# primarily by overriding the special __setattr__ method that controls +# assignment to object attributes. +# +# Once a set of Python objects have been instantiated in a hierarchy, +# calling 'instantiate(obj)' (where obj is the root of the hierarchy) +# will generate a .ini file. See simple-4cpu.py for an example +# (corresponding to m5-test/simple-4cpu.ini). +# +##################################################################### + +##################################################################### +# +# ConfigNode/SimObject classes +# +# The Python class hierarchy rooted by ConfigNode (which is the base +# class of SimObject, which in turn is the base class of all other M5 +# SimObject classes) has special attribute behavior. In general, an +# object in this hierarchy has three categories of attribute-like +# things: +# +# 1. Regular Python methods and variables. These must start with an +# underscore to be treated normally. +# +# 2. SimObject parameters. These values are stored as normal Python +# attributes, but all assignments to these attributes are checked +# against the pre-defined set of parameters stored in the class's +# _params dictionary. Assignments to attributes that do not +# correspond to predefined parameters, or that are not of the correct +# type, incur runtime errors. +# +# 3. Hierarchy children. The child nodes of a ConfigNode are stored +# in the node's _children dictionary, but can be accessed using the +# Python attribute dot-notation (just as they are printed out by the +# simulator). Children cannot be created using attribute assigment; +# they must be added by specifying the parent node in the child's +# constructor or using the '+=' operator. + +# The SimObject parameters are the most complex, for a few reasons. +# First, both parameter descriptions and parameter values are +# inherited. Thus parameter description lookup must go up the +# inheritance chain like normal attribute lookup, but this behavior +# must be explicitly coded since the lookup occurs in each class's +# _params attribute. Second, because parameter values can be set +# on SimObject classes (to implement default values), the parameter +# checking behavior must be enforced on class attribute assignments as +# well as instance attribute assignments. Finally, because we allow +# class specialization via inheritance (e.g., see the L1Cache class in +# the simple-4cpu.py example), we must do parameter checking even on +# class instantiation. To provide all these features, we use a +# metaclass to define most of the SimObject parameter behavior for +# this class hierarchy. +# +##################################################################### + +def isSimObject(value): + return isinstance(value, SimObject) + +def isSimObjectClass(value): + try: + return issubclass(value, SimObject) + except TypeError: + # happens if value is not a class at all + return False + +def isSimObjSequence(value): + if not isinstance(value, (list, tuple)): + return False + + for val in value: + if not isNullPointer(val) and not isSimObject(val): + return False + + return True + +def isSimObjClassSequence(value): + if not isinstance(value, (list, tuple)): + return False + + for val in value: + if not isNullPointer(val) and not isSimObjectClass(val): + return False + + return True + +def isNullPointer(value): + return isinstance(value, NullSimObject) + +# The metaclass for ConfigNode (and thus for everything that derives +# from ConfigNode, including SimObject). This class controls how new +# classes that derive from ConfigNode are instantiated, and provides +# inherited class behavior (just like a class controls how instances +# of that class are instantiated, and provides inherited instance +# behavior). +class MetaSimObject(type): + # Attributes that can be set only at initialization time + init_keywords = { 'abstract' : types.BooleanType, + 'type' : types.StringType } + # Attributes that can be set any time + keywords = { 'check' : types.FunctionType, + 'children' : types.ListType } + + # __new__ is called before __init__, and is where the statements + # in the body of the class definition get loaded into the class's + # __dict__. We intercept this to filter out parameter assignments + # and only allow "private" attributes to be passed to the base + # __new__ (starting with underscore). + def __new__(mcls, name, bases, dict): + if dict.has_key('_init_dict'): + # must have been called from makeSubclass() rather than + # via Python class declaration; bypass filtering process. + cls_dict = dict + else: + # Copy "private" attributes (including special methods + # such as __new__) to the official dict. Everything else + # goes in _init_dict to be filtered in __init__. + cls_dict = {} + for key,val in dict.items(): + if key.startswith('_'): + cls_dict[key] = val + del dict[key] + cls_dict['_init_dict'] = dict + return super(MetaSimObject, mcls).__new__(mcls, name, bases, cls_dict) + + # subclass initialization + def __init__(cls, name, bases, dict): + # calls type.__init__()... I think that's a no-op, but leave + # it here just in case it's not. + super(MetaSimObject, cls).__init__(name, bases, dict) + + # initialize required attributes + cls._params = multidict() + cls._values = multidict() + cls._instantiated = False # really instantiated or subclassed + cls._anon_subclass_counter = 0 + + # We don't support multiple inheritance. If you want to, you + # must fix multidict to deal with it properly. + if len(bases) > 1: + raise TypeError, "SimObjects do not support multiple inheritance" + + base = bases[0] + + # the only time the following is not true is when we define + # the SimObject class itself + if isinstance(base, MetaSimObject): + cls._params.parent = base._params + cls._values.parent = base._values + base._instantiated = True + + # now process the _init_dict items + for key,val in cls._init_dict.items(): + if isinstance(val, (types.FunctionType, types.TypeType)): + type.__setattr__(cls, key, val) + + # param descriptions + elif isinstance(val, ParamDesc): + cls._new_param(key, val) + + # init-time-only keywords + elif cls.init_keywords.has_key(key): + cls._set_keyword(key, val, cls.init_keywords[key]) + + # default: use normal path (ends up in __setattr__) + else: + setattr(cls, key, val) + + # Pull the deep-copy memoization dict out of the class dict if + # it's there... + memo = cls.__dict__.get('_memo', {}) + + # Handle SimObject values + for key,val in cls._values.iteritems(): + # SimObject instances need to be promoted to classes. + # Existing classes should not have any instance values, so + # these can only occur at the lowest level dict (the + # parameters just being set in this class definition). + if isSimObject(val): + assert(val == cls._values.local[key]) + cls._values[key] = val.makeClass(memo) + elif isSimObjSequence(val) and len(val): + assert(val == cls._values.local[key]) + cls._values[key] = [ v.makeClass(memo) for v in val ] + # SimObject classes need to be subclassed so that + # parameters that get set at this level only affect this + # level and derivatives. + elif isSimObjectClass(val): + assert(not cls._values.local.has_key(key)) + cls._values[key] = val.makeSubclass({}, memo) + elif isSimObjClassSequence(val) and len(val): + assert(not cls._values.local.has_key(key)) + cls._values[key] = [ v.makeSubclass({}, memo) for v in val ] + + + def _set_keyword(cls, keyword, val, kwtype): + if not isinstance(val, kwtype): + raise TypeError, 'keyword %s has bad type %s (expecting %s)' % \ + (keyword, type(val), kwtype) + if isinstance(val, types.FunctionType): + val = classmethod(val) + type.__setattr__(cls, keyword, val) + + def _new_param(cls, name, value): + cls._params[name] = value + if hasattr(value, 'default'): + setattr(cls, name, value.default) + + # Set attribute (called on foo.attr = value when foo is an + # instance of class cls). + def __setattr__(cls, attr, value): + # normal processing for private attributes + if attr.startswith('_'): + type.__setattr__(cls, attr, value) + return + + if cls.keywords.has_key(attr): + cls._set_keyword(attr, value, cls.keywords[attr]) + return + + # must be SimObject param + param = cls._params.get(attr, None) + if param: + # It's ok: set attribute by delegating to 'object' class. + if (isSimObject(value) or isSimObjSequence(value)) \ + and cls._instantiated: + raise AttributeError, \ + "Cannot set SimObject parameter '%s' after\n" \ + " class %s has been instantiated or subclassed" \ + % (attr, cls.__name__) + try: + cls._values[attr] = param.convert(value) + except Exception, e: + msg = "%s\nError setting param %s.%s to %s\n" % \ + (e, cls.__name__, attr, value) + e.args = (msg, ) + raise + # I would love to get rid of this + elif isSimObject(value) or isSimObjSequence(value): + cls._values[attr] = value + else: + raise AttributeError, \ + "Class %s has no parameter %s" % (cls.__name__, attr) + + def __getattr__(cls, attr): + if cls._values.has_key(attr): + return cls._values[attr] + + raise AttributeError, \ + "object '%s' has no attribute '%s'" % (cls.__name__, attr) + + # Create a subclass of this class. Basically a function interface + # to the standard Python class definition mechanism, primarily for + # internal use. 'memo' dict param supports "deep copy" (really + # "deep subclass") operations... within a given operation, + # multiple references to a class should result in a single + # subclass object with multiple references to it (as opposed to + # mutiple unique subclasses). + def makeSubclass(cls, init_dict, memo = {}): + subcls = memo.get(cls) + if not subcls: + name = cls.__name__ + '_' + str(cls._anon_subclass_counter) + cls._anon_subclass_counter += 1 + subcls = MetaSimObject(name, (cls,), + { '_init_dict': init_dict, '_memo': memo }) + return subcls + +# The ConfigNode class is the root of the special hierarchy. Most of +# the code in this class deals with the configuration hierarchy itself +# (parent/child node relationships). +class SimObject(object): + # Specify metaclass. Any class inheriting from SimObject will + # get this metaclass. + __metaclass__ = MetaSimObject + + # __new__ operator allocates new instances of the class. We + # override it here just to support "deep instantiation" operation + # via the _memo dict. When recursively instantiating an object + # hierarchy we want to make sure that each class is instantiated + # only once, and that if there are multiple references to the same + # original class, we end up with the corresponding instantiated + # references all pointing to the same instance. + def __new__(cls, _memo = None, **kwargs): + if _memo is not None and _memo.has_key(cls): + # return previously instantiated object + assert(len(kwargs) == 0) + return _memo[cls] + else: + # Need a new one... if it needs to be memoized, this will + # happen in __init__. We defer the insertion until then + # so __init__ can use the memo dict to tell whether or not + # to perform the initialization. + return super(SimObject, cls).__new__(cls, **kwargs) + + # Initialize new instance previously allocated by __new__. For + # objects with SimObject-valued params, we need to recursively + # instantiate the classes represented by those param values as + # well (in a consistent "deep copy"-style fashion; see comment + # above). + def __init__(self, _memo = None, **kwargs): + if _memo is not None: + # We're inside a "deep instantiation" + assert(isinstance(_memo, dict)) + assert(len(kwargs) == 0) + if _memo.has_key(self.__class__): + # __new__ returned an existing, already initialized + # instance, so there's nothing to do here + assert(_memo[self.__class__] == self) + return + # no pre-existing object, so remember this one here + _memo[self.__class__] = self + else: + # This is a new top-level instantiation... don't memoize + # this objcet, but prepare to memoize any recursively + # instantiated objects. + _memo = {} + + self.__class__._instantiated = True + + self._children = {} + # Inherit parameter values from class using multidict so + # individual value settings can be overridden. + self._values = multidict(self.__class__._values) + # For SimObject-valued parameters, the class should have + # classes (not instances) for the values. We need to + # instantiate these classes rather than just inheriting the + # class object. + for key,val in self.__class__._values.iteritems(): + if isSimObjectClass(val): + setattr(self, key, val(_memo)) + elif isSimObjClassSequence(val) and len(val): + setattr(self, key, [ v(_memo) for v in val ]) + # apply attribute assignments from keyword args, if any + for key,val in kwargs.iteritems(): + setattr(self, key, val) + + # Use this instance as a template to create a new class. + def makeClass(self, memo = {}): + cls = memo.get(self) + if not cls: + cls = self.__class__.makeSubclass(self._values.local) + memo[self] = cls + return cls + + # Direct instantiation of instances (cloning) is no longer + # allowed; must generate class from instance first. + def __call__(self, **kwargs): + raise TypeError, "cannot instantiate SimObject; "\ + "use makeClass() to make class first" + + def __getattr__(self, attr): + if self._values.has_key(attr): + return self._values[attr] + + raise AttributeError, "object '%s' has no attribute '%s'" \ + % (self.__class__.__name__, attr) + + # Set attribute (called on foo.attr = value when foo is an + # instance of class cls). + def __setattr__(self, attr, value): + # normal processing for private attributes + if attr.startswith('_'): + object.__setattr__(self, attr, value) + return + + # must be SimObject param + param = self._params.get(attr, None) + if param: + # It's ok: set attribute by delegating to 'object' class. + try: + value = param.convert(value) + except Exception, e: + msg = "%s\nError setting param %s.%s to %s\n" % \ + (e, self.__class__.__name__, attr, value) + e.args = (msg, ) + raise + # I would love to get rid of this + elif isSimObject(value) or isSimObjSequence(value): + pass + else: + raise AttributeError, "Class %s has no parameter %s" \ + % (self.__class__.__name__, attr) + + # clear out old child with this name, if any + self.clear_child(attr) + + if isSimObject(value): + value.set_path(self, attr) + elif isSimObjSequence(value): + value = SimObjVector(value) + [v.set_path(self, "%s%d" % (attr, i)) for i,v in enumerate(value)] + + self._values[attr] = value + + # this hack allows tacking a '[0]' onto parameters that may or may + # not be vectors, and always getting the first element (e.g. cpus) + def __getitem__(self, key): + if key == 0: + return self + raise TypeError, "Non-zero index '%s' to SimObject" % key + + # clear out children with given name, even if it's a vector + def clear_child(self, name): + if not self._children.has_key(name): + return + child = self._children[name] + if isinstance(child, SimObjVector): + for i in xrange(len(child)): + del self._children["s%d" % (name, i)] + del self._children[name] + + def add_child(self, name, value): + self._children[name] = value + + def set_path(self, parent, name): + if not hasattr(self, '_parent'): + self._parent = parent + self._name = name + parent.add_child(name, self) + + def path(self): + if not hasattr(self, '_parent'): + return 'root' + ppath = self._parent.path() + if ppath == 'root': + return self._name + return ppath + "." + self._name + + def __str__(self): + return self.path() + + def ini_str(self): + return self.path() + + def find_any(self, ptype): + if isinstance(self, ptype): + return self, True + + found_obj = None + for child in self._children.itervalues(): + if isinstance(child, ptype): + if found_obj != None and child != found_obj: + raise AttributeError, \ + 'parent.any matched more than one: %s %s' % \ + (found_obj.path, child.path) + found_obj = child + # search param space + for pname,pdesc in self._params.iteritems(): + if issubclass(pdesc.ptype, ptype): + match_obj = self._values[pname] + if found_obj != None and found_obj != match_obj: + raise AttributeError, \ + 'parent.any matched more than one: %s' % obj.path + found_obj = match_obj + return found_obj, found_obj != None + + def unproxy(self, base): + return self + + def print_ini(self): + print '[' + self.path() + ']' # .ini section header + + if hasattr(self, 'type') and not isinstance(self, ParamContext): + print 'type=%s' % self.type + + child_names = self._children.keys() + child_names.sort() + np_child_names = [c for c in child_names \ + if not isinstance(self._children[c], ParamContext)] + if len(np_child_names): + print 'children=%s' % ' '.join(np_child_names) + + param_names = self._params.keys() + param_names.sort() + for param in param_names: + value = self._values.get(param, None) + if value != None: + if isproxy(value): + try: + value = value.unproxy(self) + except: + print >> sys.stderr, \ + "Error in unproxying param '%s' of %s" % \ + (param, self.path()) + raise + setattr(self, param, value) + print '%s=%s' % (param, self._values[param].ini_str()) + + print # blank line between objects + + for child in child_names: + self._children[child].print_ini() + + # generate output file for 'dot' to display as a pretty graph. + # this code is currently broken. + def outputDot(self, dot): + label = "{%s|" % self.path + if isSimObject(self.realtype): + label += '%s|' % self.type + + if self.children: + # instantiate children in same order they were added for + # backward compatibility (else we can end up with cpu1 + # before cpu0). + for c in self.children: + dot.add_edge(pydot.Edge(self.path,c.path, style="bold")) + + simobjs = [] + for param in self.params: + try: + if param.value is None: + raise AttributeError, 'Parameter with no value' + + value = param.value + string = param.string(value) + except Exception, e: + msg = 'exception in %s:%s\n%s' % (self.name, param.name, e) + e.args = (msg, ) + raise + + if isSimObject(param.ptype) and string != "Null": + simobjs.append(string) + else: + label += '%s = %s\\n' % (param.name, string) + + for so in simobjs: + label += "|<%s> %s" % (so, so) + dot.add_edge(pydot.Edge("%s:%s" % (self.path, so), so, + tailport="w")) + label += '}' + dot.add_node(pydot.Node(self.path,shape="Mrecord",label=label)) + + # recursively dump out children + for c in self.children: + c.outputDot(dot) + +class ParamContext(SimObject): + pass + +##################################################################### +# +# Proxy object support. +# +##################################################################### + +class BaseProxy(object): + def __init__(self, search_self, search_up): + self._search_self = search_self + self._search_up = search_up + self._multiplier = None + + def __setattr__(self, attr, value): + if not attr.startswith('_'): + raise AttributeError, 'cannot set attribute on proxy object' + super(BaseProxy, self).__setattr__(attr, value) + + # support multiplying proxies by constants + def __mul__(self, other): + if not isinstance(other, (int, long, float)): + raise TypeError, "Proxy multiplier must be integer" + if self._multiplier == None: + self._multiplier = other + else: + # support chained multipliers + self._multiplier *= other + return self + + __rmul__ = __mul__ + + def _mulcheck(self, result): + if self._multiplier == None: + return result + return result * self._multiplier + + def unproxy(self, base): + obj = base + done = False + + if self._search_self: + result, done = self.find(obj) + + if self._search_up: + while not done: + try: obj = obj._parent + except: break + + result, done = self.find(obj) + + if not done: + raise AttributeError, "Can't resolve proxy '%s' from '%s'" % \ + (self.path(), base.path()) + + if isinstance(result, BaseProxy): + if result == self: + raise RuntimeError, "Cycle in unproxy" + result = result.unproxy(obj) + + return self._mulcheck(result) + + def getindex(obj, index): + if index == None: + return obj + try: + obj = obj[index] + except TypeError: + if index != 0: + raise + # if index is 0 and item is not subscriptable, just + # use item itself (so cpu[0] works on uniprocessors) + return obj + getindex = staticmethod(getindex) + + def set_param_desc(self, pdesc): + self._pdesc = pdesc + +class AttrProxy(BaseProxy): + def __init__(self, search_self, search_up, attr): + super(AttrProxy, self).__init__(search_self, search_up) + self._attr = attr + self._modifiers = [] + + def __getattr__(self, attr): + # python uses __bases__ internally for inheritance + if attr.startswith('_'): + return super(AttrProxy, self).__getattr__(self, attr) + if hasattr(self, '_pdesc'): + raise AttributeError, "Attribute reference on bound proxy" + self._modifiers.append(attr) + return self + + # support indexing on proxies (e.g., Self.cpu[0]) + def __getitem__(self, key): + if not isinstance(key, int): + raise TypeError, "Proxy object requires integer index" + self._modifiers.append(key) + return self + + def find(self, obj): + try: + val = getattr(obj, self._attr) + except: + return None, False + while isproxy(val): + val = val.unproxy(obj) + for m in self._modifiers: + if isinstance(m, str): + val = getattr(val, m) + elif isinstance(m, int): + val = val[m] + else: + assert("Item must be string or integer") + while isproxy(val): + val = val.unproxy(obj) + return val, True + + def path(self): + p = self._attr + for m in self._modifiers: + if isinstance(m, str): + p += '.%s' % m + elif isinstance(m, int): + p += '[%d]' % m + else: + assert("Item must be string or integer") + return p + +class AnyProxy(BaseProxy): + def find(self, obj): + return obj.find_any(self._pdesc.ptype) + + def path(self): + return 'any' + +def isproxy(obj): + if isinstance(obj, (BaseProxy, EthernetAddr)): + return True + elif isinstance(obj, (list, tuple)): + for v in obj: + if isproxy(v): + return True + return False + +class ProxyFactory(object): + def __init__(self, search_self, search_up): + self.search_self = search_self + self.search_up = search_up + + def __getattr__(self, attr): + if attr == 'any': + return AnyProxy(self.search_self, self.search_up) + else: + return AttrProxy(self.search_self, self.search_up, attr) + +# global objects for handling proxies +Parent = ProxyFactory(search_self = False, search_up = True) +Self = ProxyFactory(search_self = True, search_up = False) + +##################################################################### +# +# Parameter description classes +# +# The _params dictionary in each class maps parameter names to +# either a Param or a VectorParam object. These objects contain the +# parameter description string, the parameter type, and the default +# value (loaded from the PARAM section of the .odesc files). The +# _convert() method on these objects is used to force whatever value +# is assigned to the parameter to the appropriate type. +# +# Note that the default values are loaded into the class's attribute +# space when the parameter dictionary is initialized (in +# MetaConfigNode._setparams()); after that point they aren't used. +# +##################################################################### + +# Dummy base class to identify types that are legitimate for SimObject +# parameters. +class ParamValue(object): + + # default for printing to .ini file is regular string conversion. + # will be overridden in some cases + def ini_str(self): + return str(self) + + # allows us to blithely call unproxy() on things without checking + # if they're really proxies or not + def unproxy(self, base): + return self + +# Regular parameter description. +class ParamDesc(object): + def __init__(self, ptype_str, ptype, *args, **kwargs): + self.ptype_str = ptype_str + # remember ptype only if it is provided + if ptype != None: + self.ptype = ptype + + if args: + if len(args) == 1: + self.desc = args[0] + elif len(args) == 2: + self.default = args[0] + self.desc = args[1] + else: + raise TypeError, 'too many arguments' + + if kwargs.has_key('desc'): + assert(not hasattr(self, 'desc')) + self.desc = kwargs['desc'] + del kwargs['desc'] + + if kwargs.has_key('default'): + assert(not hasattr(self, 'default')) + self.default = kwargs['default'] + del kwargs['default'] + + if kwargs: + raise TypeError, 'extra unknown kwargs %s' % kwargs + + if not hasattr(self, 'desc'): + raise TypeError, 'desc attribute missing' + + def __getattr__(self, attr): + if attr == 'ptype': + try: + ptype = eval(self.ptype_str, m5.objects.__dict__) + if not isinstance(ptype, type): + panic("Param qualifier is not a type: %s" % self.ptype) + self.ptype = ptype + return ptype + except NameError: + pass + raise AttributeError, "'%s' object has no attribute '%s'" % \ + (type(self).__name__, attr) + + def convert(self, value): + if isinstance(value, BaseProxy): + value.set_param_desc(self) + return value + if not hasattr(self, 'ptype') and isNullPointer(value): + # deferred evaluation of SimObject; continue to defer if + # we're just assigning a null pointer + return value + if isinstance(value, self.ptype): + return value + if isNullPointer(value) and issubclass(self.ptype, SimObject): + return value + return self.ptype(value) + +# Vector-valued parameter description. Just like ParamDesc, except +# that the value is a vector (list) of the specified type instead of a +# single value. + +class VectorParamValue(list): + def ini_str(self): + return ' '.join([v.ini_str() for v in self]) + + def unproxy(self, base): + return [v.unproxy(base) for v in self] + +class SimObjVector(VectorParamValue): + def print_ini(self): + for v in self: + v.print_ini() + +class VectorParamDesc(ParamDesc): + # Convert assigned value to appropriate type. If the RHS is not a + # list or tuple, it generates a single-element list. + def convert(self, value): + if isinstance(value, (list, tuple)): + # list: coerce each element into new list + tmp_list = [ ParamDesc.convert(self, v) for v in value ] + if isSimObjSequence(tmp_list): + return SimObjVector(tmp_list) + else: + return VectorParamValue(tmp_list) + else: + # singleton: leave it be (could coerce to a single-element + # list here, but for some historical reason we don't... + return ParamDesc.convert(self, value) + + +class ParamFactory(object): + def __init__(self, param_desc_class, ptype_str = None): + self.param_desc_class = param_desc_class + self.ptype_str = ptype_str + + def __getattr__(self, attr): + if self.ptype_str: + attr = self.ptype_str + '.' + attr + return ParamFactory(self.param_desc_class, attr) + + # E.g., Param.Int(5, "number of widgets") + def __call__(self, *args, **kwargs): + caller_frame = inspect.currentframe().f_back + ptype = None + try: + ptype = eval(self.ptype_str, + caller_frame.f_globals, caller_frame.f_locals) + if not isinstance(ptype, type): + raise TypeError, \ + "Param qualifier is not a type: %s" % ptype + except NameError: + # if name isn't defined yet, assume it's a SimObject, and + # try to resolve it later + pass + return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs) + +Param = ParamFactory(ParamDesc) +VectorParam = ParamFactory(VectorParamDesc) + +##################################################################### +# +# Parameter Types +# +# Though native Python types could be used to specify parameter types +# (the 'ptype' field of the Param and VectorParam classes), it's more +# flexible to define our own set of types. This gives us more control +# over how Python expressions are converted to values (via the +# __init__() constructor) and how these values are printed out (via +# the __str__() conversion method). Eventually we'll need these types +# to correspond to distinct C++ types as well. +# +##################################################################### + +# superclass for "numeric" parameter values, to emulate math +# operations in a type-safe way. e.g., a Latency times an int returns +# a new Latency object. +class NumericParamValue(ParamValue): + def __str__(self): + return str(self.value) + + def __float__(self): + return float(self.value) + + # hook for bounds checking + def _check(self): + return + + def __mul__(self, other): + newobj = self.__class__(self) + newobj.value *= other + newobj._check() + return newobj + + __rmul__ = __mul__ + + def __div__(self, other): + newobj = self.__class__(self) + newobj.value /= other + newobj._check() + return newobj + + def __sub__(self, other): + newobj = self.__class__(self) + newobj.value -= other + newobj._check() + return newobj + +class Range(ParamValue): + type = int # default; can be overridden in subclasses + def __init__(self, *args, **kwargs): + + def handle_kwargs(self, kwargs): + if 'end' in kwargs: + self.second = self.type(kwargs.pop('end')) + elif 'size' in kwargs: + self.second = self.first + self.type(kwargs.pop('size')) - 1 + else: + raise TypeError, "Either end or size must be specified" + + if len(args) == 0: + self.first = self.type(kwargs.pop('start')) + handle_kwargs(self, kwargs) + + elif len(args) == 1: + if kwargs: + self.first = self.type(args[0]) + handle_kwargs(self, kwargs) + elif isinstance(args[0], Range): + self.first = self.type(args[0].first) + self.second = self.type(args[0].second) + else: + self.first = self.type(0) + self.second = self.type(args[0]) - 1 + + elif len(args) == 2: + self.first = self.type(args[0]) + self.second = self.type(args[1]) + else: + raise TypeError, "Too many arguments specified" + + if kwargs: + raise TypeError, "too many keywords: %s" % kwargs.keys() + + def __str__(self): + return '%s:%s' % (self.first, self.second) + +# Metaclass for bounds-checked integer parameters. See CheckedInt. +class CheckedIntType(type): + def __init__(cls, name, bases, dict): + super(CheckedIntType, cls).__init__(name, bases, dict) + + # CheckedInt is an abstract base class, so we actually don't + # want to do any processing on it... the rest of this code is + # just for classes that derive from CheckedInt. + if name == 'CheckedInt': + return + + if not (hasattr(cls, 'min') and hasattr(cls, 'max')): + if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')): + panic("CheckedInt subclass %s must define either\n" \ + " 'min' and 'max' or 'size' and 'unsigned'\n" \ + % name); + if cls.unsigned: + cls.min = 0 + cls.max = 2 ** cls.size - 1 + else: + cls.min = -(2 ** (cls.size - 1)) + cls.max = (2 ** (cls.size - 1)) - 1 + +# Abstract superclass for bounds-checked integer parameters. This +# class is subclassed to generate parameter classes with specific +# bounds. Initialization of the min and max bounds is done in the +# metaclass CheckedIntType.__init__. +class CheckedInt(NumericParamValue): + __metaclass__ = CheckedIntType + + def _check(self): + if not self.min <= self.value <= self.max: + raise TypeError, 'Integer param out of bounds %d < %d < %d' % \ + (self.min, self.value, self.max) + + def __init__(self, value): + if isinstance(value, str): + self.value = toInteger(value) + elif isinstance(value, (int, long, float)): + self.value = long(value) + self._check() + +class Int(CheckedInt): size = 32; unsigned = False +class Unsigned(CheckedInt): size = 32; unsigned = True + +class Int8(CheckedInt): size = 8; unsigned = False +class UInt8(CheckedInt): size = 8; unsigned = True +class Int16(CheckedInt): size = 16; unsigned = False +class UInt16(CheckedInt): size = 16; unsigned = True +class Int32(CheckedInt): size = 32; unsigned = False +class UInt32(CheckedInt): size = 32; unsigned = True +class Int64(CheckedInt): size = 64; unsigned = False +class UInt64(CheckedInt): size = 64; unsigned = True + +class Counter(CheckedInt): size = 64; unsigned = True +class Tick(CheckedInt): size = 64; unsigned = True +class TcpPort(CheckedInt): size = 16; unsigned = True +class UdpPort(CheckedInt): size = 16; unsigned = True + +class Percent(CheckedInt): min = 0; max = 100 + +class Float(ParamValue, float): + pass + +class MemorySize(CheckedInt): + size = 64 + unsigned = True + def __init__(self, value): + if isinstance(value, MemorySize): + self.value = value.value + else: + self.value = toMemorySize(value) + self._check() + +class MemorySize32(CheckedInt): + size = 32 + unsigned = True + def __init__(self, value): + if isinstance(value, MemorySize): + self.value = value.value + else: + self.value = toMemorySize(value) + self._check() + +class Addr(CheckedInt): + size = 64 + unsigned = True + def __init__(self, value): + if isinstance(value, Addr): + self.value = value.value + else: + try: + self.value = toMemorySize(value) + except TypeError: + self.value = long(value) + self._check() + +class AddrRange(Range): + type = Addr + +# String-valued parameter. Just mixin the ParamValue class +# with the built-in str class. +class String(ParamValue,str): + pass + +# Boolean parameter type. Python doesn't let you subclass bool, since +# it doesn't want to let you create multiple instances of True and +# False. Thus this is a little more complicated than String. +class Bool(ParamValue): + def __init__(self, value): + try: + self.value = toBool(value) + except TypeError: + self.value = bool(value) + + def __str__(self): + return str(self.value) + + def ini_str(self): + if self.value: + return 'true' + return 'false' + +def IncEthernetAddr(addr, val = 1): + bytes = map(lambda x: int(x, 16), addr.split(':')) + bytes[5] += val + for i in (5, 4, 3, 2, 1): + val,rem = divmod(bytes[i], 256) + bytes[i] = rem + if val == 0: + break + bytes[i - 1] += val + assert(bytes[0] <= 255) + return ':'.join(map(lambda x: '%02x' % x, bytes)) + +class NextEthernetAddr(object): + addr = "00:90:00:00:00:01" + + def __init__(self, inc = 1): + self.value = NextEthernetAddr.addr + NextEthernetAddr.addr = IncEthernetAddr(NextEthernetAddr.addr, inc) + +class EthernetAddr(ParamValue): + def __init__(self, value): + if value == NextEthernetAddr: + self.value = value + return + + if not isinstance(value, str): + raise TypeError, "expected an ethernet address and didn't get one" + + bytes = value.split(':') + if len(bytes) != 6: + raise TypeError, 'invalid ethernet address %s' % value + + for byte in bytes: + if not 0 <= int(byte) <= 256: + raise TypeError, 'invalid ethernet address %s' % value + + self.value = value + + def unproxy(self, base): + if self.value == NextEthernetAddr: + self.addr = self.value().value + return self + + def __str__(self): + if self.value == NextEthernetAddr: + if hasattr(self, 'addr'): + return self.addr + else: + return "NextEthernetAddr (unresolved)" + else: + return self.value + +# Special class for NULL pointers. Note the special check in +# make_param_value() above that lets these be assigned where a +# SimObject is required. +# only one copy of a particular node +class NullSimObject(object): + __metaclass__ = Singleton + + def __call__(cls): + return cls + + def _instantiate(self, parent = None, path = ''): + pass + + def ini_str(self): + return 'Null' + + def unproxy(self, base): + return self + + def set_path(self, parent, name): + pass + def __str__(self): + return 'Null' + +# The only instance you'll ever need... +Null = NULL = NullSimObject() + +# Enumerated types are a little more complex. The user specifies the +# type as Enum(foo) where foo is either a list or dictionary of +# alternatives (typically strings, but not necessarily so). (In the +# long run, the integer value of the parameter will be the list index +# or the corresponding dictionary value. For now, since we only check +# that the alternative is valid and then spit it into a .ini file, +# there's not much point in using the dictionary.) + +# What Enum() must do is generate a new type encapsulating the +# provided list/dictionary so that specific values of the parameter +# can be instances of that type. We define two hidden internal +# classes (_ListEnum and _DictEnum) to serve as base classes, then +# derive the new type from the appropriate base class on the fly. + + +# Metaclass for Enum types +class MetaEnum(type): + def __init__(cls, name, bases, init_dict): + if init_dict.has_key('map'): + if not isinstance(cls.map, dict): + raise TypeError, "Enum-derived class attribute 'map' " \ + "must be of type dict" + # build list of value strings from map + cls.vals = cls.map.keys() + cls.vals.sort() + elif init_dict.has_key('vals'): + if not isinstance(cls.vals, list): + raise TypeError, "Enum-derived class attribute 'vals' " \ + "must be of type list" + # build string->value map from vals sequence + cls.map = {} + for idx,val in enumerate(cls.vals): + cls.map[val] = idx + else: + raise TypeError, "Enum-derived class must define "\ + "attribute 'map' or 'vals'" + + super(MetaEnum, cls).__init__(name, bases, init_dict) + + def cpp_declare(cls): + s = 'enum %s {\n ' % cls.__name__ + s += ',\n '.join(['%s = %d' % (v,cls.map[v]) for v in cls.vals]) + s += '\n};\n' + return s + +# Base class for enum types. +class Enum(ParamValue): + __metaclass__ = MetaEnum + vals = [] + + def __init__(self, value): + if value not in self.map: + raise TypeError, "Enum param got bad value '%s' (not in %s)" \ + % (value, self.vals) + self.value = value + + def __str__(self): + return self.value + +ticks_per_sec = None + +# how big does a rounding error need to be before we warn about it? +frequency_tolerance = 0.001 # 0.1% + +# convert a floting-point # of ticks to integer, and warn if rounding +# discards too much precision +def tick_check(float_ticks): + if float_ticks == 0: + return 0 + int_ticks = int(round(float_ticks)) + err = (float_ticks - int_ticks) / float_ticks + if err > frequency_tolerance: + print >> sys.stderr, "Warning: rounding error > tolerance" + print >> sys.stderr, " %f rounded to %d" % (float_ticks, int_ticks) + #raise ValueError + return int_ticks + +def getLatency(value): + if isinstance(value, Latency) or isinstance(value, Clock): + return value.value + elif isinstance(value, Frequency) or isinstance(value, RootClock): + return 1 / value.value + elif isinstance(value, str): + try: + return toLatency(value) + except ValueError: + try: + return 1 / toFrequency(value) + except ValueError: + pass # fall through + raise ValueError, "Invalid Frequency/Latency value '%s'" % value + + +class Latency(NumericParamValue): + def __init__(self, value): + self.value = getLatency(value) + + def __getattr__(self, attr): + if attr in ('latency', 'period'): + return self + if attr == 'frequency': + return Frequency(self) + raise AttributeError, "Latency object has no attribute '%s'" % attr + + # convert latency to ticks + def ini_str(self): + return str(tick_check(self.value * ticks_per_sec)) + +class Frequency(NumericParamValue): + def __init__(self, value): + self.value = 1 / getLatency(value) + + def __getattr__(self, attr): + if attr == 'frequency': + return self + if attr in ('latency', 'period'): + return Latency(self) + raise AttributeError, "Frequency object has no attribute '%s'" % attr + + # convert frequency to ticks per period + def ini_str(self): + return self.period.ini_str() + +# Just like Frequency, except ini_str() is absolute # of ticks per sec (Hz). +# We can't inherit from Frequency because we don't want it to be directly +# assignable to a regular Frequency parameter. +class RootClock(ParamValue): + def __init__(self, value): + self.value = 1 / getLatency(value) + + def __getattr__(self, attr): + if attr == 'frequency': + return Frequency(self) + if attr in ('latency', 'period'): + return Latency(self) + raise AttributeError, "Frequency object has no attribute '%s'" % attr + + def ini_str(self): + return str(tick_check(self.value)) + +# A generic frequency and/or Latency value. Value is stored as a latency, +# but to avoid ambiguity this object does not support numeric ops (* or /). +# An explicit conversion to a Latency or Frequency must be made first. +class Clock(ParamValue): + def __init__(self, value): + self.value = getLatency(value) + + def __getattr__(self, attr): + if attr == 'frequency': + return Frequency(self) + if attr in ('latency', 'period'): + return Latency(self) + raise AttributeError, "Frequency object has no attribute '%s'" % attr + + def ini_str(self): + return self.period.ini_str() + +class NetworkBandwidth(float,ParamValue): + def __new__(cls, value): + val = toNetworkBandwidth(value) / 8.0 + return super(cls, NetworkBandwidth).__new__(cls, val) + + def __str__(self): + return str(self.val) + + def ini_str(self): + return '%f' % (ticks_per_sec / float(self)) + +class MemoryBandwidth(float,ParamValue): + def __new__(self, value): + val = toMemoryBandwidth(value) + return super(cls, MemoryBandwidth).__new__(cls, val) + + def __str__(self): + return str(self.val) + + def ini_str(self): + return '%f' % (ticks_per_sec / float(self)) + +# +# "Constants"... handy aliases for various values. +# + +# Some memory range specifications use this as a default upper bound. +MaxAddr = Addr.max +MaxTick = Tick.max +AllMemory = AddrRange(0, MaxAddr) + +##################################################################### + +# __all__ defines the list of symbols that get exported when +# 'from config import *' is invoked. Try to keep this reasonably +# short to avoid polluting other namespaces. +__all__ = ['SimObject', 'ParamContext', 'Param', 'VectorParam', + 'Parent', 'Self', + 'Enum', 'Bool', 'String', 'Float', + 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16', + 'Int32', 'UInt32', 'Int64', 'UInt64', + 'Counter', 'Addr', 'Tick', 'Percent', + 'TcpPort', 'UdpPort', 'EthernetAddr', + 'MemorySize', 'MemorySize32', + 'Latency', 'Frequency', 'RootClock', 'Clock', + 'NetworkBandwidth', 'MemoryBandwidth', + 'Range', 'AddrRange', 'MaxAddr', 'MaxTick', 'AllMemory', + 'Null', 'NULL', + 'NextEthernetAddr'] + diff --git a/src/python/m5/convert.py b/src/python/m5/convert.py new file mode 100644 index 000000000..580a579bc --- /dev/null +++ b/src/python/m5/convert.py @@ -0,0 +1,229 @@ +# Copyright (c) 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 + +# metric prefixes +exa = 1.0e18 +peta = 1.0e15 +tera = 1.0e12 +giga = 1.0e9 +mega = 1.0e6 +kilo = 1.0e3 + +milli = 1.0e-3 +micro = 1.0e-6 +nano = 1.0e-9 +pico = 1.0e-12 +femto = 1.0e-15 +atto = 1.0e-18 + +# power of 2 prefixes +kibi = 1024 +mebi = kibi * 1024 +gibi = mebi * 1024 +tebi = gibi * 1024 +pebi = tebi * 1024 +exbi = pebi * 1024 + +# memory size configuration stuff +def toFloat(value): + if not isinstance(value, str): + raise TypeError, "wrong type '%s' should be str" % type(value) + + if value.endswith('Ei'): + return float(value[:-2]) * exbi + elif value.endswith('Pi'): + return float(value[:-2]) * pebi + elif value.endswith('Ti'): + return float(value[:-2]) * tebi + elif value.endswith('Gi'): + return float(value[:-2]) * gibi + elif value.endswith('Mi'): + return float(value[:-2]) * mebi + elif value.endswith('ki'): + return float(value[:-2]) * kibi + elif value.endswith('E'): + return float(value[:-1]) * exa + elif value.endswith('P'): + return float(value[:-1]) * peta + elif value.endswith('T'): + return float(value[:-1]) * tera + elif value.endswith('G'): + return float(value[:-1]) * giga + elif value.endswith('M'): + return float(value[:-1]) * mega + elif value.endswith('k'): + return float(value[:-1]) * kilo + elif value.endswith('m'): + return float(value[:-1]) * milli + elif value.endswith('u'): + return float(value[:-1]) * micro + elif value.endswith('n'): + return float(value[:-1]) * nano + elif value.endswith('p'): + return float(value[:-1]) * pico + elif value.endswith('f'): + return float(value[:-1]) * femto + else: + return float(value) + +def toInteger(value): + value = toFloat(value) + result = long(value) + if value != result: + raise ValueError, "cannot convert '%s' to integer" % value + + return result + +_bool_dict = { + 'true' : True, 't' : True, 'yes' : True, 'y' : True, '1' : True, + 'false' : False, 'f' : False, 'no' : False, 'n' : False, '0' : False + } + +def toBool(value): + if not isinstance(value, str): + raise TypeError, "wrong type '%s' should be str" % type(value) + + value = value.lower() + result = _bool_dict.get(value, None) + if result == None: + raise ValueError, "cannot convert '%s' to bool" % value + return result + +def toFrequency(value): + if not isinstance(value, str): + raise TypeError, "wrong type '%s' should be str" % type(value) + + if value.endswith('THz'): + return float(value[:-3]) * tera + elif value.endswith('GHz'): + return float(value[:-3]) * giga + elif value.endswith('MHz'): + return float(value[:-3]) * mega + elif value.endswith('kHz'): + return float(value[:-3]) * kilo + elif value.endswith('Hz'): + return float(value[:-2]) + + raise ValueError, "cannot convert '%s' to frequency" % value + +def toLatency(value): + if not isinstance(value, str): + raise TypeError, "wrong type '%s' should be str" % type(value) + + if value.endswith('ps'): + return float(value[:-2]) * pico + elif value.endswith('ns'): + return float(value[:-2]) * nano + elif value.endswith('us'): + return float(value[:-2]) * micro + elif value.endswith('ms'): + return float(value[:-2]) * milli + elif value.endswith('s'): + return float(value[:-1]) + + raise ValueError, "cannot convert '%s' to latency" % value + +def toClockPeriod(value): + """result is a clock period""" + + if not isinstance(value, str): + raise TypeError, "wrong type '%s' should be str" % type(value) + + try: + val = toFrequency(value) + if val != 0: + val = 1 / val + return val + except ValueError: + pass + + try: + val = toLatency(value) + return val + except ValueError: + pass + + raise ValueError, "cannot convert '%s' to clock period" % value + + +def toNetworkBandwidth(value): + if not isinstance(value, str): + raise TypeError, "wrong type '%s' should be str" % type(value) + + if value.endswith('Tbps'): + return float(value[:-4]) * tera + elif value.endswith('Gbps'): + return float(value[:-4]) * giga + elif value.endswith('Mbps'): + return float(value[:-4]) * mega + elif value.endswith('kbps'): + return float(value[:-4]) * kilo + elif value.endswith('bps'): + return float(value[:-3]) + else: + return float(value) + + raise ValueError, "cannot convert '%s' to network bandwidth" % value + +def toMemoryBandwidth(value): + if not isinstance(value, str): + raise TypeError, "wrong type '%s' should be str" % type(value) + + if value.endswith('PB/s'): + return float(value[:-4]) * pebi + elif value.endswith('TB/s'): + return float(value[:-4]) * tebi + elif value.endswith('GB/s'): + return float(value[:-4]) * gibi + elif value.endswith('MB/s'): + return float(value[:-4]) * mebi + elif value.endswith('kB/s'): + return float(value[:-4]) * kibi + elif value.endswith('B/s'): + return float(value[:-3]) + + raise ValueError, "cannot convert '%s' to memory bandwidth" % value + +def toMemorySize(value): + if not isinstance(value, str): + raise TypeError, "wrong type '%s' should be str" % type(value) + + if value.endswith('PB'): + return long(value[:-2]) * pebi + elif value.endswith('TB'): + return long(value[:-2]) * tebi + elif value.endswith('GB'): + return long(value[:-2]) * gibi + elif value.endswith('MB'): + return long(value[:-2]) * mebi + elif value.endswith('kB'): + return long(value[:-2]) * kibi + elif value.endswith('B'): + return long(value[:-1]) + + raise ValueError, "cannot convert '%s' to memory size" % value diff --git a/src/python/m5/multidict.py b/src/python/m5/multidict.py new file mode 100644 index 000000000..34fc3139b --- /dev/null +++ b/src/python/m5/multidict.py @@ -0,0 +1,186 @@ +# Copyright (c) 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 + +__all__ = [ 'multidict' ] + +class multidict(object): + __nodefault = object() + def __init__(self, parent = {}, **kwargs): + self.local = dict(**kwargs) + self.parent = parent + self.deleted = {} + + def __str__(self): + return str(dict(self.items())) + + def __repr__(self): + return `dict(self.items())` + + def __contains__(self, key): + return self.local.has_key(key) or self.parent.has_key(key) + + def __delitem__(self, key): + try: + del self.local[key] + except KeyError, e: + if key in self.parent: + self.deleted[key] = True + else: + raise KeyError, e + + def __setitem__(self, key, value): + self.deleted.pop(key, False) + self.local[key] = value + + def __getitem__(self, key): + try: + return self.local[key] + except KeyError, e: + if not self.deleted.get(key, False) and key in self.parent: + return self.parent[key] + else: + raise KeyError, e + + def __len__(self): + return len(self.local) + len(self.parent) + + def next(self): + for key,value in self.local.items(): + yield key,value + + if self.parent: + for key,value in self.parent.next(): + if key not in self.local and key not in self.deleted: + yield key,value + + def has_key(self, key): + return key in self + + def iteritems(self): + for item in self.next(): + yield item + + def items(self): + return [ item for item in self.next() ] + + def iterkeys(self): + for key,value in self.next(): + yield key + + def keys(self): + return [ key for key,value in self.next() ] + + def itervalues(self): + for key,value in self.next(): + yield value + + def values(self): + return [ value for key,value in self.next() ] + + def get(self, key, default=__nodefault): + try: + return self[key] + except KeyError, e: + if default != self.__nodefault: + return default + else: + raise KeyError, e + + def setdefault(self, key, default): + try: + return self[key] + except KeyError: + self.deleted.pop(key, False) + self.local[key] = default + return default + + def _dump(self): + print 'multidict dump' + node = self + while isinstance(node, multidict): + print ' ', node.local + node = node.parent + + def _dumpkey(self, key): + values = [] + node = self + while isinstance(node, multidict): + if key in node.local: + values.append(node.local[key]) + node = node.parent + print key, values + +if __name__ == '__main__': + test1 = multidict() + test2 = multidict(test1) + test3 = multidict(test2) + test4 = multidict(test3) + + test1['a'] = 'test1_a' + test1['b'] = 'test1_b' + test1['c'] = 'test1_c' + test1['d'] = 'test1_d' + test1['e'] = 'test1_e' + + test2['a'] = 'test2_a' + del test2['b'] + test2['c'] = 'test2_c' + del test1['a'] + + test2.setdefault('f', multidict) + + print 'test1>', test1.items() + print 'test2>', test2.items() + #print test1['a'] + print test1['b'] + print test1['c'] + print test1['d'] + print test1['e'] + + print test2['a'] + #print test2['b'] + print test2['c'] + print test2['d'] + print test2['e'] + + for key in test2.iterkeys(): + print key + + test2.get('g', 'foo') + #test2.get('b') + test2.get('b', 'bar') + test2.setdefault('b', 'blah') + print test1 + print test2 + print `test2` + + print len(test2) + + test3['a'] = [ 0, 1, 2, 3 ] + + print test4 diff --git a/src/python/m5/objects/AlphaConsole.py b/src/python/m5/objects/AlphaConsole.py new file mode 100644 index 000000000..329b8c5bd --- /dev/null +++ b/src/python/m5/objects/AlphaConsole.py @@ -0,0 +1,9 @@ +from m5.config import * +from Device import BasicPioDevice + +class AlphaConsole(BasicPioDevice): + type = 'AlphaConsole' + cpu = Param.BaseCPU(Parent.any, "Processor") + disk = Param.SimpleDisk("Simple Disk") + sim_console = Param.SimConsole(Parent.any, "The Simulator Console") + system = Param.AlphaSystem(Parent.any, "system object") diff --git a/src/python/m5/objects/AlphaFullCPU.py b/src/python/m5/objects/AlphaFullCPU.py new file mode 100644 index 000000000..2988305d3 --- /dev/null +++ b/src/python/m5/objects/AlphaFullCPU.py @@ -0,0 +1,98 @@ +from m5 import build_env +from m5.config import * +from BaseCPU import BaseCPU + +class DerivAlphaFullCPU(BaseCPU): + type = 'DerivAlphaFullCPU' + activity = Param.Unsigned("Initial count") + numThreads = Param.Unsigned("number of HW thread contexts") + + checker = Param.BaseCPU(NULL, "checker") + + cachePorts = Param.Unsigned("Cache Ports") + + decodeToFetchDelay = Param.Unsigned("Decode to fetch delay") + renameToFetchDelay = Param.Unsigned("Rename to fetch delay") + iewToFetchDelay = Param.Unsigned("Issue/Execute/Writeback to fetch " + "delay") + commitToFetchDelay = Param.Unsigned("Commit to fetch delay") + fetchWidth = Param.Unsigned("Fetch width") + + renameToDecodeDelay = Param.Unsigned("Rename to decode delay") + iewToDecodeDelay = Param.Unsigned("Issue/Execute/Writeback to decode " + "delay") + commitToDecodeDelay = Param.Unsigned("Commit to decode delay") + fetchToDecodeDelay = Param.Unsigned("Fetch to decode delay") + decodeWidth = Param.Unsigned("Decode width") + + iewToRenameDelay = Param.Unsigned("Issue/Execute/Writeback to rename " + "delay") + commitToRenameDelay = Param.Unsigned("Commit to rename delay") + decodeToRenameDelay = Param.Unsigned("Decode to rename delay") + renameWidth = Param.Unsigned("Rename width") + + commitToIEWDelay = Param.Unsigned("Commit to " + "Issue/Execute/Writeback delay") + renameToIEWDelay = Param.Unsigned("Rename to " + "Issue/Execute/Writeback delay") + issueToExecuteDelay = Param.Unsigned("Issue to execute delay (internal " + "to the IEW stage)") + issueWidth = Param.Unsigned("Issue width") + executeWidth = Param.Unsigned("Execute width") + executeIntWidth = Param.Unsigned("Integer execute width") + executeFloatWidth = Param.Unsigned("Floating point execute width") + executeBranchWidth = Param.Unsigned("Branch execute width") + executeMemoryWidth = Param.Unsigned("Memory execute width") + fuPool = Param.FUPool(NULL, "Functional Unit pool") + + iewToCommitDelay = Param.Unsigned("Issue/Execute/Writeback to commit " + "delay") + renameToROBDelay = Param.Unsigned("Rename to reorder buffer delay") + commitWidth = Param.Unsigned("Commit width") + squashWidth = Param.Unsigned("Squash width") + trapLatency = Param.Tick("Trap latency") + fetchTrapLatency = Param.Tick("Fetch trap latency") + + predType = Param.String("Branch predictor type ('local', 'tournament')") + localPredictorSize = Param.Unsigned("Size of local predictor") + localCtrBits = Param.Unsigned("Bits per counter") + localHistoryTableSize = Param.Unsigned("Size of local history table") + localHistoryBits = Param.Unsigned("Bits for the local history") + globalPredictorSize = Param.Unsigned("Size of global predictor") + globalCtrBits = Param.Unsigned("Bits per counter") + globalHistoryBits = Param.Unsigned("Bits of history") + choicePredictorSize = Param.Unsigned("Size of choice predictor") + choiceCtrBits = Param.Unsigned("Bits of choice counters") + + BTBEntries = Param.Unsigned("Number of BTB entries") + BTBTagSize = Param.Unsigned("Size of the BTB tags, in bits") + + RASSize = Param.Unsigned("RAS size") + + LQEntries = Param.Unsigned("Number of load queue entries") + SQEntries = Param.Unsigned("Number of store queue entries") + LFSTSize = Param.Unsigned("Last fetched store table size") + SSITSize = Param.Unsigned("Store set ID table size") + + numRobs = Param.Unsigned("Number of Reorder Buffers"); + + numPhysIntRegs = Param.Unsigned("Number of physical integer registers") + numPhysFloatRegs = Param.Unsigned("Number of physical floating point " + "registers") + numIQEntries = Param.Unsigned("Number of instruction queue entries") + numROBEntries = Param.Unsigned("Number of reorder buffer entries") + + instShiftAmt = Param.Unsigned("Number of bits to shift instructions by") + + function_trace = Param.Bool(False, "Enable function trace") + function_trace_start = Param.Tick(0, "Cycle to start function trace") + + smtNumFetchingThreads = Param.Unsigned("SMT Number of Fetching Threads") + smtFetchPolicy = Param.String("SMT Fetch policy") + smtLSQPolicy = Param.String("SMT LSQ Sharing Policy") + smtLSQThreshold = Param.String("SMT LSQ Threshold Sharing Parameter") + smtIQPolicy = Param.String("SMT IQ Sharing Policy") + smtIQThreshold = Param.String("SMT IQ Threshold Sharing Parameter") + smtROBPolicy = Param.String("SMT ROB Sharing Policy") + smtROBThreshold = Param.String("SMT ROB Threshold Sharing Parameter") + smtCommitPolicy = Param.String("SMT Commit Policy") diff --git a/src/python/m5/objects/AlphaTLB.py b/src/python/m5/objects/AlphaTLB.py new file mode 100644 index 000000000..11c1792ee --- /dev/null +++ b/src/python/m5/objects/AlphaTLB.py @@ -0,0 +1,13 @@ +from m5.config import * +class AlphaTLB(SimObject): + type = 'AlphaTLB' + abstract = True + size = Param.Int("TLB size") + +class AlphaDTB(AlphaTLB): + type = 'AlphaDTB' + size = 64 + +class AlphaITB(AlphaTLB): + type = 'AlphaITB' + size = 48 diff --git a/src/python/m5/objects/BadDevice.py b/src/python/m5/objects/BadDevice.py new file mode 100644 index 000000000..186b733fa --- /dev/null +++ b/src/python/m5/objects/BadDevice.py @@ -0,0 +1,6 @@ +from m5.config import * +from Device import BasicPioDevice + +class BadDevice(BasicPioDevice): + type = 'BadDevice' + devicename = Param.String("Name of device to error on") diff --git a/src/python/m5/objects/BaseCPU.py b/src/python/m5/objects/BaseCPU.py new file mode 100644 index 000000000..2e78578df --- /dev/null +++ b/src/python/m5/objects/BaseCPU.py @@ -0,0 +1,29 @@ +from m5 import build_env +from m5.config import * + +class BaseCPU(SimObject): + type = 'BaseCPU' + abstract = True + mem = Param.MemObject("memory") + + if build_env['FULL_SYSTEM']: + dtb = Param.AlphaDTB("Data TLB") + itb = Param.AlphaITB("Instruction TLB") + system = Param.System(Parent.any, "system object") + cpu_id = Param.Int(-1, "CPU identifier") + else: + workload = VectorParam.Process("processes to run") + + 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") + + defer_registration = Param.Bool(False, + "defer registration with system (for sampling)") + + clock = Param.Clock(Parent.clock, "clock speed") diff --git a/src/python/m5/objects/BaseCache.py b/src/python/m5/objects/BaseCache.py new file mode 100644 index 000000000..33f44759b --- /dev/null +++ b/src/python/m5/objects/BaseCache.py @@ -0,0 +1,65 @@ +from m5.config import * +from BaseMem import BaseMem + +class Prefetch(Enum): vals = ['none', 'tagged', 'stride', 'ghb'] + +class BaseCache(BaseMem): + type = 'BaseCache' + adaptive_compression = Param.Bool(False, + "Use an adaptive compression scheme") + assoc = Param.Int("associativity") + block_size = Param.Int("block size in bytes") + compressed_bus = Param.Bool(False, + "This cache connects to a compressed memory") + compression_latency = Param.Latency('0ns', + "Latency in cycles of compression algorithm") + do_copy = Param.Bool(False, "perform fast copies in the cache") + hash_delay = Param.Int(1, "time in cycles of hash access") + in_bus = Param.Bus(NULL, "incoming bus object") + lifo = Param.Bool(False, + "whether this NIC partition should use LIFO repl. policy") + max_miss_count = Param.Counter(0, + "number of misses to handle before calling exit") + mem_trace = Param.MemTraceWriter(NULL, + "memory trace writer to record accesses") + mshrs = Param.Int("number of MSHRs (max outstanding requests)") + out_bus = Param.Bus("outgoing bus object") + prioritizeRequests = Param.Bool(False, + "always service demand misses first") + protocol = Param.CoherenceProtocol(NULL, "coherence protocol to use") + repl = Param.Repl(NULL, "replacement policy") + size = Param.MemorySize("capacity in bytes") + split = Param.Bool(False, "whether or not this cache is split") + split_size = Param.Int(0, + "How many ways of the cache belong to CPU/LRU partition") + store_compressed = Param.Bool(False, + "Store compressed data in the cache") + subblock_size = Param.Int(0, + "Size of subblock in IIC used for compression") + tgts_per_mshr = Param.Int("max number of accesses per MSHR") + trace_addr = Param.Addr(0, "address to trace") + two_queue = Param.Bool(False, + "whether the lifo should have two queue replacement") + write_buffers = Param.Int(8, "number of write buffers") + prefetch_miss = Param.Bool(False, + "wheter you are using the hardware prefetcher from Miss stream") + prefetch_access = Param.Bool(False, + "wheter you are using the hardware prefetcher from Access stream") + prefetcher_size = Param.Int(100, + "Number of entries in the harware prefetch queue") + prefetch_past_page = Param.Bool(False, + "Allow prefetches to cross virtual page boundaries") + prefetch_serial_squash = Param.Bool(False, + "Squash prefetches with a later time on a subsequent miss") + prefetch_degree = Param.Int(1, + "Degree of the prefetch depth") + prefetch_latency = Param.Tick(10, + "Latency of the prefetcher") + prefetch_policy = Param.Prefetch('none', + "Type of prefetcher to use") + prefetch_cache_check_push = Param.Bool(True, + "Check if in cash on push or pop of prefetch queue") + prefetch_use_cpu_id = Param.Bool(True, + "Use the CPU ID to seperate calculations of prefetches") + prefetch_data_accesses_only = Param.Bool(False, + "Only prefetch on data not on instruction accesses") diff --git a/src/python/m5/objects/Bridge.py b/src/python/m5/objects/Bridge.py new file mode 100644 index 000000000..880535755 --- /dev/null +++ b/src/python/m5/objects/Bridge.py @@ -0,0 +1,9 @@ +from m5.config import * +from MemObject import MemObject + +class Bridge(MemObject): + type = 'Bridge' + queue_size_a = Param.Int(16, "The number of requests to buffer") + queue_size_b = Param.Int(16, "The number of requests to buffer") + delay = Param.Latency('0ns', "The latency of this bridge") + write_ack = Param.Bool(False, "Should this bridge ack writes") diff --git a/src/python/m5/objects/Bus.py b/src/python/m5/objects/Bus.py new file mode 100644 index 000000000..c37dab438 --- /dev/null +++ b/src/python/m5/objects/Bus.py @@ -0,0 +1,6 @@ +from m5.config import * +from MemObject import MemObject + +class Bus(MemObject): + type = 'Bus' + bus_id = Param.Int(0, "blah") diff --git a/src/python/m5/objects/CoherenceProtocol.py b/src/python/m5/objects/CoherenceProtocol.py new file mode 100644 index 000000000..64b6cbacf --- /dev/null +++ b/src/python/m5/objects/CoherenceProtocol.py @@ -0,0 +1,7 @@ +from m5.config import * +class Coherence(Enum): vals = ['uni', 'msi', 'mesi', 'mosi', 'moesi'] + +class CoherenceProtocol(SimObject): + type = 'CoherenceProtocol' + do_upgrades = Param.Bool(True, "use upgrade transactions?") + protocol = Param.Coherence("name of coherence protocol") diff --git a/src/python/m5/objects/Device.py b/src/python/m5/objects/Device.py new file mode 100644 index 000000000..7798f5f04 --- /dev/null +++ b/src/python/m5/objects/Device.py @@ -0,0 +1,18 @@ +from m5.config import * +from MemObject import MemObject + +class PioDevice(MemObject): + type = 'PioDevice' + abstract = True + platform = Param.Platform(Parent.any, "Platform this device is part of") + system = Param.System(Parent.any, "System this device is part of") + +class BasicPioDevice(PioDevice): + type = 'BasicPioDevice' + abstract = True + pio_addr = Param.Addr("Device Address") + pio_latency = Param.Tick(1, "Programmed IO latency in simticks") + +class DmaDevice(PioDevice): + type = 'DmaDevice' + abstract = True diff --git a/src/python/m5/objects/DiskImage.py b/src/python/m5/objects/DiskImage.py new file mode 100644 index 000000000..70d8b2e45 --- /dev/null +++ b/src/python/m5/objects/DiskImage.py @@ -0,0 +1,15 @@ +from m5.config import * +class DiskImage(SimObject): + type = 'DiskImage' + abstract = True + image_file = Param.String("disk image file") + read_only = Param.Bool(False, "read only image") + +class RawDiskImage(DiskImage): + type = 'RawDiskImage' + +class CowDiskImage(DiskImage): + type = 'CowDiskImage' + child = Param.DiskImage("child image") + table_size = Param.Int(65536, "initial table size") + image_file = '' diff --git a/src/python/m5/objects/Ethernet.py b/src/python/m5/objects/Ethernet.py new file mode 100644 index 000000000..418670592 --- /dev/null +++ b/src/python/m5/objects/Ethernet.py @@ -0,0 +1,116 @@ +from m5 import build_env +from m5.config import * +from Device import DmaDevice +from Pci import PciDevice + +class EtherInt(SimObject): + type = 'EtherInt' + abstract = True + peer = Param.EtherInt(NULL, "peer interface") + +class EtherLink(SimObject): + type = 'EtherLink' + int1 = Param.EtherInt("interface 1") + int2 = Param.EtherInt("interface 2") + delay = Param.Latency('0us', "packet transmit delay") + delay_var = Param.Latency('0ns', "packet transmit delay variability") + speed = Param.NetworkBandwidth('1Gbps', "link speed") + dump = Param.EtherDump(NULL, "dump object") + +class EtherBus(SimObject): + type = 'EtherBus' + loopback = Param.Bool(True, "send packet back to the sending interface") + dump = Param.EtherDump(NULL, "dump object") + speed = Param.NetworkBandwidth('100Mbps', "bus speed in bits per second") + +class EtherTap(EtherInt): + type = 'EtherTap' + bufsz = Param.Int(10000, "tap buffer size") + dump = Param.EtherDump(NULL, "dump object") + port = Param.UInt16(3500, "tap port") + +class EtherDump(SimObject): + type = 'EtherDump' + file = Param.String("dump file") + maxlen = Param.Int(96, "max portion of packet data to dump") + +if build_env['ALPHA_TLASER']: + + class EtherDev(DmaDevice): + type = 'EtherDev' + hardware_address = Param.EthernetAddr(NextEthernetAddr, + "Ethernet Hardware Address") + + dma_data_free = Param.Bool(False, "DMA of Data is free") + dma_desc_free = Param.Bool(False, "DMA of Descriptors is free") + dma_read_delay = Param.Latency('0us', "fixed delay for dma reads") + dma_read_factor = Param.Latency('0us', "multiplier for dma reads") + dma_write_delay = Param.Latency('0us', "fixed delay for dma writes") + dma_write_factor = Param.Latency('0us', "multiplier for dma writes") + dma_no_allocate = Param.Bool(True, "Should we allocate cache on read") + + rx_filter = Param.Bool(True, "Enable Receive Filter") + rx_delay = Param.Latency('1us', "Receive Delay") + tx_delay = Param.Latency('1us', "Transmit Delay") + + intr_delay = Param.Latency('0us', "Interrupt Delay") + payload_bus = Param.Bus(NULL, "The IO Bus to attach to for payload") + physmem = Param.PhysicalMemory(Parent.any, "Physical Memory") + tlaser = Param.Turbolaser(Parent.any, "Turbolaser") + + class EtherDevInt(EtherInt): + type = 'EtherDevInt' + device = Param.EtherDev("Ethernet device of this interface") + +class EtherDevBase(PciDevice): + hardware_address = Param.EthernetAddr(NextEthernetAddr, + "Ethernet Hardware Address") + + clock = Param.Clock('0ns', "State machine processor frequency") + + dma_read_delay = Param.Latency('0us', "fixed delay for dma reads") + dma_read_factor = Param.Latency('0us', "multiplier for dma reads") + dma_write_delay = Param.Latency('0us', "fixed delay for dma writes") + dma_write_factor = Param.Latency('0us', "multiplier for dma writes") + + rx_delay = Param.Latency('1us', "Receive Delay") + tx_delay = Param.Latency('1us', "Transmit Delay") + rx_fifo_size = Param.MemorySize('512kB', "max size of rx fifo") + tx_fifo_size = Param.MemorySize('512kB', "max size of tx fifo") + + rx_filter = Param.Bool(True, "Enable Receive Filter") + intr_delay = Param.Latency('10us', "Interrupt propagation delay") + rx_thread = Param.Bool(False, "dedicated kernel thread for transmit") + tx_thread = Param.Bool(False, "dedicated kernel threads for receive") + rss = Param.Bool(False, "Receive Side Scaling") + +class NSGigE(EtherDevBase): + type = 'NSGigE' + + dma_data_free = Param.Bool(False, "DMA of Data is free") + dma_desc_free = Param.Bool(False, "DMA of Descriptors is free") + dma_no_allocate = Param.Bool(True, "Should we allocate cache on read") + + +class NSGigEInt(EtherInt): + type = 'NSGigEInt' + device = Param.NSGigE("Ethernet device of this interface") + +class Sinic(EtherDevBase): + type = 'Sinic' + + rx_max_copy = Param.MemorySize('1514B', "rx max copy") + tx_max_copy = Param.MemorySize('16kB', "tx max copy") + rx_max_intr = Param.UInt32(10, "max rx packets per interrupt") + rx_fifo_threshold = Param.MemorySize('384kB', "rx fifo high threshold") + rx_fifo_low_mark = Param.MemorySize('128kB', "rx fifo low threshold") + tx_fifo_high_mark = Param.MemorySize('384kB', "tx fifo high threshold") + tx_fifo_threshold = Param.MemorySize('128kB', "tx fifo low threshold") + virtual_count = Param.UInt32(1, "Virtualized SINIC") + zero_copy = Param.Bool(False, "Zero copy receive") + delay_copy = Param.Bool(False, "Delayed copy transmit") + virtual_addr = Param.Bool(False, "Virtual addressing") + +class SinicInt(EtherInt): + type = 'SinicInt' + device = Param.Sinic("Ethernet device of this interface") diff --git a/src/python/m5/objects/FUPool.py b/src/python/m5/objects/FUPool.py new file mode 100644 index 000000000..cbf1089cf --- /dev/null +++ b/src/python/m5/objects/FUPool.py @@ -0,0 +1,5 @@ +from m5.config import * + +class FUPool(SimObject): + type = 'FUPool' + FUList = VectorParam.FUDesc("list of FU's for this pool") diff --git a/src/python/m5/objects/Ide.py b/src/python/m5/objects/Ide.py new file mode 100644 index 000000000..9ee578177 --- /dev/null +++ b/src/python/m5/objects/Ide.py @@ -0,0 +1,14 @@ +from m5.config import * +from Pci import PciDevice + +class IdeID(Enum): vals = ['master', 'slave'] + +class IdeDisk(SimObject): + type = 'IdeDisk' + delay = Param.Latency('1us', "Fixed disk delay in microseconds") + driveID = Param.IdeID('master', "Drive ID") + image = Param.DiskImage("Disk image") + +class IdeController(PciDevice): + type = 'IdeController' + disks = VectorParam.IdeDisk("IDE disks attached to this controller") diff --git a/src/python/m5/objects/IntrControl.py b/src/python/m5/objects/IntrControl.py new file mode 100644 index 000000000..514c3fc62 --- /dev/null +++ b/src/python/m5/objects/IntrControl.py @@ -0,0 +1,4 @@ +from m5.config import * +class IntrControl(SimObject): + type = 'IntrControl' + cpu = Param.BaseCPU(Parent.any, "the cpu") diff --git a/src/python/m5/objects/MemObject.py b/src/python/m5/objects/MemObject.py new file mode 100644 index 000000000..d957dae17 --- /dev/null +++ b/src/python/m5/objects/MemObject.py @@ -0,0 +1,5 @@ +from m5.config import * + +class MemObject(SimObject): + type = 'MemObject' + abstract = True diff --git a/src/python/m5/objects/MemTest.py b/src/python/m5/objects/MemTest.py new file mode 100644 index 000000000..9916d7cb4 --- /dev/null +++ b/src/python/m5/objects/MemTest.py @@ -0,0 +1,19 @@ +from m5.config import * +class MemTest(SimObject): + type = 'MemTest' + cache = Param.BaseCache("L1 cache") + check_mem = Param.FunctionalMemory("check memory") + main_mem = Param.FunctionalMemory("hierarchical memory") + max_loads = Param.Counter("number of loads to execute") + memory_size = Param.Int(65536, "memory size") + percent_copies = Param.Percent(0, "target copy percentage") + percent_dest_unaligned = Param.Percent(50, + "percent of copy dest address that are unaligned") + percent_reads = Param.Percent(65, "target read percentage") + percent_source_unaligned = Param.Percent(50, + "percent of copy source address that are unaligned") + percent_uncacheable = Param.Percent(10, + "target uncacheable percentage") + progress_interval = Param.Counter(1000000, + "progress report interval (in accesses)") + trace_addr = Param.Addr(0, "address to trace") diff --git a/src/python/m5/objects/OzoneCPU.py b/src/python/m5/objects/OzoneCPU.py new file mode 100644 index 000000000..f2d9aea84 --- /dev/null +++ b/src/python/m5/objects/OzoneCPU.py @@ -0,0 +1,91 @@ +from m5 import build_env +from m5.config import * +from BaseCPU import BaseCPU + +class DerivOzoneCPU(BaseCPU): + type = 'DerivOzoneCPU' + + numThreads = Param.Unsigned("number of HW thread contexts") + + if not build_env['FULL_SYSTEM']: + mem = Param.FunctionalMemory(NULL, "memory") + + checker = Param.BaseCPU("Checker CPU") + + width = Param.Unsigned("Width") + frontEndWidth = Param.Unsigned("Front end width") + backEndWidth = Param.Unsigned("Back end width") + backEndSquashLatency = Param.Unsigned("Back end squash latency") + backEndLatency = Param.Unsigned("Back end latency") + maxInstBufferSize = Param.Unsigned("Maximum instruction buffer size") + maxOutstandingMemOps = Param.Unsigned("Maximum number of outstanding memory operations") + decodeToFetchDelay = Param.Unsigned("Decode to fetch delay") + renameToFetchDelay = Param.Unsigned("Rename to fetch delay") + iewToFetchDelay = Param.Unsigned("Issue/Execute/Writeback to fetch " + "delay") + commitToFetchDelay = Param.Unsigned("Commit to fetch delay") + fetchWidth = Param.Unsigned("Fetch width") + + renameToDecodeDelay = Param.Unsigned("Rename to decode delay") + iewToDecodeDelay = Param.Unsigned("Issue/Execute/Writeback to decode " + "delay") + commitToDecodeDelay = Param.Unsigned("Commit to decode delay") + fetchToDecodeDelay = Param.Unsigned("Fetch to decode delay") + decodeWidth = Param.Unsigned("Decode width") + + iewToRenameDelay = Param.Unsigned("Issue/Execute/Writeback to rename " + "delay") + commitToRenameDelay = Param.Unsigned("Commit to rename delay") + decodeToRenameDelay = Param.Unsigned("Decode to rename delay") + renameWidth = Param.Unsigned("Rename width") + + commitToIEWDelay = Param.Unsigned("Commit to " + "Issue/Execute/Writeback delay") + renameToIEWDelay = Param.Unsigned("Rename to " + "Issue/Execute/Writeback delay") + issueToExecuteDelay = Param.Unsigned("Issue to execute delay (internal " + "to the IEW stage)") + issueWidth = Param.Unsigned("Issue width") + executeWidth = Param.Unsigned("Execute width") + executeIntWidth = Param.Unsigned("Integer execute width") + executeFloatWidth = Param.Unsigned("Floating point execute width") + executeBranchWidth = Param.Unsigned("Branch execute width") + executeMemoryWidth = Param.Unsigned("Memory execute width") + + iewToCommitDelay = Param.Unsigned("Issue/Execute/Writeback to commit " + "delay") + renameToROBDelay = Param.Unsigned("Rename to reorder buffer delay") + commitWidth = Param.Unsigned("Commit width") + squashWidth = Param.Unsigned("Squash width") + + predType = Param.String("Type of branch predictor ('local', 'tournament')") + localPredictorSize = Param.Unsigned("Size of local predictor") + localCtrBits = Param.Unsigned("Bits per counter") + localHistoryTableSize = Param.Unsigned("Size of local history table") + localHistoryBits = Param.Unsigned("Bits for the local history") + globalPredictorSize = Param.Unsigned("Size of global predictor") + globalCtrBits = Param.Unsigned("Bits per counter") + globalHistoryBits = Param.Unsigned("Bits of history") + choicePredictorSize = Param.Unsigned("Size of choice predictor") + choiceCtrBits = Param.Unsigned("Bits of choice counters") + + BTBEntries = Param.Unsigned("Number of BTB entries") + BTBTagSize = Param.Unsigned("Size of the BTB tags, in bits") + + RASSize = Param.Unsigned("RAS size") + + LQEntries = Param.Unsigned("Number of load queue entries") + SQEntries = Param.Unsigned("Number of store queue entries") + LFSTSize = Param.Unsigned("Last fetched store table size") + SSITSize = Param.Unsigned("Store set ID table size") + + numPhysIntRegs = Param.Unsigned("Number of physical integer registers") + numPhysFloatRegs = Param.Unsigned("Number of physical floating point " + "registers") + numIQEntries = Param.Unsigned("Number of instruction queue entries") + numROBEntries = Param.Unsigned("Number of reorder buffer entries") + + instShiftAmt = Param.Unsigned("Number of bits to shift instructions by") + + function_trace = Param.Bool(False, "Enable function trace") + function_trace_start = Param.Tick(0, "Cycle to start function trace") diff --git a/src/python/m5/objects/Pci.py b/src/python/m5/objects/Pci.py new file mode 100644 index 000000000..9e1e91b13 --- /dev/null +++ b/src/python/m5/objects/Pci.py @@ -0,0 +1,55 @@ +from m5.config import * +from Device import BasicPioDevice, DmaDevice + +class PciConfigData(SimObject): + type = 'PciConfigData' + VendorID = Param.UInt16("Vendor ID") + DeviceID = Param.UInt16("Device ID") + Command = Param.UInt16(0, "Command") + Status = Param.UInt16(0, "Status") + Revision = Param.UInt8(0, "Device") + ProgIF = Param.UInt8(0, "Programming Interface") + SubClassCode = Param.UInt8(0, "Sub-Class Code") + ClassCode = Param.UInt8(0, "Class Code") + CacheLineSize = Param.UInt8(0, "System Cacheline Size") + LatencyTimer = Param.UInt8(0, "PCI Latency Timer") + HeaderType = Param.UInt8(0, "PCI Header Type") + BIST = Param.UInt8(0, "Built In Self Test") + + BAR0 = Param.UInt32(0x00, "Base Address Register 0") + BAR1 = Param.UInt32(0x00, "Base Address Register 1") + BAR2 = Param.UInt32(0x00, "Base Address Register 2") + BAR3 = Param.UInt32(0x00, "Base Address Register 3") + BAR4 = Param.UInt32(0x00, "Base Address Register 4") + BAR5 = Param.UInt32(0x00, "Base Address Register 5") + BAR0Size = Param.MemorySize32('0B', "Base Address Register 0 Size") + BAR1Size = Param.MemorySize32('0B', "Base Address Register 1 Size") + BAR2Size = Param.MemorySize32('0B', "Base Address Register 2 Size") + BAR3Size = Param.MemorySize32('0B', "Base Address Register 3 Size") + BAR4Size = Param.MemorySize32('0B', "Base Address Register 4 Size") + BAR5Size = Param.MemorySize32('0B', "Base Address Register 5 Size") + + CardbusCIS = Param.UInt32(0x00, "Cardbus Card Information Structure") + SubsystemID = Param.UInt16(0x00, "Subsystem ID") + SubsystemVendorID = Param.UInt16(0x00, "Subsystem Vendor ID") + ExpansionROM = Param.UInt32(0x00, "Expansion ROM Base Address") + InterruptLine = Param.UInt8(0x00, "Interrupt Line") + InterruptPin = Param.UInt8(0x00, "Interrupt Pin") + MaximumLatency = Param.UInt8(0x00, "Maximum Latency") + MinimumGrant = Param.UInt8(0x00, "Minimum Grant") + +class PciConfigAll(BasicPioDevice): + type = 'PciConfigAll' + +class PciDevice(DmaDevice): + type = 'PciDevice' + abstract = True + pci_bus = Param.Int("PCI bus") + pci_dev = Param.Int("PCI device number") + pci_func = Param.Int("PCI function code") + pio_latency = Param.Tick(1, "Programmed IO latency in simticks") + configdata = Param.PciConfigData(Parent.any, "PCI Config data") + configspace = Param.PciConfigAll(Parent.any, "PCI Configspace") + +class PciFake(PciDevice): + type = 'PciFake' diff --git a/src/python/m5/objects/PhysicalMemory.py b/src/python/m5/objects/PhysicalMemory.py new file mode 100644 index 000000000..bed90d555 --- /dev/null +++ b/src/python/m5/objects/PhysicalMemory.py @@ -0,0 +1,8 @@ +from m5.config import * +from MemObject import * + +class PhysicalMemory(MemObject): + type = 'PhysicalMemory' + range = Param.AddrRange("Device Address") + file = Param.String('', "memory mapped file") + latency = Param.Latency(Parent.clock, "latency of an access") diff --git a/src/python/m5/objects/Platform.py b/src/python/m5/objects/Platform.py new file mode 100644 index 000000000..89fee9991 --- /dev/null +++ b/src/python/m5/objects/Platform.py @@ -0,0 +1,5 @@ +from m5.config import * +class Platform(SimObject): + type = 'Platform' + abstract = True + intrctrl = Param.IntrControl(Parent.any, "interrupt controller") diff --git a/src/python/m5/objects/Process.py b/src/python/m5/objects/Process.py new file mode 100644 index 000000000..0091d8654 --- /dev/null +++ b/src/python/m5/objects/Process.py @@ -0,0 +1,27 @@ +from m5.config import * +class Process(SimObject): + type = 'Process' + abstract = True + output = Param.String('cout', 'filename for stdout/stderr') + system = Param.System(Parent.any, "system process will run on") + +class LiveProcess(Process): + type = 'LiveProcess' + executable = Param.String('', "executable (overrides cmd[0] if set)") + cmd = VectorParam.String("command line (executable plus arguments)") + env = VectorParam.String('', "environment settings") + input = Param.String('cin', "filename for stdin") + +class AlphaLiveProcess(LiveProcess): + type = 'AlphaLiveProcess' + +class SparcLiveProcess(LiveProcess): + type = 'SparcLiveProcess' + +class MipsLiveProcess(LiveProcess): + type = 'MipsLiveProcess' + +class EioProcess(Process): + type = 'EioProcess' + chkpt = Param.String('', "EIO checkpoint file name (optional)") + file = Param.String("EIO trace file name") diff --git a/src/python/m5/objects/Repl.py b/src/python/m5/objects/Repl.py new file mode 100644 index 000000000..8e9f1094f --- /dev/null +++ b/src/python/m5/objects/Repl.py @@ -0,0 +1,10 @@ +from m5.config import * +class Repl(SimObject): + type = 'Repl' + abstract = True + +class GenRepl(Repl): + type = 'GenRepl' + fresh_res = Param.Int("associativity") + num_pools = Param.Int("capacity in bytes") + pool_res = Param.Int("block size in bytes") diff --git a/src/python/m5/objects/Root.py b/src/python/m5/objects/Root.py new file mode 100644 index 000000000..373475a7a --- /dev/null +++ b/src/python/m5/objects/Root.py @@ -0,0 +1,23 @@ +from m5.config import * +from Serialize import Serialize +from Statistics import Statistics +from Trace import Trace +from ExeTrace import ExecutionTrace +from Debug import Debug + +class Root(SimObject): + type = 'Root' + clock = Param.RootClock('200MHz', "tick frequency") + max_tick = Param.Tick('0', "maximum simulation ticks (0 = infinite)") + progress_interval = Param.Tick('0', + "print a progress message every n ticks (0 = never)") + output_file = Param.String('cout', "file to dump simulator output to") + checkpoint = Param.String('', "checkpoint file to load") +# stats = Param.Statistics(Statistics(), "statistics object") +# trace = Param.Trace(Trace(), "trace object") +# serialize = Param.Serialize(Serialize(), "checkpoint generation options") + stats = Statistics() + trace = Trace() + exetrace = ExecutionTrace() + serialize = Serialize() + debug = Debug() diff --git a/src/python/m5/objects/SimConsole.py b/src/python/m5/objects/SimConsole.py new file mode 100644 index 000000000..9e1452c6d --- /dev/null +++ b/src/python/m5/objects/SimConsole.py @@ -0,0 +1,12 @@ +from m5.config import * +class ConsoleListener(SimObject): + type = 'ConsoleListener' + port = Param.TcpPort(3456, "listen port") + +class SimConsole(SimObject): + type = 'SimConsole' + append_name = Param.Bool(True, "append name() to filename") + intr_control = Param.IntrControl(Parent.any, "interrupt controller") + listener = Param.ConsoleListener("console listener") + number = Param.Int(0, "console number") + output = Param.String('console', "file to dump output to") diff --git a/src/python/m5/objects/SimpleDisk.py b/src/python/m5/objects/SimpleDisk.py new file mode 100644 index 000000000..44ef709af --- /dev/null +++ b/src/python/m5/objects/SimpleDisk.py @@ -0,0 +1,5 @@ +from m5.config import * +class SimpleDisk(SimObject): + type = 'SimpleDisk' + disk = Param.DiskImage("Disk Image") + system = Param.System(Parent.any, "Sysetm Pointer") diff --git a/src/python/m5/objects/SimpleOzoneCPU.py b/src/python/m5/objects/SimpleOzoneCPU.py new file mode 100644 index 000000000..5d968cab0 --- /dev/null +++ b/src/python/m5/objects/SimpleOzoneCPU.py @@ -0,0 +1,87 @@ +from m5 import build_env +from m5.config import * +from BaseCPU import BaseCPU + +class SimpleOzoneCPU(BaseCPU): + type = 'SimpleOzoneCPU' + + numThreads = Param.Unsigned("number of HW thread contexts") + + if not build_env['FULL_SYSTEM']: + mem = Param.FunctionalMemory(NULL, "memory") + + width = Param.Unsigned("Width") + frontEndWidth = Param.Unsigned("Front end width") + backEndWidth = Param.Unsigned("Back end width") + backEndSquashLatency = Param.Unsigned("Back end squash latency") + backEndLatency = Param.Unsigned("Back end latency") + maxInstBufferSize = Param.Unsigned("Maximum instruction buffer size") + decodeToFetchDelay = Param.Unsigned("Decode to fetch delay") + renameToFetchDelay = Param.Unsigned("Rename to fetch delay") + iewToFetchDelay = Param.Unsigned("Issue/Execute/Writeback to fetch " + "delay") + commitToFetchDelay = Param.Unsigned("Commit to fetch delay") + fetchWidth = Param.Unsigned("Fetch width") + + renameToDecodeDelay = Param.Unsigned("Rename to decode delay") + iewToDecodeDelay = Param.Unsigned("Issue/Execute/Writeback to decode " + "delay") + commitToDecodeDelay = Param.Unsigned("Commit to decode delay") + fetchToDecodeDelay = Param.Unsigned("Fetch to decode delay") + decodeWidth = Param.Unsigned("Decode width") + + iewToRenameDelay = Param.Unsigned("Issue/Execute/Writeback to rename " + "delay") + commitToRenameDelay = Param.Unsigned("Commit to rename delay") + decodeToRenameDelay = Param.Unsigned("Decode to rename delay") + renameWidth = Param.Unsigned("Rename width") + + commitToIEWDelay = Param.Unsigned("Commit to " + "Issue/Execute/Writeback delay") + renameToIEWDelay = Param.Unsigned("Rename to " + "Issue/Execute/Writeback delay") + issueToExecuteDelay = Param.Unsigned("Issue to execute delay (internal " + "to the IEW stage)") + issueWidth = Param.Unsigned("Issue width") + executeWidth = Param.Unsigned("Execute width") + executeIntWidth = Param.Unsigned("Integer execute width") + executeFloatWidth = Param.Unsigned("Floating point execute width") + executeBranchWidth = Param.Unsigned("Branch execute width") + executeMemoryWidth = Param.Unsigned("Memory execute width") + + iewToCommitDelay = Param.Unsigned("Issue/Execute/Writeback to commit " + "delay") + renameToROBDelay = Param.Unsigned("Rename to reorder buffer delay") + commitWidth = Param.Unsigned("Commit width") + squashWidth = Param.Unsigned("Squash width") + + localPredictorSize = Param.Unsigned("Size of local predictor") + localCtrBits = Param.Unsigned("Bits per counter") + localHistoryTableSize = Param.Unsigned("Size of local history table") + localHistoryBits = Param.Unsigned("Bits for the local history") + globalPredictorSize = Param.Unsigned("Size of global predictor") + globalCtrBits = Param.Unsigned("Bits per counter") + globalHistoryBits = Param.Unsigned("Bits of history") + choicePredictorSize = Param.Unsigned("Size of choice predictor") + choiceCtrBits = Param.Unsigned("Bits of choice counters") + + BTBEntries = Param.Unsigned("Number of BTB entries") + BTBTagSize = Param.Unsigned("Size of the BTB tags, in bits") + + RASSize = Param.Unsigned("RAS size") + + LQEntries = Param.Unsigned("Number of load queue entries") + SQEntries = Param.Unsigned("Number of store queue entries") + LFSTSize = Param.Unsigned("Last fetched store table size") + SSITSize = Param.Unsigned("Store set ID table size") + + numPhysIntRegs = Param.Unsigned("Number of physical integer registers") + numPhysFloatRegs = Param.Unsigned("Number of physical floating point " + "registers") + numIQEntries = Param.Unsigned("Number of instruction queue entries") + numROBEntries = Param.Unsigned("Number of reorder buffer entries") + + instShiftAmt = Param.Unsigned("Number of bits to shift instructions by") + + function_trace = Param.Bool(False, "Enable function trace") + function_trace_start = Param.Tick(0, "Cycle to start function trace") diff --git a/src/python/m5/objects/System.py b/src/python/m5/objects/System.py new file mode 100644 index 000000000..9a1e1d690 --- /dev/null +++ b/src/python/m5/objects/System.py @@ -0,0 +1,20 @@ +from m5 import build_env +from m5.config import * + +class System(SimObject): + type = 'System' + physmem = Param.PhysicalMemory(Parent.any, "phsyical memory") + if build_env['FULL_SYSTEM']: + boot_cpu_frequency = Param.Frequency(Self.cpu[0].clock.frequency, + "boot processor frequency") + init_param = Param.UInt64(0, "numerical value to pass into simulator") + boot_osflags = Param.String("a", "boot flags to pass to the kernel") + kernel = Param.String("file that contains the kernel code") + readfile = Param.String("", "file to read startup script from") + +class AlphaSystem(System): + type = 'AlphaSystem' + console = Param.String("file that contains the console code") + pal = Param.String("file that contains palcode") + system_type = Param.UInt64("Type of system we are emulating") + system_rev = Param.UInt64("Revision of system we are emulating") diff --git a/src/python/m5/objects/Tsunami.py b/src/python/m5/objects/Tsunami.py new file mode 100644 index 000000000..4613571d8 --- /dev/null +++ b/src/python/m5/objects/Tsunami.py @@ -0,0 +1,27 @@ +from m5.config import * +from Device import BasicPioDevice +from Platform import Platform + +class Tsunami(Platform): + type = 'Tsunami' +# pciconfig = Param.PciConfigAll("PCI configuration") + system = Param.System(Parent.any, "system") + +class TsunamiCChip(BasicPioDevice): + type = 'TsunamiCChip' + tsunami = Param.Tsunami(Parent.any, "Tsunami") + +class IsaFake(BasicPioDevice): + type = 'IsaFake' + pio_size = Param.Addr(0x8, "Size of address range") + +class TsunamiIO(BasicPioDevice): + type = 'TsunamiIO' + time = Param.UInt64(1136073600, + "System time to use (0 for actual time, default is 1/1/06)") + tsunami = Param.Tsunami(Parent.any, "Tsunami") + frequency = Param.Frequency('1024Hz', "frequency of interrupts") + +class TsunamiPChip(BasicPioDevice): + type = 'TsunamiPChip' + tsunami = Param.Tsunami(Parent.any, "Tsunami") diff --git a/src/python/m5/objects/Uart.py b/src/python/m5/objects/Uart.py new file mode 100644 index 000000000..8e1fd1a37 --- /dev/null +++ b/src/python/m5/objects/Uart.py @@ -0,0 +1,16 @@ +from m5 import build_env +from m5.config import * +from Device import BasicPioDevice + +class Uart(BasicPioDevice): + type = 'Uart' + abstract = True + sim_console = Param.SimConsole(Parent.any, "The console") + +class Uart8250(Uart): + type = 'Uart8250' + +if build_env['ALPHA_TLASER']: + class Uart8530(Uart): + type = 'Uart8530' + diff --git a/src/python/m5/smartdict.py b/src/python/m5/smartdict.py new file mode 100644 index 000000000..d85dbd517 --- /dev/null +++ b/src/python/m5/smartdict.py @@ -0,0 +1,154 @@ +# Copyright (c) 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 + +# The SmartDict class fixes a couple of issues with using the content +# of os.environ or similar dicts of strings as Python variables: +# +# 1) Undefined variables should return False rather than raising KeyError. +# +# 2) String values of 'False', '0', etc., should evaluate to False +# (not just the empty string). +# +# #1 is solved by overriding __getitem__, and #2 is solved by using a +# proxy class for values and overriding __nonzero__ on the proxy. +# Everything else is just to (a) make proxies behave like normal +# values otherwise, (b) make sure any dict operation returns a proxy +# rather than a normal value, and (c) coerce values written to the +# dict to be strings. + + +from convert import * + +class Variable(str): + """Intelligent proxy class for SmartDict. Variable will use the + various convert functions to attempt to convert values to useable + types""" + def __int__(self): + return toInteger(str(self)) + def __long__(self): + return toLong(str(self)) + def __float__(self): + return toFloat(str(self)) + def __nonzero__(self): + return toBool(str(self)) + def convert(self, other): + t = type(other) + if t == bool: + return bool(self) + if t == int: + return int(self) + if t == long: + return long(self) + if t == float: + return float(self) + return str(self) + def __lt__(self, other): + return self.convert(other) < other + def __le__(self, other): + return self.convert(other) <= other + def __eq__(self, other): + return self.convert(other) == other + def __ne__(self, other): + return self.convert(other) != other + def __gt__(self, other): + return self.convert(other) > other + def __ge__(self, other): + return self.convert(other) >= other + + def __add__(self, other): + return self.convert(other) + other + def __sub__(self, other): + return self.convert(other) - other + def __mul__(self, other): + return self.convert(other) * other + def __div__(self, other): + return self.convert(other) / other + def __truediv__(self, other): + return self.convert(other) / other + + def __radd__(self, other): + return other + self.convert(other) + def __rsub__(self, other): + return other - self.convert(other) + def __rmul__(self, other): + return other * self.convert(other) + def __rdiv__(self, other): + return other / self.convert(other) + def __rtruediv__(self, other): + return other / self.convert(other) + +class UndefinedVariable(object): + """Placeholder class to represent undefined variables. Will + generally cause an exception whenever it is used, but evaluates to + zero for boolean truth testing such as in an if statement""" + def __nonzero__(self): + return False + +class SmartDict(dict): + """Dictionary class that holds strings, but intelligently converts + those strings to other types depending on their usage""" + + def __getitem__(self, key): + """returns a Variable proxy if the values exists in the database and + returns an UndefinedVariable otherwise""" + + if key in self: + return Variable(dict.get(self, key)) + else: + # Note that this does *not* change the contents of the dict, + # so that even after we call env['foo'] we still get a + # meaningful answer from "'foo' in env" (which + # calls dict.__contains__, which we do not override). + return UndefinedVariable() + + def __setitem__(self, key, item): + """intercept the setting of any variable so that we always + store strings in the dict""" + dict.__setitem__(self, key, str(item)) + + def values(self): + return [ Variable(v) for v in dict.values(self) ] + + def itervalues(self): + for value in dict.itervalues(self): + yield Variable(value) + + def items(self): + return [ (k, Variable(v)) for k,v in dict.items(self) ] + + def iteritems(self): + for key,value in dict.iteritems(self): + yield key, Variable(value) + + def get(self, key, default='False'): + return Variable(dict.get(self, key, str(default))) + + def setdefault(self, key, default='False'): + return Variable(dict.setdefault(self, key, str(default))) + +__all__ = [ 'SmartDict' ] diff --git a/src/sim/async.hh b/src/sim/async.hh new file mode 100644 index 000000000..50ae73040 --- /dev/null +++ b/src/sim/async.hh @@ -0,0 +1,52 @@ +/* + * Copyright (c) 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: Nathan Binkert + * Steve Reinhardt + */ + +#ifndef __ASYNC_HH__ +#define __ASYNC_HH__ + +/// +/// @file sim/async.hh +/// This file defines flags used to handle asynchronous simulator events. +/// + +/// @name Asynchronous event flags. +/// To avoid races, signal handlers simply set these flags, which are +/// then checked in the main event loop. Defined in main.cc. +/// @note See the PollQueue object (in pollevent.hh) for the use of async_io and async_alarm. +//@{ +extern volatile bool async_event; ///< Some asynchronous event has happened. +extern volatile bool async_dump; ///< Async request to dump stats. +extern volatile bool async_exit; ///< Async request to exit simulator. +extern volatile bool async_io; ///< Async I/O request (SIGIO). +extern volatile bool async_alarm; ///< Async alarm event (SIGALRM). +//@} + +#endif // __ASYNC_HH__ diff --git a/src/sim/builder.cc b/src/sim/builder.cc new file mode 100644 index 000000000..121275c83 --- /dev/null +++ b/src/sim/builder.cc @@ -0,0 +1,179 @@ +/* + * Copyright (c) 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: Nathan Binkert + */ + +#include <assert.h> + +#include "base/inifile.hh" +#include "base/misc.hh" +#include "sim/builder.hh" +#include "sim/configfile.hh" +#include "sim/config_node.hh" +#include "sim/host.hh" +#include "sim/sim_object.hh" +#include "sim/root.hh" + +using namespace std; + +SimObjectBuilder::SimObjectBuilder(ConfigNode *_configNode) + : ParamContext(_configNode->getPath(), NoAutoInit), + configNode(_configNode) +{ +} + +SimObjectBuilder::~SimObjectBuilder() +{ +} + +/////////////////////////////////////////// +// +// SimObjectBuilder member definitions +// +/////////////////////////////////////////// + +// override ParamContext::parseParams() to check params based on +// instance name first. If not found, then check based on iniSection +// (as in default ParamContext implementation). +void +SimObjectBuilder::parseParams(IniFile &iniFile) +{ + iniFilePtr = &iniFile; // set object member + + ParamList::iterator i; + + for (i = paramList->begin(); i != paramList->end(); ++i) { + string string_value; + if (iniFile.find(iniSection, (*i)->name, string_value)) + (*i)->parse(string_value); + } +} + + +void +SimObjectBuilder::printErrorProlog(ostream &os) +{ + ccprintf(os, "Error creating object '%s' of type '%s':\n", + iniSection, configNode->getType()); +} + + +//////////////////////////////////////////////////////////////////////// +// +// SimObjectClass member definitions +// +//////////////////////////////////////////////////////////////////////// + +// Map of class names to SimObjectBuilder creation functions. Need to +// make this a pointer so we can force initialization on the first +// reference; otherwise, some SimObjectClass constructors may be invoked +// before the classMap constructor. +map<string,SimObjectClass::CreateFunc> *SimObjectClass::classMap = NULL; + +// SimObjectClass constructor: add mapping to classMap +SimObjectClass::SimObjectClass(const string &className, CreateFunc createFunc) +{ + if (classMap == NULL) + classMap = new map<string,SimObjectClass::CreateFunc>(); + + if ((*classMap)[className]) + panic("Error: simulation object class '%s' redefined\n", className); + + // add className --> createFunc to class map + (*classMap)[className] = createFunc; +} + + +// +// +SimObject * +SimObjectClass::createObject(IniFile &configDB, ConfigNode *configNode) +{ + const string &type = configNode->getType(); + + // look up className to get appropriate createFunc + if (classMap->find(type) == classMap->end()) + panic("Simulator object type '%s' not found.\n", type); + + + CreateFunc createFunc = (*classMap)[type]; + + // call createFunc with config hierarchy node to get object + // builder instance (context with parameters for object creation) + SimObjectBuilder *objectBuilder = (*createFunc)(configNode); + + assert(objectBuilder != NULL); + + // parse all parameters in context to generate parameter values + objectBuilder->parseParams(configDB); + + // now create the actual simulation object + SimObject *object = objectBuilder->create(); + + assert(object != NULL); + + // echo object parameters to stats file (for documenting the + // config used to generate the associated stats) + ccprintf(*configStream, "[%s]\n", object->name()); + ccprintf(*configStream, "type=%s\n", type); + objectBuilder->showParams(*configStream); + ccprintf(*configStream, "\n"); + + // done with the SimObjectBuilder now + delete objectBuilder; + + return object; +} + + +// +// static method: +// +void +SimObjectClass::describeAllClasses(ostream &os) +{ + map<string,CreateFunc>::iterator iter; + + for (iter = classMap->begin(); iter != classMap->end(); ++iter) { + const string &className = iter->first; + CreateFunc createFunc = iter->second; + + os << "[" << className << "]\n"; + + // create dummy object builder just to instantiate parameters + SimObjectBuilder *objectBuilder = (*createFunc)(NULL); + + // now get the object builder to describe ite params + objectBuilder->describeParams(os); + + os << endl; + + // done with the object builder now + delete objectBuilder; + } +} diff --git a/src/sim/builder.hh b/src/sim/builder.hh new file mode 100644 index 000000000..8d0846155 --- /dev/null +++ b/src/sim/builder.hh @@ -0,0 +1,191 @@ +/* + * Copyright (c) 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: Nathan Binkert + */ + +#ifndef __BUILDER_HH__ +#define __BUILDER_HH__ + +#include <iosfwd> +#include <list> +#include <map> +#include <vector> + +#include "sim/param.hh" + +class SimObject; + +// +// A SimObjectBuilder serves as an evaluation context for a set of +// parameters that describe a specific instance of a SimObject. This +// evaluation context corresponds to a section in the .ini file (as +// with the base ParamContext) plus an optional node in the +// configuration hierarchy (the configNode member) for resolving +// SimObject references. SimObjectBuilder is an abstract superclass; +// derived classes specialize the class for particular subclasses of +// SimObject (e.g., BaseCache). +// +// For typical usage, see the definition of +// SimObjectClass::createObject(). +// +class SimObjectBuilder : public ParamContext +{ + private: + // The corresponding node in the configuration hierarchy. + // (optional: may be null if the created object is not in the + // hierarchy) + ConfigNode *configNode; + + public: + SimObjectBuilder(ConfigNode *_configNode); + + virtual ~SimObjectBuilder(); + + // call parse() on all params in this context to convert string + // representations to parameter values + virtual void parseParams(IniFile &iniFile); + + // parameter error prolog (override of ParamContext) + virtual void printErrorProlog(std::ostream &); + + // generate the name for this SimObject instance (derived from the + // configuration hierarchy node label and position) + virtual const std::string &getInstanceName() { return iniSection; } + + // return the configuration hierarchy node for this context. + virtual ConfigNode *getConfigNode() { return configNode; } + + // Create the actual SimObject corresponding to the parameter + // values in this context. This function is overridden in derived + // classes to call a specific constructor for a particular + // subclass of SimObject. + virtual SimObject *create() = 0; +}; + + +// +// Handy macros for initializing parameter members of classes derived +// from SimObjectBuilder. Assumes that the name of the parameter +// member object is the same as the textual parameter name seen by the +// user. (Note that '#p' is expanded by the preprocessor to '"p"'.) +// +#define INIT_PARAM(p, desc) p(this, #p, desc) +#define INIT_PARAM_DFLT(p, desc, dflt) p(this, #p, desc, dflt) + +// +// Initialize an enumeration variable... assumes that 'map' is the +// name of an array of mappings (char * for SimpleEnumParam, or +// EnumParamMap for MappedEnumParam). +// +#define INIT_ENUM_PARAM(p, desc, map) \ + p(this, #p, desc, map, sizeof(map)/sizeof(map[0])) +#define INIT_ENUM_PARAM_DFLT(p, desc, map, dflt) \ + p(this, #p, desc, map, sizeof(map)/sizeof(map[0]), dflt) + +// +// An instance of SimObjectClass corresponds to a class derived from +// SimObject. The SimObjectClass instance serves to bind the string +// name (found in the config file) to a function that creates an +// instance of the appropriate derived class. +// +// This would be much cleaner in Smalltalk or Objective-C, where types +// are first-class objects themselves. +// +class SimObjectClass +{ + public: + // Type CreateFunc is a pointer to a function that creates a new + // simulation object builder based on a .ini-file parameter + // section (specified by the first string argument), a unique name + // for the object (specified by the second string argument), and + // an optional config hierarchy node (specified by the third + // argument). A pointer to the new SimObjectBuilder is returned. + typedef SimObjectBuilder *(*CreateFunc)(ConfigNode *configNode); + + static std::map<std::string,CreateFunc> *classMap; + + // Constructor. For example: + // + // SimObjectClass baseCacheClass("BaseCache", newBaseCacheBuilder); + // + SimObjectClass(const std::string &className, CreateFunc createFunc); + + // create SimObject given name of class and pointer to + // configuration hierarchy node + static SimObject *createObject(IniFile &configDB, ConfigNode *configNode); + + // print descriptions of all parameters registered with all + // SimObject classes + static void describeAllClasses(std::ostream &os); +}; + +// +// Macros to encapsulate the magic of declaring & defining +// SimObjectBuilder and SimObjectClass objects +// + +#define BEGIN_DECLARE_SIM_OBJECT_PARAMS(OBJ_CLASS) \ +class OBJ_CLASS##Builder : public SimObjectBuilder \ +{ \ + public: + +#define END_DECLARE_SIM_OBJECT_PARAMS(OBJ_CLASS) \ + \ + OBJ_CLASS##Builder(ConfigNode *configNode); \ + virtual ~OBJ_CLASS##Builder() {} \ + \ + OBJ_CLASS *create(); \ +}; + +#define BEGIN_INIT_SIM_OBJECT_PARAMS(OBJ_CLASS) \ +OBJ_CLASS##Builder::OBJ_CLASS##Builder(ConfigNode *configNode) \ + : SimObjectBuilder(configNode), + + +#define END_INIT_SIM_OBJECT_PARAMS(OBJ_CLASS) \ +{ \ +} + +#define CREATE_SIM_OBJECT(OBJ_CLASS) \ +OBJ_CLASS *OBJ_CLASS##Builder::create() + +#define REGISTER_SIM_OBJECT(CLASS_NAME, OBJ_CLASS) \ +SimObjectBuilder * \ +new##OBJ_CLASS##Builder(ConfigNode *configNode) \ +{ \ + return new OBJ_CLASS##Builder(configNode); \ +} \ + \ +SimObjectClass the##OBJ_CLASS##Class(CLASS_NAME, \ + new##OBJ_CLASS##Builder); \ + \ +/* see param.hh */ \ +DEFINE_SIM_OBJECT_CLASS_NAME(CLASS_NAME, OBJ_CLASS) + + +#endif // __BUILDER_HH__ diff --git a/src/sim/byteswap.hh b/src/sim/byteswap.hh new file mode 100644 index 000000000..a3138a25e --- /dev/null +++ b/src/sim/byteswap.hh @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2004 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 + */ + +//The purpose of this file is to provide endainness conversion utility +//functions. Depending on the endianness of the guest system, either +//the LittleEndianGuest or BigEndianGuest namespace is used. + +#ifndef __SIM_BYTE_SWAP_HH__ +#define __SIM_BYTE_SWAP_HH__ + +#include "sim/host.hh" + +// This lets us figure out what the byte order of the host system is +#if defined(linux) +#include <endian.h> +// If this is a linux system, lets used the optimized definitions if they exist. +// If one doesn't exist, we pretty much get what is listed below, so it all +// works out +#include <byteswap.h> +#else +#include <machine/endian.h> +#endif + +//These functions actually perform the swapping for parameters +//of various bit lengths +static inline uint64_t +swap_byte64(uint64_t x) +{ +#if defined(linux) + return bswap_64(x); +#else + return (uint64_t)((((uint64_t)(x) & 0xff) << 56) | + ((uint64_t)(x) & 0xff00ULL) << 40 | + ((uint64_t)(x) & 0xff0000ULL) << 24 | + ((uint64_t)(x) & 0xff000000ULL) << 8 | + ((uint64_t)(x) & 0xff00000000ULL) >> 8 | + ((uint64_t)(x) & 0xff0000000000ULL) >> 24 | + ((uint64_t)(x) & 0xff000000000000ULL) >> 40 | + ((uint64_t)(x) & 0xff00000000000000ULL) >> 56) ; +#endif +} + +static inline uint32_t +swap_byte32(uint32_t x) +{ +#if defined(linux) + return bswap_32(x); +#else + return (uint32_t)(((uint32_t)(x) & 0xff) << 24 | + ((uint32_t)(x) & 0xff00) << 8 | ((uint32_t)(x) & 0xff0000) >> 8 | + ((uint32_t)(x) & 0xff000000) >> 24); +#endif +} + +static inline uint16_t +swap_byte16(uint16_t x) +{ +#if defined(linux) + return bswap_16(x); +#else + return (uint16_t)(((uint16_t)(x) & 0xff) << 8 | + ((uint16_t)(x) & 0xff00) >> 8); +#endif +} + +//This lets the compiler figure out how to call the swap_byte functions above +//for different data types. +static inline uint64_t swap_byte(uint64_t x) {return swap_byte64(x);} +static inline int64_t swap_byte(int64_t x) {return swap_byte64((uint64_t)x);} +static inline uint32_t swap_byte(uint32_t x) {return swap_byte32(x);} +static inline int32_t swap_byte(int32_t x) {return swap_byte32((uint32_t)x);} +//This is to prevent the following two functions from compiling on +//64bit machines. It won't detect everything, so it should be changed. +#ifndef __x86_64__ +static inline long swap_byte(long x) {return swap_byte32((long)x);} +static inline unsigned long swap_byte(unsigned long x) + { return swap_byte32((unsigned long)x);} +#endif +static inline uint16_t swap_byte(uint16_t x) {return swap_byte32(x);} +static inline int16_t swap_byte(int16_t x) {return swap_byte16((uint16_t)x);} +static inline uint8_t swap_byte(uint8_t x) {return x;} +static inline int8_t swap_byte(int8_t x) {return x;} +static inline double swap_byte(double x) {return swap_byte64((uint64_t)x);} +static inline float swap_byte(float x) {return swap_byte32((uint32_t)x);} + +//The conversion functions with fixed endianness on both ends don't need to +//be in a namespace +template <typename T> static inline T betole(T value) {return swap_byte(value);} +template <typename T> static inline T letobe(T value) {return swap_byte(value);} + +//For conversions not involving the guest system, we can define the functions +//conditionally based on the BYTE_ORDER macro and outside of the namespaces +#if BYTE_ORDER == BIG_ENDIAN +template <typename T> static inline T htole(T value) {return swap_byte(value);} +template <typename T> static inline T letoh(T value) {return swap_byte(value);} +template <typename T> static inline T htobe(T value) {return value;} +template <typename T> static inline T betoh(T value) {return value;} +#elif BYTE_ORDER == LITTLE_ENDIAN +template <typename T> static inline T htole(T value) {return value;} +template <typename T> static inline T letoh(T value) {return value;} +template <typename T> static inline T htobe(T value) {return swap_byte(value);} +template <typename T> static inline T betoh(T value) {return swap_byte(value);} +#else + #error Invalid Endianess +#endif + +namespace BigEndianGuest +{ + template <typename T> + static inline T gtole(T value) {return betole(value);} + template <typename T> + static inline T letog(T value) {return letobe(value);} + template <typename T> + static inline T gtobe(T value) {return value;} + template <typename T> + static inline T betog(T value) {return value;} + template <typename T> + static inline T htog(T value) {return htobe(value);} + template <typename T> + static inline T gtoh(T value) {return betoh(value);} +} + +namespace LittleEndianGuest +{ + template <typename T> + static inline T gtole(T value) {return value;} + template <typename T> + static inline T letog(T value) {return value;} + template <typename T> + static inline T gtobe(T value) {return letobe(value);} + template <typename T> + static inline T betog(T value) {return betole(value);} + template <typename T> + static inline T htog(T value) {return htole(value);} + template <typename T> + static inline T gtoh(T value) {return letoh(value);} +} +#endif // __SIM_BYTE_SWAP_HH__ diff --git a/src/sim/debug.cc b/src/sim/debug.cc new file mode 100644 index 000000000..b82219f7d --- /dev/null +++ b/src/sim/debug.cc @@ -0,0 +1,139 @@ +/* + * Copyright (c) 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: Nathan Binkert + * Steve Reinhardt + */ + +#include <sys/types.h> +#include <signal.h> +#include <unistd.h> + +#include <string> +#include <vector> + +#include "sim/debug.hh" +#include "sim/eventq.hh" +#include "sim/param.hh" +#include "sim/sim_events.hh" + +using namespace std; + +void +debug_break() +{ +#ifndef NDEBUG + kill(getpid(), SIGTRAP); +#else + cprintf("debug_break suppressed, compiled with NDEBUG\n"); +#endif +} + +// +// Debug event: place a breakpoint on the process function and +// schedule the event to break at a particular cycle +// +class DebugBreakEvent : public Event +{ + public: + + DebugBreakEvent(EventQueue *q, Tick _when); + + void process(); // process event + virtual const char *description(); +}; + +// +// constructor: schedule at specified time +// +DebugBreakEvent::DebugBreakEvent(EventQueue *q, Tick _when) + : Event(q, Debug_Break_Pri) +{ + setFlags(AutoDelete); + schedule(_when); +} + +// +// handle debug event: set debugger breakpoint on this function +// +void +DebugBreakEvent::process() +{ + debug_break(); +} + + +const char * +DebugBreakEvent::description() +{ + return "debug break"; +} + +// +// Parameter context for global debug options +// +class DebugContext : public ParamContext +{ + public: + DebugContext(const string &_iniSection) + : ParamContext(_iniSection) {} + void checkParams(); +}; + +DebugContext debugParams("debug"); + +VectorParam<Tick> break_cycles(&debugParams, "break_cycles", + "cycle(s) to create breakpoint events"); + +void +DebugContext::checkParams() +{ + if (break_cycles.isValid()) { + vector<Tick> &cycles = break_cycles; + + vector<Tick>::iterator i = cycles.begin(); + vector<Tick>::iterator end = cycles.end(); + + for (; i < end; ++i) + new DebugBreakEvent(&mainEventQueue, *i); + } +} + +// +// handy function to schedule DebugBreakEvent on main event queue +// (callable from debugger) +// +extern "C" void sched_break_cycle(Tick when) +{ + new DebugBreakEvent(&mainEventQueue, when); +} + +extern "C" void eventq_dump() +{ + mainEventQueue.dump(); +} + diff --git a/src/sim/debug.hh b/src/sim/debug.hh new file mode 100644 index 000000000..79792234b --- /dev/null +++ b/src/sim/debug.hh @@ -0,0 +1,36 @@ +/* + * Copyright (c) 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: Nathan Binkert + */ + +#ifndef __DEBUG_HH__ +#define __DEBUG_HH__ + +void debug_break(); + +#endif // __DEBUG_HH__ diff --git a/src/sim/eventq.cc b/src/sim/eventq.cc new file mode 100644 index 000000000..6ae838897 --- /dev/null +++ b/src/sim/eventq.cc @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2000-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 + * Steve Raasch + */ + +#include <assert.h> + +#include <iostream> +#include <string> +#include <vector> + +#include "cpu/smt.hh" +#include "base/misc.hh" + +#include "sim/eventq.hh" +#include "base/trace.hh" +#include "sim/root.hh" + +using namespace std; + +// +// Main Event Queue +// +// Events on this queue are processed at the *beginning* of each +// cycle, before the pipeline simulation is performed. +// +EventQueue mainEventQueue("MainEventQueue"); + +void +EventQueue::insert(Event *event) +{ + if (head == NULL || event->when() < head->when() || + (event->when() == head->when() && + event->priority() <= head->priority())) { + event->next = head; + head = event; + } else { + Event *prev = head; + Event *curr = head->next; + + while (curr) { + if (event->when() <= curr->when() && + (event->when() < curr->when() || + event->priority() <= curr->priority())) + break; + + prev = curr; + curr = curr->next; + } + + event->next = curr; + prev->next = event; + } +} + +void +EventQueue::remove(Event *event) +{ + if (head == NULL) + return; + + if (head == event){ + head = event->next; + return; + } + + Event *prev = head; + Event *curr = head->next; + while (curr && curr != event) { + prev = curr; + curr = curr->next; + } + + if (curr == event) + prev->next = curr->next; +} + +Event * +EventQueue::serviceOne() +{ + Event *event = head; + event->clearFlags(Event::Scheduled); + head = event->next; + + // handle action + if (!event->squashed()) { + event->process(); + if (event->isExitEvent()) { + assert(!event->getFlags(Event::AutoDelete)); // would be silly + return event; + } + } else { + event->clearFlags(Event::Squashed); + } + + if (event->getFlags(Event::AutoDelete) && !event->scheduled()) + delete event; + + return NULL; +} + + +void +Event::serialize(std::ostream &os) +{ + SERIALIZE_SCALAR(_when); + SERIALIZE_SCALAR(_priority); + SERIALIZE_ENUM(_flags); +} + + +void +Event::unserialize(Checkpoint *cp, const string §ion) +{ + if (scheduled()) + deschedule(); + + UNSERIALIZE_SCALAR(_when); + UNSERIALIZE_SCALAR(_priority); + + // need to see if original event was in a scheduled, unsquashed + // state, but don't want to restore those flags in the current + // object itself (since they aren't immediately true) + UNSERIALIZE_ENUM(_flags); + bool wasScheduled = (_flags & Scheduled) && !(_flags & Squashed); + _flags &= ~(Squashed | Scheduled); + + if (wasScheduled) { + DPRINTF(Config, "rescheduling at %d\n", _when); + schedule(_when); + } +} + +void +EventQueue::serialize(ostream &os) +{ + std::list<Event *> eventPtrs; + + int numEvents = 0; + Event *event = head; + while (event) { + if (event->getFlags(Event::AutoSerialize)) { + eventPtrs.push_back(event); + paramOut(os, csprintf("event%d", numEvents++), event->name()); + } + event = event->next; + } + + SERIALIZE_SCALAR(numEvents); + + for (std::list<Event *>::iterator it=eventPtrs.begin(); + it != eventPtrs.end(); ++it) { + (*it)->nameOut(os); + (*it)->serialize(os); + } +} + +void +EventQueue::unserialize(Checkpoint *cp, const std::string §ion) +{ + int numEvents; + UNSERIALIZE_SCALAR(numEvents); + + std::string eventName; + for (int i = 0; i < numEvents; i++) { + // get the pointer value associated with the event + paramIn(cp, section, csprintf("event%d", i), eventName); + + // create the event based on its pointer value + Serializable::create(cp, eventName); + } +} + +void +EventQueue::dump() +{ + cprintf("============================================================\n"); + cprintf("EventQueue Dump (cycle %d)\n", curTick); + cprintf("------------------------------------------------------------\n"); + + if (empty()) + cprintf("<No Events>\n"); + else { + Event *event = head; + while (event) { + event->dump(); + event = event->next; + } + } + + cprintf("============================================================\n"); +} + +extern "C" +void +dumpMainQueue() +{ + mainEventQueue.dump(); +} + + +const char * +Event::description() +{ + return "generic"; +} + +#if TRACING_ON +void +Event::trace(const char *action) +{ + // This DPRINTF is unconditional because calls to this function + // are protected by an 'if (DTRACE(Event))' in the inlined Event + // methods. + // + // This is just a default implementation for derived classes where + // it's not worth doing anything special. If you want to put a + // more informative message in the trace, override this method on + // the particular subclass where you have the information that + // needs to be printed. + DPRINTFN("%s event %s @ %d\n", description(), action, when()); +} +#endif + +void +Event::dump() +{ + cprintf("Event (%s)\n", description()); + cprintf("Flags: %#x\n", _flags); +#if TRACING_ON + cprintf("Created: %d\n", when_created); +#endif + if (scheduled()) { +#if TRACING_ON + cprintf("Scheduled at %d\n", when_scheduled); +#endif + cprintf("Scheduled for %d, priority %d\n", when(), _priority); + } + else { + cprintf("Not Scheduled\n"); + } +} diff --git a/src/sim/eventq.hh b/src/sim/eventq.hh new file mode 100644 index 000000000..430473df3 --- /dev/null +++ b/src/sim/eventq.hh @@ -0,0 +1,414 @@ +/* + * Copyright (c) 2000-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 + */ + +/* @file + * EventQueue interfaces + */ + +#ifndef __SIM_EVENTQ_HH__ +#define __SIM_EVENTQ_HH__ + +#include <assert.h> + +#include <algorithm> +#include <map> +#include <string> +#include <vector> + +#include "sim/host.hh" // for Tick + +#include "base/fast_alloc.hh" +#include "base/trace.hh" +#include "sim/serialize.hh" + +class EventQueue; // forward declaration + +////////////////////// +// +// Main Event Queue +// +// Events on this queue are processed at the *beginning* of each +// cycle, before the pipeline simulation is performed. +// +// defined in eventq.cc +// +////////////////////// +extern EventQueue mainEventQueue; + + +/* + * An item on an event queue. The action caused by a given + * event is specified by deriving a subclass and overriding the + * process() member function. + */ +class Event : public Serializable, public FastAlloc +{ + friend class EventQueue; + + private: + /// queue to which this event belongs (though it may or may not be + /// scheduled on this queue yet) + EventQueue *queue; + + Event *next; + + Tick _when; //!< timestamp when event should be processed + int _priority; //!< event priority + char _flags; + + protected: + enum Flags { + None = 0x0, + Squashed = 0x1, + Scheduled = 0x2, + AutoDelete = 0x4, + AutoSerialize = 0x8, + IsExitEvent = 0x10 + }; + + bool getFlags(Flags f) const { return (_flags & f) == f; } + void setFlags(Flags f) { _flags |= f; } + void clearFlags(Flags f) { _flags &= ~f; } + + protected: + EventQueue *theQueue() const { return queue; } + +#if TRACING_ON + Tick when_created; //!< Keep track of creation time For debugging + Tick when_scheduled; //!< Keep track of creation time For debugging + + virtual void trace(const char *action); //!< trace event activity +#else + void trace(const char *) {} +#endif + + unsigned annotated_value; + + public: + + /// Event priorities, to provide tie-breakers for events scheduled + /// at the same cycle. Most events are scheduled at the default + /// priority; these values are used to control events that need to + /// be ordered within a cycle. + enum Priority { + /// Breakpoints should happen before anything else, so we + /// don't miss any action when debugging. + Debug_Break_Pri = -100, + + /// For some reason "delayed" inter-cluster writebacks are + /// scheduled before regular writebacks (which have default + /// priority). Steve? + Delayed_Writeback_Pri = -1, + + /// Default is zero for historical reasons. + Default_Pri = 0, + + /// CPU switches schedule the new CPU's tick event for the + /// same cycle (after unscheduling the old CPU's tick event). + /// The switch needs to come before any tick events to make + /// sure we don't tick both CPUs in the same cycle. + CPU_Switch_Pri = 31, + + /// Serailization needs to occur before tick events also, so + /// that a serialize/unserialize is identical to an on-line + /// CPU switch. + Serialize_Pri = 32, + + /// CPU ticks must come after other associated CPU events + /// (such as writebacks). + CPU_Tick_Pri = 50, + + /// Statistics events (dump, reset, etc.) come after + /// everything else, but before exit. + Stat_Event_Pri = 90, + + /// If we want to exit on this cycle, it's the very last thing + /// we do. + Sim_Exit_Pri = 100 + }; + + /* + * Event constructor + * @param queue that the event gets scheduled on + */ + Event(EventQueue *q, Priority p = Default_Pri) + : queue(q), next(NULL), _priority(p), _flags(None), +#if TRACING_ON + when_created(curTick), when_scheduled(0), +#endif + annotated_value(0) + { + } + + ~Event() {} + + virtual const std::string name() const { + return csprintf("Event_%x", (uintptr_t)this); + } + + /// Determine if the current event is scheduled + bool scheduled() const { return getFlags(Scheduled); } + + /// Schedule the event with the current priority or default priority + void schedule(Tick t); + + /// Reschedule the event with the current priority + void reschedule(Tick t); + + /// Remove the event from the current schedule + void deschedule(); + + /// Return a C string describing the event. This string should + /// *not* be dynamically allocated; just a const char array + /// describing the event class. + virtual const char *description(); + + /// Dump the current event data + void dump(); + + /* + * This member function is invoked when the event is processed + * (occurs). There is no default implementation; each subclass + * must provide its own implementation. The event is not + * automatically deleted after it is processed (to allow for + * statically allocated event objects). + * + * If the AutoDestroy flag is set, the object is deleted once it + * is processed. + */ + virtual void process() = 0; + + void annotate(unsigned value) { annotated_value = value; }; + unsigned annotation() { return annotated_value; } + + /// Squash the current event + void squash() { setFlags(Squashed); } + + /// Check whether the event is squashed + bool squashed() { return getFlags(Squashed); } + + /// See if this is a SimExitEvent (without resorting to RTTI) + bool isExitEvent() { return getFlags(IsExitEvent); } + + /// Get the time that the event is scheduled + Tick when() const { return _when; } + + /// Get the event priority + int priority() const { return _priority; } + + struct priority_compare : + public std::binary_function<Event *, Event *, bool> + { + bool operator()(const Event *l, const Event *r) const { + return l->when() >= r->when() || l->priority() >= r->priority(); + } + }; + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); +}; + +template <class T, void (T::* F)()> +void +DelayFunction(Tick when, T *object) +{ + class DelayEvent : public Event + { + private: + T *object; + + public: + DelayEvent(Tick when, T *o) + : Event(&mainEventQueue), object(o) + { setFlags(this->AutoDestroy); schedule(when); } + void process() { (object->*F)(); } + const char *description() { return "delay"; } + }; + + new DelayEvent(when, object); +} + +template <class T, void (T::* F)()> +class EventWrapper : public Event +{ + private: + T *object; + + public: + EventWrapper(T *obj, bool del = false, EventQueue *q = &mainEventQueue, + Priority p = Default_Pri) + : Event(q, p), object(obj) + { + if (del) + setFlags(AutoDelete); + } + void process() { (object->*F)(); } +}; + +/* + * Queue of events sorted in time order + */ +class EventQueue : public Serializable +{ + protected: + std::string objName; + + private: + Event *head; + + void insert(Event *event); + void remove(Event *event); + + public: + + // constructor + EventQueue(const std::string &n) + : objName(n), head(NULL) + {} + + virtual const std::string name() const { return objName; } + + // schedule the given event on this queue + void schedule(Event *ev); + void deschedule(Event *ev); + void reschedule(Event *ev); + + Tick nextTick() { return head->when(); } + Event *serviceOne(); + + // process all events up to the given timestamp. we inline a + // quick test to see if there are any events to process; if so, + // call the internal out-of-line version to process them all. + void serviceEvents(Tick when) { + while (!empty()) { + if (nextTick() > when) + break; + + /** + * @todo this assert is a good bug catcher. I need to + * make it true again. + */ + //assert(head->when() >= when && "event scheduled in the past"); + serviceOne(); + } + } + + // default: process all events up to 'now' (curTick) + void serviceEvents() { serviceEvents(curTick); } + + // return true if no events are queued + bool empty() { return head == NULL; } + + void dump(); + + Tick nextEventTime() { return empty() ? curTick : head->when(); } + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); +}; + + +////////////////////// +// +// inline functions +// +// can't put these inside declaration due to circular dependence +// between Event and EventQueue classes. +// +////////////////////// + +// schedule at specified time (place on event queue specified via +// constructor) +inline void +Event::schedule(Tick t) +{ + assert(!scheduled()); + assert(t >= curTick); + + setFlags(Scheduled); +#if TRACING_ON + when_scheduled = curTick; +#endif + _when = t; + queue->schedule(this); +} + +inline void +Event::deschedule() +{ + assert(scheduled()); + + clearFlags(Squashed); + clearFlags(Scheduled); + queue->deschedule(this); +} + +inline void +Event::reschedule(Tick t) +{ + assert(scheduled()); + clearFlags(Squashed); + +#if TRACING_ON + when_scheduled = curTick; +#endif + _when = t; + queue->reschedule(this); +} + +inline void +EventQueue::schedule(Event *event) +{ + insert(event); + if (DTRACE(Event)) + event->trace("scheduled"); +} + +inline void +EventQueue::deschedule(Event *event) +{ + remove(event); + if (DTRACE(Event)) + event->trace("descheduled"); +} + +inline void +EventQueue::reschedule(Event *event) +{ + remove(event); + insert(event); + if (DTRACE(Event)) + event->trace("rescheduled"); +} + + + +#endif // __SIM_EVENTQ_HH__ diff --git a/src/sim/faults.cc b/src/sim/faults.cc new file mode 100644 index 000000000..650b728f7 --- /dev/null +++ b/src/sim/faults.cc @@ -0,0 +1,55 @@ +/* + * Copyright (c) 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: Nathan Binkert + * Gabe Black + */ + +#include "base/misc.hh" +#include "sim/faults.hh" +#include "cpu/thread_context.hh" +#include "cpu/base.hh" + +#if !FULL_SYSTEM +void FaultBase::invoke(ThreadContext * tc) +{ + fatal("fault (%s) detected @ PC 0x%08p", name(), tc->readPC()); +} +#else +void FaultBase::invoke(ThreadContext * tc) +{ + DPRINTF(Fault, "Fault %s at PC: %#x\n", name(), tc->readPC()); + tc->getCpuPtr()->recordEvent(csprintf("Fault %s", name())); + + assert(!tc->misspeculating()); +} +#endif + +void UnimpFault::invoke(ThreadContext * tc) +{ + panic("Unimpfault: %s\n", panicStr.c_str()); +} diff --git a/src/sim/faults.hh b/src/sim/faults.hh new file mode 100644 index 000000000..23385c649 --- /dev/null +++ b/src/sim/faults.hh @@ -0,0 +1,83 @@ +/* + * Copyright (c) 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: Nathan Binkert + * Gabe Black + */ + +#ifndef __FAULTS_HH__ +#define __FAULTS_HH__ + +#include "base/refcnt.hh" +#include "sim/stats.hh" +#include "config/full_system.hh" + +class ThreadContext; +class FaultBase; +typedef RefCountingPtr<FaultBase> Fault; + +typedef const char * FaultName; +typedef Stats::Scalar<> FaultStat; + +// Each class has it's name statically define in _name, +// and has a virtual function to access it's name. +// The function is necessary because otherwise, all objects +// which are being accessed cast as a FaultBase * (namely +// all faults returned using the Fault type) will use the +// generic FaultBase name. + +class FaultBase : public RefCounted +{ + public: + virtual FaultName name() = 0; +#if FULL_SYSTEM + virtual void invoke(ThreadContext * tc); +#else + virtual void invoke(ThreadContext * tc); +#endif +// template<typename T> +// bool isA() {return dynamic_cast<T *>(this);} + virtual bool isMachineCheckFault() {return false;} + virtual bool isAlignmentFault() {return false;} +}; + +FaultBase * const NoFault = 0; + +class UnimpFault : public FaultBase +{ + private: + std::string panicStr; + public: + UnimpFault(std::string _str) + : panicStr(_str) + { } + + FaultName name() {return "Unimplemented simulator feature";} + void invoke(ThreadContext * tc); +}; + +#endif // __FAULTS_HH__ diff --git a/src/sim/host.hh b/src/sim/host.hh new file mode 100644 index 000000000..9c79580b1 --- /dev/null +++ b/src/sim/host.hh @@ -0,0 +1,71 @@ +/* + * Copyright (c) 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: Nathan Binkert + */ + +/** + * @file + * Defines host-dependent types: + * Counter, Tick, and (indirectly) {int,uint}{8,16,32,64}_t. + */ + +#ifndef __HOST_HH__ +#define __HOST_HH__ + +#include <inttypes.h> + +/** uint64_t constant */ +#define ULL(N) ((uint64_t)N##ULL) +/** int64_t constant */ +#define LL(N) (((int64_t)N##LL) + +/** Statistics counter type. Not much excuse for not using a 64-bit + * integer here, but if you're desperate and only run short + * simulations you could make this 32 bits. + */ +typedef int64_t Counter; + +/** + * Clock cycle count type. + * @note using an unsigned breaks the cache. + */ +typedef int64_t Tick; + +const Tick MaxTick = (1LL << 62); + +/** + * Address type + * This will probably be moved somewhere else in the near future. + * This should be at least as big as the biggest address width in use + * in the system, which will probably be 64 bits. + */ +typedef uint64_t Addr; + +const Addr MaxAddr = (Addr)-1; + +#endif // __HOST_H__ diff --git a/src/sim/main.cc b/src/sim/main.cc new file mode 100644 index 000000000..741926056 --- /dev/null +++ b/src/sim/main.cc @@ -0,0 +1,426 @@ +/* + * Copyright (c) 2000-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 + * Steve Reinhardt + */ + +/// +/// @file sim/main.cc +/// +#include <Python.h> // must be before system headers... see Python docs + +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <libgen.h> +#include <stdlib.h> +#include <signal.h> +#include <unistd.h> + +#include <list> +#include <string> +#include <vector> + +#include "base/callback.hh" +#include "base/inifile.hh" +#include "base/misc.hh" +#include "base/output.hh" +#include "base/pollevent.hh" +#include "base/statistics.hh" +#include "base/str.hh" +#include "base/time.hh" +#include "cpu/base.hh" +#include "cpu/smt.hh" +#include "sim/async.hh" +#include "sim/builder.hh" +#include "sim/configfile.hh" +#include "sim/host.hh" +#include "sim/sim_events.hh" +#include "sim/sim_exit.hh" +#include "sim/sim_object.hh" +#include "sim/stat_control.hh" +#include "sim/stats.hh" +#include "sim/root.hh" + +using namespace std; + +// See async.h. +volatile bool async_event = false; +volatile bool async_dump = false; +volatile bool async_dumpreset = false; +volatile bool async_exit = false; +volatile bool async_io = false; +volatile bool async_alarm = false; + +/// Stats signal handler. +void +dumpStatsHandler(int sigtype) +{ + async_event = true; + async_dump = true; +} + +void +dumprstStatsHandler(int sigtype) +{ + async_event = true; + async_dumpreset = true; +} + +/// Exit signal handler. +void +exitNowHandler(int sigtype) +{ + async_event = true; + async_exit = true; +} + +/// Abort signal handler. +void +abortHandler(int sigtype) +{ + cerr << "Program aborted at cycle " << curTick << endl; + +#if TRACING_ON + // dump trace buffer, if there is one + Trace::theLog.dump(cerr); +#endif +} + + +const char *briefCopyright = +"Copyright (c) 2001-2006\n" +"The Regents of The University of Michigan\n" +"All Rights Reserved\n"; + +/// Print welcome message. +void +sayHello(ostream &out) +{ + extern const char *compileDate; // from date.cc + + ccprintf(out, "M5 Simulator System\n"); + // display copyright + ccprintf(out, "%s\n", briefCopyright); + ccprintf(out, "M5 compiled %d\n", compileDate); + ccprintf(out, "M5 started %s\n", Time::start); + + char *host = getenv("HOSTNAME"); + if (!host) + host = getenv("HOST"); + + if (host) + ccprintf(out, "M5 executing on %s\n", host); +} + + +extern "C" { void init_main(); } + +int +main(int argc, char **argv) +{ + sayHello(cerr); + + signal(SIGFPE, SIG_IGN); // may occur on misspeculated paths + signal(SIGTRAP, SIG_IGN); + signal(SIGUSR1, dumpStatsHandler); // dump intermediate stats + signal(SIGUSR2, dumprstStatsHandler); // dump and reset stats + signal(SIGINT, exitNowHandler); // dump final stats and exit + signal(SIGABRT, abortHandler); + + Py_SetProgramName(argv[0]); + + // default path to m5 python code is the currently executing + // file... Python ZipImporter will find embedded zip archive + char *pythonpath = argv[0]; + + bool interactive = false; + bool getopt_done = false; + do { + switch (getopt(argc, argv, "+p:i")) { + // -p <path> prepends <path> to PYTHONPATH instead of + // using built-in zip archive. Useful when + // developing/debugging changes to built-in Python + // libraries, as the new Python can be tested without + // building a new m5 binary. + case 'p': + pythonpath = optarg; + break; + + // -i forces entry into interactive mode after the + // supplied script is executed (just like the -i option to + // the Python interpreter). + case 'i': + interactive = true; + break; + + case -1: + getopt_done = true; + break; + + default: + fatal("Unrecognized option %c\n", optopt); + } + } while (!getopt_done); + + // Fix up argc & argv to hide arguments we just processed. + // getopt() sets optind to the index of the first non-processed + // argv element. + argc -= optind; + argv += optind; + + // Set up PYTHONPATH to make sure the m5 module is found + string newpath(pythonpath); + + char *oldpath = getenv("PYTHONPATH"); + if (oldpath != NULL) { + newpath += ":"; + newpath += oldpath; + } + + if (setenv("PYTHONPATH", newpath.c_str(), true) == -1) + fatal("setenv: %s\n", strerror(errno)); + + // initialize embedded Python interpreter + Py_Initialize(); + PySys_SetArgv(argc, argv); + + // initialize SWIG 'main' module + init_main(); + + if (argc > 0) { + // extra arg(s): first is script file, remaining ones are args + // to script file + char *filename = argv[0]; + FILE *fp = fopen(filename, "r"); + if (!fp) { + fatal("cannot open file '%s'\n", filename); + } + + PyRun_AnyFile(fp, filename); + } else { + // no script file argument... force interactive prompt + interactive = true; + } + + if (interactive) { + // The following code to import readline was copied from Python + // 2.4.3's Modules/main.c. + // Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 + // Python Software Foundation; All Rights Reserved + // We should only enable this if we're actually using an + // interactive prompt. + PyObject *v; + v = PyImport_ImportModule("readline"); + if (v == NULL) + PyErr_Clear(); + else + Py_DECREF(v); + + PyRun_InteractiveLoop(stdin, "stdin"); + } + + // clean up Python intepreter. + Py_Finalize(); +} + + +/// Initialize C++ configuration. Exported to Python via SWIG; invoked +/// from m5.instantiate(). +void +initialize() +{ + configStream = simout.find("config.out"); + + // The configuration database is now complete; start processing it. + IniFile inifile; + inifile.load("config.ini"); + + // Initialize statistics database + Stats::InitSimStats(); + + // Now process the configuration hierarchy and create the SimObjects. + ConfigHierarchy configHierarchy(inifile); + configHierarchy.build(); + configHierarchy.createSimObjects(); + + // Parse and check all non-config-hierarchy parameters. + ParamContext::parseAllContexts(inifile); + ParamContext::checkAllContexts(); + + // Echo all parameter settings to stats file as well. + ParamContext::showAllContexts(*configStream); + + // Any objects that can't connect themselves until after construction should + // do so now + SimObject::connectAll(); + + // Do a second pass to finish initializing the sim objects + SimObject::initAll(); + + // Restore checkpointed state, if any. + configHierarchy.unserializeSimObjects(); + + // Done processing the configuration database. + // Check for unreferenced entries. + if (inifile.printUnreferenced()) + panic("unreferenced sections/entries in the intermediate ini file"); + + SimObject::regAllStats(); + + // uncomment the following to get PC-based execution-time profile +#ifdef DO_PROFILE + init_profile((char *)&_init, (char *)&_fini); +#endif + + // Check to make sure that the stats package is properly initialized + Stats::check(); + + // Reset to put the stats in a consistent state. + Stats::reset(); + + SimStartup(); +} + + +/** Simulate for num_cycles additional cycles. If num_cycles is -1 + * (the default), do not limit simulation; some other event must + * terminate the loop. Exported to Python via SWIG. + * @return The SimLoopExitEvent that caused the loop to exit. + */ +SimLoopExitEvent * +simulate(Tick num_cycles = -1) +{ + warn("Entering event queue @ %d. Starting simulation...\n", curTick); + + // Fix up num_cycles. Special default value -1 means simulate + // "forever"... schedule event at MaxTick just to be safe. + // Otherwise it's a delta for additional cycles to simulate past + // curTick, and thus must be non-negative. + if (num_cycles == -1) + num_cycles = MaxTick; + else if (num_cycles < 0) + fatal("simulate: num_cycles must be >= 0 (was %d)\n", num_cycles); + else + num_cycles = curTick + num_cycles; + + Event *limit_event = new SimLoopExitEvent(num_cycles, + "simulate() limit reached"); + + while (1) { + // there should always be at least one event (the SimLoopExitEvent + // we just scheduled) in the queue + assert(!mainEventQueue.empty()); + assert(curTick <= mainEventQueue.nextTick() && + "event scheduled in the past"); + + // forward current cycle to the time of the first event on the + // queue + curTick = mainEventQueue.nextTick(); + Event *exit_event = mainEventQueue.serviceOne(); + if (exit_event != NULL) { + // hit some kind of exit event; return to Python + // event must be subclass of SimLoopExitEvent... + SimLoopExitEvent *se_event = dynamic_cast<SimLoopExitEvent *>(exit_event); + if (se_event == NULL) + panic("Bogus exit event class!"); + + // if we didn't hit limit_event, delete it + if (se_event != limit_event) { + assert(limit_event->scheduled()); + limit_event->deschedule(); + delete limit_event; + } + + return se_event; + } + + if (async_event) { + async_event = false; + if (async_dump) { + async_dump = false; + + using namespace Stats; + SetupEvent(Dump, curTick); + } + + if (async_dumpreset) { + async_dumpreset = false; + + using namespace Stats; + SetupEvent(Dump | Reset, curTick); + } + + if (async_exit) { + async_exit = false; + exitSimLoop("user interrupt received"); + } + + if (async_io || async_alarm) { + async_io = false; + async_alarm = false; + pollQueue.service(); + } + } + } + + // not reached... only exit is return on SimLoopExitEvent +} + +/** + * Queue of C++ callbacks to invoke on simulator exit. + */ +CallbackQueue exitCallbacks; + +/** + * Register an exit callback. + */ +void +registerExitCallback(Callback *callback) +{ + exitCallbacks.add(callback); +} + +/** + * Do C++ simulator exit processing. Exported to SWIG to be invoked + * when simulator terminates via Python's atexit mechanism. + */ +void +doExitCleanup() +{ + exitCallbacks.process(); + exitCallbacks.clear(); + + cout.flush(); + + ParamContext::cleanupAllContexts(); + + // print simulation stats + Stats::DumpNow(); +} diff --git a/src/sim/param.cc b/src/sim/param.cc new file mode 100644 index 000000000..7f648b8e1 --- /dev/null +++ b/src/sim/param.cc @@ -0,0 +1,795 @@ +/* + * 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: Steve Reinhardt + */ + +#include <algorithm> +#include <cassert> +#include <list> +#include <string> +#include <vector> + +#include "base/inifile.hh" +#include "base/misc.hh" +#include "base/range.hh" +#include "base/str.hh" +#include "base/trace.hh" +#include "sim/config_node.hh" +#include "sim/configfile.hh" +#include "sim/param.hh" +#include "sim/sim_object.hh" + +using namespace std; + + +//////////////////////////////////////////////////////////////////////// +// +// BaseParam member definitions +// +//////////////////////////////////////////////////////////////////////// + +void +BaseParam::die(const string &err) const +{ + context->printErrorProlog(cerr); + cerr << " parameter '" << name << "': " + << err << endl; + abort(); +} + + +//////////////////////////////////////////////////////////////////////// +// +// Param<T> and VectorParam<T> member definitions +// +// We implement parsing & displaying values for various parameter +// types T using a set of overloaded functions: +// +// - parseParam(string s, T &value) parses s into value +// - showParam(ostream &os, T &value) displays value on os +// +// By making these independent functions, we can reuse the same code +// for type T in both Param<T> and VectorParam<T>. +// +// For enum types, the parseParam function requires additional +// arguments, in which case we must specialize the Param<T>::parse and +// VectorParam<T>::parse calls as well. +// +// Type-specific instances come first, followed by more generic +// templated versions and their instantiations. +// +//////////////////////////////////////////////////////////////////////// + +// +// The base implementations use to_number for parsing and '<<' for +// displaying, suitable for integer types. +// +template <class T> +bool +parseParam(const string &s, T &value) +{ + return to_number(s, value); +} + +template <class T> +void +showParam(ostream &os, T const &value) +{ + os << value; +} + +// +// Template specializations: +// - char (8-bit integer) +// - floating-point types +// - bool +// - string +// + +// Treat 8-bit ints (chars) as ints on output, not as chars +template <> +void +showParam(ostream &os, const char &value) +{ + os << (int)value; +} + + +template <> +void +showParam(ostream &os, const unsigned char &value) +{ + os << (unsigned int)value; +} + + +// Use sscanf() for FP types as to_number() only handles integers +template <> +bool +parseParam(const string &s, float &value) +{ + return (sscanf(s.c_str(), "%f", &value) == 1); +} + +template <> +bool +parseParam(const string &s, double &value) +{ + return (sscanf(s.c_str(), "%lf", &value) == 1); +} + +// Be flexible about what we take for bool +template <> +bool +parseParam(const string &s, bool &value) +{ + const string &ls = to_lower(s); + + if (ls == "true" || ls == "t" || ls == "yes" || ls == "y" || ls == "1") { + value = true; + return true; + } + + if (ls == "false" || ls == "f" || ls == "no" || ls == "n" || ls == "0") { + value = false; + return true; + } + + return false; +} + +// Display bools as strings +template <> +void +showParam(ostream &os, const bool &value) +{ + os << (value ? "true" : "false"); +} + + +// String requires no processing to speak of +template <> +bool +parseParam(const string &s, string &value) +{ + value = s; + return true; +} + +template <> +bool +parseParam(const string &s, Range<uint32_t> &value) +{ + value = s; + return value.valid(); +} + +template <> +bool +parseParam(const string &s, Range<uint64_t> &value) +{ + value = s; + return value.valid(); +} + +// +// End of parseParam/showParam definitions. Now we move on to +// incorporate them into the Param/VectorParam parse() and showValue() +// methods. +// + +// These definitions for Param<T>::parse and VectorParam<T>::parse +// work for any type for which parseParam() takes only two arguments +// (i.e., all the fundamental types like int, bool, etc.), thanks to +// overloading. +template <class T> +void +Param<T>::parse(const string &s) +{ + if (parseParam(s, value)) { + wasSet = true; + } + else { + string err("could not parse \""); + + err += s; + err += "\""; + + die(err); + } +} + +template <class T> +void +VectorParam<T>::parse(const string &s) +{ + if (s.empty()) { + wasSet = true; + return; + } + + vector<string> tokens; + + tokenize(tokens, s, ' '); + + value.resize(tokens.size()); + + for (int i = 0; i < tokens.size(); i++) { + // need to parse into local variable to handle vector<bool>, + // for which operator[] returns a special reference class + // that's not the same as 'bool&', (since it's a packed + // vector) + T scalar_value; + if (!parseParam(tokens[i], scalar_value)) { + string err("could not parse \""); + + err += s; + err += "\""; + + die(err); + } + + // assign parsed value to vector + value[i] = scalar_value; + } + + wasSet = true; +} + +// These definitions for Param<T>::showValue() and +// VectorParam<T>::showValue() work for any type where showParam() +// takes only two arguments (i.e., everything but the SimpleEnum and +// MappedEnum classes). +template <class T> +void +Param<T>::showValue(ostream &os) const +{ + showParam(os, value); +} + +template <class T> +void +VectorParam<T>::showValue(ostream &os) const +{ + for (int i = 0; i < value.size(); i++) { + if (i != 0) { + os << " "; + } + showParam(os, value[i]); + } +} + + +#ifdef INSURE_BUILD +#define INSTANTIATE_PARAM_TEMPLATES(type, typestr) \ +void Param<type>::showType(ostream &os) const { os << typestr; } \ +void VectorParam<type>::showType(ostream &os) const { \ + os << "vector of " << typestr; \ +} \ +template Param<type>; \ +template VectorParam<type>; + +#else +// instantiate all four methods (parse/show, scalar/vector) for basic +// types that can use the above templates +#define INSTANTIATE_PARAM_TEMPLATES(type, typestr) \ +template bool parseParam<type>(const string &s, type &value); \ +template void showParam<type>(ostream &os, type const &value); \ +template void Param<type>::parse(const string &); \ +template void VectorParam<type>::parse(const string &); \ +template void Param<type>::showValue(ostream &) const; \ +template void VectorParam<type>::showValue(ostream &) const; \ +template <> void Param<type>::showType(ostream &os) const { os << typestr; } \ +template <> void VectorParam<type>::showType(ostream &os) const { \ + os << "vector of " << typestr; \ +} +#endif + +INSTANTIATE_PARAM_TEMPLATES(unsigned long long, "ull") +INSTANTIATE_PARAM_TEMPLATES(signed long long, "sll") +INSTANTIATE_PARAM_TEMPLATES(unsigned long, "uns long") +INSTANTIATE_PARAM_TEMPLATES(signed long, "long") +INSTANTIATE_PARAM_TEMPLATES(unsigned int, "uns") +INSTANTIATE_PARAM_TEMPLATES(signed int, "int") +INSTANTIATE_PARAM_TEMPLATES(unsigned short, "uns short") +INSTANTIATE_PARAM_TEMPLATES(signed short, "short") +INSTANTIATE_PARAM_TEMPLATES(unsigned char, "uns char") +INSTANTIATE_PARAM_TEMPLATES(signed char, "char") + +INSTANTIATE_PARAM_TEMPLATES(float, "float") +INSTANTIATE_PARAM_TEMPLATES(double, "double") + +INSTANTIATE_PARAM_TEMPLATES(bool, "bool") +INSTANTIATE_PARAM_TEMPLATES(string, "string") + +INSTANTIATE_PARAM_TEMPLATES(Range<uint64_t>, "uint64 range") +INSTANTIATE_PARAM_TEMPLATES(Range<uint32_t>, "uint32 range") + +#undef INSTANTIATE_PARAM_TEMPLATES + +// +// SimpleEnumParam & MappedEnumParam must specialize their parse(), +// showValue(), and showType() methods. +// + +// +// SimpleEnumParam & SimpleEnumVectorParam +// +bool +parseEnumParam(const char *const *map, const int num_values, + const string &s, int &value) +{ + for (int i = 0; i < num_values; ++i) { + if (s == map[i]) { + value = i; + return true; + } + } + + return false; +} + +void +showEnumParam(ostream &os, + const char *const *map, const int num_values, + int value) +{ + assert(0 <= value && value < num_values); + os << map[value]; +} + +void +showEnumType(ostream &os, + const char *const *map, const int num_values) +{ + os << "{" << map[0]; + for (int i = 1; i < num_values; ++i) + os << "," << map[i]; + + os << "}"; +} + + +// +// MappedEnumParam & MappedEnumVectorParam +// +bool +parseEnumParam(const EnumParamMap *map, const int num_values, + const string &s, int &value) +{ + for (int i = 0; i < num_values; ++i) { + if (s == map[i].name) { + value = map[i].value; + return true; + } + } + + return false; +} + +void +showEnumParam(ostream &os, + const EnumParamMap *map, const int num_values, + int value) +{ + for (int i = 0; i < num_values; ++i) { + if (value == map[i].value) { + os << map[i].name; + return; + } + } + + // if we can't find a reverse mapping just print the int value + os << value; +} + +void +showEnumType(ostream &os, + const EnumParamMap *map, const int num_values) +{ + os << "{" << map[0].name; + for (int i = 1; i < num_values; ++i) + os << "," << map[i].name; + + os << "}"; +} + + +template <class Map> +void +EnumParam<Map>::parse(const string &s) +{ + if (parseEnumParam(map, num_values, s, value)) { + wasSet = true; + } else { + string err("no match for enum string \""); + + err += s; + err += "\""; + + die(err); + } +} + +template <class Map> +void +EnumVectorParam<Map>::parse(const string &s) +{ + vector<string> tokens; + + if (s.empty()) { + wasSet = true; + return; + } + + tokenize(tokens, s, ' '); + + value.resize(tokens.size()); + + for (int i = 0; i < tokens.size(); i++) { + if (!parseEnumParam(map, num_values, tokens[i], value[i])) { + string err("no match for enum string \""); + + err += s; + err += "\""; + + die(err); + } + } + + wasSet = true; +} + +template <class Map> +void +EnumParam<Map>::showValue(ostream &os) const +{ + showEnumParam(os, map, num_values, value); +} + +template <class Map> +void +EnumVectorParam<Map>::showValue(ostream &os) const +{ + for (int i = 0; i < value.size(); i++) { + if (i != 0) { + os << " "; + } + showEnumParam(os, map, num_values, value[i]); + } +} + +template <class Map> +void +EnumParam<Map>::showType(ostream &os) const +{ + showEnumType(os, map, num_values); +} + +template <class Map> +void +EnumVectorParam<Map>::showType(ostream &os) const +{ + os << "vector of"; + showEnumType(os, map, num_values); +} + +template class EnumParam<const char *>; +template class EnumVectorParam<const char *>; + +template class EnumParam<EnumParamMap>; +template class EnumVectorParam<EnumParamMap>; + +//////////////////////////////////////////////////////////////////////// +// +// SimObjectBaseParam methods +// +//////////////////////////////////////////////////////////////////////// + +bool +parseSimObjectParam(ParamContext *context, const string &s, SimObject *&value) +{ + SimObject *obj; + + if (to_lower(s) == "null") { + // explicitly set to null by user; assume that's OK + obj = NULL; + } + else { + obj = context->resolveSimObject(s); + + if (obj == NULL) + return false; + } + + value = obj; + return true; +} + + +void +SimObjectBaseParam::showValue(ostream &os, SimObject *value) const +{ + os << (value ? value->name() : "null"); +} + +void +SimObjectBaseParam::parse(const string &s, SimObject *&value) +{ + if (parseSimObjectParam(context, s, value)) { + wasSet = true; + } + else { + string err("could not resolve object name \""); + + err += s; + err += "\""; + + die(err); + } +} + +void +SimObjectBaseParam::parse(const string &s, vector<SimObject *>&value) +{ + vector<string> tokens; + + tokenize(tokens, s, ' '); + + value.resize(tokens.size()); + + for (int i = 0; i < tokens.size(); i++) { + if (!parseSimObjectParam(context, tokens[i], value[i])) { + string err("could not resolve object name \""); + + err += s; + err += "\""; + + die(err); + } + } + + wasSet = true; +} + +//////////////////////////////////////////////////////////////////////// +// +// ParamContext member definitions +// +//////////////////////////////////////////////////////////////////////// + +list<ParamContext *> *ParamContext::ctxList = NULL; + +ParamContext::ParamContext(const string &_iniSection, InitPhase _initPhase) + : iniFilePtr(NULL), // initialized on call to parseParams() + iniSection(_iniSection), paramList(NULL), + initPhase(_initPhase) +{ + // Put this context on global list for initialization + if (initPhase != NoAutoInit) { + if (ctxList == NULL) + ctxList = new list<ParamContext *>(); + + // keep list sorted by ascending initPhase values + list<ParamContext *>::iterator i = ctxList->begin(); + list<ParamContext *>::iterator end = ctxList->end(); + for (; i != end; ++i) { + if (initPhase <= (*i)->initPhase) { + // found where we want to insert + break; + } + } + // (fall through case: insert at end) + ctxList->insert(i, this); + } +} + + +void +ParamContext::addParam(BaseParam *param) +{ + getParamList()->push_back(param); +} + + +void +ParamContext::parseParams(IniFile &iniFile) +{ + iniFilePtr = &iniFile; // set object member + + ParamList::iterator i; + + for (i = getParamList()->begin(); i != getParamList()->end(); ++i) { + string string_value; + + if (iniFile.find(iniSection, (*i)->name, string_value)) + (*i)->parse(string_value); + } +} + + +// Check parameter values for validity & consistency. Default +// implementation is no-op; derive subclass & override to add +// actual functionality here. +void +ParamContext::checkParams() +{ + // nada +} + + +// Clean up context-related objects at end of execution. Default +// implementation is no-op; derive subclass & override to add actual +// functionality here. +void +ParamContext::cleanup() +{ + // nada +} + + +void +ParamContext::describeParams(ostream &os) +{ + ParamList::iterator i; + + for (i = getParamList()->begin(); i != getParamList()->end(); ++i) { + BaseParam *p = *i; + + os << p->name << " ("; + p->showType(os); + os << "): " << p->description << "\n"; + } +} + + + +void +ParamContext::showParams(ostream &os) +{ + ParamList::iterator i; + + for (i = getParamList()->begin(); i != getParamList()->end(); ++i) { + BaseParam *p = *i; + + if (p->isValid()) { + os << p->name << "="; + p->showValue(os); + os << endl; + } + else { + os << "// "<< p->name << " not specified" << endl; + } + } +} + + +void +ParamContext::printErrorProlog(ostream &os) +{ + os << "Parameter error in section [" << iniSection << "]: " << endl; +} + +// +// Resolve an object name to a SimObject pointer. The object will be +// created as a side-effect if necessary. If the name contains a +// colon (e.g., "iq:IQ"), then the object is local (invisible to +// outside this context). If there is no colon, the name needs to be +// resolved through the configuration hierarchy (only possible for +// SimObjectBuilder objects, which return non-NULL for configNode()). +// +SimObject * +ParamContext::resolveSimObject(const string &name) +{ + ConfigNode *n = getConfigNode(); + return n ? n->resolveSimObject(name) : NULL; +} + + +// +// static method: call parseParams() on all registered contexts +// +void +ParamContext::parseAllContexts(IniFile &iniFile) +{ + list<ParamContext *>::iterator iter; + + for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) { + ParamContext *pc = *iter; + + pc->parseParams(iniFile); + } +} + + +// +// static method: call checkParams() on all registered contexts +// +void +ParamContext::checkAllContexts() +{ + list<ParamContext *>::iterator iter; + + for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) { + ParamContext *pc = *iter; + + pc->checkParams(); + } +} + + +// +// static method: call showParams() on all registered contexts +// +void +ParamContext::showAllContexts(ostream &os) +{ + list<ParamContext *>::iterator iter; + + for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) { + ParamContext *pc = *iter; + + os << "[" << pc->iniSection << "]" << endl; + pc->showParams(os); + os << endl; + } +} + + +// +// static method: call cleanup() on all registered contexts +// +void +ParamContext::cleanupAllContexts() +{ + list<ParamContext *>::iterator iter; + + for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) { + ParamContext *pc = *iter; + + pc->cleanup(); + } +} + + +// +// static method: call describeParams() on all registered contexts +// +void +ParamContext::describeAllContexts(ostream &os) +{ + list<ParamContext *>::iterator iter; + + for (iter = ctxList->begin(); iter != ctxList->end(); ++iter) { + ParamContext *pc = *iter; + + os << "[" << pc->iniSection << "]\n"; + pc->describeParams(os); + os << endl; + } +} diff --git a/src/sim/param.hh b/src/sim/param.hh new file mode 100644 index 000000000..49db17df9 --- /dev/null +++ b/src/sim/param.hh @@ -0,0 +1,790 @@ +/* + * 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: Steve Reinhardt + */ + +#ifndef __SIM_PARAM_HH__ +#define __SIM_PARAM_HH__ + +#include <iostream> +#include <list> +#include <string> +#include <vector> + +#include "sim/configfile.hh" +#include "sim/startup.hh" + +// forward decls +class BaseParam; +class SimObject; + +// +// The context of a parameter definition... usually a subclass of +// SimObjectBuilder (which derives from ParamContext), but abstracted +// here to support more global simulator control parameters as well. +// +class ParamContext : protected StartupCallback +{ + private: + + // static list of all ParamContext objects, built as a side effect + // of the ParamContext constructor + static std::list<ParamContext *> *ctxList; + + protected: + + // .ini file (database) for parameter lookup... initialized on call + // to parseParams() + IniFile *iniFilePtr; + + // .ini file section for parameter lookup + const std::string iniSection; + + typedef std::vector<BaseParam *> ParamList; + + // list of parameters defined in this context + ParamList *paramList; + + ParamList *getParamList() { + if (!paramList) + paramList = new ParamList; + return paramList; + } + + public: + + /// Initialization phases for ParamContext objects. + enum InitPhase { + NoAutoInit = -1, ///< Don't initialize at all... params + /// will be parsed later (used by + /// SimObjectBuilder, which parses + /// params in SimObject::create(). + OutputInitPhase = 0, ///< Output stream initialization + TraceInitPhase = 1, ///< Trace context initialization: + /// depends on output streams, but + /// needs to come before others so we + /// can use tracing in other + /// ParamContext init code + StatsInitPhase = 2, ///< Stats output initialization + DefaultInitPhase = 3 ///< Everything else + }; + + /// Records the initialization phase for this ParamContext. + InitPhase initPhase; + + /// Constructor. + /// @param _iniSection Name of .ini section corresponding to this context. + /// @param _initPhase Initialization phase (see InitPhase). + ParamContext(const std::string &_iniSection, + InitPhase _initPhase = DefaultInitPhase); + + virtual ~ParamContext() {} + + // add a parameter to the context... called from the parameter + // object's constructor (see BaseParam::BaseParam()) + void addParam(BaseParam *); + + // call parse() on all params in this context to convert string + // representations to parameter values + virtual void parseParams(IniFile &iniFile); + + // Check parameter values for validity & consistency. Default + // implementation is no-op; derive subclass & override to add + // actual functionality here + virtual void checkParams(); + + // Clean up at end of execution: close file descriptors, etc. + // Default implementation is no-op; derive subclass & override to + // add actual functionality here + virtual void cleanup(); + + // dump parameter descriptions + void describeParams(std::ostream &); + + // Display the parameters & values used + void showParams(std::ostream &); + + // print context information for parameter error + virtual void printErrorProlog(std::ostream &); + + // resolve a SimObject name in this context to an object pointer. + virtual SimObject *resolveSimObject(const std::string &name); + + // generate the name for this instance of this context (used as a + // prefix to create unique names in resolveSimObject() + virtual const std::string &getInstanceName() { return iniSection; } + + // return the configuration hierarchy node for this context. Bare + // ParamContext objects have no corresponding node, so the default + // implementation returns NULL. + virtual ConfigNode *getConfigNode() { return NULL; } + + // Parse all parameters registered with all ParamContext objects. + static void parseAllContexts(IniFile &iniFile); + + // Check all parameters registered with all ParamContext objects. + // (calls checkParams() on each) + static void checkAllContexts(); + + // Print all parameter values on indicated ostream. + static void showAllContexts(std::ostream &os); + + // Clean up all registered ParamContext objects. (calls cleanup() + // on each) + static void cleanupAllContexts(); + + // print descriptions of all parameters registered with all + // ParamContext objects + static void describeAllContexts(std::ostream &os); +}; + + +// +// Base class for all parameter objects +// +class BaseParam +{ + public: + + ParamContext *context; + std::string name; + std::string description; // text description for help message + bool wasSet; // true if parameter was set by user + bool hasDefault; // true if parameter has default value + + BaseParam(ParamContext *_context, const std::string &_name, + const std::string &_description, bool _hasDefault) + : context(_context), name(_name), description(_description), + wasSet(false), hasDefault(_hasDefault) + { + context->addParam(this); + } + + virtual ~BaseParam() {} + + // a parameter is valid only if its value was set by the user or + // it has a default value + bool isValid() const + { + return (wasSet || hasDefault); + } + + // set value by parsing string + virtual void parse(const std::string &s) = 0; + + // display value to stream + virtual void showValue(std::ostream &) const = 0; + + // display type to stream + virtual void showType(std::ostream &) const = 0; + + // signal parse or usage error + virtual void die(const std::string &err) const; +}; + +// +// Template classes to specialize parameters to specific types. +// +// Param<T> is for single-valued (scalar) parameters of type T. +// VectorParam<T> is for multi-valued (vector) parameters of type T. +// These are specified in the .ini file as a space-delimited list of +// arguments. +// +template <class T> +class Param : public BaseParam +{ + protected: + + T value; + + public: + + // Param with default value: set value to default + Param(ParamContext *context, + const std::string &name, const std::string &description, T dfltValue) + : BaseParam(context, name, description, true), + value(dfltValue) + { + } + + // Param with no default value: leave value uninitialized + Param(ParamContext *context, + const std::string &name, const std::string &description) + : BaseParam(context, name, description, false) + { + } + + virtual ~Param() {} + + operator T&() + { + // if we attempt to reference an invalid parameter (i.e., one + // with no default value that was not set by the user), die. + if (!isValid()) + die("not found"); + return value; + } + + // display value to stream + virtual void showValue(std::ostream &os) const; + + // display type to stream + virtual void showType(std::ostream &) const; + + // set value by parsing string + virtual void parse(const std::string &s); +}; + + +// +// Template class for vector-valued parameters (lists) +// +template <class T> +class VectorParam : public BaseParam +{ + protected: + + std::vector<T> value; + + public: + + typedef typename std::vector<T>::size_type size_type; + + // Param with default value: set value to default + VectorParam(ParamContext *context, const std::string &name, + const std::string &description, + const std::vector<T> &dfltValue) + : BaseParam(context, name, description, true), + value(dfltValue) + { + } + + // Param with no default value: leave value uninitialized + VectorParam(ParamContext *context, + const std::string &name, const std::string &description) + : BaseParam(context, name, description, false) + { + } + + virtual ~VectorParam() {} + + // basic vector access methods + size_type size() const + { + if (!isValid()) + die("not found"); + return value.size(); + } + + const T &operator[](size_type n) const + { + if (!isValid()) + die("not found"); + return value[n]; + } + + // return reference to value vector + operator std::vector<T>&() + { + if (!isValid()) + die("not found"); + return value; + } + + // display value to stream + virtual void showValue(std::ostream &os) const; + + // display type to stream + virtual void showType(std::ostream &) const; + + // set value by parsing string + virtual void parse(const std::string &s); +}; + +// +// Specialization of Param<int> and VectorParam<int> to handle +// enumerated types is done in two ways, using SimpleEnumParam and +// MappedEnumParam (and their vector counterparts, +// SimpleEnumVectorParam and MappedEnumVectorParam). SimpleEnumParam +// takes an array of strings and maps them to integers based on array +// index. MappedEnumParam takes an array of string-to-int mappings, +// allowing for mapping strings to non-contiguous integer values, or +// mapping multiple strings to the same integer value. +// +// Both SimpleEnumParam and MappedEnumParam are implemented using a +// single template class, EnumParam<Map>, which takes the type of the map +// as a parameter (const char * or EnumParamMap). Similarly, +// SimpleEnumVectorParam and MappedEnumVectorParam are both +// implemented using EnumVectorParam<Map>. +// +template <class Map> +class EnumParam : public Param<int> +{ + const int num_values; + const Map *map; + + public: + + // Param with default value: set value to default + EnumParam(ParamContext *context, + const std::string &name, const std::string &description, + const Map *_map, int _num_values, + int dfltValue) + : Param<int>(context, name, description, dfltValue), + num_values(_num_values), map(_map) + { + } + + // Param with no default value: leave value uninitialized + EnumParam(ParamContext *context, + const std::string &name, const std::string &description, + const Map *_map, int _num_values) + : Param<int>(context, name, description), + num_values(_num_values), map(_map) + { + } + + virtual ~EnumParam() {} + + // display value to stream + virtual void showValue(std::ostream &os) const; + + // display type to stream + virtual void showType(std::ostream &) const; + + // set value by parsing string + virtual void parse(const std::string &s); +}; + +// +// Vector counterpart to SimpleEnumParam +// +template <class Map> +class EnumVectorParam : public VectorParam<int> +{ + const int num_values; + const Map *map; + + public: + + // Param with default value: set value to default + EnumVectorParam(ParamContext *context, + const std::string &name, const std::string &description, + const Map *_map, int _num_values, + std::vector<int> &dfltValue) + : VectorParam<int>(context, name, description, dfltValue), + num_values(_num_values), map(_map) + { + } + + // Param with no default value: leave value uninitialized + EnumVectorParam(ParamContext *context, + const std::string &name, const std::string &description, + const Map *_map, int _num_values) + : VectorParam<int>(context, name, description), + num_values(_num_values), map(_map) + { + } + + virtual ~EnumVectorParam() {} + + // display value to stream + virtual void showValue(std::ostream &os) const; + + // display type to stream + virtual void showType(std::ostream &) const; + + // set value by parsing string + virtual void parse(const std::string &s); +}; + +// Specialize EnumParam for a particular enumeration type ENUM +// (automates casting to get value of enum type) + +template <class ENUM> +class SimpleEnumParam : public EnumParam<const char *> +{ + public: + + SimpleEnumParam(ParamContext *context, + const std::string &name, const std::string &description, + const char **_map, int _num_values, + ENUM dfltValue) + : EnumParam<const char *>(context, name, description, + _map, _num_values, (int)dfltValue) + { + } + + SimpleEnumParam(ParamContext *context, + const std::string &name, const std::string &description, + const char **_map, int _num_values) + : EnumParam<const char *>(context, name, description, + _map, _num_values) + { + } + + operator ENUM() const + { + if (!isValid()) + die("not found"); + return (ENUM)value; + } +}; + + +// Specialize EnumParam for a particular enumeration type ENUM +// (automates casting to get value of enum type) + +template <class ENUM> +class SimpleEnumVectorParam : public EnumVectorParam<const char *> +{ + public: + + // skip default value constructor: too much pain to convert + // vector<ENUM> initializer to vector<int> + + + SimpleEnumVectorParam(ParamContext *context, + const std::string &name, + const std::string &description, + const char **_map, int _num_values) + : EnumVectorParam<const char *>(context, name, description, + _map, _num_values) + { + } + + ENUM operator[](size_type n) + { + if (!isValid()) + die("not found"); + return (ENUM)value[n]; + } +}; + + +// +// Handle enums via string-to-int map (see comment above). +// + +// An array of string-to-int mappings must be supplied using the +// following type. +typedef struct { + const char *name; + int value; +} EnumParamMap; + +// Specialize EnumParam for a particular enumeration type ENUM +// (automates casting to get value of enum type) + +template <class ENUM> +class MappedEnumParam : public EnumParam<EnumParamMap> +{ + public: + + MappedEnumParam(ParamContext *context, + const std::string &name, const std::string &description, + const EnumParamMap *_map, int _num_values, + ENUM dfltValue) + : EnumParam<EnumParamMap>(context, name, description, + _map, _num_values, (int)dfltValue) + { + } + + MappedEnumParam(ParamContext *context, + const std::string &name, const std::string &description, + const EnumParamMap *_map, int _num_values) + : EnumParam<EnumParamMap>(context, name, description, + _map, _num_values) + { + } + + operator ENUM() + { + if (!isValid()) + die("not found"); + return (ENUM)value[this->n]; + } +}; + + +// Specialize EnumParam for a particular enumeration type ENUM +// (automates casting to get value of enum type) + +template <class ENUM> +class MappedEnumVectorParam : public EnumVectorParam<EnumParamMap> +{ + public: + + // skip default value constructor: too much pain to convert + // vector<ENUM> initializer to vector<int> + + + MappedEnumVectorParam(ParamContext *context, + const std::string &name, + const std::string &description, + const EnumParamMap *_map, int _num_values) + : EnumVectorParam<EnumParamMap>(context, name, description, + _map, _num_values) + { + } + + ENUM operator[](size_type n) + { + if (!isValid()) + die("not found"); + return (ENUM)value[n]; + } +}; + + +// +// Parameters that point to other simulation objects (e.g. caches, +// busses, etc.) are handled by specializing SimObjectBaseParam to the +// specific subtype. The main purpose of SimObjectBaseParam is to +// provide a place to stick several helper functions common to all +// SimObject-derived parameters. +// +class SimObjectBaseParam : public BaseParam +{ + public: + + SimObjectBaseParam(ParamContext *context, const std::string &name, + const std::string &description, bool hasDefault) + : BaseParam(context, name, description, hasDefault) + { + } + + virtual ~SimObjectBaseParam() {} + + // helper function for SimObjectParam<T>::showValue() + void showValue(std::ostream &os, SimObject *obj) const; + + // helper function for SimObjectParam<T>::parse() + void parse(const std::string &s, SimObject *&value); + + // helper function for SimObjectParam<T>::parse() + void parse(const std::string &s, std::vector<SimObject *>&value_vec); +}; + + +// +// Parameter to a specific type of SimObject. Note that T must be a +// pointer to a class derived from SimObject (e.g., <CPU *>). +// + +template <class T> class SimObjectParam; + +template <class T> +class SimObjectParam<T *> : public SimObjectBaseParam +{ + protected: + + T *value; + + public: + + // initialization w/o default + SimObjectParam(ParamContext *context, + const std::string &name, const std::string &description) + : SimObjectBaseParam(context, name, description, false) + { + } + + // initialization wit=h default + SimObjectParam(ParamContext *context, + const std::string &name, const std::string &description, + T *dfltValue) + : SimObjectBaseParam(context, name, description, true), + value(dfltValue) + { + } + + virtual ~SimObjectParam() {} + + // convert to pointer + operator T*() + { + if (!isValid()) + die("not found"); + return value; + } + + T *operator->() const + { + if (!isValid()) + die("not found"); + return value; + } + + // display value to stream + virtual void showValue(std::ostream &os) const + { + SimObjectBaseParam::showValue(os, value); + } + + // display type to stream: see REGISTER_SIM_OBJECT macro in + // sim_object.hh for declaration + virtual void showType(std::ostream &os) const; + + // set value by parsing string + virtual void parse(const std::string &s) + { + SimObject *so_ptr; + // first parse to generic SimObject * + SimObjectBaseParam::parse(s, so_ptr); + // now dynamic_cast to specific derived type + value = dynamic_cast<T *>(so_ptr); + // check for failure of dynamic_cast + if (value == NULL && so_ptr != NULL) + die("not of appropriate type"); + } +}; + + +// +// Vector counterpart to SimObjectParam<T> +// + +template <class T> class SimObjectVectorParam; + +template <class T> +class SimObjectVectorParam<T *> : public SimObjectBaseParam +{ + protected: + + std::vector<T *> value; + + public: + + typedef typename std::vector<T *>::size_type size_type; + + SimObjectVectorParam(ParamContext *context, + const std::string &name, + const std::string &description) + : SimObjectBaseParam(context, name, description, false) + { + } + + SimObjectVectorParam(ParamContext *context, + const std::string &name, + const std::string &description, + std::vector<T *> dfltValue) + : SimObjectBaseParam(context, name, description, true), + value(dfltValue) + { + } + + virtual ~SimObjectVectorParam() {} + + // basic vector access methods + size_type size() const + { + if (!isValid()) + die("not found"); + return value.size(); + } + + T *&operator[](size_type n) + { + if (!isValid()) + die("not found"); + return value[n]; + } + + // return reference to value vector + operator std::vector<T *>&() + { + if (!isValid()) + die("not found"); + return value; + } + + // display value to stream + virtual void showValue(std::ostream &os) const + { + for (int i = 0; i < value.size(); i++) { + if (i != 0) + os << " "; + SimObjectBaseParam::showValue(os, value[i]); + } + } + + // display type to stream: see + virtual void showType(std::ostream &os) const; + + // set value by parsing string + virtual void parse(const std::string &s) + { + std::vector<SimObject *> so_ptr_vec; + // first parse to generic SimObject * vector (from SimObjectBaseParam) + SimObjectBaseParam::parse(s, so_ptr_vec); + + value.resize(so_ptr_vec.size()); + + for (int i = 0; i < so_ptr_vec.size(); ++i) { + // now dynamic_cast to specific derived type + value[i] = dynamic_cast<T *>(so_ptr_vec[i]); + // check for failure of dynamic_cast + if (value[i] == NULL && so_ptr_vec[i] != NULL) + die("not of appropriate type"); + } + } +}; + +// +// Macro to define showType() methods for SimObjectParam & +// SimObjectVectorParam. Can't do this automatically as it requires a +// string name for the type, which you can't get from a template +// argument. For concrete derived SimObject types, this macro is +// automatically invoked by REGISTER_SIM_OBJECT() (see sim_object.hh). +// +#define DEFINE_SIM_OBJECT_CLASS_NAME(CLASS_NAME, OBJ_CLASS) \ +template<> \ +void \ +SimObjectParam<OBJ_CLASS *>::showType(std::ostream &os) const \ +{ \ + os << CLASS_NAME; \ +} \ + \ +template<> \ +void \ +SimObjectVectorParam<OBJ_CLASS *>::showType(std::ostream &os) const \ +{ \ + os << "vector of " << CLASS_NAME; \ +} + + +// +// Declarations for low-level parsing & displaying functions. These +// are used internally, but should not be used directly by clients of +// the parameter mechanism, but are declared here so they can be +// shared with the serialization code (see sim/serialize.cc). +template <class T> bool parseParam(const std::string &str, T &data); +template <class T> void showParam(std::ostream &os, const T &data); + +#endif // _SIM_PARAM_HH_ diff --git a/src/sim/process.cc b/src/sim/process.cc new file mode 100644 index 000000000..1533a376d --- /dev/null +++ b/src/sim/process.cc @@ -0,0 +1,365 @@ +/* + * 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 + * Steve Reinhardt + * Ali Saidi + */ + +#include <unistd.h> +#include <fcntl.h> + +#include <string> + +#include "base/intmath.hh" +#include "base/loader/object_file.hh" +#include "base/loader/symtab.hh" +#include "base/statistics.hh" +#include "config/full_system.hh" +#include "cpu/thread_context.hh" +#include "mem/page_table.hh" +#include "mem/physical.hh" +#include "mem/translating_port.hh" +#include "sim/builder.hh" +#include "sim/process.hh" +#include "sim/stats.hh" +#include "sim/syscall_emul.hh" +#include "sim/system.hh" + +using namespace std; +using namespace TheISA; + +// +// The purpose of this code is to fake the loader & syscall mechanism +// when there's no OS: thus there's no resone to use it in FULL_SYSTEM +// mode when we do have an OS +// +#if FULL_SYSTEM +#error "process.cc not compatible with FULL_SYSTEM" +#endif + +// current number of allocated processes +int num_processes = 0; + +Process::Process(const string &nm, + System *_system, + int stdin_fd, // initial I/O descriptors + int stdout_fd, + int stderr_fd) + : SimObject(nm), system(_system) +{ + // initialize first 3 fds (stdin, stdout, stderr) + fd_map[STDIN_FILENO] = stdin_fd; + fd_map[STDOUT_FILENO] = stdout_fd; + fd_map[STDERR_FILENO] = stderr_fd; + + // mark remaining fds as free + for (int i = 3; i <= MAX_FD; ++i) { + fd_map[i] = -1; + } + + mmap_start = mmap_end = 0; + nxm_start = nxm_end = 0; + pTable = new PageTable(system); + // other parameters will be initialized when the program is loaded +} + + +void +Process::regStats() +{ + using namespace Stats; + + num_syscalls + .name(name() + ".PROG:num_syscalls") + .desc("Number of system calls") + ; +} + +// +// static helper functions +// +int +Process::openInputFile(const string &filename) +{ + int fd = open(filename.c_str(), O_RDONLY); + + if (fd == -1) { + perror(NULL); + cerr << "unable to open \"" << filename << "\" for reading\n"; + fatal("can't open input file"); + } + + return fd; +} + + +int +Process::openOutputFile(const string &filename) +{ + int fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0774); + + if (fd == -1) { + perror(NULL); + cerr << "unable to open \"" << filename << "\" for writing\n"; + fatal("can't open output file"); + } + + return fd; +} + + +int +Process::registerThreadContext(ThreadContext *tc) +{ + // add to list + int myIndex = threadContexts.size(); + threadContexts.push_back(tc); + + // return CPU number to caller + return myIndex; +} + +void +Process::startup() +{ + if (threadContexts.empty()) + fatal("Process %s is not associated with any CPUs!\n", name()); + + // first thread context for this process... initialize & enable + ThreadContext *tc = threadContexts[0]; + + // mark this context as active so it will start ticking. + tc->activate(0); + + Port *mem_port; + mem_port = system->physmem->getPort("functional"); + initVirtMem = new TranslatingPort("process init port", pTable, true); + mem_port->setPeer(initVirtMem); + initVirtMem->setPeer(mem_port); +} + +void +Process::replaceThreadContext(ThreadContext *tc, int tcIndex) +{ + if (tcIndex >= threadContexts.size()) { + panic("replaceThreadContext: bad tcIndex, %d >= %d\n", + tcIndex, threadContexts.size()); + } + + threadContexts[tcIndex] = tc; +} + +// map simulator fd sim_fd to target fd tgt_fd +void +Process::dup_fd(int sim_fd, int tgt_fd) +{ + if (tgt_fd < 0 || tgt_fd > MAX_FD) + panic("Process::dup_fd tried to dup past MAX_FD (%d)", tgt_fd); + + fd_map[tgt_fd] = sim_fd; +} + + +// generate new target fd for sim_fd +int +Process::alloc_fd(int sim_fd) +{ + // in case open() returns an error, don't allocate a new fd + if (sim_fd == -1) + return -1; + + // find first free target fd + for (int free_fd = 0; free_fd < MAX_FD; ++free_fd) { + if (fd_map[free_fd] == -1) { + fd_map[free_fd] = sim_fd; + return free_fd; + } + } + + panic("Process::alloc_fd: out of file descriptors!"); +} + + +// free target fd (e.g., after close) +void +Process::free_fd(int tgt_fd) +{ + if (fd_map[tgt_fd] == -1) + warn("Process::free_fd: request to free unused fd %d", tgt_fd); + + fd_map[tgt_fd] = -1; +} + + +// look up simulator fd for given target fd +int +Process::sim_fd(int tgt_fd) +{ + if (tgt_fd > MAX_FD) + return -1; + + return fd_map[tgt_fd]; +} + + + +// +// need to declare these here since there is no concrete Process type +// that can be constructed (i.e., no REGISTER_SIM_OBJECT() macro call, +// which is where these get declared for concrete types). +// +DEFINE_SIM_OBJECT_CLASS_NAME("Process", Process) + + +//////////////////////////////////////////////////////////////////////// +// +// LiveProcess member definitions +// +//////////////////////////////////////////////////////////////////////// + + +void +copyStringArray(vector<string> &strings, Addr array_ptr, Addr data_ptr, + TranslatingPort* memPort) +{ + Addr data_ptr_swap; + for (int i = 0; i < strings.size(); ++i) { + data_ptr_swap = htog(data_ptr); + memPort->writeBlob(array_ptr, (uint8_t*)&data_ptr_swap, sizeof(Addr)); + memPort->writeString(data_ptr, strings[i].c_str()); + array_ptr += sizeof(Addr); + data_ptr += strings[i].size() + 1; + } + // add NULL terminator + data_ptr = 0; + + memPort->writeBlob(array_ptr, (uint8_t*)&data_ptr, sizeof(Addr)); +} + +LiveProcess::LiveProcess(const string &nm, ObjectFile *_objFile, + System *_system, + int stdin_fd, int stdout_fd, int stderr_fd, + vector<string> &_argv, vector<string> &_envp) + : Process(nm, _system, stdin_fd, stdout_fd, stderr_fd), + objFile(_objFile), argv(_argv), envp(_envp) +{ + prog_fname = argv[0]; + + // load up symbols, if any... these may be used for debugging or + // profiling. + if (!debugSymbolTable) { + debugSymbolTable = new SymbolTable(); + if (!objFile->loadGlobalSymbols(debugSymbolTable) || + !objFile->loadLocalSymbols(debugSymbolTable)) { + // didn't load any symbols + delete debugSymbolTable; + debugSymbolTable = NULL; + } + } +} + +void +LiveProcess::argsInit(int intSize, int pageSize) +{ + Process::startup(); + + // load object file into target memory + objFile->loadSections(initVirtMem); + + // Calculate how much space we need for arg & env arrays. + int argv_array_size = intSize * (argv.size() + 1); + int envp_array_size = intSize * (envp.size() + 1); + int arg_data_size = 0; + for (int i = 0; i < argv.size(); ++i) { + arg_data_size += argv[i].size() + 1; + } + int env_data_size = 0; + for (int i = 0; i < envp.size(); ++i) { + env_data_size += envp[i].size() + 1; + } + + int space_needed = + argv_array_size + envp_array_size + arg_data_size + env_data_size; + // for SimpleScalar compatibility + if (space_needed < 16384) + space_needed = 16384; + + // set bottom of stack + stack_min = stack_base - space_needed; + // align it + stack_min &= ~(intSize-1); + stack_size = stack_base - stack_min; + // map memory + pTable->allocate(roundDown(stack_min, pageSize), + roundUp(stack_size, pageSize)); + + // map out initial stack contents + Addr argv_array_base = stack_min + intSize; // room for argc + Addr envp_array_base = argv_array_base + argv_array_size; + Addr arg_data_base = envp_array_base + envp_array_size; + Addr env_data_base = arg_data_base + arg_data_size; + + // write contents to stack + uint64_t argc = argv.size(); + if (intSize == 8) + argc = htog((uint64_t)argc); + else if (intSize == 4) + argc = htog((uint32_t)argc); + else + panic("Unknown int size"); + + initVirtMem->writeBlob(stack_min, (uint8_t*)&argc, intSize); + + copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem); + copyStringArray(envp, envp_array_base, env_data_base, initVirtMem); + + threadContexts[0]->setIntReg(ArgumentReg0, argc); + threadContexts[0]->setIntReg(ArgumentReg1, argv_array_base); + threadContexts[0]->setIntReg(StackPointerReg, stack_min); + + Addr prog_entry = objFile->entryPoint(); + threadContexts[0]->setPC(prog_entry); + threadContexts[0]->setNextPC(prog_entry + sizeof(MachInst)); + threadContexts[0]->setNextNPC(prog_entry + (2 * sizeof(MachInst))); + + num_processes++; +} + +void +LiveProcess::syscall(int64_t callnum, ThreadContext *tc) +{ + num_syscalls++; + + SyscallDesc *desc = getDesc(callnum); + if (desc == NULL) + fatal("Syscall %d out of range", callnum); + + desc->doSyscall(callnum, this, tc); +} + +DEFINE_SIM_OBJECT_CLASS_NAME("LiveProcess", LiveProcess); diff --git a/src/sim/process.hh b/src/sim/process.hh new file mode 100644 index 000000000..edbc1e492 --- /dev/null +++ b/src/sim/process.hh @@ -0,0 +1,194 @@ +/* + * 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 + * Steve Reinhardt + */ + +#ifndef __PROCESS_HH__ +#define __PROCESS_HH__ + +// +// The purpose of this code is to fake the loader & syscall mechanism +// when there's no OS: thus there's no reason to use it in FULL_SYSTEM +// mode when we do have an OS. +// +#include "config/full_system.hh" + +#if !FULL_SYSTEM + +#include <vector> + +#include "base/statistics.hh" +#include "sim/sim_object.hh" + +class ThreadContext; +class SyscallDesc; +class PageTable; +class TranslatingPort; +class System; + +void +copyStringArray(std::vector<std::string> &strings, Addr array_ptr, + Addr data_ptr, TranslatingPort* memPort); + +class Process : public SimObject +{ + public: + + /// Pointer to object representing the system this process is + /// running on. + System *system; + + // have we initialized a thread context from this process? If + // yes, subsequent contexts are assumed to be for dynamically + // created threads and are not initialized. + bool initialContextLoaded; + + // thread contexts associated with this process + std::vector<ThreadContext *> threadContexts; + + // number of CPUs (esxec contexts, really) assigned to this process. + unsigned int numCpus() { return threadContexts.size(); } + + // record of blocked context + struct WaitRec + { + Addr waitChan; + ThreadContext *waitingContext; + + WaitRec(Addr chan, ThreadContext *ctx) + : waitChan(chan), waitingContext(ctx) + { } + }; + + // list of all blocked contexts + std::list<WaitRec> waitList; + + Addr brk_point; // top of the data segment + + Addr stack_base; // stack segment base (highest address) + unsigned stack_size; // initial stack size + Addr stack_min; // lowest address accessed on the stack + + // addr to use for next stack region (for multithreaded apps) + Addr next_thread_stack_base; + + // Base of region for mmaps (when user doesn't specify an address). + Addr mmap_start; + Addr mmap_end; + + // Base of region for nxm data + Addr nxm_start; + Addr nxm_end; + + std::string prog_fname; // file name + + Stats::Scalar<> num_syscalls; // number of syscalls executed + + + protected: + // constructor + Process(const std::string &nm, + System *_system, + int stdin_fd, // initial I/O descriptors + int stdout_fd, + int stderr_fd); + + // post initialization startup + virtual void startup(); + + protected: + /// Memory object for initialization (image loading) + TranslatingPort *initVirtMem; + + public: + PageTable *pTable; + + private: + // file descriptor remapping support + static const int MAX_FD = 256; // max legal fd value + int fd_map[MAX_FD+1]; + + public: + // static helper functions to generate file descriptors for constructor + static int openInputFile(const std::string &filename); + static int openOutputFile(const std::string &filename); + + // override of virtual SimObject method: register statistics + virtual void regStats(); + + // register a thread context for this process. + // returns tc's cpu number (index into threadContexts[]) + int registerThreadContext(ThreadContext *tc); + + + void replaceThreadContext(ThreadContext *tc, int tcIndex); + + // map simulator fd sim_fd to target fd tgt_fd + void dup_fd(int sim_fd, int tgt_fd); + + // generate new target fd for sim_fd + int alloc_fd(int sim_fd); + + // free target fd (e.g., after close) + void free_fd(int tgt_fd); + + // look up simulator fd for given target fd + int sim_fd(int tgt_fd); + + virtual void syscall(int64_t callnum, ThreadContext *tc) = 0; +}; + +// +// "Live" process with system calls redirected to host system +// +class ObjectFile; +class LiveProcess : public Process +{ + protected: + ObjectFile *objFile; + std::vector<std::string> argv; + std::vector<std::string> envp; + + LiveProcess(const std::string &nm, ObjectFile *objFile, + System *_system, int stdin_fd, int stdout_fd, int stderr_fd, + std::vector<std::string> &argv, + std::vector<std::string> &envp); + + virtual void argsInit(int intSize, int pageSize); + + public: + virtual void syscall(int64_t callnum, ThreadContext *tc); + + virtual SyscallDesc* getDesc(int callnum) = 0; +}; + + +#endif // !FULL_SYSTEM + +#endif // __PROCESS_HH__ diff --git a/src/sim/pseudo_inst.cc b/src/sim/pseudo_inst.cc new file mode 100644 index 000000000..ae52cdd41 --- /dev/null +++ b/src/sim/pseudo_inst.cc @@ -0,0 +1,292 @@ +/* + * 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: Nathan Binkert + */ + +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> + +#include <string> + +#include "sim/pseudo_inst.hh" +#include "arch/vtophys.hh" +#include "cpu/base.hh" +#include "cpu/sampler/sampler.hh" +#include "cpu/thread_context.hh" +#include "cpu/quiesce_event.hh" +#include "kern/kernel_stats.hh" +#include "sim/param.hh" +#include "sim/serialize.hh" +#include "sim/sim_exit.hh" +#include "sim/stat_control.hh" +#include "sim/stats.hh" +#include "sim/system.hh" +#include "sim/debug.hh" +#include "sim/vptr.hh" + +using namespace std; + +extern Sampler *SampCPU; + +using namespace Stats; +using namespace TheISA; + +namespace AlphaPseudo +{ + bool doStatisticsInsts; + bool doCheckpointInsts; + bool doQuiesce; + + void + arm(ThreadContext *tc) + { + if (tc->getKernelStats()) + tc->getKernelStats()->arm(); + } + + void + quiesce(ThreadContext *tc) + { + if (!doQuiesce) + return; + + tc->suspend(); + if (tc->getKernelStats()) + tc->getKernelStats()->quiesce(); + } + + void + quiesceNs(ThreadContext *tc, uint64_t ns) + { + if (!doQuiesce || ns == 0) + return; + + EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent(); + + if (quiesceEvent->scheduled()) + quiesceEvent->reschedule(curTick + Clock::Int::ns * ns); + else + quiesceEvent->schedule(curTick + Clock::Int::ns * ns); + + tc->suspend(); + if (tc->getKernelStats()) + tc->getKernelStats()->quiesce(); + } + + void + quiesceCycles(ThreadContext *tc, uint64_t cycles) + { + if (!doQuiesce || cycles == 0) + return; + + EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent(); + + if (quiesceEvent->scheduled()) + quiesceEvent->reschedule(curTick + + tc->getCpuPtr()->cycles(cycles)); + else + quiesceEvent->schedule(curTick + + tc->getCpuPtr()->cycles(cycles)); + + tc->suspend(); + if (tc->getKernelStats()) + tc->getKernelStats()->quiesce(); + } + + uint64_t + quiesceTime(ThreadContext *tc) + { + return (tc->readLastActivate() - tc->readLastSuspend()) / Clock::Int::ns; + } + + void + ivlb(ThreadContext *tc) + { + if (tc->getKernelStats()) + tc->getKernelStats()->ivlb(); + } + + void + ivle(ThreadContext *tc) + { + } + + void + m5exit_old(ThreadContext *tc) + { + exitSimLoop(curTick, "m5_exit_old instruction encountered"); + } + + void + m5exit(ThreadContext *tc, Tick delay) + { + Tick when = curTick + delay * Clock::Int::ns; + exitSimLoop(when, "m5_exit instruction encountered"); + } + + void + resetstats(ThreadContext *tc, Tick delay, Tick period) + { + if (!doStatisticsInsts) + return; + + + Tick when = curTick + delay * Clock::Int::ns; + Tick repeat = period * Clock::Int::ns; + + using namespace Stats; + SetupEvent(Reset, when, repeat); + } + + void + dumpstats(ThreadContext *tc, Tick delay, Tick period) + { + if (!doStatisticsInsts) + return; + + + Tick when = curTick + delay * Clock::Int::ns; + Tick repeat = period * Clock::Int::ns; + + using namespace Stats; + SetupEvent(Dump, when, repeat); + } + + void + addsymbol(ThreadContext *tc, Addr addr, Addr symbolAddr) + { + char symb[100]; + CopyStringOut(tc, symb, symbolAddr, 100); + std::string symbol(symb); + + DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr); + + tc->getSystemPtr()->kernelSymtab->insert(addr,symbol); + } + + void + dumpresetstats(ThreadContext *tc, Tick delay, Tick period) + { + if (!doStatisticsInsts) + return; + + + Tick when = curTick + delay * Clock::Int::ns; + Tick repeat = period * Clock::Int::ns; + + using namespace Stats; + SetupEvent(Dump|Reset, when, repeat); + } + + void + m5checkpoint(ThreadContext *tc, Tick delay, Tick period) + { + if (!doCheckpointInsts) + return; + + + Tick when = curTick + delay * Clock::Int::ns; + Tick repeat = period * Clock::Int::ns; + + Checkpoint::setup(when, repeat); + } + + uint64_t + readfile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset) + { + const string &file = tc->getCpuPtr()->system->params()->readfile; + if (file.empty()) { + return ULL(0); + } + + uint64_t result = 0; + + int fd = ::open(file.c_str(), O_RDONLY, 0); + if (fd < 0) + panic("could not open file %s\n", file); + + if (::lseek(fd, offset, SEEK_SET) < 0) + panic("could not seek: %s", strerror(errno)); + + char *buf = new char[len]; + char *p = buf; + while (len > 0) { + int bytes = ::read(fd, p, len); + if (bytes <= 0) + break; + + p += bytes; + result += bytes; + len -= bytes; + } + + close(fd); + CopyIn(tc, vaddr, buf, result); + delete [] buf; + return result; + } + + class Context : public ParamContext + { + public: + Context(const string §ion) : ParamContext(section) {} + void checkParams(); + }; + + Context context("pseudo_inst"); + + Param<bool> __quiesce(&context, "quiesce", + "enable quiesce instructions", + true); + Param<bool> __statistics(&context, "statistics", + "enable statistics pseudo instructions", + true); + Param<bool> __checkpoint(&context, "checkpoint", + "enable checkpoint pseudo instructions", + true); + + void + Context::checkParams() + { + doQuiesce = __quiesce; + doStatisticsInsts = __statistics; + doCheckpointInsts = __checkpoint; + } + + void debugbreak(ThreadContext *tc) + { + debug_break(); + } + + void switchcpu(ThreadContext *tc) + { + if (SampCPU) + SampCPU->switchCPUs(); + } +} diff --git a/src/sim/pseudo_inst.hh b/src/sim/pseudo_inst.hh new file mode 100644 index 000000000..5e5b7d95f --- /dev/null +++ b/src/sim/pseudo_inst.hh @@ -0,0 +1,64 @@ +/* + * 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: Nathan Binkert + */ + +class ThreadContext; + +//We need the "Tick" data type from here +#include "sim/host.hh" +//We need the "Addr" data type from here +#include "arch/isa_traits.hh" + +namespace AlphaPseudo +{ + /** + * @todo these externs are only here for a hack in fullCPU::takeOver... + */ + extern bool doStatisticsInsts; + extern bool doCheckpointInsts; + extern bool doQuiesce; + + void arm(ThreadContext *tc); + void quiesce(ThreadContext *tc); + void quiesceNs(ThreadContext *tc, uint64_t ns); + void quiesceCycles(ThreadContext *tc, uint64_t cycles); + uint64_t quiesceTime(ThreadContext *tc); + void ivlb(ThreadContext *tc); + void ivle(ThreadContext *tc); + void m5exit(ThreadContext *tc, Tick delay); + void m5exit_old(ThreadContext *tc); + void resetstats(ThreadContext *tc, Tick delay, Tick period); + void dumpstats(ThreadContext *tc, Tick delay, Tick period); + void dumpresetstats(ThreadContext *tc, Tick delay, Tick period); + void m5checkpoint(ThreadContext *tc, Tick delay, Tick period); + uint64_t readfile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset); + void debugbreak(ThreadContext *tc); + void switchcpu(ThreadContext *tc); + void addsymbol(ThreadContext *tc, Addr addr, Addr symbolAddr); +} diff --git a/src/sim/root.cc b/src/sim/root.cc new file mode 100644 index 000000000..ec5e2f7e2 --- /dev/null +++ b/src/sim/root.cc @@ -0,0 +1,160 @@ +/* + * 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 + * Steve Reinhardt + */ + +#include <cstring> +#include <fstream> +#include <list> +#include <string> +#include <vector> + +#include "base/misc.hh" +#include "base/output.hh" +#include "sim/builder.hh" +#include "sim/host.hh" +#include "sim/sim_events.hh" +#include "sim/sim_exit.hh" +#include "sim/sim_object.hh" +#include "sim/root.hh" + +using namespace std; + +Tick curTick = 0; +ostream *outputStream; +ostream *configStream; + +/// The simulated frequency of curTick. (This is only here for a short time) +Tick ticksPerSecond; + +namespace Clock { +/// The simulated frequency of curTick. (In ticks per second) +Tick Frequency; + +namespace Float { +double s; +double ms; +double us; +double ns; +double ps; + +double Hz; +double kHz; +double MHz; +double GHZ; +/* namespace Float */ } + +namespace Int { +Tick s; +Tick ms; +Tick us; +Tick ns; +Tick ps; +/* namespace Float */ } + +/* namespace Clock */ } + + +// Dummy Object +class Root : public SimObject +{ + private: + Tick max_tick; + Tick progress_interval; + + public: + Root(const std::string &name, Tick maxtick, Tick pi) + : SimObject(name), max_tick(maxtick), progress_interval(pi) + {} + + virtual void startup(); +}; + +void +Root::startup() +{ + if (max_tick != 0) + exitSimLoop(curTick + max_tick, "reached maximum cycle count"); + + if (progress_interval != 0) + new ProgressEvent(&mainEventQueue, progress_interval); +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(Root) + + Param<Tick> clock; + Param<Tick> max_tick; + Param<Tick> progress_interval; + Param<string> output_file; + +END_DECLARE_SIM_OBJECT_PARAMS(Root) + +BEGIN_INIT_SIM_OBJECT_PARAMS(Root) + + INIT_PARAM(clock, "tick frequency"), + INIT_PARAM(max_tick, "maximum simulation time"), + INIT_PARAM(progress_interval, "print a progress message"), + INIT_PARAM(output_file, "file to dump simulator output to") + +END_INIT_SIM_OBJECT_PARAMS(Root) + +CREATE_SIM_OBJECT(Root) +{ + static bool created = false; + if (created) + panic("only one root object allowed!"); + + created = true; + + outputStream = simout.find(output_file); + Root *root = new Root(getInstanceName(), max_tick, progress_interval); + + using namespace Clock; + Frequency = clock; + Float::s = static_cast<double>(Frequency); + Float::ms = Float::s / 1.0e3; + Float::us = Float::s / 1.0e6; + Float::ns = Float::s / 1.0e9; + Float::ps = Float::s / 1.0e12; + + Float::Hz = 1.0 / Float::s; + Float::kHz = 1.0 / Float::ms; + Float::MHz = 1.0 / Float::us; + Float::GHZ = 1.0 / Float::ns; + + Int::s = Frequency; + Int::ms = Int::s / 1000; + Int::us = Int::ms / 1000; + Int::ns = Int::us / 1000; + Int::ps = Int::ns / 1000; + + return root; +} + +REGISTER_SIM_OBJECT("Root", Root) diff --git a/src/sim/serialize.cc b/src/sim/serialize.cc new file mode 100644 index 000000000..5270802d1 --- /dev/null +++ b/src/sim/serialize.cc @@ -0,0 +1,487 @@ +/* + * 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: Erik Hallnor + * Steve Reinhardt + */ + +#include <sys/time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> + +#include <fstream> +#include <list> +#include <string> +#include <vector> + +#include "base/inifile.hh" +#include "base/misc.hh" +#include "base/output.hh" +#include "base/str.hh" +#include "base/trace.hh" +#include "sim/config_node.hh" +#include "sim/eventq.hh" +#include "sim/param.hh" +#include "sim/serialize.hh" +#include "sim/sim_events.hh" +#include "sim/sim_exit.hh" +#include "sim/sim_object.hh" + +using namespace std; + +int Serializable::ckptMaxCount = 0; +int Serializable::ckptCount = 0; +int Serializable::ckptPrevCount = -1; + +void +Serializable::nameOut(ostream &os) +{ + os << "\n[" << name() << "]\n"; +} + +void +Serializable::nameOut(ostream &os, const string &_name) +{ + os << "\n[" << _name << "]\n"; +} + +template <class T> +void +paramOut(ostream &os, const std::string &name, const T ¶m) +{ + os << name << "="; + showParam(os, param); + os << "\n"; +} + + +template <class T> +void +paramIn(Checkpoint *cp, const std::string §ion, + const std::string &name, T ¶m) +{ + std::string str; + if (!cp->find(section, name, str) || !parseParam(str, param)) { + fatal("Can't unserialize '%s:%s'\n", section, name); + } +} + + +template <class T> +void +arrayParamOut(ostream &os, const std::string &name, + const T *param, int size) +{ + os << name << "="; + if (size > 0) + showParam(os, param[0]); + for (int i = 1; i < size; ++i) { + os << " "; + showParam(os, param[i]); + } + os << "\n"; +} + + +template <class T> +void +arrayParamIn(Checkpoint *cp, const std::string §ion, + const std::string &name, T *param, int size) +{ + std::string str; + if (!cp->find(section, name, str)) { + fatal("Can't unserialize '%s:%s'\n", section, name); + } + + // code below stolen from VectorParam<T>::parse(). + // it would be nice to unify these somehow... + + vector<string> tokens; + + tokenize(tokens, str, ' '); + + // Need this if we were doing a vector + // value.resize(tokens.size()); + + if (tokens.size() != size) { + fatal("Array size mismatch on %s:%s'\n", section, name); + } + + for (int i = 0; i < tokens.size(); i++) { + // need to parse into local variable to handle vector<bool>, + // for which operator[] returns a special reference class + // that's not the same as 'bool&', (since it's a packed + // vector) + T scalar_value; + if (!parseParam(tokens[i], scalar_value)) { + string err("could not parse \""); + + err += str; + err += "\""; + + fatal(err); + } + + // assign parsed value to vector + param[i] = scalar_value; + } +} + + +void +objParamIn(Checkpoint *cp, const std::string §ion, + const std::string &name, Serializable * ¶m) +{ + if (!cp->findObj(section, name, param)) { + fatal("Can't unserialize '%s:%s'\n", section, name); + } +} + + +#define INSTANTIATE_PARAM_TEMPLATES(type) \ +template void \ +paramOut(ostream &os, const std::string &name, type const ¶m); \ +template void \ +paramIn(Checkpoint *cp, const std::string §ion, \ + const std::string &name, type & param); \ +template void \ +arrayParamOut(ostream &os, const std::string &name, \ + type const *param, int size); \ +template void \ +arrayParamIn(Checkpoint *cp, const std::string §ion, \ + const std::string &name, type *param, int size); + +INSTANTIATE_PARAM_TEMPLATES(signed char) +INSTANTIATE_PARAM_TEMPLATES(unsigned char) +INSTANTIATE_PARAM_TEMPLATES(signed short) +INSTANTIATE_PARAM_TEMPLATES(unsigned short) +INSTANTIATE_PARAM_TEMPLATES(signed int) +INSTANTIATE_PARAM_TEMPLATES(unsigned int) +INSTANTIATE_PARAM_TEMPLATES(signed long) +INSTANTIATE_PARAM_TEMPLATES(unsigned long) +INSTANTIATE_PARAM_TEMPLATES(signed long long) +INSTANTIATE_PARAM_TEMPLATES(unsigned long long) +INSTANTIATE_PARAM_TEMPLATES(bool) +INSTANTIATE_PARAM_TEMPLATES(string) + + +///////////////////////////// + +/// Container for serializing global variables (not associated with +/// any serialized object). +class Globals : public Serializable +{ + public: + const string name() const; + void serialize(ostream &os); + void unserialize(Checkpoint *cp); +}; + +/// The one and only instance of the Globals class. +Globals globals; + +const string +Globals::name() const +{ + return "Globals"; +} + +void +Globals::serialize(ostream &os) +{ + nameOut(os); + SERIALIZE_SCALAR(curTick); + + nameOut(os, "MainEventQueue"); + mainEventQueue.serialize(os); +} + +void +Globals::unserialize(Checkpoint *cp) +{ + const string §ion = name(); + UNSERIALIZE_SCALAR(curTick); + + mainEventQueue.unserialize(cp, "MainEventQueue"); +} + +void +Serializable::serializeAll() +{ + string dir = Checkpoint::dir(); + if (mkdir(dir.c_str(), 0775) == -1 && errno != EEXIST) + fatal("couldn't mkdir %s\n", dir); + + string cpt_file = dir + Checkpoint::baseFilename; + ofstream outstream(cpt_file.c_str()); + time_t t = time(NULL); + outstream << "// checkpoint generated: " << ctime(&t); + + globals.serialize(outstream); + SimObject::serializeAll(outstream); + + assert(Serializable::ckptPrevCount + 1 == Serializable::ckptCount); + Serializable::ckptPrevCount++; + if (ckptMaxCount && ++ckptCount >= ckptMaxCount) + exitSimLoop(curTick + 1, "Maximum number of checkpoints dropped"); + +} + + +void +Serializable::unserializeGlobals(Checkpoint *cp) +{ + globals.unserialize(cp); +} + + +class SerializeEvent : public Event +{ + protected: + Tick repeat; + + public: + SerializeEvent(Tick _when, Tick _repeat); + virtual void process(); + virtual void serialize(std::ostream &os) + { + panic("Cannot serialize the SerializeEvent"); + } + +}; + +SerializeEvent::SerializeEvent(Tick _when, Tick _repeat) + : Event(&mainEventQueue, Serialize_Pri), repeat(_repeat) +{ + setFlags(AutoDelete); + schedule(_when); +} + +void +SerializeEvent::process() +{ + Serializable::serializeAll(); + if (repeat) + schedule(curTick + repeat); +} + +const char *Checkpoint::baseFilename = "m5.cpt"; + +static string checkpointDirBase; + +string +Checkpoint::dir() +{ + // use csprintf to insert curTick into directory name if it + // appears to have a format placeholder in it. + return (checkpointDirBase.find("%") != string::npos) ? + csprintf(checkpointDirBase, curTick) : checkpointDirBase; +} + +void +Checkpoint::setup(Tick when, Tick period) +{ + new SerializeEvent(when, period); +} + +class SerializeParamContext : public ParamContext +{ + private: + SerializeEvent *event; + + public: + SerializeParamContext(const string §ion); + ~SerializeParamContext(); + void checkParams(); +}; + +SerializeParamContext serialParams("serialize"); + +Param<string> serialize_dir(&serialParams, "dir", + "dir to stick checkpoint in " + "(sprintf format with cycle #)"); + +Param<Counter> serialize_cycle(&serialParams, + "cycle", + "cycle to serialize", + 0); + +Param<Counter> serialize_period(&serialParams, + "period", + "period to repeat serializations", + 0); + +Param<int> serialize_count(&serialParams, "count", + "maximum number of checkpoints to drop"); + +SerializeParamContext::SerializeParamContext(const string §ion) + : ParamContext(section), event(NULL) +{ } + +SerializeParamContext::~SerializeParamContext() +{ +} + +void +SerializeParamContext::checkParams() +{ + checkpointDirBase = simout.resolve(serialize_dir); + + // guarantee that directory ends with a '/' + if (checkpointDirBase[checkpointDirBase.size() - 1] != '/') + checkpointDirBase += "/"; + + if (serialize_cycle > 0) + Checkpoint::setup(serialize_cycle, serialize_period); + + Serializable::ckptMaxCount = serialize_count; +} + +void +debug_serialize() +{ + Serializable::serializeAll(); +} + +void +debug_serialize(Tick when) +{ + new SerializeEvent(when, 0); +} + +//////////////////////////////////////////////////////////////////////// +// +// SerializableClass member definitions +// +//////////////////////////////////////////////////////////////////////// + +// Map of class names to SerializableBuilder creation functions. +// Need to make this a pointer so we can force initialization on the +// first reference; otherwise, some SerializableClass constructors +// may be invoked before the classMap constructor. +map<string,SerializableClass::CreateFunc> *SerializableClass::classMap = 0; + +// SerializableClass constructor: add mapping to classMap +SerializableClass::SerializableClass(const string &className, + CreateFunc createFunc) +{ + if (classMap == NULL) + classMap = new map<string,SerializableClass::CreateFunc>(); + + if ((*classMap)[className]) + { + cerr << "Error: simulation object class " << className << " redefined" + << endl; + fatal(""); + } + + // add className --> createFunc to class map + (*classMap)[className] = createFunc; +} + + +// +// +Serializable * +SerializableClass::createObject(Checkpoint *cp, + const std::string §ion) +{ + string className; + + if (!cp->find(section, "type", className)) { + fatal("Serializable::create: no 'type' entry in section '%s'.\n", + section); + } + + CreateFunc createFunc = (*classMap)[className]; + + if (createFunc == NULL) { + fatal("Serializable::create: no create function for class '%s'.\n", + className); + } + + Serializable *object = createFunc(cp, section); + + assert(object != NULL); + + return object; +} + + +Serializable * +Serializable::create(Checkpoint *cp, const std::string §ion) +{ + Serializable *object = SerializableClass::createObject(cp, section); + object->unserialize(cp, section); + return object; +} + + +Checkpoint::Checkpoint(const std::string &cpt_dir, const std::string &path, + const ConfigNode *_configNode) + : db(new IniFile), basePath(path), configNode(_configNode), cptDir(cpt_dir) +{ + string filename = cpt_dir + "/" + Checkpoint::baseFilename; + if (!db->load(filename)) { + fatal("Can't load checkpoint file '%s'\n", filename); + } +} + + +bool +Checkpoint::find(const std::string §ion, const std::string &entry, + std::string &value) +{ + return db->find(section, entry, value); +} + + +bool +Checkpoint::findObj(const std::string §ion, const std::string &entry, + Serializable *&value) +{ + string path; + + if (!db->find(section, entry, path)) + return false; + + if ((value = configNode->resolveSimObject(path)) != NULL) + return true; + + if ((value = objMap[path]) != NULL) + return true; + + return false; +} + + +bool +Checkpoint::sectionExists(const std::string §ion) +{ + return db->sectionExists(section); +} diff --git a/src/sim/serialize.hh b/src/sim/serialize.hh new file mode 100644 index 000000000..1eb721cf4 --- /dev/null +++ b/src/sim/serialize.hh @@ -0,0 +1,246 @@ +/* + * 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: Erik Hallnor + * Steve Reinhardt + */ + +/* @file + * Serialization Interface Declarations + */ + +#ifndef __SERIALIZE_HH__ +#define __SERIALIZE_HH__ + + +#include <list> +#include <iostream> +#include <map> + +#include "sim/host.hh" +#include "sim/configfile.hh" + +class Serializable; +class Checkpoint; + +template <class T> +void paramOut(std::ostream &os, const std::string &name, const T ¶m); + +template <class T> +void paramIn(Checkpoint *cp, const std::string §ion, + const std::string &name, T ¶m); + +template <class T> +void arrayParamOut(std::ostream &os, const std::string &name, + const T *param, int size); + +template <class T> +void arrayParamIn(Checkpoint *cp, const std::string §ion, + const std::string &name, T *param, int size); + +void +objParamIn(Checkpoint *cp, const std::string §ion, + const std::string &name, Serializable * ¶m); + + +// +// These macros are streamlined to use in serialize/unserialize +// functions. It's assumed that serialize() has a parameter 'os' for +// the ostream, and unserialize() has parameters 'cp' and 'section'. +#define SERIALIZE_SCALAR(scalar) paramOut(os, #scalar, scalar) + +#define UNSERIALIZE_SCALAR(scalar) paramIn(cp, section, #scalar, scalar) + +// ENUMs are like SCALARs, but we cast them to ints on the way out +#define SERIALIZE_ENUM(scalar) paramOut(os, #scalar, (int)scalar) + +#define UNSERIALIZE_ENUM(scalar) \ + do { \ + int tmp; \ + paramIn(cp, section, #scalar, tmp); \ + scalar = (typeof(scalar))tmp; \ + } while (0) + +#define SERIALIZE_ARRAY(member, size) \ + arrayParamOut(os, #member, member, size) + +#define UNSERIALIZE_ARRAY(member, size) \ + arrayParamIn(cp, section, #member, member, size) + +#define SERIALIZE_OBJPTR(objptr) paramOut(os, #objptr, (objptr)->name()) + +#define UNSERIALIZE_OBJPTR(objptr) \ + do { \ + Serializable *sptr; \ + objParamIn(cp, section, #objptr, sptr); \ + objptr = dynamic_cast<typeof(objptr)>(sptr); \ + } while (0) + +/* + * Basic support for object serialization. + */ +class Serializable +{ + protected: + void nameOut(std::ostream &os); + void nameOut(std::ostream &os, const std::string &_name); + + public: + Serializable() {} + virtual ~Serializable() {} + + // manditory virtual function, so objects must provide names + virtual const std::string name() const = 0; + + virtual void serialize(std::ostream &os) {} + virtual void unserialize(Checkpoint *cp, const std::string §ion) {} + + static Serializable *create(Checkpoint *cp, + const std::string §ion); + + static int ckptCount; + static int ckptMaxCount; + static int ckptPrevCount; + static void serializeAll(); + static void unserializeGlobals(Checkpoint *cp); +}; + +// +// A SerializableBuilder serves as an evaluation context for a set of +// parameters that describe a specific instance of a Serializable. This +// evaluation context corresponds to a section in the .ini file (as +// with the base ParamContext) plus an optional node in the +// configuration hierarchy (the configNode member) for resolving +// Serializable references. SerializableBuilder is an abstract superclass; +// derived classes specialize the class for particular subclasses of +// Serializable (e.g., BaseCache). +// +// For typical usage, see the definition of +// SerializableClass::createObject(). +// +class SerializableBuilder +{ + public: + + SerializableBuilder() {} + + virtual ~SerializableBuilder() {} + + // Create the actual Serializable corresponding to the parameter + // values in this context. This function is overridden in derived + // classes to call a specific constructor for a particular + // subclass of Serializable. + virtual Serializable *create() = 0; +}; + +// +// An instance of SerializableClass corresponds to a class derived from +// Serializable. The SerializableClass instance serves to bind the string +// name (found in the config file) to a function that creates an +// instance of the appropriate derived class. +// +// This would be much cleaner in Smalltalk or Objective-C, where types +// are first-class objects themselves. +// +class SerializableClass +{ + public: + + // Type CreateFunc is a pointer to a function that creates a new + // simulation object builder based on a .ini-file parameter + // section (specified by the first string argument), a unique name + // for the object (specified by the second string argument), and + // an optional config hierarchy node (specified by the third + // argument). A pointer to the new SerializableBuilder is returned. + typedef Serializable *(*CreateFunc)(Checkpoint *cp, + const std::string §ion); + + static std::map<std::string,CreateFunc> *classMap; + + // Constructor. For example: + // + // SerializableClass baseCacheSerializableClass("BaseCacheSerializable", + // newBaseCacheSerializableBuilder); + // + SerializableClass(const std::string &className, CreateFunc createFunc); + + // create Serializable given name of class and pointer to + // configuration hierarchy node + static Serializable *createObject(Checkpoint *cp, + const std::string §ion); +}; + +// +// Macros to encapsulate the magic of declaring & defining +// SerializableBuilder and SerializableClass objects +// + +#define REGISTER_SERIALIZEABLE(CLASS_NAME, OBJ_CLASS) \ +SerializableClass the##OBJ_CLASS##Class(CLASS_NAME, \ + OBJ_CLASS::createForUnserialize); + +class Checkpoint +{ + private: + + IniFile *db; + const std::string basePath; + const ConfigNode *configNode; + std::map<std::string, Serializable*> objMap; + + public: + Checkpoint(const std::string &cpt_dir, const std::string &path, + const ConfigNode *_configNode); + + const std::string cptDir; + + bool find(const std::string §ion, const std::string &entry, + std::string &value); + + bool findObj(const std::string §ion, const std::string &entry, + Serializable *&value); + + bool sectionExists(const std::string §ion); + + // The following static functions have to do with checkpoint + // creation rather than restoration. This class makes a handy + // namespace for them though. + + // Export current checkpoint directory name so other objects can + // derive filenames from it (e.g., memory). The return value is + // guaranteed to end in '/' so filenames can be directly appended. + // This function is only valid while a checkpoint is being created. + static std::string dir(); + + // Filename for base checkpoint file within directory. + static const char *baseFilename; + + // Set up a checkpoint creation event or series of events. + static void setup(Tick when, Tick period = 0); +}; + +#endif // __SERIALIZE_HH__ diff --git a/src/sim/sim_events.cc b/src/sim/sim_events.cc new file mode 100644 index 000000000..b7901832d --- /dev/null +++ b/src/sim/sim_events.cc @@ -0,0 +1,161 @@ +/* + * 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 + */ + +#include <string> + +#include "base/callback.hh" +#include "base/hostinfo.hh" +#include "sim/eventq.hh" +#include "sim/param.hh" +#include "sim/sim_events.hh" +#include "sim/sim_exit.hh" +#include "sim/startup.hh" +#include "sim/stats.hh" + +using namespace std; + +// +// handle termination event +// +void +SimLoopExitEvent::process() +{ + // if this got scheduled on a different queue (e.g. the committed + // instruction queue) then make a corresponding event on the main + // queue. + if (theQueue() != &mainEventQueue) { + exitSimLoop(cause, code); + delete this; + } + + // otherwise do nothing... the IsExitEvent flag takes care of + // exiting the simulation loop and returning this object to Python +} + + +const char * +SimLoopExitEvent::description() +{ + return "simulation loop exit"; +} + +void +exitSimLoop(Tick when, const std::string &message, int exit_code) +{ + new SimLoopExitEvent(when, message, exit_code); +} + +void +exitSimLoop(const std::string &message, int exit_code) +{ + exitSimLoop(curTick, message, exit_code); +} + +// +// constructor: automatically schedules at specified time +// +CountedExitEvent::CountedExitEvent(EventQueue *q, const std::string &_cause, + Tick _when, int &_downCounter) + : Event(q, Sim_Exit_Pri), + cause(_cause), + downCounter(_downCounter) +{ + // catch stupid mistakes + assert(downCounter > 0); + + schedule(_when); +} + + +// +// handle termination event +// +void +CountedExitEvent::process() +{ + if (--downCounter == 0) { + exitSimLoop(cause, 0); + } +} + + +const char * +CountedExitEvent::description() +{ + return "counted exit"; +} + +#ifdef CHECK_SWAP_CYCLES +new CheckSwapEvent(&mainEventQueue, CHECK_SWAP_CYCLES); +#endif + +void +CheckSwapEvent::process() +{ + /* Check the amount of free swap space */ + long swap; + + /* returns free swap in KBytes */ + swap = procInfo("/proc/meminfo", "SwapFree:"); + + if (swap < 1000) + ccprintf(cerr, "\a\a\aWarning! Swap space is low (%d)\n", swap); + + if (swap < 100) { + cerr << "\a\aAborting Simulation! Inadequate swap space!\n\n"; + exitSimLoop("Lack of swap space"); + } + + schedule(curTick + interval); +} + +const char * +CheckSwapEvent::description() +{ + return "check swap"; +} + +// +// handle progress event: print message and reschedule +// +void +ProgressEvent::process() +{ + DPRINTFN("ProgressEvent\n"); + // reschedule for next interval + schedule(curTick + interval); +} + + +const char * +ProgressEvent::description() +{ + return "progress message"; +} diff --git a/src/sim/sim_events.hh b/src/sim/sim_events.hh new file mode 100644 index 000000000..4f305ad38 --- /dev/null +++ b/src/sim/sim_events.hh @@ -0,0 +1,122 @@ +/* + * 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 + */ + +#ifndef __SIM_SIM_EVENTS_HH__ +#define __SIM_SIM_EVENTS_HH__ + +#include "sim/eventq.hh" + +// +// Event to terminate simulation at a particular cycle/instruction +// +class SimLoopExitEvent : public Event +{ + private: + // string explaining why we're terminating + std::string cause; + int code; + + public: + SimLoopExitEvent(Tick _when, const std::string &_cause, int c = 0) + : Event(&mainEventQueue, Sim_Exit_Pri), cause(_cause), + code(c) + { setFlags(IsExitEvent); schedule(_when); } + + SimLoopExitEvent(EventQueue *q, + Tick _when, const std::string &_cause, int c = 0) + : Event(q, Sim_Exit_Pri), cause(_cause), code(c) + { setFlags(IsExitEvent); schedule(_when); } + + std::string getCause() { return cause; } + int getCode() { return code; } + + void process(); // process event + + virtual const char *description(); +}; + +// +// Event class to terminate simulation after 'n' related events have +// occurred using a shared counter: used to terminate when *all* +// threads have reached a particular instruction count +// +class CountedExitEvent : public Event +{ + private: + std::string cause; // string explaining why we're terminating + int &downCounter; // decrement & terminate if zero + + public: + CountedExitEvent(EventQueue *q, const std::string &_cause, + Tick _when, int &_downCounter); + + void process(); // process event + + virtual const char *description(); +}; + +// +// Event to check swap usage +// +class CheckSwapEvent : public Event +{ + private: + int interval; + + public: + CheckSwapEvent(EventQueue *q, int ival) + : Event(q), interval(ival) + { schedule(curTick + interval); } + + void process(); // process event + + virtual const char *description(); +}; + +// +// Progress event: print out cycle every so often so we know we're +// making forward progress. +// +class ProgressEvent : public Event +{ + protected: + Tick interval; + + public: + ProgressEvent(EventQueue *q, Tick ival) + : Event(q), interval(ival) + { schedule(curTick + interval); } + + void process(); // process event + + virtual const char *description(); +}; + +#endif // __SIM_SIM_EVENTS_HH__ diff --git a/src/sim/sim_exit.hh b/src/sim/sim_exit.hh new file mode 100644 index 000000000..545bf4ae0 --- /dev/null +++ b/src/sim/sim_exit.hh @@ -0,0 +1,58 @@ +/* + * Copyright (c) 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: Nathan Binkert + * Steve Reinhardt + */ + +#ifndef __SIM_EXIT_HH__ +#define __SIM_EXIT_HH__ + +#include <string> + +#include "sim/host.hh" + +// forward declaration +class Callback; + +/// Register a callback to be called when Python exits. Defined in +/// sim/main.cc. +void registerExitCallback(Callback *); + +/// Schedule an event to exit the simulation loop (returning to +/// Python) at the indicated tick. The message and exit_code +/// parameters are saved in the SimLoopExitEvent to indicate why the +/// exit occurred. +void exitSimLoop(Tick when, const std::string &message, int exit_code = 0); + +/// Schedule an event to exit the simulation loop (returning to +/// Python) at the end of the current cycle (curTick). The message +/// and exit_code parameters are saved in the SimLoopExitEvent to +/// indicate why the exit occurred. +void exitSimLoop(const std::string &cause, int exit_code = 0); + +#endif // __SIM_EXIT_HH__ diff --git a/src/sim/sim_object.cc b/src/sim/sim_object.cc new file mode 100644 index 000000000..117ca9325 --- /dev/null +++ b/src/sim/sim_object.cc @@ -0,0 +1,261 @@ +/* + * 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 + */ + +#include <assert.h> + +#include "base/callback.hh" +#include "base/inifile.hh" +#include "base/match.hh" +#include "base/misc.hh" +#include "base/trace.hh" +#include "base/stats/events.hh" +#include "base/serializer.hh" +#include "sim/configfile.hh" +#include "sim/host.hh" +#include "sim/sim_object.hh" +#include "sim/stats.hh" +#include "sim/param.hh" + +using namespace std; + + +//////////////////////////////////////////////////////////////////////// +// +// SimObject member definitions +// +//////////////////////////////////////////////////////////////////////// + +// +// static list of all SimObjects, used for initialization etc. +// +SimObject::SimObjectList SimObject::simObjectList; + +namespace Stats { + extern ObjectMatch event_ignore; +} + +// +// SimObject constructor: used to maintain static simObjectList +// +SimObject::SimObject(Params *p) + : _params(p) +{ +#ifdef DEBUG + doDebugBreak = false; +#endif + + doRecordEvent = !Stats::event_ignore.match(name()); + simObjectList.push_back(this); +} + +// +// SimObject constructor: used to maintain static simObjectList +// +SimObject::SimObject(const string &_name) + : _params(new Params) +{ + _params->name = _name; +#ifdef DEBUG + doDebugBreak = false; +#endif + + doRecordEvent = !Stats::event_ignore.match(name()); + simObjectList.push_back(this); +} + +void +SimObject::connect() +{ +} + +void +SimObject::init() +{ +} + +// +// no default statistics, so nothing to do in base implementation +// +void +SimObject::regStats() +{ +} + +void +SimObject::regFormulas() +{ +} + +void +SimObject::resetStats() +{ +} + +// +// static function: +// call regStats() on all SimObjects and then regFormulas() on all +// SimObjects. +// +struct SimObjectResetCB : public Callback +{ + virtual void process() { SimObject::resetAllStats(); } +}; + +namespace { + static SimObjectResetCB StatResetCB; +} + +void +SimObject::regAllStats() +{ + SimObjectList::iterator i; + SimObjectList::iterator end = simObjectList.end(); + + /** + * @todo change cprintfs to DPRINTFs + */ + for (i = simObjectList.begin(); i != end; ++i) { +#ifdef STAT_DEBUG + cprintf("registering stats for %s\n", (*i)->name()); +#endif + (*i)->regStats(); + } + + for (i = simObjectList.begin(); i != end; ++i) { +#ifdef STAT_DEBUG + cprintf("registering formulas for %s\n", (*i)->name()); +#endif + (*i)->regFormulas(); + } + + Stats::registerResetCallback(&StatResetCB); +} + +// +// static function: call connect() on all SimObjects. +// +void +SimObject::connectAll() +{ + SimObjectList::iterator i = simObjectList.begin(); + SimObjectList::iterator end = simObjectList.end(); + + for (; i != end; ++i) { + SimObject *obj = *i; + obj->connect(); + } +} + +// +// static function: call init() on all SimObjects. +// +void +SimObject::initAll() +{ + SimObjectList::iterator i = simObjectList.begin(); + SimObjectList::iterator end = simObjectList.end(); + + for (; i != end; ++i) { + SimObject *obj = *i; + obj->init(); + } +} + +// +// static function: call resetStats() on all SimObjects. +// +void +SimObject::resetAllStats() +{ + SimObjectList::iterator i = simObjectList.begin(); + SimObjectList::iterator end = simObjectList.end(); + + for (; i != end; ++i) { + SimObject *obj = *i; + obj->resetStats(); + } +} + +// +// static function: serialize all SimObjects. +// +void +SimObject::serializeAll(ostream &os) +{ + SimObjectList::reverse_iterator ri = simObjectList.rbegin(); + SimObjectList::reverse_iterator rend = simObjectList.rend(); + + for (; ri != rend; ++ri) { + SimObject *obj = *ri; + obj->nameOut(os); + obj->serialize(os); + } +} + +#ifdef DEBUG +// +// static function: flag which objects should have the debugger break +// +void +SimObject::debugObjectBreak(const string &objs) +{ + SimObjectList::const_iterator i = simObjectList.begin(); + SimObjectList::const_iterator end = simObjectList.end(); + + ObjectMatch match(objs); + for (; i != end; ++i) { + SimObject *obj = *i; + obj->doDebugBreak = match.match(obj->name()); + } +} + +extern "C" +void +debugObjectBreak(const char *objs) +{ + SimObject::debugObjectBreak(string(objs)); +} +#endif + +void +SimObject::recordEvent(const std::string &stat) +{ + if (doRecordEvent) + Stats::recordEvent(stat); +} + +void +SimObject::drain(Serializer *serializer) +{ + serializer->signalDrained(); +} + +DEFINE_SIM_OBJECT_CLASS_NAME("SimObject", SimObject) diff --git a/src/sim/sim_object.hh b/src/sim/sim_object.hh new file mode 100644 index 000000000..84e9376a0 --- /dev/null +++ b/src/sim/sim_object.hh @@ -0,0 +1,122 @@ +/* + * 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 + */ + +/* @file + * User Console Definitions + */ + +#ifndef __SIM_OBJECT_HH__ +#define __SIM_OBJECT_HH__ + +#include <map> +#include <list> +#include <vector> +#include <iostream> + +#include "sim/serialize.hh" +#include "sim/startup.hh" + +class Serializer; + +/* + * Abstract superclass for simulation objects. Represents things that + * correspond to physical components and can be specified via the + * config file (CPUs, caches, etc.). + */ +class SimObject : public Serializable, protected StartupCallback +{ + public: + struct Params { + std::string name; + }; + + protected: + Params *_params; + + public: + const Params *params() const { return _params; } + + private: + friend class Serializer; + + typedef std::vector<SimObject *> SimObjectList; + + // list of all instantiated simulation objects + static SimObjectList simObjectList; + + public: + SimObject(Params *_params); + SimObject(const std::string &_name); + + virtual ~SimObject() {} + + virtual const std::string name() const { return params()->name; } + + // initialization pass of all objects. + // Gets invoked after construction, before unserialize. + virtual void init(); + virtual void connect(); + static void initAll(); + static void connectAll(); + + // register statistics for this object + virtual void regStats(); + virtual void regFormulas(); + virtual void resetStats(); + + // static: call reg_stats on all SimObjects + static void regAllStats(); + + // static: call resetStats on all SimObjects + static void resetAllStats(); + + // static: call nameOut() & serialize() on all SimObjects + static void serializeAll(std::ostream &); + + // Methods to drain objects in order to take checkpoints + // Or switch from timing -> atomic memory model + virtual void drain(Serializer *serializer); + virtual void resume() { return;} ; + virtual void serializationComplete() + { assert(0 && "Unimplemented"); }; + +#ifdef DEBUG + public: + bool doDebugBreak; + static void debugObjectBreak(const std::string &objs); +#endif + + public: + bool doRecordEvent; + void recordEvent(const std::string &stat); +}; + +#endif // __SIM_OBJECT_HH__ diff --git a/src/sim/startup.cc b/src/sim/startup.cc new file mode 100644 index 000000000..838352107 --- /dev/null +++ b/src/sim/startup.cc @@ -0,0 +1,66 @@ +/* + * 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: Nathan Binkert + * Kevin Lim + */ + +#include <list> + +#include "base/misc.hh" +#include "sim/debug.hh" +#include "sim/startup.hh" + +typedef std::list<StartupCallback *> startupq_t; + +startupq_t *startupq = NULL; + +StartupCallback::StartupCallback() +{ + if (startupq == NULL) + startupq = new startupq_t; + startupq->push_back(this); +} + +StartupCallback::~StartupCallback() +{ + startupq->remove(this); +} + +void StartupCallback::startup() { } + +void +SimStartup() +{ + startupq_t::iterator i = startupq->begin(); + startupq_t::iterator end = startupq->end(); + + while (i != end) { + (*i)->startup(); + ++i; + } +} diff --git a/src/sim/startup.hh b/src/sim/startup.hh new file mode 100644 index 000000000..cfc4450f4 --- /dev/null +++ b/src/sim/startup.hh @@ -0,0 +1,43 @@ +/* + * 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: Nathan Binkert + */ + +#ifndef __SIM_STARTUP_HH__ +#define __SIM_STARTUP_HH__ + +struct StartupCallback +{ + StartupCallback(); + virtual ~StartupCallback(); + virtual void startup(); +}; + +void SimStartup(); + +#endif // __SIM_STARTUP_HH__ diff --git a/src/sim/stat_control.cc b/src/sim/stat_control.cc new file mode 100644 index 000000000..f7fc03d74 --- /dev/null +++ b/src/sim/stat_control.cc @@ -0,0 +1,229 @@ +/* + * 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: Nathan Binkert + */ + +// This file will contain default statistics for the simulator that +// don't really belong to a specific simulator object + +#include <fstream> +#include <iostream> +#include <list> + +#include "base/callback.hh" +#include "base/hostinfo.hh" +#include "base/statistics.hh" +#include "base/str.hh" +#include "base/time.hh" +#include "base/stats/output.hh" +#include "cpu/base.hh" +#include "sim/eventq.hh" +#include "sim/sim_object.hh" +#include "sim/stat_control.hh" +#include "sim/root.hh" + +using namespace std; + +Stats::Formula hostInstRate; +Stats::Formula hostTickRate; +Stats::Value hostMemory; +Stats::Value hostSeconds; + +Stats::Value simTicks; +Stats::Value simInsts; +Stats::Value simFreq; +Stats::Formula simSeconds; + +namespace Stats { + +Time statTime(true); +Tick startTick; +Tick lastDump(0); + +class SimTicksReset : public Callback +{ + public: + void process() + { + statTime.set(); + startTick = curTick; + } +}; + +double +statElapsedTime() +{ + Time now(true); + Time elapsed = now - statTime; + return elapsed(); +} + +Tick +statElapsedTicks() +{ + return curTick - startTick; +} + +SimTicksReset simTicksReset; + +void +InitSimStats() +{ + simInsts + .functor(BaseCPU::numSimulatedInstructions) + .name("sim_insts") + .desc("Number of instructions simulated") + .precision(0) + .prereq(simInsts) + ; + + simSeconds + .name("sim_seconds") + .desc("Number of seconds simulated") + ; + + simFreq + .scalar(Clock::Frequency) + .name("sim_freq") + .desc("Frequency of simulated ticks") + ; + + simTicks + .functor(statElapsedTicks) + .name("sim_ticks") + .desc("Number of ticks simulated") + ; + + hostInstRate + .name("host_inst_rate") + .desc("Simulator instruction rate (inst/s)") + .precision(0) + .prereq(simInsts) + ; + + hostMemory + .functor(memUsage) + .name("host_mem_usage") + .desc("Number of bytes of host memory used") + .prereq(hostMemory) + ; + + hostSeconds + .functor(statElapsedTime) + .name("host_seconds") + .desc("Real time elapsed on the host") + .precision(2) + ; + + hostTickRate + .name("host_tick_rate") + .desc("Simulator tick rate (ticks/s)") + .precision(0) + ; + + simSeconds = simTicks / simFreq; + hostInstRate = simInsts / hostSeconds; + hostTickRate = simTicks / hostSeconds; + + registerResetCallback(&simTicksReset); +} + +class StatEvent : public Event +{ + protected: + int flags; + Tick repeat; + + public: + StatEvent(int _flags, Tick _when, Tick _repeat); + virtual void process(); + virtual const char *description(); +}; + +StatEvent::StatEvent(int _flags, Tick _when, Tick _repeat) + : Event(&mainEventQueue, Stat_Event_Pri), + flags(_flags), repeat(_repeat) +{ + setFlags(AutoDelete); + schedule(_when); +} + +const char * +StatEvent::description() +{ + return "Statistics dump and/or reset"; +} + +void +StatEvent::process() +{ + if (flags & Stats::Dump) + DumpNow(); + + if (flags & Stats::Reset) + reset(); + + if (repeat) + schedule(curTick + repeat); +} + +list<Output *> OutputList; + +void +DumpNow() +{ + assert(lastDump <= curTick); + if (lastDump == curTick) + return; + lastDump = curTick; + + list<Output *>::iterator i = OutputList.begin(); + list<Output *>::iterator end = OutputList.end(); + for (; i != end; ++i) { + Output *output = *i; + if (!output->valid()) + continue; + + output->output(); + } +} + +void +SetupEvent(int flags, Tick when, Tick repeat) +{ + new StatEvent(flags, when, repeat); +} + +/* namespace Stats */ } + +extern "C" void +debugDumpStats() +{ + Stats::DumpNow(); +} + diff --git a/src/sim/stat_control.hh b/src/sim/stat_control.hh new file mode 100644 index 000000000..fb369f640 --- /dev/null +++ b/src/sim/stat_control.hh @@ -0,0 +1,54 @@ +/* + * 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: Nathan Binkert + */ + +#ifndef __SIM_STAT_CONTROL_HH__ +#define __SIM_STAT_CONTROL_HH__ + +#include <fstream> +#include <list> + +namespace Stats { + +enum { + Reset = 0x1, + Dump = 0x2 +}; + +class Output; +extern std::list<Output *> OutputList; + +void DumpNow(); +void SetupEvent(int flags, Tick when, Tick repeat = 0); + +void InitSimStats(); + +/* namespace Stats */ } + +#endif // __SIM_STAT_CONTROL_HH__ diff --git a/src/sim/stats.hh b/src/sim/stats.hh new file mode 100644 index 000000000..97251283d --- /dev/null +++ b/src/sim/stats.hh @@ -0,0 +1,39 @@ +/* + * 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: Nathan Binkert + */ + +#ifndef __SIM_STATS_HH__ +#define __SIM_STATS_HH__ + +#include "base/statistics.hh" + +extern Stats::Formula simSeconds; +extern Stats::Value simTicks; + +#endif // __SIM_SIM_STATS_HH__ diff --git a/src/sim/syscall_emul.cc b/src/sim/syscall_emul.cc new file mode 100644 index 000000000..848b6f869 --- /dev/null +++ b/src/sim/syscall_emul.cc @@ -0,0 +1,487 @@ +/* + * Copyright (c) 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 Reinhardt + * Ali Saidi + * Korey Sewell + */ + +#include <fcntl.h> +#include <unistd.h> + +#include <string> +#include <iostream> + +#include "sim/syscall_emul.hh" +#include "base/chunk_generator.hh" +#include "base/trace.hh" +#include "cpu/thread_context.hh" +#include "cpu/base.hh" +#include "mem/page_table.hh" +#include "sim/process.hh" + +#include "sim/sim_exit.hh" + +using namespace std; +using namespace TheISA; + +void +SyscallDesc::doSyscall(int callnum, Process *process, ThreadContext *tc) +{ + DPRINTFR(SyscallVerbose, "%d: %s: syscall %s called w/arguments %d,%d,%d,%d\n", + curTick,tc->getCpuPtr()->name(), name, + tc->getSyscallArg(0),tc->getSyscallArg(1), + tc->getSyscallArg(2),tc->getSyscallArg(3)); + + SyscallReturn retval = (*funcPtr)(this, callnum, process, tc); + + DPRINTFR(SyscallVerbose, "%d: %s: syscall %s returns %d\n", + curTick,tc->getCpuPtr()->name(), name, retval.value()); + + if (!(flags & SyscallDesc::SuppressReturnValue)) + tc->setSyscallReturn(retval); +} + + +SyscallReturn +unimplementedFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + fatal("syscall %s (#%d) unimplemented.", desc->name, callnum); + + return 1; +} + + +SyscallReturn +ignoreFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + warn("ignoring syscall %s(%d, %d, ...)", desc->name, + tc->getSyscallArg(0), tc->getSyscallArg(1)); + + return 0; +} + + +SyscallReturn +exitFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + exitSimLoop("target called exit()", tc->getSyscallArg(0) & 0xff); + + return 1; +} + + +SyscallReturn +getpagesizeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) +{ + return (int)VMPageSize; +} + + +SyscallReturn +obreakFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) +{ + Addr junk; + + // change brk addr to first arg + Addr new_brk = tc->getSyscallArg(0); + if (new_brk != 0) { + for (ChunkGenerator gen(p->brk_point, new_brk - p->brk_point, + VMPageSize); !gen.done(); gen.next()) { + if (!p->pTable->translate(gen.addr(), junk)) + p->pTable->allocate(roundDown(gen.addr(), VMPageSize), + VMPageSize); + } + p->brk_point = new_brk; + } + DPRINTF(SyscallVerbose, "Break Point changed to: %#X\n", p->brk_point); + return p->brk_point; +} + + +SyscallReturn +closeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) +{ + int target_fd = tc->getSyscallArg(0); + int status = close(p->sim_fd(target_fd)); + if (status >= 0) + p->free_fd(target_fd); + return status; +} + + +SyscallReturn +readFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) +{ + int fd = p->sim_fd(tc->getSyscallArg(0)); + int nbytes = tc->getSyscallArg(2); + BufferArg bufArg(tc->getSyscallArg(1), nbytes); + + int bytes_read = read(fd, bufArg.bufferPtr(), nbytes); + + if (bytes_read != -1) + bufArg.copyOut(tc->getMemPort()); + + return bytes_read; +} + +SyscallReturn +writeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) +{ + int fd = p->sim_fd(tc->getSyscallArg(0)); + int nbytes = tc->getSyscallArg(2); + BufferArg bufArg(tc->getSyscallArg(1), nbytes); + + bufArg.copyIn(tc->getMemPort()); + + int bytes_written = write(fd, bufArg.bufferPtr(), nbytes); + + fsync(fd); + + return bytes_written; +} + + +SyscallReturn +lseekFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) +{ + int fd = p->sim_fd(tc->getSyscallArg(0)); + uint64_t offs = tc->getSyscallArg(1); + int whence = tc->getSyscallArg(2); + + off_t result = lseek(fd, offs, whence); + + return (result == (off_t)-1) ? -errno : result; +} + + +SyscallReturn +munmapFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) +{ + // given that we don't really implement mmap, munmap is really easy + return 0; +} + + +const char *hostname = "m5.eecs.umich.edu"; + +SyscallReturn +gethostnameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) +{ + int name_len = tc->getSyscallArg(1); + BufferArg name(tc->getSyscallArg(0), name_len); + + strncpy((char *)name.bufferPtr(), hostname, name_len); + + name.copyOut(tc->getMemPort()); + + return 0; +} + +SyscallReturn +unlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) +{ + string path; + + if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) + return (TheISA::IntReg)-EFAULT; + + int result = unlink(path.c_str()); + return (result == -1) ? -errno : result; +} + +SyscallReturn +renameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) +{ + string old_name; + + if (!tc->getMemPort()->tryReadString(old_name, tc->getSyscallArg(0))) + return -EFAULT; + + string new_name; + + if (!tc->getMemPort()->tryReadString(new_name, tc->getSyscallArg(1))) + return -EFAULT; + + int64_t result = rename(old_name.c_str(), new_name.c_str()); + return (result == -1) ? -errno : result; +} + +SyscallReturn +truncateFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) +{ + string path; + + if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) + return -EFAULT; + + off_t length = tc->getSyscallArg(1); + + int result = truncate(path.c_str(), length); + return (result == -1) ? -errno : result; +} + +SyscallReturn +ftruncateFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc) +{ + int fd = process->sim_fd(tc->getSyscallArg(0)); + + if (fd < 0) + return -EBADF; + + off_t length = tc->getSyscallArg(1); + + int result = ftruncate(fd, length); + return (result == -1) ? -errno : result; +} + +SyscallReturn +chownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) +{ + string path; + + if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) + return -EFAULT; + + /* XXX endianess */ + uint32_t owner = tc->getSyscallArg(1); + uid_t hostOwner = owner; + uint32_t group = tc->getSyscallArg(2); + gid_t hostGroup = group; + + int result = chown(path.c_str(), hostOwner, hostGroup); + return (result == -1) ? -errno : result; +} + +SyscallReturn +fchownFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc) +{ + int fd = process->sim_fd(tc->getSyscallArg(0)); + + if (fd < 0) + return -EBADF; + + /* XXX endianess */ + uint32_t owner = tc->getSyscallArg(1); + uid_t hostOwner = owner; + uint32_t group = tc->getSyscallArg(2); + gid_t hostGroup = group; + + int result = fchown(fd, hostOwner, hostGroup); + return (result == -1) ? -errno : result; +} + + +SyscallReturn +fcntlFunc(SyscallDesc *desc, int num, Process *process, + ThreadContext *tc) +{ + int fd = tc->getSyscallArg(0); + + if (fd < 0 || process->sim_fd(fd) < 0) + return -EBADF; + + int cmd = tc->getSyscallArg(1); + switch (cmd) { + case 0: // F_DUPFD + // if we really wanted to support this, we'd need to do it + // in the target fd space. + warn("fcntl(%d, F_DUPFD) not supported, error returned\n", fd); + return -EMFILE; + + case 1: // F_GETFD (get close-on-exec flag) + case 2: // F_SETFD (set close-on-exec flag) + return 0; + + case 3: // F_GETFL (get file flags) + case 4: // F_SETFL (set file flags) + // not sure if this is totally valid, but we'll pass it through + // to the underlying OS + warn("fcntl(%d, %d) passed through to host\n", fd, cmd); + return fcntl(process->sim_fd(fd), cmd); + // return 0; + + case 7: // F_GETLK (get lock) + case 8: // F_SETLK (set lock) + case 9: // F_SETLKW (set lock and wait) + // don't mess with file locking... just act like it's OK + warn("File lock call (fcntl(%d, %d)) ignored.\n", fd, cmd); + return 0; + + default: + warn("Unknown fcntl command %d\n", cmd); + return 0; + } +} + +SyscallReturn +fcntl64Func(SyscallDesc *desc, int num, Process *process, + ThreadContext *tc) +{ + int fd = tc->getSyscallArg(0); + + if (fd < 0 || process->sim_fd(fd) < 0) + return -EBADF; + + int cmd = tc->getSyscallArg(1); + switch (cmd) { + case 33: //F_GETLK64 + warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", fd); + return -EMFILE; + + case 34: // F_SETLK64 + case 35: // F_SETLKW64 + warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n", fd); + return -EMFILE; + + default: + // not sure if this is totally valid, but we'll pass it through + // to the underlying OS + warn("fcntl64(%d, %d) passed through to host\n", fd, cmd); + return fcntl(process->sim_fd(fd), cmd); + // return 0; + } +} + +SyscallReturn +pipePseudoFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + int fds[2], sim_fds[2]; + int pipe_retval = pipe(fds); + + if (pipe_retval < 0) { + // error + return pipe_retval; + } + + sim_fds[0] = process->alloc_fd(fds[0]); + sim_fds[1] = process->alloc_fd(fds[1]); + + // Alpha Linux convention for pipe() is that fd[0] is returned as + // the return value of the function, and fd[1] is returned in r20. + tc->setIntReg(SyscallPseudoReturnReg, sim_fds[1]); + return sim_fds[0]; +} + + +SyscallReturn +getpidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + // Make up a PID. There's no interprocess communication in + // fake_syscall mode, so there's no way for a process to know it's + // not getting a unique value. + + tc->setIntReg(SyscallPseudoReturnReg, 99); + return 100; +} + + +SyscallReturn +getuidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + // Make up a UID and EUID... it shouldn't matter, and we want the + // simulation to be deterministic. + + // EUID goes in r20. + tc->setIntReg(SyscallPseudoReturnReg, 100); //EUID + return 100; // UID +} + + +SyscallReturn +getgidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + // Get current group ID. EGID goes in r20. + tc->setIntReg(SyscallPseudoReturnReg, 100); //EGID + return 100; +} + + +SyscallReturn +setuidFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + // can't fathom why a benchmark would call this. + warn("Ignoring call to setuid(%d)\n", tc->getSyscallArg(0)); + return 0; +} + +SyscallReturn +getpidFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + // Make up a PID. There's no interprocess communication in + // fake_syscall mode, so there's no way for a process to know it's + // not getting a unique value. + + tc->setIntReg(SyscallPseudoReturnReg, 99); //PID + return 100; +} + +SyscallReturn +getppidFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + return 99; +} + +SyscallReturn +getuidFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + return 100; // UID +} + +SyscallReturn +geteuidFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + return 100; // UID +} + +SyscallReturn +getgidFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + return 100; +} + +SyscallReturn +getegidFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + return 100; +} + + diff --git a/src/sim/syscall_emul.hh b/src/sim/syscall_emul.hh new file mode 100644 index 000000000..f027dbf24 --- /dev/null +++ b/src/sim/syscall_emul.hh @@ -0,0 +1,857 @@ +/* + * Copyright (c) 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 Reinhardt + * Kevin Lim + * Korey Sewell + */ + +#ifndef __SIM_SYSCALL_EMUL_HH__ +#define __SIM_SYSCALL_EMUL_HH__ + +#define BSD_HOST (defined(__APPLE__) || defined(__OpenBSD__) || \ + defined(__FreeBSD__)) + +/// +/// @file syscall_emul.hh +/// +/// This file defines objects used to emulate syscalls from the target +/// application on the host machine. + +#include <errno.h> +#include <string> +#ifdef __CYGWIN32__ +#include <sys/fcntl.h> // for O_BINARY +#endif +#include <sys/uio.h> + +#include "arch/isa_traits.hh" // for Addr +#include "base/chunk_generator.hh" +#include "base/intmath.hh" // for RoundUp +#include "base/misc.hh" +#include "base/trace.hh" +#include "cpu/base.hh" +#include "cpu/thread_context.hh" +#include "mem/translating_port.hh" +#include "mem/page_table.hh" +#include "sim/process.hh" + +/// +/// System call descriptor. +/// +class SyscallDesc { + + public: + + /// Typedef for target syscall handler functions. + typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num, + Process *, ThreadContext *); + + const char *name; //!< Syscall name (e.g., "open"). + FuncPtr funcPtr; //!< Pointer to emulation function. + int flags; //!< Flags (see Flags enum). + + /// Flag values for controlling syscall behavior. + enum Flags { + /// Don't set return regs according to funcPtr return value. + /// Used for syscalls with non-standard return conventions + /// that explicitly set the ThreadContext regs (e.g., + /// sigreturn). + SuppressReturnValue = 1 + }; + + /// Constructor. + SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0) + : name(_name), funcPtr(_funcPtr), flags(_flags) + { + } + + /// Emulate the syscall. Public interface for calling through funcPtr. + void doSyscall(int callnum, Process *proc, ThreadContext *tc); +}; + + +class BaseBufferArg { + + public: + + BaseBufferArg(Addr _addr, int _size) : addr(_addr), size(_size) + { + bufPtr = new uint8_t[size]; + // clear out buffer: in case we only partially populate this, + // and then do a copyOut(), we want to make sure we don't + // introduce any random junk into the simulated address space + memset(bufPtr, 0, size); + } + + virtual ~BaseBufferArg() { delete [] bufPtr; } + + // + // copy data into simulator space (read from target memory) + // + virtual bool copyIn(TranslatingPort *memport) + { + memport->readBlob(addr, bufPtr, size); + return true; // no EFAULT detection for now + } + + // + // copy data out of simulator space (write to target memory) + // + virtual bool copyOut(TranslatingPort *memport) + { + memport->writeBlob(addr, bufPtr, size); + return true; // no EFAULT detection for now + } + + protected: + Addr addr; + int size; + uint8_t *bufPtr; +}; + + +class BufferArg : public BaseBufferArg +{ + public: + BufferArg(Addr _addr, int _size) : BaseBufferArg(_addr, _size) { } + void *bufferPtr() { return bufPtr; } +}; + +template <class T> +class TypedBufferArg : public BaseBufferArg +{ + public: + // user can optionally specify a specific number of bytes to + // allocate to deal with those structs that have variable-size + // arrays at the end + TypedBufferArg(Addr _addr, int _size = sizeof(T)) + : BaseBufferArg(_addr, _size) + { } + + // type case + operator T*() { return (T *)bufPtr; } + + // dereference operators + T &operator*() { return *((T *)bufPtr); } + T* operator->() { return (T *)bufPtr; } + T &operator[](int i) { return ((T *)bufPtr)[i]; } +}; + +////////////////////////////////////////////////////////////////////// +// +// The following emulation functions are generic enough that they +// don't need to be recompiled for different emulated OS's. They are +// defined in sim/syscall_emul.cc. +// +////////////////////////////////////////////////////////////////////// + + +/// Handler for unimplemented syscalls that we haven't thought about. +SyscallReturn unimplementedFunc(SyscallDesc *desc, int num, + Process *p, ThreadContext *tc); + +/// Handler for unimplemented syscalls that we never intend to +/// implement (signal handling, etc.) and should not affect the correct +/// behavior of the program. Print a warning only if the appropriate +/// trace flag is enabled. Return success to the target program. +SyscallReturn ignoreFunc(SyscallDesc *desc, int num, + Process *p, ThreadContext *tc); + +/// Target exit() handler: terminate simulation. +SyscallReturn exitFunc(SyscallDesc *desc, int num, + Process *p, ThreadContext *tc); + +/// Target getpagesize() handler. +SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, + Process *p, ThreadContext *tc); + +/// Target obreak() handler: set brk address. +SyscallReturn obreakFunc(SyscallDesc *desc, int num, + Process *p, ThreadContext *tc); + +/// Target close() handler. +SyscallReturn closeFunc(SyscallDesc *desc, int num, + Process *p, ThreadContext *tc); + +/// Target read() handler. +SyscallReturn readFunc(SyscallDesc *desc, int num, + Process *p, ThreadContext *tc); + +/// Target write() handler. +SyscallReturn writeFunc(SyscallDesc *desc, int num, + Process *p, ThreadContext *tc); + +/// Target lseek() handler. +SyscallReturn lseekFunc(SyscallDesc *desc, int num, + Process *p, ThreadContext *tc); + +/// Target munmap() handler. +SyscallReturn munmapFunc(SyscallDesc *desc, int num, + Process *p, ThreadContext *tc); + +/// Target gethostname() handler. +SyscallReturn gethostnameFunc(SyscallDesc *desc, int num, + Process *p, ThreadContext *tc); + +/// Target unlink() handler. +SyscallReturn unlinkFunc(SyscallDesc *desc, int num, + Process *p, ThreadContext *tc); + +/// Target rename() handler. +SyscallReturn renameFunc(SyscallDesc *desc, int num, + Process *p, ThreadContext *tc); + + +/// Target truncate() handler. +SyscallReturn truncateFunc(SyscallDesc *desc, int num, + Process *p, ThreadContext *tc); + + +/// Target ftruncate() handler. +SyscallReturn ftruncateFunc(SyscallDesc *desc, int num, + Process *p, ThreadContext *tc); + + +/// Target chown() handler. +SyscallReturn chownFunc(SyscallDesc *desc, int num, + Process *p, ThreadContext *tc); + + +/// Target fchown() handler. +SyscallReturn fchownFunc(SyscallDesc *desc, int num, + Process *p, ThreadContext *tc); + +/// Target fnctl() handler. +SyscallReturn fcntlFunc(SyscallDesc *desc, int num, + Process *process, ThreadContext *tc); + +/// Target fcntl64() handler. +SyscallReturn fcntl64Func(SyscallDesc *desc, int num, + Process *process, ThreadContext *tc); + +/// Target setuid() handler. +SyscallReturn setuidFunc(SyscallDesc *desc, int num, + Process *p, ThreadContext *tc); + +/// Target getpid() handler. +SyscallReturn getpidFunc(SyscallDesc *desc, int num, + Process *p, ThreadContext *tc); + +/// Target getuid() handler. +SyscallReturn getuidFunc(SyscallDesc *desc, int num, + Process *p, ThreadContext *tc); + +/// Target getgid() handler. +SyscallReturn getgidFunc(SyscallDesc *desc, int num, + Process *p, ThreadContext *tc); + +/// Target getppid() handler. +SyscallReturn getppidFunc(SyscallDesc *desc, int num, + Process *p, ThreadContext *tc); + +/// Target geteuid() handler. +SyscallReturn geteuidFunc(SyscallDesc *desc, int num, + Process *p, ThreadContext *tc); + +/// Target getegid() handler. +SyscallReturn getegidFunc(SyscallDesc *desc, int num, + Process *p, ThreadContext *tc); + + + +/// Pseudo Funcs - These functions use a different return convension, +/// returning a second value in a register other than the normal return register +SyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, + Process *process, ThreadContext *tc); + +/// Target getpidPseudo() handler. +SyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, + Process *p, ThreadContext *tc); + +/// Target getuidPseudo() handler. +SyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, + Process *p, ThreadContext *tc); + +/// Target getgidPseudo() handler. +SyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, + Process *p, ThreadContext *tc); + + +/// This struct is used to build an target-OS-dependent table that +/// maps the target's open() flags to the host open() flags. +struct OpenFlagTransTable { + int tgtFlag; //!< Target system flag value. + int hostFlag; //!< Corresponding host system flag value. +}; + + + +/// A readable name for 1,000,000, for converting microseconds to seconds. +const int one_million = 1000000; + +/// Approximate seconds since the epoch (1/1/1970). About a billion, +/// by my reckoning. We want to keep this a constant (not use the +/// real-world time) to keep simulations repeatable. +const unsigned seconds_since_epoch = 1000000000; + +/// Helper function to convert current elapsed time to seconds and +/// microseconds. +template <class T1, class T2> +void +getElapsedTime(T1 &sec, T2 &usec) +{ + int elapsed_usecs = curTick / Clock::Int::us; + sec = elapsed_usecs / one_million; + usec = elapsed_usecs % one_million; +} + +////////////////////////////////////////////////////////////////////// +// +// The following emulation functions are generic, but need to be +// templated to account for differences in types, constants, etc. +// +////////////////////////////////////////////////////////////////////// + +/// Target ioctl() handler. For the most part, programs call ioctl() +/// only to find out if their stdout is a tty, to determine whether to +/// do line or block buffering. +template <class OS> +SyscallReturn +ioctlFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + int fd = tc->getSyscallArg(0); + unsigned req = tc->getSyscallArg(1); + + DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req); + + if (fd < 0 || process->sim_fd(fd) < 0) { + // doesn't map to any simulator fd: not a valid target fd + return -EBADF; + } + + switch (req) { + case OS::TIOCISATTY: + case OS::TIOCGETP: + case OS::TIOCSETP: + case OS::TIOCSETN: + case OS::TIOCSETC: + case OS::TIOCGETC: + case OS::TIOCGETS: + case OS::TIOCGETA: + return -ENOTTY; + + default: + fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ 0x%llx\n", + fd, req, tc->readPC()); + } +} + +/// Target open() handler. +template <class OS> +SyscallReturn +openFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + std::string path; + + if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) + return -EFAULT; + + if (path == "/dev/sysdev0") { + // This is a memory-mapped high-resolution timer device on Alpha. + // We don't support it, so just punt. + warn("Ignoring open(%s, ...)\n", path); + return -ENOENT; + } + + int tgtFlags = tc->getSyscallArg(1); + int mode = tc->getSyscallArg(2); + int hostFlags = 0; + + // translate open flags + for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { + if (tgtFlags & OS::openFlagTable[i].tgtFlag) { + tgtFlags &= ~OS::openFlagTable[i].tgtFlag; + hostFlags |= OS::openFlagTable[i].hostFlag; + } + } + + // any target flags left? + if (tgtFlags != 0) + warn("Syscall: open: cannot decode flags 0x%x", tgtFlags); + +#ifdef __CYGWIN32__ + hostFlags |= O_BINARY; +#endif + + DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str()); + + // open the file + int fd = open(path.c_str(), hostFlags, mode); + + return (fd == -1) ? -errno : process->alloc_fd(fd); +} + + +/// Target chmod() handler. +template <class OS> +SyscallReturn +chmodFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + std::string path; + + if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) + return -EFAULT; + + uint32_t mode = tc->getSyscallArg(1); + mode_t hostMode = 0; + + // XXX translate mode flags via OS::something??? + hostMode = mode; + + // do the chmod + int result = chmod(path.c_str(), hostMode); + if (result < 0) + return -errno; + + return 0; +} + + +/// Target fchmod() handler. +template <class OS> +SyscallReturn +fchmodFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + int fd = tc->getSyscallArg(0); + if (fd < 0 || process->sim_fd(fd) < 0) { + // doesn't map to any simulator fd: not a valid target fd + return -EBADF; + } + + uint32_t mode = tc->getSyscallArg(1); + mode_t hostMode = 0; + + // XXX translate mode flags via OS::someting??? + hostMode = mode; + + // do the fchmod + int result = fchmod(process->sim_fd(fd), hostMode); + if (result < 0) + return -errno; + + return 0; +} + + +/// Target stat() handler. +template <class OS> +SyscallReturn +statFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + std::string path; + + if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) + return -EFAULT; + + struct stat hostBuf; + int result = stat(path.c_str(), &hostBuf); + + if (result < 0) + return -errno; + + OS::copyOutStatBuf(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf); + + return 0; +} + + +/// Target fstat64() handler. +template <class OS> +SyscallReturn +fstat64Func(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + int fd = tc->getSyscallArg(0); + if (fd < 0 || process->sim_fd(fd) < 0) { + // doesn't map to any simulator fd: not a valid target fd + return -EBADF; + } + +#if BSD_HOST + struct stat hostBuf; + int result = fstat(process->sim_fd(fd), &hostBuf); +#else + struct stat64 hostBuf; + int result = fstat64(process->sim_fd(fd), &hostBuf); +#endif + + if (result < 0) + return -errno; + + OS::copyOutStat64Buf(tc->getMemPort(), fd, tc->getSyscallArg(1), &hostBuf); + + return 0; +} + + +/// Target lstat() handler. +template <class OS> +SyscallReturn +lstatFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + std::string path; + + if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) + return -EFAULT; + + struct stat hostBuf; + int result = lstat(path.c_str(), &hostBuf); + + if (result < 0) + return -errno; + + OS::copyOutStatBuf(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf); + + return 0; +} + +/// Target lstat64() handler. +template <class OS> +SyscallReturn +lstat64Func(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + std::string path; + + if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) + return -EFAULT; + +#if BSD_HOST + struct stat hostBuf; + int result = lstat(path.c_str(), &hostBuf); +#else + struct stat64 hostBuf; + int result = lstat64(path.c_str(), &hostBuf); +#endif + + if (result < 0) + return -errno; + + OS::copyOutStat64Buf(tc->getMemPort(), -1, tc->getSyscallArg(1), &hostBuf); + + return 0; +} + +/// Target fstat() handler. +template <class OS> +SyscallReturn +fstatFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + int fd = process->sim_fd(tc->getSyscallArg(0)); + + DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd); + + if (fd < 0) + return -EBADF; + + struct stat hostBuf; + int result = fstat(fd, &hostBuf); + + if (result < 0) + return -errno; + + OS::copyOutStatBuf(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf); + + return 0; +} + + +/// Target statfs() handler. +template <class OS> +SyscallReturn +statfsFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + std::string path; + + if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) + return -EFAULT; + + struct statfs hostBuf; + int result = statfs(path.c_str(), &hostBuf); + + if (result < 0) + return -errno; + + OS::copyOutStatfsBuf(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf); + + return 0; +} + + +/// Target fstatfs() handler. +template <class OS> +SyscallReturn +fstatfsFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + int fd = process->sim_fd(tc->getSyscallArg(0)); + + if (fd < 0) + return -EBADF; + + struct statfs hostBuf; + int result = fstatfs(fd, &hostBuf); + + if (result < 0) + return -errno; + + OS::copyOutStatfsBuf(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf); + + return 0; +} + + +/// Target writev() handler. +template <class OS> +SyscallReturn +writevFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + int fd = tc->getSyscallArg(0); + if (fd < 0 || process->sim_fd(fd) < 0) { + // doesn't map to any simulator fd: not a valid target fd + return -EBADF; + } + + TranslatingPort *p = tc->getMemPort(); + uint64_t tiov_base = tc->getSyscallArg(1); + size_t count = tc->getSyscallArg(2); + struct iovec hiov[count]; + for (int i = 0; i < count; ++i) + { + typename OS::tgt_iovec tiov; + + p->readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), + (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); + hiov[i].iov_len = gtoh(tiov.iov_len); + hiov[i].iov_base = new char [hiov[i].iov_len]; + p->readBlob(gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, + hiov[i].iov_len); + } + + int result = writev(process->sim_fd(fd), hiov, count); + + for (int i = 0; i < count; ++i) + { + delete [] (char *)hiov[i].iov_base; + } + + if (result < 0) + return -errno; + + return 0; +} + + +/// Target mmap() handler. +/// +/// We don't really handle mmap(). If the target is mmaping an +/// anonymous region or /dev/zero, we can get away with doing basically +/// nothing (since memory is initialized to zero and the simulator +/// doesn't really check addresses anyway). Always print a warning, +/// since this could be seriously broken if we're not mapping +/// /dev/zero. +// +/// Someday we should explicitly check for /dev/zero in open, flag the +/// file descriptor, and fail (or implement!) a non-anonymous mmap to +/// anything else. +template <class OS> +SyscallReturn +mmapFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) +{ + Addr start = tc->getSyscallArg(0); + uint64_t length = tc->getSyscallArg(1); + // int prot = tc->getSyscallArg(2); + int flags = tc->getSyscallArg(3); + // int fd = p->sim_fd(tc->getSyscallArg(4)); + // int offset = tc->getSyscallArg(5); + + if ((start % TheISA::VMPageSize) != 0 || + (length % TheISA::VMPageSize) != 0) { + warn("mmap failing: arguments not page-aligned: " + "start 0x%x length 0x%x", + start, length); + return -EINVAL; + } + + if (start != 0) { + warn("mmap: ignoring suggested map address 0x%x, using 0x%x", + start, p->mmap_end); + } + + // pick next address from our "mmap region" + start = p->mmap_end; + p->pTable->allocate(start, length); + p->mmap_end += length; + + if (!(flags & OS::TGT_MAP_ANONYMOUS)) { + warn("allowing mmap of file @ fd %d. " + "This will break if not /dev/zero.", tc->getSyscallArg(4)); + } + + return start; +} + +/// Target getrlimit() handler. +template <class OS> +SyscallReturn +getrlimitFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + unsigned resource = tc->getSyscallArg(0); + TypedBufferArg<typename OS::rlimit> rlp(tc->getSyscallArg(1)); + + switch (resource) { + case OS::TGT_RLIMIT_STACK: + // max stack size in bytes: make up a number (2MB for now) + rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; + rlp->rlim_cur = htog(rlp->rlim_cur); + rlp->rlim_max = htog(rlp->rlim_max); + break; + + default: + std::cerr << "getrlimitFunc: unimplemented resource " << resource + << std::endl; + abort(); + break; + } + + rlp.copyOut(tc->getMemPort()); + return 0; +} + +/// Target gettimeofday() handler. +template <class OS> +SyscallReturn +gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + TypedBufferArg<typename OS::timeval> tp(tc->getSyscallArg(0)); + + getElapsedTime(tp->tv_sec, tp->tv_usec); + tp->tv_sec += seconds_since_epoch; + tp->tv_sec = htog(tp->tv_sec); + tp->tv_usec = htog(tp->tv_usec); + + tp.copyOut(tc->getMemPort()); + + return 0; +} + + +/// Target utimes() handler. +template <class OS> +SyscallReturn +utimesFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + std::string path; + + if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) + return -EFAULT; + + TypedBufferArg<typename OS::timeval [2]> tp(tc->getSyscallArg(1)); + tp.copyIn(tc->getMemPort()); + + struct timeval hostTimeval[2]; + for (int i = 0; i < 2; ++i) + { + hostTimeval[i].tv_sec = gtoh((*tp)[i].tv_sec); + hostTimeval[i].tv_usec = gtoh((*tp)[i].tv_usec); + } + int result = utimes(path.c_str(), hostTimeval); + + if (result < 0) + return -errno; + + return 0; +} +/// Target getrusage() function. +template <class OS> +SyscallReturn +getrusageFunc(SyscallDesc *desc, int callnum, Process *process, + ThreadContext *tc) +{ + int who = tc->getSyscallArg(0); // THREAD, SELF, or CHILDREN + TypedBufferArg<typename OS::rusage> rup(tc->getSyscallArg(1)); + + if (who != OS::TGT_RUSAGE_SELF) { + // don't really handle THREAD or CHILDREN, but just warn and + // plow ahead + warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", + who); + } + + getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); + rup->ru_utime.tv_sec = htog(rup->ru_utime.tv_sec); + rup->ru_utime.tv_usec = htog(rup->ru_utime.tv_usec); + + rup->ru_stime.tv_sec = 0; + rup->ru_stime.tv_usec = 0; + rup->ru_maxrss = 0; + rup->ru_ixrss = 0; + rup->ru_idrss = 0; + rup->ru_isrss = 0; + rup->ru_minflt = 0; + rup->ru_majflt = 0; + rup->ru_nswap = 0; + rup->ru_inblock = 0; + rup->ru_oublock = 0; + rup->ru_msgsnd = 0; + rup->ru_msgrcv = 0; + rup->ru_nsignals = 0; + rup->ru_nvcsw = 0; + rup->ru_nivcsw = 0; + + rup.copyOut(tc->getMemPort()); + + return 0; +} + + + + +#endif // __SIM_SYSCALL_EMUL_HH__ diff --git a/src/sim/system.cc b/src/sim/system.cc new file mode 100644 index 000000000..b3c7870fd --- /dev/null +++ b/src/sim/system.cc @@ -0,0 +1,286 @@ +/* + * 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 + * Lisa Hsu + * Nathan Binkert + * Ali Saidi + */ + +#include "arch/isa_traits.hh" +#include "base/loader/object_file.hh" +#include "base/loader/symtab.hh" +#include "base/trace.hh" +#include "cpu/thread_context.hh" +#include "mem/mem_object.hh" +#include "mem/physical.hh" +#include "sim/builder.hh" +#include "sim/byteswap.hh" +#include "sim/system.hh" +#if FULL_SYSTEM +#include "arch/vtophys.hh" +#include "base/remote_gdb.hh" +#include "kern/kernel_stats.hh" +#endif + +using namespace std; +using namespace TheISA; + +vector<System *> System::systemList; + +int System::numSystemsRunning = 0; + +System::System(Params *p) + : SimObject(p->name), physmem(p->physmem), numcpus(0), +#if FULL_SYSTEM + init_param(p->init_param), + functionalPort(p->name + "-fport"), + virtPort(p->name + "-vport"), +#else + page_ptr(0), +#endif + _params(p) +{ + // add self to global system list + systemList.push_back(this); + +#if FULL_SYSTEM + kernelSymtab = new SymbolTable; + debugSymbolTable = new SymbolTable; + + + /** + * Get a functional port to memory + */ + Port *mem_port; + mem_port = physmem->getPort("functional"); + functionalPort.setPeer(mem_port); + mem_port->setPeer(&functionalPort); + + mem_port = physmem->getPort("functional"); + virtPort.setPeer(mem_port); + mem_port->setPeer(&virtPort); + + + /** + * Load the kernel code into memory + */ + // Load kernel code + kernel = createObjectFile(params()->kernel_path); + if (kernel == NULL) + fatal("Could not load kernel file %s", params()->kernel_path); + + // Load program sections into memory + kernel->loadSections(&functionalPort, LoadAddrMask); + + // setup entry points + kernelStart = kernel->textBase(); + kernelEnd = kernel->bssBase() + kernel->bssSize(); + kernelEntry = kernel->entryPoint(); + + // load symbols + if (!kernel->loadGlobalSymbols(kernelSymtab)) + panic("could not load kernel symbols\n"); + + if (!kernel->loadLocalSymbols(kernelSymtab)) + panic("could not load kernel local symbols\n"); + + if (!kernel->loadGlobalSymbols(debugSymbolTable)) + panic("could not load kernel symbols\n"); + + if (!kernel->loadLocalSymbols(debugSymbolTable)) + panic("could not load kernel local symbols\n"); + + DPRINTF(Loader, "Kernel start = %#x\n", kernelStart); + DPRINTF(Loader, "Kernel end = %#x\n", kernelEnd); + DPRINTF(Loader, "Kernel entry = %#x\n", kernelEntry); + DPRINTF(Loader, "Kernel loaded...\n"); + + kernelBinning = new Kernel::Binning(this); +#endif // FULL_SYSTEM + + // increment the number of running systms + numSystemsRunning++; +} + +System::~System() +{ +#if FULL_SYSTEM + delete kernelSymtab; + delete kernel; +#else + panic("System::fixFuncEventAddr needs to be rewritten " + "to work with syscall emulation"); +#endif // FULL_SYSTEM} +} + +#if FULL_SYSTEM + + +int rgdb_wait = -1; + +#endif // FULL_SYSTEM + +int +System::registerThreadContext(ThreadContext *tc, int id) +{ + if (id == -1) { + for (id = 0; id < threadContexts.size(); id++) { + if (!threadContexts[id]) + break; + } + } + + if (threadContexts.size() <= id) + threadContexts.resize(id + 1); + + if (threadContexts[id]) + panic("Cannot have two CPUs with the same id (%d)\n", id); + + threadContexts[id] = tc; + numcpus++; + +#if FULL_SYSTEM + RemoteGDB *rgdb = new RemoteGDB(this, tc); + GDBListener *gdbl = new GDBListener(rgdb, 7000 + id); + gdbl->listen(); + /** + * Uncommenting this line waits for a remote debugger to connect + * to the simulator before continuing. + */ + if (rgdb_wait != -1 && rgdb_wait == id) + gdbl->accept(); + + if (remoteGDB.size() <= id) { + remoteGDB.resize(id + 1); + } + + remoteGDB[id] = rgdb; +#endif // FULL_SYSTEM + + return id; +} + +void +System::startup() +{ + int i; + for (i = 0; i < threadContexts.size(); i++) + threadContexts[i]->activate(0); +} + +void +System::replaceThreadContext(ThreadContext *tc, int id) +{ + if (id >= threadContexts.size()) { + panic("replaceThreadContext: bad id, %d >= %d\n", + id, threadContexts.size()); + } + + threadContexts[id] = tc; +#if FULL_SYSTEM + remoteGDB[id]->replaceThreadContext(tc); +#endif // FULL_SYSTEM +} + +#if !FULL_SYSTEM +Addr +System::new_page() +{ + Addr return_addr = page_ptr << LogVMPageSize; + ++page_ptr; + return return_addr; +} +#endif + +void +System::serialize(ostream &os) +{ +#if FULL_SYSTEM + kernelSymtab->serialize("kernel_symtab", os); +#endif // FULL_SYSTEM +} + + +void +System::unserialize(Checkpoint *cp, const string §ion) +{ +#if FULL_SYSTEM + kernelSymtab->unserialize("kernel_symtab", cp, section); +#endif // FULL_SYSTEM +} + +void +System::printSystems() +{ + vector<System *>::iterator i = systemList.begin(); + vector<System *>::iterator end = systemList.end(); + for (; i != end; ++i) { + System *sys = *i; + cerr << "System " << sys->name() << ": " << hex << sys << endl; + } +} + +extern "C" +void +printSystems() +{ + System::printSystems(); +} + +#if FULL_SYSTEM + +// In full system mode, only derived classes (e.g. AlphaLinuxSystem) +// can be created directly. + +DEFINE_SIM_OBJECT_CLASS_NAME("System", System) + +#else + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(System) + + SimObjectParam<PhysicalMemory *> physmem; + +END_DECLARE_SIM_OBJECT_PARAMS(System) + +BEGIN_INIT_SIM_OBJECT_PARAMS(System) + + INIT_PARAM(physmem, "physical memory") + +END_INIT_SIM_OBJECT_PARAMS(System) + +CREATE_SIM_OBJECT(System) +{ + System::Params *p = new System::Params; + p->name = getInstanceName(); + p->physmem = physmem; + return new System(p); +} + +REGISTER_SIM_OBJECT("System", System) + +#endif diff --git a/src/sim/system.hh b/src/sim/system.hh new file mode 100644 index 000000000..059dc92dc --- /dev/null +++ b/src/sim/system.hh @@ -0,0 +1,226 @@ +/* + * 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: Steve Reinhardt + * Lisa Hsu + * Nathan Binkert + */ + +#ifndef __SYSTEM_HH__ +#define __SYSTEM_HH__ + +#include <string> +#include <vector> + +#include "base/loader/symtab.hh" +#include "base/misc.hh" +#include "base/statistics.hh" +#include "cpu/pc_event.hh" +#include "mem/port.hh" +#include "sim/sim_object.hh" +#if FULL_SYSTEM +#include "kern/system_events.hh" +#include "mem/vport.hh" +#endif + +class BaseCPU; +class ThreadContext; +class ObjectFile; +class PhysicalMemory; + +#if FULL_SYSTEM +class Platform; +class GDBListener; +class RemoteGDB; +#endif + +class System : public SimObject +{ + public: + PhysicalMemory *physmem; + PCEventQueue pcEventQueue; + + std::vector<ThreadContext *> threadContexts; + int numcpus; + + int getNumCPUs() + { + if (numcpus != threadContexts.size()) + panic("cpu array not fully populated!"); + + return numcpus; + } + +#if FULL_SYSTEM + Platform *platform; + uint64_t init_param; + + /** Port to physical memory used for writing object files into ram at + * boot.*/ + FunctionalPort functionalPort; + VirtualPort virtPort; + + /** kernel symbol table */ + SymbolTable *kernelSymtab; + + /** Object pointer for the kernel code */ + ObjectFile *kernel; + + /** Begining of kernel code */ + Addr kernelStart; + + /** End of kernel code */ + Addr kernelEnd; + + /** Entry point in the kernel to start at */ + Addr kernelEntry; + +#else + + int page_ptr; + + +#endif // FULL_SYSTEM + + protected: + +#if FULL_SYSTEM + /** + * Fix up an address used to match PCs for hooking simulator + * events on to target function executions. See comment in + * system.cc for details. + */ + virtual Addr fixFuncEventAddr(Addr addr) = 0; + + /** + * Add a function-based event to the given function, to be looked + * up in the specified symbol table. + */ + template <class T> + T *System::addFuncEvent(SymbolTable *symtab, const char *lbl) + { + Addr addr = 0; // initialize only to avoid compiler warning + + if (symtab->findAddress(lbl, addr)) { + T *ev = new T(&pcEventQueue, lbl, fixFuncEventAddr(addr)); + return ev; + } + + return NULL; + } + + /** Add a function-based event to kernel code. */ + template <class T> + T *System::addKernelFuncEvent(const char *lbl) + { + return addFuncEvent<T>(kernelSymtab, lbl); + } + +#endif + public: +#if FULL_SYSTEM + std::vector<RemoteGDB *> remoteGDB; + std::vector<GDBListener *> gdbListen; + virtual bool breakpoint() = 0; +#endif // FULL_SYSTEM + + public: + struct Params + { + std::string name; + PhysicalMemory *physmem; + +#if FULL_SYSTEM + Tick boot_cpu_frequency; + std::string boot_osflags; + uint64_t init_param; + + std::string kernel_path; + std::string readfile; +#endif + }; + + protected: + Params *_params; + + public: + System(Params *p); + ~System(); + + void startup(); + + const Params *params() const { return (const Params *)_params; } + + public: + +#if FULL_SYSTEM + /** + * Returns the addess the kernel starts at. + * @return address the kernel starts at + */ + Addr getKernelStart() const { return kernelStart; } + + /** + * Returns the addess the kernel ends at. + * @return address the kernel ends at + */ + Addr getKernelEnd() const { return kernelEnd; } + + /** + * Returns the addess the entry point to the kernel code. + * @return entry point of the kernel code + */ + Addr getKernelEntry() const { return kernelEntry; } + +#else + + Addr new_page(); + +#endif // FULL_SYSTEM + + int registerThreadContext(ThreadContext *tc, int tcIndex); + void replaceThreadContext(ThreadContext *tc, int tcIndex); + + void serialize(std::ostream &os); + void unserialize(Checkpoint *cp, const std::string §ion); + + public: + //////////////////////////////////////////// + // + // STATIC GLOBAL SYSTEM LIST + // + //////////////////////////////////////////// + + static std::vector<System *> systemList; + static int numSystemsRunning; + + static void printSystems(); + + +}; + +#endif // __SYSTEM_HH__ diff --git a/src/sim/vptr.hh b/src/sim/vptr.hh new file mode 100644 index 000000000..bcc22f0ca --- /dev/null +++ b/src/sim/vptr.hh @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Nathan Binkert + */ + +#ifndef __ARCH_ALPHA_VPTR_HH__ +#define __ARCH_ALPHA_VPTR_HH__ + +#include "arch/vtophys.hh" +#include "arch/isa_traits.hh" + +class ThreadContext; + +template <class T> +class VPtr +{ + public: + typedef T Type; + + private: + ThreadContext *tc; + Addr ptr; + + public: + ThreadContext *GetTC() const { return tc; } + Addr GetPointer() const { return ptr; } + + public: + explicit VPtr(ThreadContext *_tc, Addr p = 0) : tc(_tc), ptr(p) { } + template <class U> + VPtr(const VPtr<U> &vp) : tc(vp.GetTC()), ptr(vp.GetPointer()) {} + ~VPtr() {} + + bool operator!() const + { + return ptr == 0; + } + + VPtr<T> operator+(int offset) + { + VPtr<T> ptr(*this); + ptr += offset; + + return ptr; + } + + const VPtr<T> &operator+=(int offset) + { + ptr += offset; + assert((ptr & (TheISA::PageBytes - 1)) + sizeof(T) + < TheISA::PageBytes); + + return *this; + } + + const VPtr<T> &operator=(Addr p) + { + assert((p & (TheISA::PageBytes - 1)) + sizeof(T) + < TheISA::PageBytes); + ptr = p; + + return *this; + } + + template <class U> + const VPtr<T> &operator=(const VPtr<U> &vp) + { + tc = vp.GetTC(); + ptr = vp.GetPointer(); + + return *this; + } + + operator T *() + { + panic("Needs to be rewritten\n"); +/* void *addr = vtomem(tc, ptr, sizeof(T)); + return (T *)addr; + */ + } + + T *operator->() + { + panic("Needs to be rewritten\n"); +/* void *addr = vtomem(tc, ptr, sizeof(T)); + return (T *)addr; + */ + } + + T &operator*() + { + panic("Needs to be rewritten\n"); +/* void *addr = vtomem(tc, ptr, sizeof(T)); + return *(T *)addr; + */ + } +}; + +#endif // __ARCH_ALPHA_VPTR_HH__ diff --git a/src/unittest/Makefile b/src/unittest/Makefile new file mode 100644 index 000000000..1f0584066 --- /dev/null +++ b/src/unittest/Makefile @@ -0,0 +1,98 @@ +# 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: Nathan Binkert +# Steve Reinhardt + +CC?= gcc +CXX?= g++ +PYTHON?=/usr/bin/env python + +CURDIR?= $(shell /bin/pwd) +SRCDIR?= $(CURDIR)/.. + +CCFLAGS= -g -O0 -MMD -I. -I$(SRCDIR) -I- -DTRACING_ON=0 +MYSQL= -I/usr/include/mysql -L/usr/lib/mysql -lmysqlclient + +VPATH=$(SRCDIR):$(CURDIR) + +default: + @echo "You must specify a target" + +base/traceflags.cc base/traceflags.hh: $(SRCDIR)/base/traceflags.py + mkdir -p base; \ + cd base; \ + $(PYTHON) $< + +bitvectest: test/bitvectest.cc + $(CXX) $(CCFLAGS) -o $@ $^ + +circletest: test/circletest.cc base/circlebuf.cc + $(CXX) $(CCFLAGS) -o $@ $^ + +cprintftest: test/cprintftest.cc base/cprintf.cc + $(CXX) $(CCFLAGS) -o $@ $^ + +initest: test/initest.cc base/str.cc base/inifile.cc base/cprintf.cc + $(CXX) $(CCFLAGS) -o $@ $^ + +lrutest: test/lru_test.cc + $(CXX) $(CCFLAGS) -o $@ $^ + +nmtest: test/nmtest.cc base/output.cc base/hostinfo.cc base/cprintf.cc base/misc.cc base/loader/object_file.cc base/loader/symtab.cc base/misc.cc base/str.cc base/loader/aout_object.cc base/loader/ecoff_object.cc base/loader/elf_object.cc + $(CXX) $(CCFLAGS) -I/n/ziff/z/binkertn/build/work/ALPHA_FS -lelf -o $@ $^ + +offtest: test/offtest.cc + $(CXX) $(CCFLAGS) -o $@ $^ + +rangetest: test/rangetest.cc base/range.cc base/str.cc + $(CXX) $(CCFLAGS) -o $@ $^ + +STATTEST+= base/cprintf.cc base/hostinfo.cc base/misc.cc base/mysql.cc +STATTEST+= base/python.cc base/str.cc base/time.cc +STATTEST+= base/statistics.cc base/stats/mysql.cc base/stats/python.cc +STATTEST+= base/stats/statdb.cc base/stats/text.cc base/stats/visit.cc +STATTEST+= test/stattest.cc +stattest: $(STATTEST) + $(CXX) $(CCFLAGS) $(MYSQL) -o $@ $^ + +strnumtest: test/strnumtest.cc base/str.cc + $(CXX) $(CCFLAGS) -o $@ $^ + +symtest: test/symtest.cc base/misc.cc base/symtab.cc base/str.cc + $(CXX) $(CCFLAGS) -o $@ $^ + +tokentest: test/tokentest.cc base/str.cc + $(CXX) $(CCFLAGS) -o $@ $^ + +TRACE+=test/tracetest.cc base/trace.cc base/trace_flags.cc base/cprintf.cc +TRACE+=base/str.cc base/misc.cc +tracetest: $(TRACE) + $(CXX) $(CCFLAGS) -o $@ $^ + +clean: + @rm -rf *test *~ .#* *.core core base +.PHONY: clean diff --git a/src/unittest/bitvectest.cc b/src/unittest/bitvectest.cc new file mode 100644 index 000000000..440a150a3 --- /dev/null +++ b/src/unittest/bitvectest.cc @@ -0,0 +1,68 @@ +/* + * 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 + */ + +#include <iostream.h> + +#include <vector> + +int +main() +{ + vector<bool> v1(100); + + v1[0] = true; + v1.resize(500); + v1[100] = true; + v1[499] = true; + v1.resize(10000); + v1[9999] = true; + + cout << "v1.size() = " << v1.size() << "\n"; + for (int i = 0; i < v1.size(); i++) + if (v1[i]) + cout << "v1[" << i << "] = " << v1[i] << "\n"; + + cout << "\n"; + + vector<bool> v2 = v1; + + for (int i = 0; i < v2.size(); i++) + if (v2[i]) + cout << "v2[" << i << "] = " << v2[i] << "\n"; + + cout << "v1 " << ((v1 == v2) ? "==" : "!=") << " v2" << "\n"; + v2[8583] = true; + cout << "v1 " << ((v1 == v2) ? "==" : "!=") << " v2" << "\n"; + v1[8583] = true; + cout << "v1 " << ((v1 == v2) ? "==" : "!=") << " v2" << "\n"; + v1.resize(100000); + cout << "v1 " << ((v1 == v2) ? "==" : "!=") << " v2" << "\n"; + cout << flush; +} diff --git a/src/unittest/circletest.cc b/src/unittest/circletest.cc new file mode 100644 index 000000000..f072cf044 --- /dev/null +++ b/src/unittest/circletest.cc @@ -0,0 +1,74 @@ +/* + * 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 + */ + +#include <fcntl.h> +#include <iostream.h> +#include <unistd.h> + +#include "base/circlebuf.hh" + +char *strings[] = +{ "This is the first test\n", + "he went with his woman to the store\n", + "the man with the bat hit the woman with the hat\n", + "that that is is that that was\n", + "sue sells sea shells by the sea shore\n", + "go to the store and buy me some milk and bread\n", + "the friendly flight attendants spoke soothingly to the frightened passengers in their native languages\n" +}; + +const int num_strings = sizeof(strings) / sizeof(char *); + +int +main() +{ + CircleBuf buf(1024); + + for (int count = 0; count < 100; count++) + buf.write(strings[count % num_strings]); + buf.read(STDOUT_FILENO); + write(STDOUT_FILENO, "<\n", 2); + + for (int count = 0; count < 100; count++) + buf.write(strings[count % num_strings]); + buf.read(STDOUT_FILENO, 100); + write(STDOUT_FILENO, "<\n", 2); + + buf.flush(); + buf.write("asdfa asdf asd fasdf asdf\n"); + buf.write(""); + buf.write(""); + buf.write(""); + buf.write(""); + buf.write(""); + buf.write(""); + buf.read(STDOUT_FILENO); + write(STDOUT_FILENO, "<\n", 2); +} diff --git a/src/unittest/cprintftest.cc b/src/unittest/cprintftest.cc new file mode 100644 index 000000000..9c3eb0cd6 --- /dev/null +++ b/src/unittest/cprintftest.cc @@ -0,0 +1,165 @@ +/* + * 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 + */ + +#include <iostream> +#include <list> +#include <string> +#include <sstream> + +#include "base/cprintf.hh" + +using namespace std; + +int +main() +{ + char foo[9]; + cprintf("%s\n", foo); + + cprintf("%shits%%s + %smisses%%s\n", "test", "test"); + cprintf("%%s%-10s %c he went home \'\"%d %#o %#x %1.5f %1.2E\n", + "hello", 'A', 1, 0xff, 0xfffffffffffffULL, 3.141592653589, 1.1e10); + + cout << cformat("%s %#x %s\n") << "hello" << 0 << "foo 0\n"; + cerr << cformat("%s %#x\n") << "hello" << 1 << "foo 1\n"; + + cprintf("another test\n"); + + stringstream buffer; + ccprintf(buffer, "%-10s %c he home \'\"%d %#o %#x %1.5f %1.2E\n", + "hello", 'A', 1, 0xff, 0xfffffffffffffULL, 3.14159265, 1.1e10); + + double f = 314159.26535897932384; + + #define ctest(x, y) printf(x, y); cprintf(x, y); cprintf("\n"); + ctest("%1.8f\n", f); + ctest("%2.8f\n", f); + ctest("%3.8f\n", f); + ctest("%4.8f\n", f); + ctest("%5.8f\n", f); + ctest("%6.8f\n", f); + ctest("%12.8f\n", f); + ctest("%1000.8f\n", f); + ctest("%1.0f\n", f); + ctest("%1.1f\n", f); + ctest("%1.2f\n", f); + ctest("%1.3f\n", f); + ctest("%1.4f\n", f); + ctest("%1.5f\n", f); + ctest("%1.6f\n", f); + ctest("%1.7f\n", f); + ctest("%1.8f\n", f); + ctest("%1.9f\n", f); + ctest("%1.10f\n", f); + ctest("%1.11f\n", f); + ctest("%1.12f\n", f); + ctest("%1.13f\n", f); + ctest("%1.14f\n", f); + ctest("%1.15f\n", f); + ctest("%1.16f\n", f); + ctest("%1.17f\n", f); + ctest("%1.18f\n", f); + + cout << "foo\n"; + + f = 0.00000026535897932384; + ctest("%1.8f\n", f); + ctest("%2.8f\n", f); + ctest("%3.8f\n", f); + ctest("%4.8f\n", f); + ctest("%5.8f\n", f); + ctest("%6.8f\n", f); + ctest("%12.8f\n", f); + ctest("%1.0f\n", f); + ctest("%1.1f\n", f); + ctest("%1.2f\n", f); + ctest("%1.3f\n", f); + ctest("%1.4f\n", f); + ctest("%1.5f\n", f); + ctest("%1.6f\n", f); + ctest("%1.7f\n", f); + ctest("%1.8f\n", f); + ctest("%1.9f\n", f); + ctest("%1.10f\n", f); + ctest("%1.11f\n", f); + ctest("%1.12f\n", f); + ctest("%1.13f\n", f); + ctest("%1.14f\n", f); + ctest("%1.15f\n", f); + ctest("%1.16f\n", f); + ctest("%1.17f\n", f); + ctest("%1.18f\n", f); + + f = 0.00000026535897932384; + ctest("%1.8e\n", f); + ctest("%2.8e\n", f); + ctest("%3.8e\n", f); + ctest("%4.8e\n", f); + ctest("%5.8e\n", f); + ctest("%6.8e\n", f); + ctest("%12.8e\n", f); + ctest("%1.0e\n", f); + ctest("%1.1e\n", f); + ctest("%1.2e\n", f); + ctest("%1.3e\n", f); + ctest("%1.4e\n", f); + ctest("%1.5e\n", f); + ctest("%1.6e\n", f); + ctest("%1.7e\n", f); + ctest("%1.8e\n", f); + ctest("%1.9e\n", f); + ctest("%1.10e\n", f); + ctest("%1.11e\n", f); + ctest("%1.12e\n", f); + ctest("%1.13e\n", f); + ctest("%1.14e\n", f); + ctest("%1.15e\n", f); + ctest("%1.16e\n", f); + ctest("%1.17e\n", f); + ctest("%1.18e\n", f); + + cout << buffer.str(); + + cout.width(0); + cout.precision(1); + cout << f << "\n"; + + string foo1 = "string test"; + cprintf("%s\n", foo1); + + stringstream foo2; + foo2 << "stringstream test"; + cprintf("%s\n", foo2); + + cprintf("%c %c\n", 'c', 65); + + cout << '9'; + return 0; +} diff --git a/test/foo.ini b/src/unittest/foo.ini index 534a4e001..534a4e001 100644 --- a/test/foo.ini +++ b/src/unittest/foo.ini diff --git a/src/unittest/genini.py b/src/unittest/genini.py new file mode 100755 index 000000000..a969a6ee4 --- /dev/null +++ b/src/unittest/genini.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python +# Copyright (c) 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 + +import getopt, os, os.path, sys +from os.path import join as joinpath, realpath + +mypath = sys.path[0] +sys.path.append(joinpath(mypath, '..')) +sys.path.append(joinpath(mypath, '../python')) +sys.path.append(joinpath(mypath, '../util/pbs')) + +pathlist = [ '.' ] + +m5_build_env = {} + +try: + opts, args = getopt.getopt(sys.argv[1:], '-E:I:') + for opt,arg in opts: + if opt == '-E': + offset = arg.find('=') + if offset == -1: + name = arg + value = 'True' + else: + name = arg[:offset] + value = arg[offset+1:] + os.environ[name] = value + m5_build_env[name] = value + if opt == '-I': + pathlist.append(arg) +except getopt.GetoptError: + sys.exit('Improper Usage') + +import __main__ +__main__.m5_build_env = m5_build_env + +from m5 import * + +for path in pathlist: + AddToPath(path) + +for arg in args: + m5execfile(arg, globals()) + +if globals().has_key('root') and isinstance(root, Root): + instantiate(root) +else: + print "Instantiation skipped: no root object found." diff --git a/src/unittest/initest.cc b/src/unittest/initest.cc new file mode 100644 index 000000000..8f53fce5c --- /dev/null +++ b/src/unittest/initest.cc @@ -0,0 +1,145 @@ +/* + * 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 + * Steve Reinhardt + */ + +#include <iostream> +#include <fstream> +#include <string> +#include <vector> + +#include "base/inifile.hh" +#include "base/cprintf.hh" + +using namespace std; + +char *progname; + +void +usage() +{ + cout << "Usage: " << progname << " <ini file>\n"; + exit(1); +} + +#if 0 +char *defines = getenv("CONFIG_DEFINES"); +if (defines) { + char *c = defines; + while ((c = strchr(c, ' ')) != NULL) { + *c++ = '\0'; + count++; + } + count++; +} + +#endif + +int +main(int argc, char *argv[]) +{ + IniFile simConfigDB; + + progname = argv[0]; + + vector<char *> cppArgs; + + vector<char *> cpp_options; + cpp_options.reserve(argc * 2); + + for (int i = 1; i < argc; ++i) { + char *arg_str = argv[i]; + + // if arg starts with '-', parse as option, + // else treat it as a configuration file name and load it + if (arg_str[0] == '-') { + + // switch on second char + switch (arg_str[1]) { + case 'D': + case 'U': + case 'I': + // cpp options: record & pass to cpp. Note that these + // cannot have spaces, i.e., '-Dname=val' is OK, but + // '-D name=val' is not. I don't consider this a + // problem, since even though gnu cpp accepts the + // latter, other cpp implementations do not (Tru64, + // for one). + cppArgs.push_back(arg_str); + break; + + case '-': + // command-line configuration parameter: + // '--<section>:<parameter>=<value>' + + if (!simConfigDB.add(arg_str + 2)) { + // parse error + ccprintf(cerr, + "Could not parse configuration argument '%s'\n" + "Expecting --<section>:<parameter>=<value>\n", + arg_str); + exit(0); + } + break; + + default: + usage(); + } + } + else { + // no '-', treat as config file name + + if (!simConfigDB.loadCPP(arg_str, cppArgs)) { + cprintf("Error processing file %s\n", arg_str); + exit(1); + } + } + } + + string value; + +#define FIND(C, E) \ + if (simConfigDB.find(C, E, value)) \ + cout << ">" << value << "<\n"; \ + else \ + cout << "Not Found!\n" + + FIND("General", "Test2"); + FIND("Junk", "Test3"); + FIND("Junk", "Test4"); + FIND("General", "Test1"); + FIND("Junk2", "test3"); + FIND("General", "Test3"); + + cout << "\n"; + + simConfigDB.dump(); + + return 0; +} diff --git a/test/initest.ini b/src/unittest/initest.ini index ebf2719d8..ebf2719d8 100644 --- a/test/initest.ini +++ b/src/unittest/initest.ini diff --git a/src/unittest/lru_test.cc b/src/unittest/lru_test.cc new file mode 100644 index 000000000..d10eb1dd0 --- /dev/null +++ b/src/unittest/lru_test.cc @@ -0,0 +1,85 @@ +/* + * Copyright (c) 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: Dave Greene + * Nathan Binkert + */ + +#include <iostream> +#include "bhgp.hh" + +int main(void) +{ + typedef AssociativeTable<unsigned int, unsigned int> tableType; + tableType table(10, 4); // 40 entry table + + std::cout << "Initial state:" << std::endl; + table.dump(); + + std::cout << "Inserting (2, 1)" << std::endl; + table[2] = 1; + table.dump(); + + std::cout << "Inserting (5, 2)" << std::endl; + table[5] = 2; + table.dump(); + + std::cout << "Inserting (10 + 2, 3)" << std::endl; + table[10 + 2] = 3; + table.dump(); + + tableType::const_iterator i = table.find(2); + assert(i != table.end()); + std::cout << "Accessed 2: " << *i << std::endl; + table.dump(); + + i = table.find(10 + 2); + assert(i != table.end()); + std::cout << "Accessed 10 + 2: " << *i << std::endl; + table.dump(); + + i = table.find(34); + assert(i == table.end()); + + std::cout << "Inserting (2 * 10 + 2, 4)" << std::endl; + table[2 * 10 + 2] = 4; + table.dump(); + + std::cout << "Replacing (10 + 2) with 5" << std::endl; + table[10 + 2] = 5; + table.dump(); + + std::cout << "Inserting (3 * 10 + 2, 6)" << std::endl; + table[3 * 10 + 2] = 6; + table.dump(); + + std::cout << "Inserting (4 * 10 + 2, 7)" << std::endl; + table[4 * 10 + 2] = 7; + table.dump(); + + return(0); +} diff --git a/src/unittest/nmtest.cc b/src/unittest/nmtest.cc new file mode 100644 index 000000000..b6b74e08d --- /dev/null +++ b/src/unittest/nmtest.cc @@ -0,0 +1,85 @@ +/* + * 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 + */ + +#include <iostream> +#include <string> +#include <vector> + +#include "base/loader/object_file.hh" +#include "base/loader/symtab.hh" +#include "base/misc.hh" +#include "base/str.hh" + +using namespace std; +Tick curTick; + +ostream *outputStream = &cout; + +int +main(int argc, char *argv[]) +{ + if (argc != 2 && argc != 3) + panic("usage: %s <filename> <symbol>\n", argv[0]); + + ObjectFile *obj = createObjectFile(argv[1]); + if (!obj) + panic("file not found\n"); + + SymbolTable symtab; + obj->loadGlobalSymbols(&symtab); + obj->loadLocalSymbols(&symtab); + + if (argc == 2) { + SymbolTable::ATable::const_iterator i = symtab.getAddrTable().begin(); + SymbolTable::ATable::const_iterator end = symtab.getAddrTable().end(); + while (i != end) { + cprintf("%#x %s\n", i->first, i->second); + ++i; + } + } else { + string symbol = argv[2]; + Addr address; + + if (symbol[0] == '0' && symbol[1] == 'x') { + if (to_number(symbol, address) && + symtab.findSymbol(address, symbol)) + cprintf("address = %#x, symbol = %s\n", address, symbol); + else + cprintf("address = %#x was not found\n", address); + } else { + if (symtab.findAddress(symbol, address)) + cprintf("symbol = %s address = %#x\n", symbol, address); + else + cprintf("symbol = %s was not found\n", symbol); + } + } + + return 0; +} diff --git a/src/unittest/offtest.cc b/src/unittest/offtest.cc new file mode 100644 index 000000000..ebfb2515c --- /dev/null +++ b/src/unittest/offtest.cc @@ -0,0 +1,72 @@ +/* + * 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 + */ + +#include <sys/types.h> +#include <stddef.h> +#include <stdio.h> +#include "dev/pcireg.h" + +int +main() +{ +#define POFFSET(x) \ + printf("offsetof(PCIConfig, hdr."#x") = %d\n", \ + offsetof(PCIConfig, hdr.x)) + + POFFSET(vendor); + POFFSET(device); + POFFSET(command); + POFFSET(status); + POFFSET(revision); + POFFSET(progIF); + POFFSET(subClassCode); + POFFSET(classCode); + POFFSET(cacheLineSize); + POFFSET(latencyTimer); + POFFSET(headerType); + POFFSET(bist); + POFFSET(pci0.baseAddr0); + POFFSET(pci0.baseAddr1); + POFFSET(pci0.baseAddr2); + POFFSET(pci0.baseAddr3); + POFFSET(pci0.baseAddr4); + POFFSET(pci0.baseAddr5); + POFFSET(pci0.cardbusCIS); + POFFSET(pci0.subsystemVendorID); + POFFSET(pci0.expansionROM); + POFFSET(pci0.reserved0); + POFFSET(pci0.reserved1); + POFFSET(pci0.interruptLine); + POFFSET(pci0.interruptPin); + POFFSET(pci0.minimumGrant); + POFFSET(pci0.minimumLatency); + + return 0; +} diff --git a/src/unittest/paramtest.cc b/src/unittest/paramtest.cc new file mode 100644 index 000000000..e513ab981 --- /dev/null +++ b/src/unittest/paramtest.cc @@ -0,0 +1,107 @@ +/* + * 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 + */ + +// +// This file is not part of the regular simulator. It is solely for +// testing the parameter code. Edit the Makefile to add param_test.cc +// to the sources list, then use configs/test.ini as the configuration +// file. +// +#include "sim/sim_object.hh" +#include "mem/cache/cache.hh" + +class ParamTest : public SimObject +{ + public: + ParamTest(string name) + : SimObject(name) + { + } + + virtual ~ParamTest() {} +}; + +enum Enum1Type { Enum0 }; +enum Enum2Type { Enum10 }; + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(ParamTest) + + Param<int> intparam; + VectorParam<int> vecint; + Param<string> stringparam; + VectorParam<string> vecstring; + Param<bool> boolparam; + VectorParam<bool> vecbool; + SimObjectParam<BaseMemory *> memobj; + SimObjectVectorParam<BaseMemory *> vecmemobj; + SimpleEnumParam<Enum1Type> enum1; + MappedEnumParam<Enum2Type> enum2; + SimpleEnumVectorParam<Enum1Type> vecenum1; + MappedEnumVectorParam<Enum2Type> vecenum2; + +END_DECLARE_SIM_OBJECT_PARAMS(ParamTest) + +const char *enum1_strings[] = +{ + "zero", "one", "two", "three" +}; + +const EnumParamMap enum2_map[] = +{ + { "ten", 10 }, + { "twenty", 20 }, + { "thirty", 30 }, + { "forty", 40 } +}; + +BEGIN_INIT_SIM_OBJECT_PARAMS(ParamTest) + + INIT_PARAM(intparam, "intparam"), + INIT_PARAM(vecint, "vecint"), + INIT_PARAM(stringparam, "stringparam"), + INIT_PARAM(vecstring, "vecstring"), + INIT_PARAM(boolparam, "boolparam"), + INIT_PARAM(vecbool, "vecbool"), + INIT_PARAM(memobj, "memobj"), + INIT_PARAM(vecmemobj, "vecmemobj"), + INIT_ENUM_PARAM(enum1, "enum1", enum1_strings), + INIT_ENUM_PARAM(enum2, "enum2", enum2_map), + INIT_ENUM_PARAM(vecenum1, "vecenum1", enum1_strings), + INIT_ENUM_PARAM(vecenum2, "vecenum2", enum2_map) + +END_INIT_SIM_OBJECT_PARAMS(ParamTest) + + +CREATE_SIM_OBJECT(ParamTest) +{ + return new ParamTest(getInstanceName()); +} + +REGISTER_SIM_OBJECT("ParamTest", ParamTest) diff --git a/src/unittest/rangetest.cc b/src/unittest/rangetest.cc new file mode 100644 index 000000000..b7a68ab44 --- /dev/null +++ b/src/unittest/rangetest.cc @@ -0,0 +1,76 @@ +/* + * 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 + */ + +#include <iostream> +#include <string> + +#include "base/range.hh" + +using namespace std; + +int +main() +{ + Range<int> r1(make_pair(9, 28)); + Range<unsigned> r2("0x1000:+0x100"); + + cout << r1 << "\n" + << r2 << "\n"; + +#define RANGETEST(X, C, Y) \ + cout << X << " "#C" " << Y << " => " << ((X C Y) ? "true" : "false") << "\n" + +#define TESTEM(X, Y) do { \ + RANGETEST(X, < , Y); \ + RANGETEST(X, <=, Y); \ + RANGETEST(X, > , Y); \ + RANGETEST(X, >=, Y); \ + RANGETEST(X, ==, Y); \ + RANGETEST(X, !=, Y); \ + RANGETEST(Y, < , X); \ + RANGETEST(Y, <=, X); \ + RANGETEST(Y, > , X); \ + RANGETEST(Y, >=, X); \ + RANGETEST(Y, ==, X); \ + RANGETEST(Y, !=, X); \ +} while (0) + + TESTEM(8, r1); + TESTEM(9, r1); + TESTEM(27, r1); + TESTEM(28, r1); + + TESTEM(0x0fff, r2); + TESTEM(0x1000, r2); + TESTEM(0x10ff, r2); + TESTEM(0x1100, r2); + + return 0; +} diff --git a/src/unittest/sized_test.cc b/src/unittest/sized_test.cc new file mode 100644 index 000000000..f1bf7528f --- /dev/null +++ b/src/unittest/sized_test.cc @@ -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: Dave Greene + * Nathan Binkert + */ + +#include <iostream> +#include <algorithm> + +#include "sized.hh" +#include <queue> +#include <typeinfo> + +template<typename C> +void print(C &cont) +{ + std::cout << std::endl; + std::cout << "Printing " << typeid(cont).name() << std::endl; + while (!cont.empty()) { + std::cout << cont.front() << " "; + cont.pop(); + } + std::cout << std::endl; +} + +int main(void) +{ + sized<std::queue<int>, sized_error_policy<std::queue<int> > > + error_queue(10); + sized<std::queue<int>, sized_drop_policy<std::queue<int> > > + drop_queue(5); + + for (int i = 0; i < 10; ++i) { + error_queue.push(i); + } + + for (int i = 0; i < 3; ++i) { + drop_queue.push(i); + } + + print(error_queue); + print(drop_queue); + + return(0); +} diff --git a/src/unittest/stattest.cc b/src/unittest/stattest.cc new file mode 100644 index 000000000..4e504fde9 --- /dev/null +++ b/src/unittest/stattest.cc @@ -0,0 +1,556 @@ +/* + * Copyright (c) 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: Nathan Binkert + */ + +#include <iomanip> +#include <iostream> +#include <fstream> +#include <string> +#include <unistd.h> + +#include "base/cprintf.hh" +#include "base/misc.hh" +#include "base/statistics.hh" +#include "base/stats/text.hh" +#include "base/stats/mysql.hh" +#include "sim/host.hh" + +using namespace std; +using namespace Stats; + +Tick curTick = 0; +Tick ticksPerSecond = ULL(2000000000); + +Scalar<> s1; +Scalar<> s2; +Average<> s3; +Scalar<> s4; +Vector<> s5; +Distribution<> s6; +Vector<> s7; +AverageVector<> s8; +StandardDeviation<> s9; +AverageDeviation<> s10; +Scalar<> s11; +Distribution<> s12; +VectorDistribution<> s13; +VectorStandardDeviation<> s14; +VectorAverageDeviation<> s15; +Vector2d<> s16; + +Formula f1; +Formula f2; +Formula f3; +Value f4; +Value f5; +Formula f6; +Formula f7; + +ostream *outputStream = &cout; + +double +testfunc() +{ + return 9.8; +} + +class TestClass { + public: + double operator()() { return 9.7; } +}; + +char *progname = ""; + +void +usage() +{ + panic("incorrect usage.\n" + "usage:\n" + "\t%s [-t [-c] [-d]]\n", progname); +} + +int +main(int argc, char *argv[]) +{ + bool descriptions = false; + bool compat = false; + bool text = false; + string mysql_name; + string mysql_host; + string mysql_user = "binkertn"; + string mysql_passwd; + + char c; + progname = argv[0]; + while ((c = getopt(argc, argv, "cdh:P:p:s:tu:")) != -1) { + switch (c) { + case 'c': + compat = true; + break; + case 'd': + descriptions = true; + break; + case 'h': + mysql_host = optarg; + break; + case 'P': + mysql_passwd = optarg; + break; + case 's': + mysql_name = optarg; + break; + case 't': + text = true; + break; + case 'u': + mysql_user = optarg; + break; + default: + usage(); + } + } + + if (!text && (compat || descriptions)) + usage(); + + s5.init(5); + s6.init(1, 100, 13); + s7.init(7); + s8.init(10); + s12.init(1, 100, 13); + s13.init(4, 0, 99, 10); + s14.init(9); + s15.init(10); + s16.init(2, 9); + + s1 + .name("Stat01") + .desc("this is statistic 1") + ; + + s2 + .name("Stat02") + .desc("this is statistic 2") + .prereq(s11) + ; + + s3 + .name("Stat03") + .desc("this is statistic 3") + .prereq(f7) + ; + + s4 + .name("Stat04") + .desc("this is statistic 4") + .prereq(s11) + ; + + s5 + .name("Stat05") + .desc("this is statistic 5") + .prereq(s11) + .subname(0, "foo1") + .subname(1, "foo2") + .subname(2, "foo3") + .subname(3, "foo4") + .subname(4, "foo5") + ; + + s6 + .name("Stat06") + .desc("this is statistic 6") + .prereq(s11) + ; + + s7 + .name("Stat07") + .desc("this is statistic 7") + .precision(1) + .flags(pdf | total) + .prereq(s11) + ; + + s8 + .name("Stat08") + .desc("this is statistic 8") + .precision(2) + .prereq(s11) + .subname(4, "blarg") + ; + + s9 + .name("Stat09") + .desc("this is statistic 9") + .precision(4) + .prereq(s11) + ; + + s10 + .name("Stat10") + .desc("this is statistic 10") + .prereq(s11) + ; + + s12 + .name("Stat12") + .desc("this is statistic 12") + ; + + s13 + .name("Stat13") + .desc("this is statistic 13") + ; + + s14 + .name("Stat14") + .desc("this is statistic 14") + ; + + s15 + .name("Stat15") + .desc("this is statistic 15") + ; + + s16 + .name("Stat16") + .desc("this is statistic 16") + .flags(total) + .subname(0, "sub0") + .subname(1, "sub1") + .ysubname(0, "y0") + .ysubname(1, "y1") + ; + + f1 + .name("Formula1") + .desc("this is formula 1") + .prereq(s11) + ; + + f2 + .name("Formula2") + .desc("this is formula 2") + .prereq(s11) + .precision(1) + ; + + f3 + .name("Formula3") + .desc("this is formula 3") + .prereq(s11) + .subname(0, "bar1") + .subname(1, "bar2") + .subname(2, "bar3") + .subname(3, "bar4") + .subname(4, "bar5") + ; + + f4 + .functor(testfunc) + .name("Formula4") + .desc("this is formula 4") + ; + + TestClass testclass; + f5 + .functor(testclass) + .name("Formula5") + .desc("this is formula 5") + ; + + f6 + .name("Formula6") + .desc("this is formula 6") + ; + + f1 = s1 + s2; + f2 = (-s1) / (-s2) * (-s3 + ULL(100) + s4); + f3 = sum(s5) * s7; + f6 += constant(10.0); + f6 += s5[3]; + f7 = constant(1); + + check(); + reset(); + + s16[1][0] = 1; + s16[0][1] = 3; + s16[0][0] = 2; + s16[1][1] = 9; + s16[1][1] += 9; + s16[1][8] += 8; + s16[1][7] += 7; + s16[1][6] += 6; + s16[1][5] += 5; + s16[1][4] += 4; + + s11 = 1; + s3 = 9; + s8[3] = 9; + s15[0].sample(1234); + s15[1].sample(1234); + s15[2].sample(1234); + s15[3].sample(1234); + s15[4].sample(1234); + s15[5].sample(1234); + s15[6].sample(1234); + s15[7].sample(1234); + s15[8].sample(1234); + s15[9].sample(1234); + + s10.sample(1000000000); + curTick += ULL(1000000); + s10.sample(100000); + s10.sample(100000); + s10.sample(100000); + s10.sample(100000); + s10.sample(100000); + s10.sample(100000); + s10.sample(100000); + s10.sample(100000); + s10.sample(100000); + s10.sample(100000); + s10.sample(100000); + s10.sample(100000); + s10.sample(100000); + s13[0].sample(12); + s13[1].sample(29); + s13[2].sample(12); + s13[3].sample(29); + s13[0].sample(42); + s13[1].sample(29); + s13[2].sample(42); + s13[3].sample(32); + s13[0].sample(52); + s13[1].sample(49); + s13[2].sample(42); + s13[3].sample(25); + s13[0].sample(32); + s13[1].sample(49); + s13[2].sample(22); + s13[3].sample(49); + s13[0].sample(62); + s13[1].sample(99); + s13[2].sample(72); + s13[3].sample(23); + s13[0].sample(52); + s13[1].sample(78); + s13[2].sample(69); + s13[3].sample(49); + + s14[0].sample(1234); + s14[1].sample(4134); + s14[4].sample(1213); + s14[3].sample(1124); + s14[2].sample(1243); + s14[7].sample(1244); + s14[4].sample(7234); + s14[2].sample(9234); + s14[3].sample(1764); + s14[7].sample(1564); + s14[3].sample(3234); + s14[1].sample(2234); + s14[5].sample(1234); + s14[2].sample(4334); + s14[2].sample(1234); + s14[4].sample(4334); + s14[6].sample(1234); + s14[8].sample(8734); + s14[1].sample(5234); + s14[3].sample(8234); + s14[7].sample(5234); + s14[4].sample(4434); + s14[3].sample(7234); + s14[2].sample(1934); + s14[1].sample(9234); + s14[5].sample(5634); + s14[3].sample(1264); + s14[7].sample(5223); + s14[0].sample(1234); + s14[0].sample(5434); + s14[3].sample(8634); + s14[1].sample(1234); + + + s15[0].sample(1234); + s15[1].sample(4134); + curTick += ULL(1000000); + s15[4].sample(1213); + curTick += ULL(1000000); + s15[3].sample(1124); + curTick += ULL(1000000); + s15[2].sample(1243); + curTick += ULL(1000000); + s15[7].sample(1244); + curTick += ULL(1000000); + s15[4].sample(7234); + s15[2].sample(9234); + s15[3].sample(1764); + s15[7].sample(1564); + s15[3].sample(3234); + s15[1].sample(2234); + curTick += ULL(1000000); + s15[5].sample(1234); + curTick += ULL(1000000); + s15[9].sample(4334); + curTick += ULL(1000000); + s15[2].sample(1234); + curTick += ULL(1000000); + s15[4].sample(4334); + s15[6].sample(1234); + curTick += ULL(1000000); + s15[8].sample(8734); + curTick += ULL(1000000); + s15[1].sample(5234); + curTick += ULL(1000000); + s15[3].sample(8234); + curTick += ULL(1000000); + s15[7].sample(5234); + s15[4].sample(4434); + s15[3].sample(7234); + s15[2].sample(1934); + s15[1].sample(9234); + curTick += ULL(1000000); + s15[5].sample(5634); + s15[3].sample(1264); + s15[7].sample(5223); + s15[0].sample(1234); + s15[0].sample(5434); + s15[3].sample(8634); + curTick += ULL(1000000); + s15[1].sample(1234); + + s4 = curTick; + + s8[3] = 99999; + + s3 = 12; + s3++; + curTick += 9; + + s1 = 9; + s1 += 9; + s1 -= 11; + s1++; + ++s1; + s1--; + --s1; + + s2 = 9; + + s5[0] += 1; + s5[1] += 2; + s5[2] += 3; + s5[3] += 4; + s5[4] += 5; + + s7[0] = 10; + s7[1] = 20; + s7[2] = 30; + s7[3] = 40; + s7[4] = 50; + s7[5] = 60; + s7[6] = 70; + + s6.sample(0); + s6.sample(1); + s6.sample(2); + s6.sample(3); + s6.sample(4); + s6.sample(5); + s6.sample(6); + s6.sample(7); + s6.sample(8); + s6.sample(9); + + s6.sample(10); + s6.sample(10); + s6.sample(10); + s6.sample(10); + s6.sample(10); + s6.sample(10); + s6.sample(10); + s6.sample(10); + s6.sample(11); + s6.sample(19); + s6.sample(20); + s6.sample(20); + s6.sample(21); + s6.sample(21); + s6.sample(31); + s6.sample(98); + s6.sample(99); + s6.sample(99); + s6.sample(99); + + s7[0] = 700; + s7[1] = 600; + s7[2] = 500; + s7[3] = 400; + s7[4] = 300; + s7[5] = 200; + s7[6] = 100; + + s9.sample(100); + s9.sample(100); + s9.sample(100); + s9.sample(100); + s9.sample(10); + s9.sample(10); + s9.sample(10); + s9.sample(10); + s9.sample(10); + + curTick += 9; + s4 = curTick; + s6.sample(100); + s6.sample(100); + s6.sample(100); + s6.sample(101); + s6.sample(102); + + s12.sample(100); + + if (text) { + Text out(cout); + out.descriptions = descriptions; + out.compat = compat; + out(); + } + + if (!mysql_name.empty()) { + MySql out; + out.connect(mysql_host, mysql_user, mysql_passwd, "m5stats", + mysql_name, "test"); + out(); + } + + return 0; +} diff --git a/src/unittest/strnumtest.cc b/src/unittest/strnumtest.cc new file mode 100644 index 000000000..ea28e35df --- /dev/null +++ b/src/unittest/strnumtest.cc @@ -0,0 +1,78 @@ +/* + * 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 + */ + +#include <iostream.h> + +#include <string> +#include <vector> + +#include "base/str.hh" + +using namespace std; + +int +main(int argc, char *argv[]) +{ + if (argc != 2) { + cout << "Usage: " << argv[0] << " <number>\n"; + exit(1); + } + + string s = argv[1]; + +#define OUTVAL(valtype, type) do { \ + valtype value; \ + cout << "TYPE = " #valtype "\n"; \ + if (to_number(s, value)) { \ + cout << "Number(" << s << ") = " << dec \ + << (unsigned long long)(unsigned type)value << "\n" \ + << "Number(" << s << ") = " << dec \ + << (signed long long)(signed type)value << "\n" \ + << "Number(" << s << ") = 0x" << hex \ + << (unsigned long long)(unsigned type)value << "\n" \ + << "Number(" << s << ") = 0" << oct \ + << (unsigned long long)(unsigned type)value << "\n\n"; \ + } else \ + cout << "Number(" << s << ") is invalid\n\n"; \ + } while (0) + + OUTVAL(signed long long, long long); + OUTVAL(unsigned long long, long long); + OUTVAL(signed long, long); + OUTVAL(unsigned long, long); + OUTVAL(signed int, int); + OUTVAL(unsigned int, int); + OUTVAL(signed short, short); + OUTVAL(unsigned short, short); + OUTVAL(signed char, char); + OUTVAL(unsigned char, char); + + return 0; +} diff --git a/src/unittest/symtest.cc b/src/unittest/symtest.cc new file mode 100644 index 000000000..f0142b923 --- /dev/null +++ b/src/unittest/symtest.cc @@ -0,0 +1,79 @@ +/* + * 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 + */ + +#include <iostream.h> + +#include "base/str.hh" +#include "base/loader/symtab.hh" + +Tick curTick = 0; + +void +usage(const char *progname) +{ + cout << "Usage: " << progname << " <symbol file> <symbol>" << endl; + + exit(1); +} + +int +main(int argc, char *argv[]) +{ + SymbolTable symtab; + + if (argc != 3) + usage(argv[0]); + + if (!symtab.load(argv[1])) { + cout << "could not load symbol file: " << argv[1] << endl; + exit(1); + } + + string symbol = argv[2]; + Addr address; + + if (!to_number(symbol, address)) { + if (!symtab.findAddress(symbol, address)) { + cout << "could not find symbol: " << symbol << endl; + exit(1); + } + + cout << symbol << " -> " << "0x" << hex << address << endl; + } else { + if (!symtab.findSymbol(address, symbol)) { + cout << "could not find address: " << address << endl; + exit(1); + } + + cout << "0x" << hex << address << " -> " << symbol<< endl; + } + + return 0; +} diff --git a/src/unittest/tokentest.cc b/src/unittest/tokentest.cc new file mode 100644 index 000000000..128346b5b --- /dev/null +++ b/src/unittest/tokentest.cc @@ -0,0 +1,83 @@ +/* + * 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 + */ + +#include <iostream> +#include <string> +#include <vector> + +#include "base/str.hh" + +int +main(int argc, char *argv[]) +{ + using namespace std; + + if (argc != 3) { + cout << "Usage: " << argv[0] << " <string> <token>\n"; + exit(1); + } + + int i; + string test = argv[1]; + vector<string> tokens1; + vector<string> tokens2; + char token = argv[2][0]; + + cout << "string = \"" << test << "\", token = \'" << token << "\'\n"; + cout << "testing without ignore\n"; + tokenize(tokens1, test, token, false); + + if (tokens1.size()) { + int size = tokens1.size(); + cout << "size = " << size << "\n"; + for (i = 0; i < size; i++) { + cout << "'" << tokens1[i] << "' (" << tokens1[i].size() + << ")" << ((i == size - 1) ? "\n" : ", "); + } + } else { + cout << "no tokens" << endl; + } + + cout << "testing with ignore\n"; + tokenize(tokens2, test, token, true); + + if (tokens2.size()) { + int size = tokens2.size(); + cout << "size = " << size << "\n"; + for (i = 0; i < size; i++) { + cout << "'" << tokens2[i] << "' (" << tokens2[i].size() + << ")" << ((i == size - 1) ? "\n" : ", "); + } + } else { + cout << "no tokens" << endl; + } + + return 0; +} diff --git a/src/unittest/tracetest.cc b/src/unittest/tracetest.cc new file mode 100644 index 000000000..b1343aac3 --- /dev/null +++ b/src/unittest/tracetest.cc @@ -0,0 +1,56 @@ +/* + * Copyright (c) 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: Nathan Binkert + */ + +#include "sim/host.hh" +#include "base/trace.hh" + +using namespace std; + +Tick curTick = 0; + +struct foo +{ + foo() + { + char foo[9] = "testing"; + DPRINTF(Loader, "%s\n", foo); + } +}; + +int +main() +{ + Trace::flags[Trace::Loader] = true; + Trace::dprintf_stream = &cout; + + foo f; + + return 0; +} diff --git a/test/Makefile b/test/Makefile deleted file mode 100644 index 6fe0e5f48..000000000 --- a/test/Makefile +++ /dev/null @@ -1,69 +0,0 @@ -CC?= gcc -CXX?= g++ -PYTHON?=/usr/bin/env python - -CURDIR?= $(shell /bin/pwd) -SRCDIR?= $(CURDIR)/.. - -CCFLAGS= -g -O0 -MMD -I. -I$(SRCDIR) -I- -DTRACING_ON=0 -MYSQL= -I/usr/include/mysql -L/usr/lib/mysql -lmysqlclient - -VPATH=$(SRCDIR):$(CURDIR) - -default: - @echo "You must specify a target" - -base/traceflags.cc base/traceflags.hh: $(SRCDIR)/base/traceflags.py - mkdir -p base; \ - cd base; \ - $(PYTHON) $< - -bitvectest: test/bitvectest.cc - $(CXX) $(CCFLAGS) -o $@ $^ - -circletest: test/circletest.cc base/circlebuf.cc - $(CXX) $(CCFLAGS) -o $@ $^ - -cprintftest: test/cprintftest.cc base/cprintf.cc - $(CXX) $(CCFLAGS) -o $@ $^ - -initest: test/initest.cc base/str.cc base/inifile.cc base/cprintf.cc - $(CXX) $(CCFLAGS) -o $@ $^ - -lrutest: test/lru_test.cc - $(CXX) $(CCFLAGS) -o $@ $^ - -nmtest: test/nmtest.cc base/output.cc base/hostinfo.cc base/cprintf.cc base/misc.cc base/loader/object_file.cc base/loader/symtab.cc base/misc.cc base/str.cc base/loader/aout_object.cc base/loader/ecoff_object.cc base/loader/elf_object.cc - $(CXX) $(CCFLAGS) -I/n/ziff/z/binkertn/build/work/ALPHA_FS -lelf -o $@ $^ - -offtest: test/offtest.cc - $(CXX) $(CCFLAGS) -o $@ $^ - -rangetest: test/rangetest.cc base/range.cc base/str.cc - $(CXX) $(CCFLAGS) -o $@ $^ - -STATTEST+= base/cprintf.cc base/hostinfo.cc base/misc.cc base/mysql.cc -STATTEST+= base/python.cc base/str.cc base/time.cc -STATTEST+= base/statistics.cc base/stats/mysql.cc base/stats/python.cc -STATTEST+= base/stats/statdb.cc base/stats/text.cc base/stats/visit.cc -STATTEST+= test/stattest.cc -stattest: $(STATTEST) - $(CXX) $(CCFLAGS) $(MYSQL) -o $@ $^ - -strnumtest: test/strnumtest.cc base/str.cc - $(CXX) $(CCFLAGS) -o $@ $^ - -symtest: test/symtest.cc base/misc.cc base/symtab.cc base/str.cc - $(CXX) $(CCFLAGS) -o $@ $^ - -tokentest: test/tokentest.cc base/str.cc - $(CXX) $(CCFLAGS) -o $@ $^ - -TRACE+=test/tracetest.cc base/trace.cc base/trace_flags.cc base/cprintf.cc -TRACE+=base/str.cc base/misc.cc -tracetest: $(TRACE) - $(CXX) $(CCFLAGS) -o $@ $^ - -clean: - @rm -rf *test *~ .#* *.core core base -.PHONY: clean diff --git a/test/bitvectest.cc b/test/bitvectest.cc deleted file mode 100644 index 1b8c332f5..000000000 --- a/test/bitvectest.cc +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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. - */ - -#include <iostream.h> - -#include <vector> - -int -main() -{ - vector<bool> v1(100); - - v1[0] = true; - v1.resize(500); - v1[100] = true; - v1[499] = true; - v1.resize(10000); - v1[9999] = true; - - cout << "v1.size() = " << v1.size() << "\n"; - for (int i = 0; i < v1.size(); i++) - if (v1[i]) - cout << "v1[" << i << "] = " << v1[i] << "\n"; - - cout << "\n"; - - vector<bool> v2 = v1; - - for (int i = 0; i < v2.size(); i++) - if (v2[i]) - cout << "v2[" << i << "] = " << v2[i] << "\n"; - - cout << "v1 " << ((v1 == v2) ? "==" : "!=") << " v2" << "\n"; - v2[8583] = true; - cout << "v1 " << ((v1 == v2) ? "==" : "!=") << " v2" << "\n"; - v1[8583] = true; - cout << "v1 " << ((v1 == v2) ? "==" : "!=") << " v2" << "\n"; - v1.resize(100000); - cout << "v1 " << ((v1 == v2) ? "==" : "!=") << " v2" << "\n"; - cout << flush; -} diff --git a/test/circletest.cc b/test/circletest.cc deleted file mode 100644 index bb15f8c64..000000000 --- a/test/circletest.cc +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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. - */ - -#include <fcntl.h> -#include <iostream.h> -#include <unistd.h> - -#include "base/circlebuf.hh" - -char *strings[] = -{ "This is the first test\n", - "he went with his woman to the store\n", - "the man with the bat hit the woman with the hat\n", - "that that is is that that was\n", - "sue sells sea shells by the sea shore\n", - "go to the store and buy me some milk and bread\n", - "the friendly flight attendants spoke soothingly to the frightened passengers in their native languages\n" -}; - -const int num_strings = sizeof(strings) / sizeof(char *); - -int -main() -{ - CircleBuf buf(1024); - - for (int count = 0; count < 100; count++) - buf.write(strings[count % num_strings]); - buf.read(STDOUT_FILENO); - write(STDOUT_FILENO, "<\n", 2); - - for (int count = 0; count < 100; count++) - buf.write(strings[count % num_strings]); - buf.read(STDOUT_FILENO, 100); - write(STDOUT_FILENO, "<\n", 2); - - buf.flush(); - buf.write("asdfa asdf asd fasdf asdf\n"); - buf.write(""); - buf.write(""); - buf.write(""); - buf.write(""); - buf.write(""); - buf.write(""); - buf.read(STDOUT_FILENO); - write(STDOUT_FILENO, "<\n", 2); -} diff --git a/test/cprintftest.cc b/test/cprintftest.cc deleted file mode 100644 index 611f01bc2..000000000 --- a/test/cprintftest.cc +++ /dev/null @@ -1,164 +0,0 @@ -/* - * 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. - */ - -#include <cstdio> -#include <iostream> -#include <list> -#include <string> -#include <sstream> - -#include "base/cprintf.hh" - -using namespace std; - -int -main() -{ - char foo[9]; - cprintf("%s\n", foo); - - cprintf("%shits%%s + %smisses%%s\n", "test", "test"); - cprintf("%%s%-10s %c he went home \'\"%d %#o %#x %1.5f %1.2E\n", - "hello", 'A', 1, 0xff, 0xfffffffffffffULL, 3.141592653589, 1.1e10); - - cout << cformat("%s %#x %s\n") << "hello" << 0 << "foo 0\n"; - cerr << cformat("%s %#x\n") << "hello" << 1 << "foo 1\n"; - - cprintf("another test\n"); - - stringstream buffer; - ccprintf(buffer, "%-10s %c he home \'\"%d %#o %#x %1.5f %1.2E\n", - "hello", 'A', 1, 0xff, 0xfffffffffffffULL, 3.14159265, 1.1e10); - - double f = 314159.26535897932384; - - #define ctest(x, y) printf(x, y); cprintf(x, y); cprintf("\n"); - ctest("%1.8f\n", f); - ctest("%2.8f\n", f); - ctest("%3.8f\n", f); - ctest("%4.8f\n", f); - ctest("%5.8f\n", f); - ctest("%6.8f\n", f); - ctest("%12.8f\n", f); - ctest("%1000.8f\n", f); - ctest("%1.0f\n", f); - ctest("%1.1f\n", f); - ctest("%1.2f\n", f); - ctest("%1.3f\n", f); - ctest("%1.4f\n", f); - ctest("%1.5f\n", f); - ctest("%1.6f\n", f); - ctest("%1.7f\n", f); - ctest("%1.8f\n", f); - ctest("%1.9f\n", f); - ctest("%1.10f\n", f); - ctest("%1.11f\n", f); - ctest("%1.12f\n", f); - ctest("%1.13f\n", f); - ctest("%1.14f\n", f); - ctest("%1.15f\n", f); - ctest("%1.16f\n", f); - ctest("%1.17f\n", f); - ctest("%1.18f\n", f); - - cout << "foo\n"; - - f = 0.00000026535897932384; - ctest("%1.8f\n", f); - ctest("%2.8f\n", f); - ctest("%3.8f\n", f); - ctest("%4.8f\n", f); - ctest("%5.8f\n", f); - ctest("%6.8f\n", f); - ctest("%12.8f\n", f); - ctest("%1.0f\n", f); - ctest("%1.1f\n", f); - ctest("%1.2f\n", f); - ctest("%1.3f\n", f); - ctest("%1.4f\n", f); - ctest("%1.5f\n", f); - ctest("%1.6f\n", f); - ctest("%1.7f\n", f); - ctest("%1.8f\n", f); - ctest("%1.9f\n", f); - ctest("%1.10f\n", f); - ctest("%1.11f\n", f); - ctest("%1.12f\n", f); - ctest("%1.13f\n", f); - ctest("%1.14f\n", f); - ctest("%1.15f\n", f); - ctest("%1.16f\n", f); - ctest("%1.17f\n", f); - ctest("%1.18f\n", f); - - f = 0.00000026535897932384; - ctest("%1.8e\n", f); - ctest("%2.8e\n", f); - ctest("%3.8e\n", f); - ctest("%4.8e\n", f); - ctest("%5.8e\n", f); - ctest("%6.8e\n", f); - ctest("%12.8e\n", f); - ctest("%1.0e\n", f); - ctest("%1.1e\n", f); - ctest("%1.2e\n", f); - ctest("%1.3e\n", f); - ctest("%1.4e\n", f); - ctest("%1.5e\n", f); - ctest("%1.6e\n", f); - ctest("%1.7e\n", f); - ctest("%1.8e\n", f); - ctest("%1.9e\n", f); - ctest("%1.10e\n", f); - ctest("%1.11e\n", f); - ctest("%1.12e\n", f); - ctest("%1.13e\n", f); - ctest("%1.14e\n", f); - ctest("%1.15e\n", f); - ctest("%1.16e\n", f); - ctest("%1.17e\n", f); - ctest("%1.18e\n", f); - - cout << buffer.str(); - - cout.width(0); - cout.precision(1); - cout << f << "\n"; - - string foo1 = "string test"; - cprintf("%s\n", foo1); - - stringstream foo2; - foo2 << "stringstream test"; - cprintf("%s\n", foo2); - - cprintf("%c %c\n", 'c', 65); - - cout << '9'; - return 0; -} diff --git a/test/genini.py b/test/genini.py deleted file mode 100755 index 2af81fe2b..000000000 --- a/test/genini.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 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. - -import getopt, os, os.path, sys -from os.path import join as joinpath, realpath - -mypath = sys.path[0] -sys.path.append(joinpath(mypath, '..')) -sys.path.append(joinpath(mypath, '../python')) -sys.path.append(joinpath(mypath, '../util/pbs')) - -pathlist = [ '.' ] - -m5_build_env = {} - -try: - opts, args = getopt.getopt(sys.argv[1:], '-E:I:') - for opt,arg in opts: - if opt == '-E': - offset = arg.find('=') - if offset == -1: - name = arg - value = 'True' - else: - name = arg[:offset] - value = arg[offset+1:] - os.environ[name] = value - m5_build_env[name] = value - if opt == '-I': - pathlist.append(arg) -except getopt.GetoptError: - sys.exit('Improper Usage') - -import __main__ -__main__.m5_build_env = m5_build_env - -from m5 import * - -for path in pathlist: - AddToPath(path) - -for arg in args: - m5execfile(arg, globals()) - -if globals().has_key('root') and isinstance(root, Root): - instantiate(root) -else: - print "Instantiation skipped: no root object found." diff --git a/test/initest.cc b/test/initest.cc deleted file mode 100644 index 0c5ac2343..000000000 --- a/test/initest.cc +++ /dev/null @@ -1,142 +0,0 @@ -/* - * 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. - */ - -#include <iostream> -#include <fstream> -#include <string> -#include <vector> - -#include "base/inifile.hh" -#include "base/cprintf.hh" - -using namespace std; - -char *progname; - -void -usage() -{ - cout << "Usage: " << progname << " <ini file>\n"; - exit(1); -} - -#if 0 -char *defines = getenv("CONFIG_DEFINES"); -if (defines) { - char *c = defines; - while ((c = strchr(c, ' ')) != NULL) { - *c++ = '\0'; - count++; - } - count++; -} - -#endif - -int -main(int argc, char *argv[]) -{ - IniFile simConfigDB; - - progname = argv[0]; - - vector<char *> cppArgs; - - vector<char *> cpp_options; - cpp_options.reserve(argc * 2); - - for (int i = 1; i < argc; ++i) { - char *arg_str = argv[i]; - - // if arg starts with '-', parse as option, - // else treat it as a configuration file name and load it - if (arg_str[0] == '-') { - - // switch on second char - switch (arg_str[1]) { - case 'D': - case 'U': - case 'I': - // cpp options: record & pass to cpp. Note that these - // cannot have spaces, i.e., '-Dname=val' is OK, but - // '-D name=val' is not. I don't consider this a - // problem, since even though gnu cpp accepts the - // latter, other cpp implementations do not (Tru64, - // for one). - cppArgs.push_back(arg_str); - break; - - case '-': - // command-line configuration parameter: - // '--<section>:<parameter>=<value>' - - if (!simConfigDB.add(arg_str + 2)) { - // parse error - ccprintf(cerr, - "Could not parse configuration argument '%s'\n" - "Expecting --<section>:<parameter>=<value>\n", - arg_str); - exit(0); - } - break; - - default: - usage(); - } - } - else { - // no '-', treat as config file name - - if (!simConfigDB.loadCPP(arg_str, cppArgs)) { - cprintf("Error processing file %s\n", arg_str); - exit(1); - } - } - } - - string value; - -#define FIND(C, E) \ - if (simConfigDB.find(C, E, value)) \ - cout << ">" << value << "<\n"; \ - else \ - cout << "Not Found!\n" - - FIND("General", "Test2"); - FIND("Junk", "Test3"); - FIND("Junk", "Test4"); - FIND("General", "Test1"); - FIND("Junk2", "test3"); - FIND("General", "Test3"); - - cout << "\n"; - - simConfigDB.dump(); - - return 0; -} diff --git a/test/lru_test.cc b/test/lru_test.cc deleted file mode 100644 index 2829163de..000000000 --- a/test/lru_test.cc +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include <iostream> -#include "bhgp.hh" - -int main(void) -{ - typedef AssociativeTable<unsigned int, unsigned int> tableType; - tableType table(10, 4); // 40 entry table - - std::cout << "Initial state:" << std::endl; - table.dump(); - - std::cout << "Inserting (2, 1)" << std::endl; - table[2] = 1; - table.dump(); - - std::cout << "Inserting (5, 2)" << std::endl; - table[5] = 2; - table.dump(); - - std::cout << "Inserting (10 + 2, 3)" << std::endl; - table[10 + 2] = 3; - table.dump(); - - tableType::const_iterator i = table.find(2); - assert(i != table.end()); - std::cout << "Accessed 2: " << *i << std::endl; - table.dump(); - - i = table.find(10 + 2); - assert(i != table.end()); - std::cout << "Accessed 10 + 2: " << *i << std::endl; - table.dump(); - - i = table.find(34); - assert(i == table.end()); - - std::cout << "Inserting (2 * 10 + 2, 4)" << std::endl; - table[2 * 10 + 2] = 4; - table.dump(); - - std::cout << "Replacing (10 + 2) with 5" << std::endl; - table[10 + 2] = 5; - table.dump(); - - std::cout << "Inserting (3 * 10 + 2, 6)" << std::endl; - table[3 * 10 + 2] = 6; - table.dump(); - - std::cout << "Inserting (4 * 10 + 2, 7)" << std::endl; - table[4 * 10 + 2] = 7; - table.dump(); - - return(0); -} diff --git a/test/nmtest.cc b/test/nmtest.cc deleted file mode 100644 index e9c20d19d..000000000 --- a/test/nmtest.cc +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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. - */ - -#include <iostream> -#include <string> -#include <vector> - -#include "base/loader/object_file.hh" -#include "base/loader/symtab.hh" -#include "base/misc.hh" -#include "base/str.hh" - -using namespace std; -Tick curTick; - -ostream *outputStream = &cout; - -int -main(int argc, char *argv[]) -{ - if (argc != 2 && argc != 3) - panic("usage: %s <filename> <symbol>\n", argv[0]); - - ObjectFile *obj = createObjectFile(argv[1]); - if (!obj) - panic("file not found\n"); - - SymbolTable symtab; - obj->loadGlobalSymbols(&symtab); - obj->loadLocalSymbols(&symtab); - - if (argc == 2) { - SymbolTable::ATable::const_iterator i = symtab.getAddrTable().begin(); - SymbolTable::ATable::const_iterator end = symtab.getAddrTable().end(); - while (i != end) { - cprintf("%#x %s\n", i->first, i->second); - ++i; - } - } else { - string symbol = argv[2]; - Addr address; - - if (symbol[0] == '0' && symbol[1] == 'x') { - if (to_number(symbol, address) && - symtab.findSymbol(address, symbol)) - cprintf("address = %#x, symbol = %s\n", address, symbol); - else - cprintf("address = %#x was not found\n", address); - } else { - if (symtab.findAddress(symbol, address)) - cprintf("symbol = %s address = %#x\n", symbol, address); - else - cprintf("symbol = %s was not found\n", symbol); - } - } - - return 0; -} diff --git a/test/offtest.cc b/test/offtest.cc deleted file mode 100644 index d3f035b73..000000000 --- a/test/offtest.cc +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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. - */ - -#include <sys/types.h> -#include <stddef.h> -#include <stdio.h> -#include "dev/pcireg.h" - -int -main() -{ -#define POFFSET(x) \ - printf("offsetof(PCIConfig, hdr."#x") = %d\n", \ - offsetof(PCIConfig, hdr.x)) - - POFFSET(vendor); - POFFSET(device); - POFFSET(command); - POFFSET(status); - POFFSET(revision); - POFFSET(progIF); - POFFSET(subClassCode); - POFFSET(classCode); - POFFSET(cacheLineSize); - POFFSET(latencyTimer); - POFFSET(headerType); - POFFSET(bist); - POFFSET(pci0.baseAddr0); - POFFSET(pci0.baseAddr1); - POFFSET(pci0.baseAddr2); - POFFSET(pci0.baseAddr3); - POFFSET(pci0.baseAddr4); - POFFSET(pci0.baseAddr5); - POFFSET(pci0.cardbusCIS); - POFFSET(pci0.subsystemVendorID); - POFFSET(pci0.expansionROM); - POFFSET(pci0.reserved0); - POFFSET(pci0.reserved1); - POFFSET(pci0.interruptLine); - POFFSET(pci0.interruptPin); - POFFSET(pci0.minimumGrant); - POFFSET(pci0.minimumLatency); - - return 0; -} diff --git a/test/paramtest.cc b/test/paramtest.cc deleted file mode 100644 index cb31c49d5..000000000 --- a/test/paramtest.cc +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 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. - */ - -// -// This file is not part of the regular simulator. It is solely for -// testing the parameter code. Edit the Makefile to add param_test.cc -// to the sources list, then use configs/test.ini as the configuration -// file. -// -#include "sim/sim_object.hh" -#include "mem/cache/cache.hh" - -class ParamTest : public SimObject -{ - public: - ParamTest(string name) - : SimObject(name) - { - } - - virtual ~ParamTest() {} -}; - -enum Enum1Type { Enum0 }; -enum Enum2Type { Enum10 }; - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(ParamTest) - - Param<int> intparam; - VectorParam<int> vecint; - Param<string> stringparam; - VectorParam<string> vecstring; - Param<bool> boolparam; - VectorParam<bool> vecbool; - SimObjectParam<BaseMemory *> memobj; - SimObjectVectorParam<BaseMemory *> vecmemobj; - SimpleEnumParam<Enum1Type> enum1; - MappedEnumParam<Enum2Type> enum2; - SimpleEnumVectorParam<Enum1Type> vecenum1; - MappedEnumVectorParam<Enum2Type> vecenum2; - -END_DECLARE_SIM_OBJECT_PARAMS(ParamTest) - -const char *enum1_strings[] = -{ - "zero", "one", "two", "three" -}; - -const EnumParamMap enum2_map[] = -{ - { "ten", 10 }, - { "twenty", 20 }, - { "thirty", 30 }, - { "forty", 40 } -}; - -BEGIN_INIT_SIM_OBJECT_PARAMS(ParamTest) - - INIT_PARAM(intparam, "intparam"), - INIT_PARAM(vecint, "vecint"), - INIT_PARAM(stringparam, "stringparam"), - INIT_PARAM(vecstring, "vecstring"), - INIT_PARAM(boolparam, "boolparam"), - INIT_PARAM(vecbool, "vecbool"), - INIT_PARAM(memobj, "memobj"), - INIT_PARAM(vecmemobj, "vecmemobj"), - INIT_ENUM_PARAM(enum1, "enum1", enum1_strings), - INIT_ENUM_PARAM(enum2, "enum2", enum2_map), - INIT_ENUM_PARAM(vecenum1, "vecenum1", enum1_strings), - INIT_ENUM_PARAM(vecenum2, "vecenum2", enum2_map) - -END_INIT_SIM_OBJECT_PARAMS(ParamTest) - - -CREATE_SIM_OBJECT(ParamTest) -{ - return new ParamTest(getInstanceName()); -} - -REGISTER_SIM_OBJECT("ParamTest", ParamTest) diff --git a/test/rangetest.cc b/test/rangetest.cc deleted file mode 100644 index 41d438f48..000000000 --- a/test/rangetest.cc +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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. - */ - -#include <iostream> -#include <string> - -#include "base/range.hh" - -using namespace std; - -int -main() -{ - Range<int> r1(make_pair(9, 28)); - Range<unsigned> r2("0x1000:+0x100"); - - cout << r1 << "\n" - << r2 << "\n"; - -#define RANGETEST(X, C, Y) \ - cout << X << " "#C" " << Y << " => " << ((X C Y) ? "true" : "false") << "\n" - -#define TESTEM(X, Y) do { \ - RANGETEST(X, < , Y); \ - RANGETEST(X, <=, Y); \ - RANGETEST(X, > , Y); \ - RANGETEST(X, >=, Y); \ - RANGETEST(X, ==, Y); \ - RANGETEST(X, !=, Y); \ - RANGETEST(Y, < , X); \ - RANGETEST(Y, <=, X); \ - RANGETEST(Y, > , X); \ - RANGETEST(Y, >=, X); \ - RANGETEST(Y, ==, X); \ - RANGETEST(Y, !=, X); \ -} while (0) - - TESTEM(8, r1); - TESTEM(9, r1); - TESTEM(27, r1); - TESTEM(28, r1); - - TESTEM(0x0fff, r2); - TESTEM(0x1000, r2); - TESTEM(0x10ff, r2); - TESTEM(0x1100, r2); - - return 0; -} diff --git a/test/sized_test.cc b/test/sized_test.cc deleted file mode 100644 index 86cd13e5b..000000000 --- a/test/sized_test.cc +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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. - */ - -#include <iostream> -#include <algorithm> - -#include "sized.hh" -#include <queue> -#include <typeinfo> - -template<typename C> -void print(C &cont) -{ - std::cout << std::endl; - std::cout << "Printing " << typeid(cont).name() << std::endl; - while (!cont.empty()) { - std::cout << cont.front() << " "; - cont.pop(); - } - std::cout << std::endl; -} - -int main(void) -{ - sized<std::queue<int>, sized_error_policy<std::queue<int> > > - error_queue(10); - sized<std::queue<int>, sized_drop_policy<std::queue<int> > > - drop_queue(5); - - for (int i = 0; i < 10; ++i) { - error_queue.push(i); - } - - for (int i = 0; i < 3; ++i) { - drop_queue.push(i); - } - - print(error_queue); - print(drop_queue); - - return(0); -} diff --git a/test/stattest.cc b/test/stattest.cc deleted file mode 100644 index 468cdc5ba..000000000 --- a/test/stattest.cc +++ /dev/null @@ -1,554 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include <iomanip> -#include <iostream> -#include <fstream> -#include <string> -#include <unistd.h> - -#include "base/cprintf.hh" -#include "base/misc.hh" -#include "base/statistics.hh" -#include "base/stats/text.hh" -#include "base/stats/mysql.hh" -#include "sim/host.hh" - -using namespace std; -using namespace Stats; - -Tick curTick = 0; -Tick ticksPerSecond = ULL(2000000000); - -Scalar<> s1; -Scalar<> s2; -Average<> s3; -Scalar<> s4; -Vector<> s5; -Distribution<> s6; -Vector<> s7; -AverageVector<> s8; -StandardDeviation<> s9; -AverageDeviation<> s10; -Scalar<> s11; -Distribution<> s12; -VectorDistribution<> s13; -VectorStandardDeviation<> s14; -VectorAverageDeviation<> s15; -Vector2d<> s16; - -Formula f1; -Formula f2; -Formula f3; -Value f4; -Value f5; -Formula f6; -Formula f7; - -ostream *outputStream = &cout; - -double -testfunc() -{ - return 9.8; -} - -class TestClass { - public: - double operator()() { return 9.7; } -}; - -char *progname = ""; - -void -usage() -{ - panic("incorrect usage.\n" - "usage:\n" - "\t%s [-t [-c] [-d]]\n", progname); -} - -int -main(int argc, char *argv[]) -{ - bool descriptions = false; - bool compat = false; - bool text = false; - string mysql_name; - string mysql_host; - string mysql_user = "binkertn"; - string mysql_passwd; - - char c; - progname = argv[0]; - while ((c = getopt(argc, argv, "cdh:P:p:s:tu:")) != -1) { - switch (c) { - case 'c': - compat = true; - break; - case 'd': - descriptions = true; - break; - case 'h': - mysql_host = optarg; - break; - case 'P': - mysql_passwd = optarg; - break; - case 's': - mysql_name = optarg; - break; - case 't': - text = true; - break; - case 'u': - mysql_user = optarg; - break; - default: - usage(); - } - } - - if (!text && (compat || descriptions)) - usage(); - - s5.init(5); - s6.init(1, 100, 13); - s7.init(7); - s8.init(10); - s12.init(1, 100, 13); - s13.init(4, 0, 99, 10); - s14.init(9); - s15.init(10); - s16.init(2, 9); - - s1 - .name("Stat01") - .desc("this is statistic 1") - ; - - s2 - .name("Stat02") - .desc("this is statistic 2") - .prereq(s11) - ; - - s3 - .name("Stat03") - .desc("this is statistic 3") - .prereq(f7) - ; - - s4 - .name("Stat04") - .desc("this is statistic 4") - .prereq(s11) - ; - - s5 - .name("Stat05") - .desc("this is statistic 5") - .prereq(s11) - .subname(0, "foo1") - .subname(1, "foo2") - .subname(2, "foo3") - .subname(3, "foo4") - .subname(4, "foo5") - ; - - s6 - .name("Stat06") - .desc("this is statistic 6") - .prereq(s11) - ; - - s7 - .name("Stat07") - .desc("this is statistic 7") - .precision(1) - .flags(pdf | total) - .prereq(s11) - ; - - s8 - .name("Stat08") - .desc("this is statistic 8") - .precision(2) - .prereq(s11) - .subname(4, "blarg") - ; - - s9 - .name("Stat09") - .desc("this is statistic 9") - .precision(4) - .prereq(s11) - ; - - s10 - .name("Stat10") - .desc("this is statistic 10") - .prereq(s11) - ; - - s12 - .name("Stat12") - .desc("this is statistic 12") - ; - - s13 - .name("Stat13") - .desc("this is statistic 13") - ; - - s14 - .name("Stat14") - .desc("this is statistic 14") - ; - - s15 - .name("Stat15") - .desc("this is statistic 15") - ; - - s16 - .name("Stat16") - .desc("this is statistic 16") - .flags(total) - .subname(0, "sub0") - .subname(1, "sub1") - .ysubname(0, "y0") - .ysubname(1, "y1") - ; - - f1 - .name("Formula1") - .desc("this is formula 1") - .prereq(s11) - ; - - f2 - .name("Formula2") - .desc("this is formula 2") - .prereq(s11) - .precision(1) - ; - - f3 - .name("Formula3") - .desc("this is formula 3") - .prereq(s11) - .subname(0, "bar1") - .subname(1, "bar2") - .subname(2, "bar3") - .subname(3, "bar4") - .subname(4, "bar5") - ; - - f4 - .functor(testfunc) - .name("Formula4") - .desc("this is formula 4") - ; - - TestClass testclass; - f5 - .functor(testclass) - .name("Formula5") - .desc("this is formula 5") - ; - - f6 - .name("Formula6") - .desc("this is formula 6") - ; - - f1 = s1 + s2; - f2 = (-s1) / (-s2) * (-s3 + ULL(100) + s4); - f3 = sum(s5) * s7; - f6 += constant(10.0); - f6 += s5[3]; - f7 = constant(1); - - check(); - reset(); - - s16[1][0] = 1; - s16[0][1] = 3; - s16[0][0] = 2; - s16[1][1] = 9; - s16[1][1] += 9; - s16[1][8] += 8; - s16[1][7] += 7; - s16[1][6] += 6; - s16[1][5] += 5; - s16[1][4] += 4; - - s11 = 1; - s3 = 9; - s8[3] = 9; - s15[0].sample(1234); - s15[1].sample(1234); - s15[2].sample(1234); - s15[3].sample(1234); - s15[4].sample(1234); - s15[5].sample(1234); - s15[6].sample(1234); - s15[7].sample(1234); - s15[8].sample(1234); - s15[9].sample(1234); - - s10.sample(1000000000); - curTick += ULL(1000000); - s10.sample(100000); - s10.sample(100000); - s10.sample(100000); - s10.sample(100000); - s10.sample(100000); - s10.sample(100000); - s10.sample(100000); - s10.sample(100000); - s10.sample(100000); - s10.sample(100000); - s10.sample(100000); - s10.sample(100000); - s10.sample(100000); - s13[0].sample(12); - s13[1].sample(29); - s13[2].sample(12); - s13[3].sample(29); - s13[0].sample(42); - s13[1].sample(29); - s13[2].sample(42); - s13[3].sample(32); - s13[0].sample(52); - s13[1].sample(49); - s13[2].sample(42); - s13[3].sample(25); - s13[0].sample(32); - s13[1].sample(49); - s13[2].sample(22); - s13[3].sample(49); - s13[0].sample(62); - s13[1].sample(99); - s13[2].sample(72); - s13[3].sample(23); - s13[0].sample(52); - s13[1].sample(78); - s13[2].sample(69); - s13[3].sample(49); - - s14[0].sample(1234); - s14[1].sample(4134); - s14[4].sample(1213); - s14[3].sample(1124); - s14[2].sample(1243); - s14[7].sample(1244); - s14[4].sample(7234); - s14[2].sample(9234); - s14[3].sample(1764); - s14[7].sample(1564); - s14[3].sample(3234); - s14[1].sample(2234); - s14[5].sample(1234); - s14[2].sample(4334); - s14[2].sample(1234); - s14[4].sample(4334); - s14[6].sample(1234); - s14[8].sample(8734); - s14[1].sample(5234); - s14[3].sample(8234); - s14[7].sample(5234); - s14[4].sample(4434); - s14[3].sample(7234); - s14[2].sample(1934); - s14[1].sample(9234); - s14[5].sample(5634); - s14[3].sample(1264); - s14[7].sample(5223); - s14[0].sample(1234); - s14[0].sample(5434); - s14[3].sample(8634); - s14[1].sample(1234); - - - s15[0].sample(1234); - s15[1].sample(4134); - curTick += ULL(1000000); - s15[4].sample(1213); - curTick += ULL(1000000); - s15[3].sample(1124); - curTick += ULL(1000000); - s15[2].sample(1243); - curTick += ULL(1000000); - s15[7].sample(1244); - curTick += ULL(1000000); - s15[4].sample(7234); - s15[2].sample(9234); - s15[3].sample(1764); - s15[7].sample(1564); - s15[3].sample(3234); - s15[1].sample(2234); - curTick += ULL(1000000); - s15[5].sample(1234); - curTick += ULL(1000000); - s15[9].sample(4334); - curTick += ULL(1000000); - s15[2].sample(1234); - curTick += ULL(1000000); - s15[4].sample(4334); - s15[6].sample(1234); - curTick += ULL(1000000); - s15[8].sample(8734); - curTick += ULL(1000000); - s15[1].sample(5234); - curTick += ULL(1000000); - s15[3].sample(8234); - curTick += ULL(1000000); - s15[7].sample(5234); - s15[4].sample(4434); - s15[3].sample(7234); - s15[2].sample(1934); - s15[1].sample(9234); - curTick += ULL(1000000); - s15[5].sample(5634); - s15[3].sample(1264); - s15[7].sample(5223); - s15[0].sample(1234); - s15[0].sample(5434); - s15[3].sample(8634); - curTick += ULL(1000000); - s15[1].sample(1234); - - s4 = curTick; - - s8[3] = 99999; - - s3 = 12; - s3++; - curTick += 9; - - s1 = 9; - s1 += 9; - s1 -= 11; - s1++; - ++s1; - s1--; - --s1; - - s2 = 9; - - s5[0] += 1; - s5[1] += 2; - s5[2] += 3; - s5[3] += 4; - s5[4] += 5; - - s7[0] = 10; - s7[1] = 20; - s7[2] = 30; - s7[3] = 40; - s7[4] = 50; - s7[5] = 60; - s7[6] = 70; - - s6.sample(0); - s6.sample(1); - s6.sample(2); - s6.sample(3); - s6.sample(4); - s6.sample(5); - s6.sample(6); - s6.sample(7); - s6.sample(8); - s6.sample(9); - - s6.sample(10); - s6.sample(10); - s6.sample(10); - s6.sample(10); - s6.sample(10); - s6.sample(10); - s6.sample(10); - s6.sample(10); - s6.sample(11); - s6.sample(19); - s6.sample(20); - s6.sample(20); - s6.sample(21); - s6.sample(21); - s6.sample(31); - s6.sample(98); - s6.sample(99); - s6.sample(99); - s6.sample(99); - - s7[0] = 700; - s7[1] = 600; - s7[2] = 500; - s7[3] = 400; - s7[4] = 300; - s7[5] = 200; - s7[6] = 100; - - s9.sample(100); - s9.sample(100); - s9.sample(100); - s9.sample(100); - s9.sample(10); - s9.sample(10); - s9.sample(10); - s9.sample(10); - s9.sample(10); - - curTick += 9; - s4 = curTick; - s6.sample(100); - s6.sample(100); - s6.sample(100); - s6.sample(101); - s6.sample(102); - - s12.sample(100); - - if (text) { - Text out(cout); - out.descriptions = descriptions; - out.compat = compat; - out(); - } - - if (!mysql_name.empty()) { - MySql out; - out.connect(mysql_host, mysql_user, mysql_passwd, "m5stats", - mysql_name, "test"); - out(); - } - - return 0; -} diff --git a/test/strnumtest.cc b/test/strnumtest.cc deleted file mode 100644 index a80dd7c36..000000000 --- a/test/strnumtest.cc +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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. - */ - -#include <iostream.h> - -#include <string> -#include <vector> - -#include "base/str.hh" - -using namespace std; - -int -main(int argc, char *argv[]) -{ - if (argc != 2) { - cout << "Usage: " << argv[0] << " <number>\n"; - exit(1); - } - - string s = argv[1]; - -#define OUTVAL(valtype, type) do { \ - valtype value; \ - cout << "TYPE = " #valtype "\n"; \ - if (to_number(s, value)) { \ - cout << "Number(" << s << ") = " << dec \ - << (unsigned long long)(unsigned type)value << "\n" \ - << "Number(" << s << ") = " << dec \ - << (signed long long)(signed type)value << "\n" \ - << "Number(" << s << ") = 0x" << hex \ - << (unsigned long long)(unsigned type)value << "\n" \ - << "Number(" << s << ") = 0" << oct \ - << (unsigned long long)(unsigned type)value << "\n\n"; \ - } else \ - cout << "Number(" << s << ") is invalid\n\n"; \ - } while (0) - - OUTVAL(signed long long, long long); - OUTVAL(unsigned long long, long long); - OUTVAL(signed long, long); - OUTVAL(unsigned long, long); - OUTVAL(signed int, int); - OUTVAL(unsigned int, int); - OUTVAL(signed short, short); - OUTVAL(unsigned short, short); - OUTVAL(signed char, char); - OUTVAL(unsigned char, char); - - return 0; -} diff --git a/test/symtest.cc b/test/symtest.cc deleted file mode 100644 index 5fba71736..000000000 --- a/test/symtest.cc +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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. - */ - -#include <iostream.h> - -#include "base/str.hh" -#include "base/loader/symtab.hh" - -Tick curTick = 0; - -void -usage(const char *progname) -{ - cout << "Usage: " << progname << " <symbol file> <symbol>" << endl; - - exit(1); -} - -int -main(int argc, char *argv[]) -{ - SymbolTable symtab; - - if (argc != 3) - usage(argv[0]); - - if (!symtab.load(argv[1])) { - cout << "could not load symbol file: " << argv[1] << endl; - exit(1); - } - - string symbol = argv[2]; - Addr address; - - if (!to_number(symbol, address)) { - if (!symtab.findAddress(symbol, address)) { - cout << "could not find symbol: " << symbol << endl; - exit(1); - } - - cout << symbol << " -> " << "0x" << hex << address << endl; - } else { - if (!symtab.findSymbol(address, symbol)) { - cout << "could not find address: " << address << endl; - exit(1); - } - - cout << "0x" << hex << address << " -> " << symbol<< endl; - } - - return 0; -} diff --git a/test/tokentest.cc b/test/tokentest.cc deleted file mode 100644 index 7f27d58fe..000000000 --- a/test/tokentest.cc +++ /dev/null @@ -1,81 +0,0 @@ -/* - * 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. - */ - -#include <iostream> -#include <string> -#include <vector> - -#include "base/str.hh" - -int -main(int argc, char *argv[]) -{ - using namespace std; - - if (argc != 3) { - cout << "Usage: " << argv[0] << " <string> <token>\n"; - exit(1); - } - - int i; - string test = argv[1]; - vector<string> tokens1; - vector<string> tokens2; - char token = argv[2][0]; - - cout << "string = \"" << test << "\", token = \'" << token << "\'\n"; - cout << "testing without ignore\n"; - tokenize(tokens1, test, token, false); - - if (tokens1.size()) { - int size = tokens1.size(); - cout << "size = " << size << "\n"; - for (i = 0; i < size; i++) { - cout << "'" << tokens1[i] << "' (" << tokens1[i].size() - << ")" << ((i == size - 1) ? "\n" : ", "); - } - } else { - cout << "no tokens" << endl; - } - - cout << "testing with ignore\n"; - tokenize(tokens2, test, token, true); - - if (tokens2.size()) { - int size = tokens2.size(); - cout << "size = " << size << "\n"; - for (i = 0; i < size; i++) { - cout << "'" << tokens2[i] << "' (" << tokens2[i].size() - << ")" << ((i == size - 1) ? "\n" : ", "); - } - } else { - cout << "no tokens" << endl; - } - - return 0; -} diff --git a/test/tracetest.cc b/test/tracetest.cc deleted file mode 100644 index 866b67d9b..000000000 --- a/test/tracetest.cc +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include "sim/host.hh" -#include "base/trace.hh" - -using namespace std; - -Tick curTick = 0; - -struct foo -{ - foo() - { - char foo[9] = "testing"; - DPRINTF(Loader, "%s\n", foo); - } -}; - -int -main() -{ - Trace::flags[Trace::Loader] = true; - Trace::dprintf_stream = &cout; - - foo f; - - return 0; -} diff --git a/util/ccdrv/devtime.c b/util/ccdrv/devtime.c index 62b0e2592..d8be97bb4 100644 --- a/util/ccdrv/devtime.c +++ b/util/ccdrv/devtime.c @@ -24,6 +24,8 @@ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING 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 <linux/module.h> diff --git a/util/m5/Makefile b/util/m5/Makefile index 518542322..a98092e47 100644 --- a/util/m5/Makefile +++ b/util/m5/Makefile @@ -23,6 +23,9 @@ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING 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 +# Ali Saidi ### If we are not compiling on an alpha, we must use cross tools ### ifneq ($(shell uname -m), alpha) diff --git a/util/m5/m5.c b/util/m5/m5.c index 6fdbc0500..c9d7d5a47 100644 --- a/util/m5/m5.c +++ b/util/m5/m5.c @@ -24,6 +24,8 @@ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING 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 */ #include <inttypes.h> diff --git a/util/m5/m5op.S b/util/m5/m5op.S index a53c45277..a55532c90 100644 --- a/util/m5/m5op.S +++ b/util/m5/m5op.S @@ -24,6 +24,9 @@ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING 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 + * Ali Saidi */ #define m5_op 0x01 diff --git a/util/m5/m5op.h b/util/m5/m5op.h index 34ac7760d..f96c5097a 100644 --- a/util/m5/m5op.h +++ b/util/m5/m5op.h @@ -24,6 +24,9 @@ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING 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 + * Ali Saidi */ #ifndef __M5OP_H__ diff --git a/util/oprofile-top.py b/util/oprofile-top.py index c6e35344c..aea9dfadd 100755 --- a/util/oprofile-top.py +++ b/util/oprofile-top.py @@ -25,6 +25,9 @@ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING 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 +# Nathan Binkert # Parse sampled function profile output (quick hack). @@ -25,6 +25,8 @@ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING 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 sys import os @@ -179,10 +181,10 @@ try: if output_dir: secs_waited = 0 - while not shell.dir_exists(output_dir) and secs_waited < 45: + while not shell.dir_exists(output_dir) and secs_waited < 90: time.sleep(5) secs_waited += 5 - if secs_waited > 10: + if secs_waited > 30: print "waited", secs_waited, "seconds for", output_dir # run command diff --git a/util/rundiff b/util/rundiff index 9376e4b9e..533f448b1 100755 --- a/util/rundiff +++ b/util/rundiff @@ -25,6 +25,9 @@ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING 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 +# Steve Reinhardt # Diff two streams. # diff --git a/util/stats/db.py b/util/stats/db.py index 9d876e97f..e1198d438 100644 --- a/util/stats/db.py +++ b/util/stats/db.py @@ -23,6 +23,8 @@ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING 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 import MySQLdb, re, string diff --git a/util/stats/dbinit.py b/util/stats/dbinit.py index 203582478..036941675 100644 --- a/util/stats/dbinit.py +++ b/util/stats/dbinit.py @@ -23,6 +23,8 @@ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING 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 import MySQLdb diff --git a/util/stats/display.py b/util/stats/display.py index fbcff5c70..cb825f493 100644 --- a/util/stats/display.py +++ b/util/stats/display.py @@ -23,6 +23,8 @@ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING 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 class Value: def __init__(self, value, precision, percent = False): diff --git a/util/stats/info.py b/util/stats/info.py index c1e18bb3f..193159b4c 100644 --- a/util/stats/info.py +++ b/util/stats/info.py @@ -23,6 +23,8 @@ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING 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 __future__ import division import operator, re, types diff --git a/util/stats/orderdict.py b/util/stats/orderdict.py index 816355ae2..3f755d299 100644 --- a/util/stats/orderdict.py +++ b/util/stats/orderdict.py @@ -23,6 +23,8 @@ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING 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 __all__ = [ 'orderdict' ] diff --git a/util/stats/print.py b/util/stats/print.py index 2572fd4e7..1c83fa87d 100644 --- a/util/stats/print.py +++ b/util/stats/print.py @@ -23,6 +23,8 @@ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING 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 all = False descriptions = False diff --git a/util/stats/profile.py b/util/stats/profile.py index f28c5867c..6959e0e34 100644 --- a/util/stats/profile.py +++ b/util/stats/profile.py @@ -23,6 +23,8 @@ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING 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 orderdict import orderdict import output diff --git a/util/stats/stats.py b/util/stats/stats.py index 40ef8ac0f..2aa0d4e0b 100755 --- a/util/stats/stats.py +++ b/util/stats/stats.py @@ -25,6 +25,8 @@ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING 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 __future__ import division import re, sys, math diff --git a/util/tap/tap.cc b/util/tap/tap.cc index f4d0aadf2..b026e0220 100644 --- a/util/tap/tap.cc +++ b/util/tap/tap.cc @@ -24,6 +24,8 @@ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING 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 */ extern "C" { |